-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathCompletionHandlerTests.cs
More file actions
136 lines (111 loc) · 4.85 KB
/
Copy pathCompletionHandlerTests.cs
File metadata and controls
136 lines (111 loc) · 4.85 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
using Microsoft.Extensions.Logging.Abstractions;
using OmniSharp.Extensions.LanguageServer.Protocol.Models;
namespace Settex.LanguageServer.Tests;
/// <summary>
/// The completion handler is the largest file in the language server and the most
/// visible feature of both editor extensions, and it had no tests at all. These cover
/// what a user actually sees at each cursor position.
/// </summary>
public sealed class CompletionHandlerTests
{
[Test]
public async Task Completion_AfterADot_OffersThePropertiesOfThatObjectAsync()
{
const string source = """
settings {
Server {
Host = "localhost"
Port = 8080
}
Other = 1
}
env "Dev" {
settings {
Server.Host = "dev"
}
}
""";
// Cursor immediately after "Server." on the overlay line (0-based line 9, col 15).
var items = await CompleteAsync(source, 9, 15);
await Assert.That(items.Any(i => i.Label == "Host")).IsTrue();
await Assert.That(items.Any(i => i.Label == "Port")).IsTrue();
// Only that object's properties — a sibling key is not one of them.
await Assert.That(items.Any(i => i.Label == "Other")).IsFalse();
}
[Test]
public async Task Completion_AtTopLevel_OffersTheLanguageKeywordsAsync()
{
var items = await CompleteAsync("settings {\n A = 1\n}\n", 3, 0);
await Assert.That(items.Any(i => i.Kind == CompletionItemKind.Keyword)).IsTrue();
}
[Test]
public async Task Completion_OffersDeclaredVariablesAsync()
{
const string source = """
let basePort = 5000
settings {
Port = basePort
}
""";
// Cursor just after "Port = " (0-based line 2, column 11).
var items = await CompleteAsync(source, 2, 11);
await Assert.That(items.Any(i => i.Label == "basePort")).IsTrue();
}
/// <summary>
/// A limitation worth recording rather than hiding: properties and variables both
/// come from the evaluated AST, so while the file does not parse — which is most of
/// the time completion is wanted — only the static keyword list is offered. The
/// handler degrades instead of failing, but it does not help.
/// </summary>
[Test]
public async Task Completion_WhileTheFileDoesNotParse_OffersKeywordsOnlyAsync()
{
const string source = "let basePort = 5000\nsettings {\n Port = \n";
var items = await CompleteAsync(source, 2, 11);
await Assert.That(items.Any(i => i.Kind == CompletionItemKind.Keyword)).IsTrue();
await Assert.That(items.Any(i => i.Label == "basePort")).IsFalse();
}
[Test]
public async Task Completion_OffersDeclaredEnvironmentsAsync()
{
const string source = """
settings { A = 1 }
env "Staging" { settings { A = 2 } }
env "Production" { settings { A = 3 } }
""";
var items = await CompleteAsync(source, 3, 0);
await Assert.That(items.Any(i => i.Label == "Staging")).IsTrue();
await Assert.That(items.Any(i => i.Label == "Production")).IsTrue();
}
[Test]
public async Task Completion_OnADocumentTheServerDoesNotKnow_ReturnsNothingAsync()
{
// The handler must degrade rather than throw when asked about a URI that was
// never opened — a race the client can genuinely produce.
var handler = new SettexCompletionHandler(new SettexWorkspace(), NullLogger<SettexCompletionHandler>.Instance);
var result = await handler.Handle(Request("untitled:never-opened", 0, 0), CancellationToken.None);
await Assert.That(result.Items.Count()).IsEqualTo(0);
}
[Test]
public async Task Completion_OnAnUnparsableDocument_StillAnswersAsync()
{
// Completion is most useful exactly while the file is half-written and does not
// parse. It must not fault.
var items = await CompleteAsync("settings {\n A = \n", 1, 8);
await Assert.That(items).IsNotNull();
}
private static async Task<IReadOnlyList<CompletionItem>> CompleteAsync(string source, int line, int character)
{
var workspace = new SettexWorkspace();
const string uri = "untitled:completion-test";
workspace.DidOpen(uri, source);
var handler = new SettexCompletionHandler(workspace, NullLogger<SettexCompletionHandler>.Instance);
var result = await handler.Handle(Request(uri, line, character), CancellationToken.None);
return result.Items.ToList();
}
private static CompletionParams Request(string uri, int line, int character) => new()
{
TextDocument = new TextDocumentIdentifier { Uri = uri },
Position = new Position(line, character),
};
}