Skip to content

Commit c6b0393

Browse files
committed
Add client test for "textDocument/hover".
1 parent d24f464 commit c6b0393

File tree

3 files changed

+158
-5
lines changed

3 files changed

+158
-5
lines changed

src/Client/Processes/NamedPipeServerProcess.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -91,10 +91,10 @@ public override async Task Start()
9191
{
9292
ServerExitCompletion = new TaskCompletionSource<object>();
9393

94-
ServerInputStream = new NamedPipeServerStream(BaseName + "/in", PipeDirection.Out, 2, PipeTransmissionMode.Byte, PipeOptions.Asynchronous, inBufferSize: 1024, outBufferSize: 1024);
95-
ServerOutputStream = new NamedPipeServerStream(BaseName + "/out", PipeDirection.In, 2, PipeTransmissionMode.Byte, PipeOptions.Asynchronous, inBufferSize: 1024, outBufferSize: 1024);
96-
ClientInputStream = new NamedPipeClientStream(".", BaseName + "/out", PipeDirection.Out, PipeOptions.Asynchronous);
97-
ClientOutputStream = new NamedPipeClientStream(".", BaseName + "/in", PipeDirection.In, PipeOptions.Asynchronous);
94+
ServerInputStream = new NamedPipeServerStream(BaseName + "_in", PipeDirection.Out, 2, PipeTransmissionMode.Byte, PipeOptions.Asynchronous, inBufferSize: 1024, outBufferSize: 1024);
95+
ServerOutputStream = new NamedPipeServerStream(BaseName + "_out", PipeDirection.In, 2, PipeTransmissionMode.Byte, PipeOptions.Asynchronous, inBufferSize: 1024, outBufferSize: 1024);
96+
ClientInputStream = new NamedPipeClientStream(".", BaseName + "_out", PipeDirection.Out, PipeOptions.Asynchronous);
97+
ClientOutputStream = new NamedPipeClientStream(".", BaseName + "_in", PipeDirection.In, PipeOptions.Asynchronous);
9898

9999
// Ensure all pipes are connected before proceeding.
100100
await Task.WhenAll(

test/Client.Tests/ClientTests.cs

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
using Microsoft.Extensions.Logging;
2+
using OmniSharp.Extensions.LanguageServer.Capabilities.Server;
3+
using OmniSharp.Extensions.LanguageServer.Models;
4+
using OmniSharp.Extensions.LanguageServerProtocol.Client.Dispatcher;
5+
using OmniSharp.Extensions.LanguageServerProtocol.Client.Protocol;
6+
using OmniSharp.Extensions.LanguageServerProtocol.Client.Utilities;
7+
using System.IO;
8+
using System.Linq;
9+
using System.Threading.Tasks;
10+
using Xunit;
11+
using Xunit.Abstractions;
12+
13+
namespace OmniSharp.Extensions.LanguageServerProtocol.Client.Tests
14+
{
15+
/// <summary>
16+
/// Tests for <see cref="LanguageClient"/>.
17+
/// </summary>
18+
public class ClientTests
19+
: PipeServerTestBase
20+
{
21+
/// <summary>
22+
/// Create a new <see cref="LanguageClient"/> test suite.
23+
/// </summary>
24+
/// <param name="testOutput">
25+
/// Output for the current test.
26+
/// </param>
27+
public ClientTests(ITestOutputHelper testOutput)
28+
: base(testOutput)
29+
{
30+
}
31+
32+
/// <summary>
33+
/// Get an absolute document path for use in tests.
34+
/// </summary>
35+
string AbsoluteDocumentPath => Path.DirectorySeparatorChar + "Foo.txt"; // Absolute path, cross-platform compatible.
36+
37+
/// <summary>
38+
/// The <see cref="LanguageClient"/> under test.
39+
/// </summary>
40+
LanguageClient LanguageClient { get; set; }
41+
42+
/// <summary>
43+
/// The server-side dispatcher.
44+
/// </summary>
45+
LspDispatcher ServerDispatcher { get; } = new LspDispatcher();
46+
47+
/// <summary>
48+
/// The server-side connection.
49+
/// </summary>
50+
LspConnection ServerConnection { get; set; }
51+
52+
/// <summary>
53+
/// Ensure that the language client can successfully request Hover information.
54+
/// </summary>
55+
[Fact(DisplayName = "Language client can successfully request hover info")]
56+
public async Task Hover_Success()
57+
{
58+
await Connect();
59+
60+
const int line = 5;
61+
const int column = 5;
62+
var expectedHoverContent = new MarkedStringContainer("123", "456", "789");
63+
64+
ServerDispatcher.HandleRequest<TextDocumentPositionParams, Hover>("textDocument/hover", (request, cancellationToken) =>
65+
{
66+
Assert.NotNull(request.TextDocument);
67+
68+
Assert.Equal(AbsoluteDocumentPath,
69+
DocumentUri.GetFileSystemPath(request.TextDocument.Uri)
70+
);
71+
72+
Assert.Equal(line, request.Position.Line);
73+
Assert.Equal(column, request.Position.Character);
74+
75+
return Task.FromResult(new Hover
76+
{
77+
Contents = expectedHoverContent,
78+
Range = new Range
79+
{
80+
Start = request.Position,
81+
End = request.Position
82+
}
83+
});
84+
});
85+
86+
Hover hover = await LanguageClient.TextDocument.Hover(AbsoluteDocumentPath, line, column);
87+
88+
Assert.NotNull(hover.Range);
89+
Assert.NotNull(hover.Range.Start);
90+
Assert.NotNull(hover.Range.End);
91+
92+
Assert.Equal(line, hover.Range.Start.Line);
93+
Assert.Equal(column, hover.Range.Start.Character);
94+
95+
Assert.Equal(line, hover.Range.End.Line);
96+
Assert.Equal(column, hover.Range.End.Character);
97+
98+
Assert.NotNull(hover.Contents);
99+
Assert.Equal(expectedHoverContent.Select(markedString => markedString.Value),
100+
hover.Contents.Select(
101+
markedString => markedString.Value
102+
)
103+
);
104+
}
105+
106+
/// <summary>
107+
/// Connect the client and server.
108+
/// </summary>
109+
/// <param name="handleServerInitialize">
110+
/// Add standard handlers for server initialisation?
111+
/// </param>
112+
async Task Connect(bool handleServerInitialize = true)
113+
{
114+
ServerConnection = await CreateServerConnection();
115+
ServerConnection.Connect(ServerDispatcher);
116+
117+
if (handleServerInitialize)
118+
HandleServerInitialize();
119+
120+
LanguageClient = await CreateClient(initialize: true);
121+
}
122+
123+
/// <summary>
124+
/// Add standard handlers for sever initialisation.
125+
/// </summary>
126+
void HandleServerInitialize()
127+
{
128+
ServerDispatcher.HandleRequest<InitializeParams, InitializeResult>("initialize", (request, cancellationToken) =>
129+
{
130+
return Task.FromResult(new InitializeResult
131+
{
132+
Capabilities = new ServerCapabilities
133+
{
134+
HoverProvider = true
135+
}
136+
});
137+
});
138+
ServerDispatcher.HandleEmptyNotification("initialized", () =>
139+
{
140+
Log.LogInformation("Server initialized.");
141+
});
142+
}
143+
}
144+
}

test/Client.Tests/Logging/TestOutputLogger.cs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,16 @@ public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Except
113113
if (exception != null)
114114
message += "\n" + exception.ToString();
115115

116-
_testOutput.WriteLine(message);
116+
try
117+
{
118+
_testOutput.WriteLine(message);
119+
}
120+
catch (InvalidOperationException)
121+
{
122+
// Test has already terminated.
123+
124+
System.Diagnostics.Debug.WriteLine(message);
125+
}
117126
}
118127
}
119128
}

0 commit comments

Comments
 (0)