Skip to content

Commit 3aaee4a

Browse files
diyaayayjdesrosiers
authored andcommitted
Tests for semantic tokens
1 parent c7d9adc commit 3aaee4a

File tree

2 files changed

+273
-0
lines changed

2 files changed

+273
-0
lines changed
Lines changed: 220 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,220 @@
1+
import { beforeAll, afterAll, describe, expect, test } from "vitest";
2+
import { SemanticTokensRequest } from "vscode-languageserver";
3+
import { TestClient } from "../test-client.js";
4+
import semanticTokensFeature from "./semantic-tokens.js";
5+
import workspace from "./workspace.js";
6+
import type { DocumentSettings } from "./document-settings.js";
7+
import documentSettings from "./document-settings.js";
8+
9+
10+
describe("Feature - Semantic Tokens", () => {
11+
let client: TestClient<DocumentSettings>;
12+
let documentUri: string;
13+
14+
beforeAll(async () => {
15+
client = new TestClient([
16+
documentSettings,
17+
semanticTokensFeature,
18+
workspace
19+
]);
20+
21+
await client.start();
22+
});
23+
24+
afterAll(async () => {
25+
await client.stop();
26+
});
27+
28+
test("semantic tokens on a watched file", async () => {
29+
await client.changeConfiguration({ "schemaFilePatterns": ["**/subject.schema.json"] });
30+
documentUri = await client.openDocument("subject.schema.json", `{"$schema":"http://json-schema.org/draft-07/schema#",
31+
"type": "string",
32+
"minLength": 10,
33+
"maxLength": 5
34+
}`);
35+
36+
const response = await client.sendRequest(SemanticTokensRequest.type, {
37+
textDocument: { uri: documentUri }
38+
});
39+
40+
expect(response?.data).to.eql([0, 1, 9, 1, 0, 1, 0, 6, 1, 0, 1, 0, 11, 1, 0, 1, 0, 11, 1, 0]);
41+
});
42+
43+
test("no semantic tokens", async () => {
44+
documentUri = await client.openDocument("subject.schema.json", `{
45+
"type": "string",
46+
"minLength": 10,
47+
"maxLength": 5}`);
48+
49+
const response = await client.sendRequest(SemanticTokensRequest.type, {
50+
textDocument: { uri: documentUri }
51+
});
52+
53+
expect(response?.data).to.eql([]);
54+
});
55+
56+
test("no semantic tokens on an unwatched file", async () => {
57+
await client.changeConfiguration({ "schemaFilePatterns": ["**/subject.schema.json"] });
58+
documentUri = await client.openDocument("subjectB.schema.json", `{"$schema":"http://json-schema.org/draft-07/schema#",
59+
"type": "string",
60+
"minLength": 10,
61+
"maxLength": 5
62+
}`);
63+
64+
const response = await client.sendRequest(SemanticTokensRequest.type, {
65+
textDocument: { uri: documentUri }
66+
});
67+
68+
expect(response?.data).to.eql([]);
69+
});
70+
71+
test("change in watch file patterns refreshes tokens", async () => {
72+
documentUri = await client.openDocument("subject.schema.json", `{"$schema":"http://json-schema.org/draft-07/schema#",
73+
"type": "string",
74+
"minLength": 10,
75+
"maxLength": 5
76+
}`);
77+
78+
await client.changeConfiguration({ "schemaFilePatterns": ["**/subjectC.schema.json"] });
79+
80+
const response = await client.sendRequest(SemanticTokensRequest.type, {
81+
textDocument: { uri: documentUri }
82+
});
83+
84+
expect(response?.data).to.eql([]);
85+
});
86+
87+
test("a property in not in a schema should not be highlighted", async () => {
88+
await client.changeConfiguration({ "schemaFilePatterns": ["**/subject.schema.json"] });
89+
documentUri = await client.openDocument("subject.schema.json", `{
90+
"$schema":"http://json-schema.org/draft-07/schema#",
91+
"properties": {
92+
"items": {}
93+
}
94+
}`);
95+
96+
const response = await client.sendRequest(SemanticTokensRequest.type, {
97+
textDocument: { uri: documentUri }
98+
});
99+
100+
const expected: number[] = [1, 0, 9, 1, 0, 1, 0, 12, 1, 0];
101+
expect(response?.data).to.eql(expected);
102+
});
103+
104+
describe("2020-12", () => {
105+
let documentUri: string;
106+
107+
afterAll(async () => {
108+
await client.closeDocument(documentUri);
109+
});
110+
111+
112+
test.each([
113+
// Applicators
114+
["prefixItems", "[{}]", [1, 2, 9, 1, 0, 1, 2, 13, 1, 0]],
115+
["items", "{}", [1, 2, 9, 1, 0, 1, 2, 7, 1, 0]],
116+
["contains", "{}", [1, 2, 9, 1, 0, 1, 2, 10, 1, 0]],
117+
["additionalProperties", "{}", [1, 2, 9, 1, 0, 1, 2, 22, 1, 0]],
118+
["properties", "{}", [1, 2, 9, 1, 0, 1, 2, 12, 1, 0]],
119+
["patternProperties", "{}", [1, 2, 9, 1, 0, 1, 2, 19, 1, 0]],
120+
["dependentSchemas", "{}", [1, 2, 9, 1, 0, 1, 2, 18, 1, 0]],
121+
["propertyNames", "{}", [1, 2, 9, 1, 0, 1, 2, 15, 1, 0]],
122+
["if", "{}", [1, 2, 9, 1, 0, 1, 2, 4, 1, 0]],
123+
["then", "{}", [1, 2, 9, 1, 0, 1, 2, 6, 1, 0]],
124+
["else", "{}", [1, 2, 9, 1, 0, 1, 2, 6, 1, 0]],
125+
["allOf", "[{}]", [1, 2, 9, 1, 0, 1, 2, 7, 1, 0]],
126+
["anyOf", "[{}]", [1, 2, 9, 1, 0, 1, 2, 7, 1, 0]],
127+
["oneOf", "[{}]", [1, 2, 9, 1, 0, 1, 2, 7, 1, 0]],
128+
["not", "{}", [1, 2, 9, 1, 0, 1, 2, 5, 1, 0]],
129+
130+
// Content
131+
["contentMediaType", "\"\"", [1, 2, 9, 1, 0, 1, 2, 18, 1, 0]],
132+
["contentEncoding", "\"\"", [1, 2, 9, 1, 0, 1, 2, 17, 1, 0]],
133+
["contentSchema", "{}", [1, 2, 9, 1, 0, 1, 2, 15, 1, 0]],
134+
135+
// Core
136+
["$id", "\"\"", [1, 2, 9, 1, 0, 1, 2, 5, 1, 0]],
137+
["$anchor", "\"foo\"", [1, 2, 9, 1, 0, 1, 2, 9, 1, 0]],
138+
["$ref", "\"\"", [1, 2, 9, 1, 0, 1, 2, 6, 1, 0]],
139+
["$dynamicRef", "\"\"", [1, 2, 9, 1, 0, 1, 2, 13, 1, 0]],
140+
["$dynamicAnchor", "\"foo\"", [1, 2, 9, 1, 0, 1, 2, 16, 1, 0]],
141+
["$vocabulary", "{}", [1, 2, 9, 1, 0, 1, 2, 13, 1, 0]],
142+
["$comment", "\"\"", [1, 2, 9, 1, 0, 1, 2, 14, 2, 0]],
143+
["$defs", "{}", [1, 2, 9, 1, 0, 1, 2, 7, 1, 0]],
144+
145+
// Format
146+
["format", "\"\"", [1, 2, 9, 1, 0, 1, 2, 8, 1, 0]],
147+
148+
// Meta-data
149+
["title", "\"\"", [1, 2, 9, 1, 0, 1, 2, 7, 1, 0]],
150+
["description", "\"\"", [1, 2, 9, 1, 0, 1, 2, 13, 1, 0]],
151+
["default", "true", [1, 2, 9, 1, 0, 1, 2, 9, 1, 0]],
152+
["deprecated", "false", [1, 2, 9, 1, 0, 1, 2, 12, 1, 0]],
153+
["readOnly", "true", [1, 2, 9, 1, 0, 1, 2, 10, 1, 0]],
154+
["writeOnly", "false", [1, 2, 9, 1, 0, 1, 2, 11, 1, 0]],
155+
["examples", "[]", [1, 2, 9, 1, 0, 1, 2, 10, 1, 0]],
156+
157+
// Unevaluated
158+
["unevaluatedItems", "true", [1, 2, 9, 1, 0, 1, 2, 18, 1, 0]],
159+
["unevaluatedProperties", "true", [1, 2, 9, 1, 0, 1, 2, 23, 1, 0]],
160+
161+
// Validation
162+
["multipleOf", "1", [1, 2, 9, 1, 0, 1, 2, 12, 1, 0]],
163+
["maximum", "42", [1, 2, 9, 1, 0, 1, 2, 9, 1, 0]],
164+
["exclusiveMaximum", "42", [1, 2, 9, 1, 0, 1, 2, 18, 1, 0]],
165+
["minimum", "42", [1, 2, 9, 1, 0, 1, 2, 9, 1, 0]],
166+
["exclusiveMinimum", "42", [1, 2, 9, 1, 0, 1, 2, 18, 1, 0]],
167+
["maxLength", "42", [1, 2, 9, 1, 0, 1, 2, 11, 1, 0]],
168+
["minLength", "42", [1, 2, 9, 1, 0, 1, 2, 11, 1, 0]],
169+
["pattern", "\"\"", [1, 2, 9, 1, 0, 1, 2, 9, 1, 0]],
170+
["maxItems", "42", [1, 2, 9, 1, 0, 1, 2, 10, 1, 0]],
171+
["minItems", "42", [1, 2, 9, 1, 0, 1, 2, 10, 1, 0]],
172+
["uniqueItems", "false", [1, 2, 9, 1, 0, 1, 2, 13, 1, 0]],
173+
["maxContains", "1", [1, 2, 9, 1, 0, 1, 2, 13, 1, 0]],
174+
["minContains", "1", [1, 2, 9, 1, 0, 1, 2, 13, 1, 0]],
175+
["maxProperties", "1", [1, 2, 9, 1, 0, 1, 2, 15, 1, 0]],
176+
["minProperties", "1", [1, 2, 9, 1, 0, 1, 2, 15, 1, 0]],
177+
["required", "[]", [1, 2, 9, 1, 0, 1, 2, 10, 1, 0]],
178+
["dependentRequired", "{}", [1, 2, 9, 1, 0, 1, 2, 19, 1, 0]],
179+
["const", "true", [1, 2, 9, 1, 0, 1, 2, 7, 1, 0]],
180+
["enum", "[]", [1, 2, 9, 1, 0, 1, 2, 6, 1, 0]],
181+
["type", "\"object\"", [1, 2, 9, 1, 0, 1, 2, 6, 1, 0]]
182+
])("%s should be highlighted", async (keyword, value, expected) => {
183+
documentUri = await client.openDocument("./subject.schema.json", `{
184+
"$schema": "https://json-schema.org/draft/2020-12/schema",
185+
"${keyword}": ${value}
186+
}`);
187+
188+
const response = await client.sendRequest(SemanticTokensRequest.type, {
189+
textDocument: { uri: documentUri }
190+
});
191+
192+
expect(response?.data).to.eql(expected);
193+
});
194+
195+
196+
test.each([
197+
// Applicators
198+
["additionalItems", "true", [1, 2, 9, 1, 0]],
199+
["dependencies", "{}", [1, 2, 9, 1, 0]],
200+
201+
// Core
202+
["id", "\"\"", [1, 2, 9, 1, 0]],
203+
["$recursiveRef", "\"#\"", [1, 2, 9, 1, 0]],
204+
["$recursiveAnchor", "true", [1, 2, 9, 1, 0]],
205+
["definitions", "{}", [1, 2, 9, 1, 0]]
206+
])("%s should not be highlighted", async (keyword, value, expected) => {
207+
documentUri = await client.openDocument("./subject.schema.json", `{
208+
"$schema": "https://json-schema.org/draft/2020-12/schema",
209+
"${keyword}": ${value}
210+
}`);
211+
212+
const response = await client.sendRequest(SemanticTokensRequest.type, {
213+
textDocument: { uri: documentUri }
214+
});
215+
216+
expect(response?.data).to.eql(expected);
217+
});
218+
});
219+
});
220+

language-server/src/test-client.ts

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,59 @@ export class TestClient<Configuration> {
127127
},
128128
window: {
129129
workDoneProgress: true
130+
},
131+
textDocument: {
132+
semanticTokens: {
133+
dynamicRegistration: true,
134+
tokenTypes: [
135+
"namespace",
136+
"type",
137+
"class",
138+
"enum",
139+
"interface",
140+
"struct",
141+
"typeParameter",
142+
"parameter",
143+
"variable",
144+
"property",
145+
"enumMember",
146+
"event",
147+
"function",
148+
"method",
149+
"macro",
150+
"keyword",
151+
"modifier",
152+
"comment",
153+
"string",
154+
"number",
155+
"regexp",
156+
"operator",
157+
"decorator"
158+
],
159+
tokenModifiers: [
160+
"declaration",
161+
"definition",
162+
"readonly",
163+
"static",
164+
"deprecated",
165+
"abstract",
166+
"async",
167+
"modification",
168+
"documentation",
169+
"defaultLibrary"
170+
],
171+
formats: ["relative"],
172+
requests: {
173+
range: true,
174+
full: {
175+
delta: true
176+
}
177+
},
178+
multilineTokenSupport: false,
179+
overlappingTokenSupport: false,
180+
serverCancelSupport: true,
181+
augmentsSyntaxTokens: true
182+
}
130183
}
131184
}
132185
};

0 commit comments

Comments
 (0)