public void IncrementalParsingIsSameAsFullParsing_MultipleConcurrentEdits() { int[] FindAllIndexes(string str, string needle) { var result = new List <int>(); var foundIndex = 0; var startSearchAt = 0; while ((foundIndex = str.IndexOf(needle, startSearchAt)) != -1) { result.Add(foundIndex); startSearchAt = foundIndex + needle.Length; } return(result.ToArray()); } const string AttributeName = "sameLengthAttributeName"; var attrIndexes = FindAllIndexes(Xml2, AttributeName); XmlDocumentSyntax previousDocument = null; for (int i = 1; i <= AttributeName.Length; i++) { var currentText = Xml2; var changes = new List <TextChangeRange>(); // Reconstruct the intermediary attributes for (int j = attrIndexes.Length - 1; j >= 0; j--) { currentText = currentText.Remove(attrIndexes[j], AttributeName.Length); currentText = currentText.Insert(attrIndexes[j], AttributeName.Substring(0, i)); changes.Add(new TextChangeRange(new TextSpan(attrIndexes[j] + i - 1 - j * (AttributeName.Length - i), 0), 1)); } changes.Reverse(); // All changes should map to the same letter Assert.All(changes, c => Assert.Equal(currentText[c.Span.Start], currentText[changes[0].Span.Start])); var full = Parser.ParseText(currentText); var incremental = Parser.ParseIncremental( currentText, changes.ToArray(), previousDocument ); AssertSameNodes(full, incremental); previousDocument = incremental; } }