Path: blob/main/src/vs/editor/contrib/documentSymbols/test/browser/outlineModel.test.ts
3296 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45import assert from 'assert';6import { CancellationToken, CancellationTokenSource } from '../../../../../base/common/cancellation.js';7import { DisposableStore } from '../../../../../base/common/lifecycle.js';8import { URI } from '../../../../../base/common/uri.js';9import { Range } from '../../../../common/core/range.js';10import { DocumentSymbol, SymbolKind } from '../../../../common/languages.js';11import { LanguageFeatureDebounceService } from '../../../../common/services/languageFeatureDebounce.js';12import { LanguageFeaturesService } from '../../../../common/services/languageFeaturesService.js';13import { IModelService } from '../../../../common/services/model.js';14import { createModelServices, createTextModel } from '../../../../test/common/testTextModel.js';15import { NullLogService } from '../../../../../platform/log/common/log.js';16import { IMarker, MarkerSeverity } from '../../../../../platform/markers/common/markers.js';17import { OutlineElement, OutlineGroup, OutlineModel, OutlineModelService } from '../../browser/outlineModel.js';18import { mock } from '../../../../../base/test/common/mock.js';19import { IEnvironmentService } from '../../../../../platform/environment/common/environment.js';20import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../../base/test/common/utils.js';2122suite('OutlineModel', function () {2324const disposables = new DisposableStore();25const languageFeaturesService = new LanguageFeaturesService();2627teardown(function () {28disposables.clear();29});3031ensureNoDisposablesAreLeakedInTestSuite();3233test('OutlineModel#create, cached', async function () {3435const insta = createModelServices(disposables);36const modelService = insta.get(IModelService);37const envService = new class extends mock<IEnvironmentService>() {38override isBuilt: boolean = true;39override isExtensionDevelopment: boolean = false;40};41const service = new OutlineModelService(languageFeaturesService, new LanguageFeatureDebounceService(new NullLogService(), envService), modelService);4243const model = createTextModel('foo', undefined, undefined, URI.file('/fome/path.foo'));44let count = 0;45const reg = languageFeaturesService.documentSymbolProvider.register({ pattern: '**/path.foo' }, {46provideDocumentSymbols() {47count += 1;48return [];49}50});5152await service.getOrCreate(model, CancellationToken.None);53assert.strictEqual(count, 1);5455// cached56await service.getOrCreate(model, CancellationToken.None);57assert.strictEqual(count, 1);5859// new version60model.applyEdits([{ text: 'XXX', range: new Range(1, 1, 1, 1) }]);61await service.getOrCreate(model, CancellationToken.None);62assert.strictEqual(count, 2);6364reg.dispose();65model.dispose();66service.dispose();67});6869test('OutlineModel#create, cached/cancel', async function () {7071const insta = createModelServices(disposables);72const modelService = insta.get(IModelService);73const envService = new class extends mock<IEnvironmentService>() {74override isBuilt: boolean = true;75override isExtensionDevelopment: boolean = false;76};77const service = new OutlineModelService(languageFeaturesService, new LanguageFeatureDebounceService(new NullLogService(), envService), modelService);78const model = createTextModel('foo', undefined, undefined, URI.file('/fome/path.foo'));79let isCancelled = false;8081const reg = languageFeaturesService.documentSymbolProvider.register({ pattern: '**/path.foo' }, {82provideDocumentSymbols(d, token) {83return new Promise(resolve => {84const l = token.onCancellationRequested(_ => {85isCancelled = true;86resolve(null);87l.dispose();88});89});90}91});9293assert.strictEqual(isCancelled, false);94const s1 = new CancellationTokenSource();95service.getOrCreate(model, s1.token);96const s2 = new CancellationTokenSource();97service.getOrCreate(model, s2.token);9899s1.cancel();100assert.strictEqual(isCancelled, false);101102s2.cancel();103assert.strictEqual(isCancelled, true);104105reg.dispose();106model.dispose();107service.dispose();108109});110111function fakeSymbolInformation(range: Range, name: string = 'foo'): DocumentSymbol {112return {113name,114detail: 'fake',115kind: SymbolKind.Boolean,116tags: [],117selectionRange: range,118range: range119};120}121122function fakeMarker(range: Range): IMarker {123return { ...range, owner: 'ffff', message: 'test', severity: MarkerSeverity.Error, resource: null! };124}125126test('OutlineElement - updateMarker', function () {127128const e0 = new OutlineElement('foo1', null!, fakeSymbolInformation(new Range(1, 1, 1, 10)));129const e1 = new OutlineElement('foo2', null!, fakeSymbolInformation(new Range(2, 1, 5, 1)));130const e2 = new OutlineElement('foo3', null!, fakeSymbolInformation(new Range(6, 1, 10, 10)));131132const group = new OutlineGroup('group', null!, null!, 1);133group.children.set(e0.id, e0);134group.children.set(e1.id, e1);135group.children.set(e2.id, e2);136137const data = [fakeMarker(new Range(6, 1, 6, 7)), fakeMarker(new Range(1, 1, 1, 4)), fakeMarker(new Range(10, 2, 14, 1))];138data.sort(Range.compareRangesUsingStarts); // model does this139140group.updateMarker(data);141assert.strictEqual(data.length, 0); // all 'stolen'142assert.strictEqual(e0.marker!.count, 1);143assert.strictEqual(e1.marker, undefined);144assert.strictEqual(e2.marker!.count, 2);145146group.updateMarker([]);147assert.strictEqual(e0.marker, undefined);148assert.strictEqual(e1.marker, undefined);149assert.strictEqual(e2.marker, undefined);150});151152test('OutlineElement - updateMarker, 2', function () {153154const p = new OutlineElement('A', null!, fakeSymbolInformation(new Range(1, 1, 11, 1)));155const c1 = new OutlineElement('A/B', null!, fakeSymbolInformation(new Range(2, 4, 5, 4)));156const c2 = new OutlineElement('A/C', null!, fakeSymbolInformation(new Range(6, 4, 9, 4)));157158const group = new OutlineGroup('group', null!, null!, 1);159group.children.set(p.id, p);160p.children.set(c1.id, c1);161p.children.set(c2.id, c2);162163let data = [164fakeMarker(new Range(2, 4, 5, 4))165];166167group.updateMarker(data);168assert.strictEqual(p.marker!.count, 0);169assert.strictEqual(c1.marker!.count, 1);170assert.strictEqual(c2.marker, undefined);171172data = [173fakeMarker(new Range(2, 4, 5, 4)),174fakeMarker(new Range(2, 6, 2, 8)),175fakeMarker(new Range(7, 6, 7, 8)),176];177group.updateMarker(data);178assert.strictEqual(p.marker!.count, 0);179assert.strictEqual(c1.marker!.count, 2);180assert.strictEqual(c2.marker!.count, 1);181182data = [183fakeMarker(new Range(1, 4, 1, 11)),184fakeMarker(new Range(7, 6, 7, 8)),185];186group.updateMarker(data);187assert.strictEqual(p.marker!.count, 1);188assert.strictEqual(c1.marker, undefined);189assert.strictEqual(c2.marker!.count, 1);190});191192test('OutlineElement - updateMarker/multiple groups', function () {193194const model = new class extends OutlineModel {195constructor() {196super(null!);197}198readyForTesting() {199this._groups = this.children as any;200}201};202model.children.set('g1', new OutlineGroup('g1', model, null!, 1));203model.children.get('g1')!.children.set('c1', new OutlineElement('c1', model.children.get('g1')!, fakeSymbolInformation(new Range(1, 1, 11, 1))));204205model.children.set('g2', new OutlineGroup('g2', model, null!, 1));206model.children.get('g2')!.children.set('c2', new OutlineElement('c2', model.children.get('g2')!, fakeSymbolInformation(new Range(1, 1, 7, 1))));207model.children.get('g2')!.children.get('c2')!.children.set('c2.1', new OutlineElement('c2.1', model.children.get('g2')!.children.get('c2')!, fakeSymbolInformation(new Range(1, 3, 2, 19))));208model.children.get('g2')!.children.get('c2')!.children.set('c2.2', new OutlineElement('c2.2', model.children.get('g2')!.children.get('c2')!, fakeSymbolInformation(new Range(4, 1, 6, 10))));209210model.readyForTesting();211212const data = [213fakeMarker(new Range(1, 1, 2, 8)),214fakeMarker(new Range(6, 1, 6, 98)),215];216217model.updateMarker(data);218219assert.strictEqual(model.children.get('g1')!.children.get('c1')!.marker!.count, 2);220assert.strictEqual(model.children.get('g2')!.children.get('c2')!.children.get('c2.1')!.marker!.count, 1);221assert.strictEqual(model.children.get('g2')!.children.get('c2')!.children.get('c2.2')!.marker!.count, 1);222});223224});225226227