Skip to content

Commit 7a66efe

Browse files
committed
Add classification tests
1 parent b6d4814 commit 7a66efe

File tree

1 file changed

+156
-0
lines changed

1 file changed

+156
-0
lines changed
Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
/*---------------------------------------------------------------------------------------------
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
* Licensed under the MIT License. See License.txt in the project root for license information.
4+
*--------------------------------------------------------------------------------------------*/
5+
6+
import * as vscode from 'vscode';
7+
import * as path from 'path';
8+
import testAssetWorkspace from './testAssets/testAssetWorkspace';
9+
import { activateCSharpExtension, closeAllEditorsAsync, openFileInWorkspaceAsync } from './integrationHelpers';
10+
import { describe, beforeAll, beforeEach, afterAll, test, expect, afterEach } from '@jest/globals';
11+
12+
describe(`[${testAssetWorkspace.description}] Classification Tests`, () => {
13+
beforeAll(async () => {
14+
await activateCSharpExtension();
15+
});
16+
17+
beforeEach(async () => {
18+
await openFileInWorkspaceAsync(path.join('src', 'app', 'semantictokens.cs'));
19+
});
20+
21+
afterAll(async () => {
22+
await testAssetWorkspace.cleanupWorkspace();
23+
});
24+
25+
afterEach(async () => {
26+
await closeAllEditorsAsync();
27+
});
28+
29+
test('Semantic classification returns correct token types', async () => {
30+
const expectedTokens: Token[] = [
31+
// 0:namespace Test
32+
_keyword('namespace', 0, 0),
33+
_namespace('Test', 0, 10),
34+
// 1:{
35+
_punctuation('{', 1, 0),
36+
// 2: public class TestProgram
37+
_keyword('public', 2, 4),
38+
_keyword('class', 2, 11),
39+
_class('TestProgram', 2, 17),
40+
// 3: {
41+
_punctuation('{', 3, 4),
42+
// 4: public static int TestMain(string[] args)
43+
_keyword('public', 4, 8),
44+
_keyword('static', 4, 15),
45+
_keyword('int', 4, 22),
46+
_staticMethod('TestMain', 4, 26),
47+
_punctuation('(', 4, 34),
48+
_keyword('string', 4, 35),
49+
_punctuation('[', 4, 41),
50+
_punctuation(']', 4, 42),
51+
_parameter('args', 4, 44),
52+
_punctuation(')', 4, 48),
53+
// 5: {
54+
_punctuation('{', 5, 8),
55+
// 6: System.Console.WriteLine(string.Join(',', args));
56+
_namespace('System', 6, 12),
57+
_operator('.', 6, 18),
58+
_staticClass('Console', 6, 19),
59+
_operator('.', 6, 26),
60+
_staticMethod('WriteLine', 6, 27),
61+
_punctuation('(', 6, 36),
62+
_keyword('string', 6, 37),
63+
_operator('.', 6, 43),
64+
_staticMethod('Join', 6, 44),
65+
_punctuation('(', 6, 48),
66+
_string("','", 6, 49),
67+
_punctuation(')', 6, 52),
68+
_parameter('args', 6, 54),
69+
_punctuation(')', 6, 58),
70+
_punctuation(')', 6, 59),
71+
_punctuation(';', 6, 60),
72+
// 7: return 0;
73+
_controlKeyword('return', 7, 12),
74+
_number('0', 7, 19),
75+
_punctuation(';', 7, 20),
76+
// 8: }
77+
_punctuation('}', 8, 8),
78+
// 9: }
79+
_punctuation('}', 9, 4),
80+
//10: }
81+
_punctuation('}', 10, 0),
82+
];
83+
84+
const tokens = await getTokens();
85+
86+
expect(tokens).toStrictEqual(expectedTokens);
87+
});
88+
});
89+
90+
async function getTokens(): Promise<Token[]> {
91+
const legend = <vscode.SemanticTokensLegend>(
92+
await vscode.commands.executeCommand(
93+
'vscode.provideDocumentSemanticTokensLegend',
94+
vscode.window.activeTextEditor!.document.uri
95+
)
96+
);
97+
98+
const actual = <vscode.SemanticTokens>(
99+
await vscode.commands.executeCommand(
100+
'vscode.provideDocumentSemanticTokens',
101+
vscode.window.activeTextEditor!.document.uri
102+
)
103+
);
104+
105+
expect(legend).toBeDefined();
106+
expect(actual).toBeDefined();
107+
108+
const actualRanges: Array<Token> = [];
109+
let lastLine = 0;
110+
let lastCharacter = 0;
111+
for (let i = 0; i < actual.data.length; i += 5) {
112+
const lineDelta = actual.data[i],
113+
charDelta = actual.data[i + 1],
114+
len = actual.data[i + 2],
115+
typeIdx = actual.data[i + 3],
116+
modSet = actual.data[i + 4];
117+
const line = lastLine + lineDelta;
118+
const character = lineDelta === 0 ? lastCharacter + charDelta : charDelta;
119+
const tokenClassifiction = [
120+
legend.tokenTypes[typeIdx],
121+
...legend.tokenModifiers.filter((_, i) => modSet & (1 << i)),
122+
].join('.');
123+
actualRanges.push({
124+
startLine: line,
125+
character: character,
126+
length: len,
127+
tokenClassifiction: tokenClassifiction,
128+
});
129+
lastLine = line;
130+
lastCharacter = character;
131+
}
132+
return actualRanges;
133+
}
134+
135+
interface Token {
136+
startLine: number;
137+
character: number;
138+
length: number;
139+
tokenClassifiction: string;
140+
}
141+
142+
function t(startLine: number, character: number, length: number, tokenClassifiction: string): Token {
143+
return { startLine, character, length, tokenClassifiction };
144+
}
145+
146+
const _keyword = (text: string, line: number, col: number) => t(line, col, text.length, 'keyword');
147+
const _controlKeyword = (text: string, line: number, col: number) => t(line, col, text.length, 'controlKeyword');
148+
const _punctuation = (text: string, line: number, col: number) => t(line, col, text.length, 'punctuation');
149+
const _operator = (text: string, line: number, col: number) => t(line, col, text.length, 'operator');
150+
const _number = (text: string, line: number, col: number) => t(line, col, text.length, 'number');
151+
const _string = (text: string, line: number, col: number) => t(line, col, text.length, 'string');
152+
const _namespace = (text: string, line: number, col: number) => t(line, col, text.length, 'namespace');
153+
const _class = (text: string, line: number, col: number) => t(line, col, text.length, 'class');
154+
const _staticClass = (text: string, line: number, col: number) => t(line, col, text.length, 'class.static');
155+
const _staticMethod = (text: string, line: number, col: number) => t(line, col, text.length, 'method.static');
156+
const _parameter = (text: string, line: number, col: number) => t(line, col, text.length, 'parameter');

0 commit comments

Comments
 (0)