public async Task CodeContentTrackingAsync() { var fileSize = 10; var filename = inputGenerator.GenerateRandomFile(fileSize, null, true); var expectedContent = TestUtils.GetContent(filename); var openParams = TestUtils.GetOpenFileParams(filename); await SetupAsync(); await rpc.InvokeWithParameterObjectAsync <Task>(Methods.TextDocumentDidOpen.Name, openParams); for (var testRep = 0; testRep < 20; ++testRep) { var edits = inputGenerator.MakeRandomEdits(50, ref expectedContent, fileSize, true); Task[] processing = new Task[edits.Length]; for (var i = 0; i < edits.Length; ++i) { processing[i] = rpc.InvokeWithParameterObjectAsync <Task>(Methods.TextDocumentDidChange.Name, TestUtils.GetChangedFileParams(filename, new[] { edits[i] })); } for (var i = edits.Length - 1; i >= 0; --i) { await processing[i]; } var trackedContent = await this.GetFileContentInMemoryAsync(filename); var expected = Builder.JoinLines(expectedContent.ToArray()); var got = Builder.JoinLines(trackedContent); Assert.IsNotNull(trackedContent); Assert.AreEqual(expectedContent.Count(), trackedContent.Count(), $"expected: \n{expected} \ngot: \n{got}"); Assert.AreEqual(expected, got); } }
internal static void ApplyEdit(TextDocumentContentChangeEvent change, ref List <string> content) { if (!content.Any()) { throw new ArgumentException("the given content has to have at least on line"); } Assert.IsTrue(IsValidRange(change.Range) && change.Text != null); Assert.IsTrue(change.Range.End.Line < content.Count()); Assert.IsTrue(change.Range.Start.Character <= content[change.Range.Start.Line].Length); Assert.IsTrue(change.Range.End.Character <= content[change.Range.End.Line].Length); var(startLine, startChar) = (change.Range.Start.Line, change.Range.Start.Character); var(endLine, endChar) = (change.Range.End.Line, change.Range.End.Character); var newText = string.Concat(content[startLine].Substring(0, startChar), change.Text, content[endLine].Substring(endChar)); if (startLine > 0) { newText = content[--startLine] + newText; } if (endLine + 1 < content.Count) { newText = newText + content[++endLine]; } var lineChanges = Builder.SplitLines(newText); if (lineChanges.Length == 0 || (endLine + 1 == content.Count() && Builder.EndOfLine.Match(lineChanges.Last()).Success)) { lineChanges = lineChanges.Concat(new string[] { string.Empty }).ToArray(); } content.RemoveRange(startLine, endLine - startLine + 1); content.InsertRange(startLine, lineChanges); }
// does not modify range internal static int GetRangeLength(VisualStudio.LanguageServer.Protocol.Range range, IReadOnlyList <string> content) { Assert.IsTrue(Builder.IsValidRange(range)); if (range.Start.Line == range.End.Line) { return(range.End.Character - range.Start.Character); } var changeLength = content[range.Start.Line].Length - range.Start.Character; for (var line = range.Start.Line + 1; line < range.End.Line; ++line) { changeLength += content[line].Length; } return(changeLength + range.End.Character); }
private Range GetRandomRange(IReadOnlyList <string> content) { var(startLine, endLine) = (rnd.Next(0, content.Count), rnd.Next(0, content.Count)); var(startChar, endChar) = (rnd.Next(0, content[startLine].Length + 1), rnd.Next(0, content[endLine].Length + 1)); ((startLine, startChar), (endLine, endChar)) = startLine <= endLine ? ((startLine, startChar), (endLine, endChar)) : ((endLine, endChar), (startLine, startChar)); if (startLine == endLine && startChar > endChar) { (startChar, endChar) = (endChar, startChar); } var range = new Range { Start = new Position(startLine, startChar), End = new Position(endLine, endChar) }; Assert.IsTrue(Builder.IsValidRange(range)); return(range); }
public async Task SaveFileAsync() { var fileSize = 10; var filename = inputGenerator.GenerateRandomFile(fileSize, null); var content = File.ReadAllText(Path.GetFullPath(filename)); await SetupAsync(); // verify that safe notification can be sent immediately after sending the open notification (even if the latter has not yet finished processing) var openFileTask = rpc.InvokeWithParameterObjectAsync <Task>(Methods.TextDocumentDidOpen.Name, TestUtils.GetOpenFileParams(filename)); await rpc.InvokeWithParameterObjectAsync <Task>(Methods.TextDocumentDidSave.Name, TestUtils.GetSaveFileParams(filename, content)); // check that the file content is indeed updated on save, according to the passed parameter var newContent = String.Join(Environment.NewLine, inputGenerator.GetRandomLines(10)); await rpc.InvokeWithParameterObjectAsync <Task>(Methods.TextDocumentDidSave.Name, TestUtils.GetSaveFileParams(filename, newContent)); var trackedContent = await this.GetFileContentInMemoryAsync(filename); Assert.AreEqual(newContent, Builder.JoinLines(trackedContent)); }
public async Task TextContentTrackingAsync() { async Task RunTest(bool emptyLastLine) { var fileSize = 10; var filename = inputGenerator.GenerateRandomFile(fileSize, emptyLastLine, false); var expectedContent = TestUtils.GetContent(filename); var openParams = TestUtils.GetOpenFileParams(filename); await SetupAsync(); await rpc.InvokeWithParameterObjectAsync <Task>(Methods.TextDocumentDidOpen.Name, openParams); // check that the file content is accurately reflected upon opening var trackedContent = await this.GetFileContentInMemoryAsync(filename); var expected = Builder.JoinLines(expectedContent.ToArray()); var got = Builder.JoinLines(trackedContent); Assert.IsNotNull(trackedContent); Assert.AreEqual(expectedContent.Count(), trackedContent.Count(), $"expected: \n{expected} \ngot: \n{got}"); Assert.AreEqual(expected, got); // check whether a single array of changes is processed correctly var edits = inputGenerator.MakeRandomEdits(50, ref expectedContent, fileSize, false); await rpc.InvokeWithParameterObjectAsync <Task>(Methods.TextDocumentDidChange.Name, TestUtils.GetChangedFileParams(filename, edits)); trackedContent = await this.GetFileContentInMemoryAsync(filename); Assert.AreEqual(expectedContent.Count(), trackedContent.Count()); Assert.AreEqual(Builder.JoinLines(expectedContent.ToArray()), Builder.JoinLines(trackedContent)); // check if changes are also processed correctly if many changes (array of length one) are given in rapid succession for (var testRep = 0; testRep < 20; ++testRep) { edits = inputGenerator.MakeRandomEdits(50, ref expectedContent, fileSize, false); Task[] processing = new Task[edits.Length]; for (var i = 0; i < edits.Length; ++i) { processing[i] = rpc.InvokeWithParameterObjectAsync <Task>(Methods.TextDocumentDidChange.Name, TestUtils.GetChangedFileParams(filename, new[] { edits[i] })); } for (var i = edits.Length - 1; i >= 0; --i) { await processing[i]; } trackedContent = await this.GetFileContentInMemoryAsync(filename); expected = Builder.JoinLines(expectedContent.ToArray()); got = Builder.JoinLines(trackedContent); Assert.AreEqual(expectedContent.Count(), trackedContent.Count(), $"expected: \n{expected} \ngot: \n{got}"); Assert.AreEqual(expected, got); } } await RunTest(emptyLastLine : true); await RunTest(emptyLastLine : false); }