Skip to content

Commit 0f89dc4

Browse files
committed
test
1 parent ad4aef9 commit 0f89dc4

File tree

1 file changed

+146
-1
lines changed

1 file changed

+146
-1
lines changed

packages/language-server/test/plugins/PluginHost.test.ts

Lines changed: 146 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
11
import sinon from 'sinon';
22
import {
33
CompletionItem,
4+
DocumentSymbol,
45
Location,
56
LocationLink,
67
Position,
78
Range,
9+
SymbolInformation,
10+
SymbolKind,
811
TextDocumentItem
912
} from 'vscode-languageserver-types';
1013
import { DocumentManager, Document } from '../../src/lib/documents';
1114
import { LSPProviderConfig, PluginHost } from '../../src/plugins';
12-
import { CompletionTriggerKind } from 'vscode-languageserver';
15+
import { CompletionTriggerKind, CancellationToken } from 'vscode-languageserver';
1316
import assert from 'assert';
1417

1518
describe('PluginHost', () => {
@@ -187,4 +190,146 @@ describe('PluginHost', () => {
187190
]);
188191
});
189192
});
193+
194+
describe('getHierarchicalDocumentSymbols', () => {
195+
it('converts flat symbols to hierarchical structure', async () => {
196+
const cancellation_token: CancellationToken = {
197+
isCancellationRequested: false,
198+
onCancellationRequested: () => ({ dispose: () => {} })
199+
};
200+
201+
const flat_symbols: SymbolInformation[] = [
202+
// Root level class (lines 0-10)
203+
SymbolInformation.create(
204+
'MyClass',
205+
SymbolKind.Class,
206+
Range.create(Position.create(0, 0), Position.create(10, 0)),
207+
'file:///hello.svelte'
208+
),
209+
// Method inside class (lines 1-5)
210+
SymbolInformation.create(
211+
'myMethod',
212+
SymbolKind.Method,
213+
Range.create(Position.create(1, 0), Position.create(5, 0)),
214+
'file:///hello.svelte'
215+
),
216+
// Variable inside method (lines 2-3)
217+
SymbolInformation.create(
218+
'localVar',
219+
SymbolKind.Variable,
220+
Range.create(Position.create(2, 0), Position.create(3, 0)),
221+
'file:///hello.svelte'
222+
),
223+
// Another method in class (lines 6-8)
224+
SymbolInformation.create(
225+
'anotherMethod',
226+
SymbolKind.Method,
227+
Range.create(Position.create(6, 0), Position.create(8, 0)),
228+
'file:///hello.svelte'
229+
),
230+
// Root level function (lines 12-15)
231+
SymbolInformation.create(
232+
'topLevelFunction',
233+
SymbolKind.Function,
234+
Range.create(Position.create(12, 0), Position.create(15, 0)),
235+
'file:///hello.svelte'
236+
)
237+
];
238+
239+
const { docManager, pluginHost } = setup({
240+
getDocumentSymbols: sinon.stub().returns(flat_symbols)
241+
});
242+
docManager.openClientDocument(textDocument);
243+
244+
const result = await pluginHost.getHierarchicalDocumentSymbols(
245+
textDocument,
246+
cancellation_token
247+
);
248+
249+
// Should have 2 root symbols: MyClass and topLevelFunction
250+
assert.strictEqual(result.length, 2);
251+
252+
// Check first root symbol (MyClass)
253+
assert.strictEqual(result[0].name, 'MyClass');
254+
assert.strictEqual(result[0].kind, SymbolKind.Class);
255+
assert.strictEqual(result[0].children?.length, 2);
256+
257+
// Check children of MyClass
258+
assert.strictEqual(result[0].children![0].name, 'myMethod');
259+
assert.strictEqual(result[0].children![0].kind, SymbolKind.Method);
260+
assert.strictEqual(result[0].children![0].children?.length, 1);
261+
262+
// Check nested child (localVar inside myMethod)
263+
assert.strictEqual(result[0].children![0].children![0].name, 'localVar');
264+
assert.strictEqual(result[0].children![0].children![0].kind, SymbolKind.Variable);
265+
assert.strictEqual(result[0].children![0].children![0].children?.length, 0);
266+
267+
// Check second child of MyClass
268+
assert.strictEqual(result[0].children![1].name, 'anotherMethod');
269+
assert.strictEqual(result[0].children![1].kind, SymbolKind.Method);
270+
assert.strictEqual(result[0].children![1].children?.length, 0);
271+
272+
// Check second root symbol (topLevelFunction)
273+
assert.strictEqual(result[1].name, 'topLevelFunction');
274+
assert.strictEqual(result[1].kind, SymbolKind.Function);
275+
assert.strictEqual(result[1].children?.length, 0);
276+
});
277+
278+
it('handles empty symbol list', async () => {
279+
const cancellation_token: CancellationToken = {
280+
isCancellationRequested: false,
281+
onCancellationRequested: () => ({ dispose: () => {} })
282+
};
283+
284+
const { docManager, pluginHost } = setup({
285+
getDocumentSymbols: sinon.stub().returns([])
286+
});
287+
docManager.openClientDocument(textDocument);
288+
289+
const result = await pluginHost.getHierarchicalDocumentSymbols(
290+
textDocument,
291+
cancellation_token
292+
);
293+
294+
assert.deepStrictEqual(result, []);
295+
});
296+
297+
it('handles symbols with same start position', async () => {
298+
const cancellation_token: CancellationToken = {
299+
isCancellationRequested: false,
300+
onCancellationRequested: () => ({ dispose: () => {} })
301+
};
302+
303+
const flat_symbols: SymbolInformation[] = [
304+
// Two symbols starting at same position, longer one should be parent
305+
SymbolInformation.create(
306+
'outer',
307+
SymbolKind.Class,
308+
Range.create(Position.create(0, 0), Position.create(10, 0)),
309+
'file:///hello.svelte'
310+
),
311+
SymbolInformation.create(
312+
'inner',
313+
SymbolKind.Method,
314+
Range.create(Position.create(0, 0), Position.create(5, 0)),
315+
'file:///hello.svelte'
316+
)
317+
];
318+
319+
const { docManager, pluginHost } = setup({
320+
getDocumentSymbols: sinon.stub().returns(flat_symbols)
321+
});
322+
docManager.openClientDocument(textDocument);
323+
324+
const result = await pluginHost.getHierarchicalDocumentSymbols(
325+
textDocument,
326+
cancellation_token
327+
);
328+
329+
assert.strictEqual(result.length, 1);
330+
assert.strictEqual(result[0].name, 'outer');
331+
assert.strictEqual(result[0].children?.length, 1);
332+
assert.strictEqual(result[0].children![0].name, 'inner');
333+
});
334+
});
190335
});

0 commit comments

Comments
 (0)