diff --git a/src/vs/editor/contrib/find/test/browser/findModel.test.ts b/src/vs/editor/contrib/find/test/browser/findModel.test.ts index a7d58f958b9..9b3450c2ff6 100644 --- a/src/vs/editor/contrib/find/test/browser/findModel.test.ts +++ b/src/vs/editor/contrib/find/test/browser/findModel.test.ts @@ -4,6 +4,8 @@ *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; +import { DisposableStore } from 'vs/base/common/lifecycle'; +import { ensureNoDisposablesAreLeakedInTestSuite } from 'vs/base/test/common/utils'; import { CoreNavigationCommands } from 'vs/editor/browser/coreCommands'; import { IActiveCodeEditor, ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { Position } from 'vs/editor/common/core/position'; @@ -16,6 +18,18 @@ import { withTestCodeEditor } from 'vs/editor/test/browser/testCodeEditor'; suite('FindModel', () => { + let disposables: DisposableStore; + + setup(() => { + disposables = new DisposableStore(); + }); + + teardown(() => { + disposables.dispose(); + }); + + ensureNoDisposablesAreLeakedInTestSuite(); + function findTest(testName: string, callback: (editor: IActiveCodeEditor) => void): void { test(testName, () => { const textArr = [ @@ -87,8 +101,8 @@ suite('FindModel', () => { findTest('incremental find from beginning of file', (editor) => { editor.setPosition({ lineNumber: 1, column: 1 }); - const findState = new FindReplaceState(); - const findModel = new FindModelBoundToEditorModel(editor, findState); + const findState = disposables.add(new FindReplaceState()); + const findModel = disposables.add(new FindModelBoundToEditorModel(editor, findState)); // simulate typing the search string findState.change({ searchString: 'H' }, true); @@ -236,9 +250,9 @@ suite('FindModel', () => { }); findTest('find model removes its decorations', (editor) => { - const findState = new FindReplaceState(); + const findState = disposables.add(new FindReplaceState()); findState.change({ searchString: 'hello' }, false); - const findModel = new FindModelBoundToEditorModel(editor, findState); + const findModel = disposables.add(new FindModelBoundToEditorModel(editor, findState)); assert.strictEqual(findState.matchesCount, 5); assertFindState( @@ -266,9 +280,9 @@ suite('FindModel', () => { }); findTest('find model updates state matchesCount', (editor) => { - const findState = new FindReplaceState(); + const findState = disposables.add(new FindReplaceState()); findState.change({ searchString: 'hello' }, false); - const findModel = new FindModelBoundToEditorModel(editor, findState); + const findModel = disposables.add(new FindModelBoundToEditorModel(editor, findState)); assert.strictEqual(findState.matchesCount, 5); assertFindState( @@ -298,9 +312,9 @@ suite('FindModel', () => { }); findTest('find model reacts to position change', (editor) => { - const findState = new FindReplaceState(); + const findState = disposables.add(new FindReplaceState()); findState.change({ searchString: 'hello' }, false); - const findModel = new FindModelBoundToEditorModel(editor, findState); + const findModel = disposables.add(new FindModelBoundToEditorModel(editor, findState)); assertFindState( editor, @@ -351,9 +365,9 @@ suite('FindModel', () => { }); findTest('find model next', (editor) => { - const findState = new FindReplaceState(); + const findState = disposables.add(new FindReplaceState()); findState.change({ searchString: 'hello', wholeWord: true }, false); - const findModel = new FindModelBoundToEditorModel(editor, findState); + const findModel = disposables.add(new FindModelBoundToEditorModel(editor, findState)); assertFindState( editor, @@ -437,9 +451,9 @@ suite('FindModel', () => { }); findTest('find model next stays in scope', (editor) => { - const findState = new FindReplaceState(); + const findState = disposables.add(new FindReplaceState()); findState.change({ searchString: 'hello', wholeWord: true, searchScope: [new Range(7, 1, 9, 1)] }, false); - const findModel = new FindModelBoundToEditorModel(editor, findState); + const findModel = disposables.add(new FindModelBoundToEditorModel(editor, findState)); assertFindState( editor, @@ -489,9 +503,9 @@ suite('FindModel', () => { }); findTest('multi-selection find model next stays in scope (overlap)', (editor) => { - const findState = new FindReplaceState(); + const findState = disposables.add(new FindReplaceState()); findState.change({ searchString: 'hello', wholeWord: true, searchScope: [new Range(7, 1, 8, 2), new Range(8, 1, 9, 1)] }, false); - const findModel = new FindModelBoundToEditorModel(editor, findState); + const findModel = disposables.add(new FindModelBoundToEditorModel(editor, findState)); assertFindState( editor, @@ -541,9 +555,9 @@ suite('FindModel', () => { }); findTest('multi-selection find model next stays in scope', (editor) => { - const findState = new FindReplaceState(); + const findState = disposables.add(new FindReplaceState()); findState.change({ searchString: 'hello', matchCase: true, wholeWord: false, searchScope: [new Range(6, 1, 7, 38), new Range(9, 3, 9, 38)] }, false); - const findModel = new FindModelBoundToEditorModel(editor, findState); + const findModel = disposables.add(new FindModelBoundToEditorModel(editor, findState)); assertFindState( editor, @@ -614,9 +628,9 @@ suite('FindModel', () => { }); findTest('find model prev', (editor) => { - const findState = new FindReplaceState(); + const findState = disposables.add(new FindReplaceState()); findState.change({ searchString: 'hello', wholeWord: true }, false); - const findModel = new FindModelBoundToEditorModel(editor, findState); + const findModel = disposables.add(new FindModelBoundToEditorModel(editor, findState)); assertFindState( editor, @@ -700,9 +714,9 @@ suite('FindModel', () => { }); findTest('find model prev stays in scope', (editor) => { - const findState = new FindReplaceState(); + const findState = disposables.add(new FindReplaceState()); findState.change({ searchString: 'hello', wholeWord: true, searchScope: [new Range(7, 1, 9, 1)] }, false); - const findModel = new FindModelBoundToEditorModel(editor, findState); + const findModel = disposables.add(new FindModelBoundToEditorModel(editor, findState)); assertFindState( editor, @@ -752,9 +766,9 @@ suite('FindModel', () => { }); findTest('find model next/prev with no matches', (editor) => { - const findState = new FindReplaceState(); + const findState = disposables.add(new FindReplaceState()); findState.change({ searchString: 'helloo', wholeWord: true }, false); - const findModel = new FindModelBoundToEditorModel(editor, findState); + const findModel = disposables.add(new FindModelBoundToEditorModel(editor, findState)); assertFindState( editor, @@ -784,9 +798,9 @@ suite('FindModel', () => { }); findTest('find model next/prev respects cursor position', (editor) => { - const findState = new FindReplaceState(); + const findState = disposables.add(new FindReplaceState()); findState.change({ searchString: 'hello', wholeWord: true }, false); - const findModel = new FindModelBoundToEditorModel(editor, findState); + const findModel = disposables.add(new FindModelBoundToEditorModel(editor, findState)); assertFindState( editor, @@ -833,9 +847,9 @@ suite('FindModel', () => { }); findTest('find ^', (editor) => { - const findState = new FindReplaceState(); + const findState = disposables.add(new FindReplaceState()); findState.change({ searchString: '^', isRegex: true }, false); - const findModel = new FindModelBoundToEditorModel(editor, findState); + const findModel = disposables.add(new FindModelBoundToEditorModel(editor, findState)); assertFindState( editor, @@ -904,9 +918,9 @@ suite('FindModel', () => { }); findTest('find $', (editor) => { - const findState = new FindReplaceState(); + const findState = disposables.add(new FindReplaceState()); findState.change({ searchString: '$', isRegex: true }, false); - const findModel = new FindModelBoundToEditorModel(editor, findState); + const findModel = disposables.add(new FindModelBoundToEditorModel(editor, findState)); assertFindState( editor, @@ -996,9 +1010,9 @@ suite('FindModel', () => { }); findTest('find next ^$', (editor) => { - const findState = new FindReplaceState(); + const findState = disposables.add(new FindReplaceState()); findState.change({ searchString: '^$', isRegex: true }, false); - const findModel = new FindModelBoundToEditorModel(editor, findState); + const findModel = disposables.add(new FindModelBoundToEditorModel(editor, findState)); assertFindState( editor, @@ -1048,9 +1062,9 @@ suite('FindModel', () => { }); findTest('find .*', (editor) => { - const findState = new FindReplaceState(); + const findState = disposables.add(new FindReplaceState()); findState.change({ searchString: '.*', isRegex: true }, false); - const findModel = new FindModelBoundToEditorModel(editor, findState); + const findModel = disposables.add(new FindModelBoundToEditorModel(editor, findState)); assertFindState( editor, @@ -1077,9 +1091,9 @@ suite('FindModel', () => { }); findTest('find next ^.*$', (editor) => { - const findState = new FindReplaceState(); + const findState = disposables.add(new FindReplaceState()); findState.change({ searchString: '^.*$', isRegex: true }, false); - const findModel = new FindModelBoundToEditorModel(editor, findState); + const findModel = disposables.add(new FindModelBoundToEditorModel(editor, findState)); assertFindState( editor, @@ -1148,9 +1162,9 @@ suite('FindModel', () => { }); findTest('find prev ^.*$', (editor) => { - const findState = new FindReplaceState(); + const findState = disposables.add(new FindReplaceState()); findState.change({ searchString: '^.*$', isRegex: true }, false); - const findModel = new FindModelBoundToEditorModel(editor, findState); + const findModel = disposables.add(new FindModelBoundToEditorModel(editor, findState)); assertFindState( editor, @@ -1219,9 +1233,9 @@ suite('FindModel', () => { }); findTest('find prev ^$', (editor) => { - const findState = new FindReplaceState(); + const findState = disposables.add(new FindReplaceState()); findState.change({ searchString: '^$', isRegex: true }, false); - const findModel = new FindModelBoundToEditorModel(editor, findState); + const findModel = disposables.add(new FindModelBoundToEditorModel(editor, findState)); assertFindState( editor, @@ -1271,9 +1285,9 @@ suite('FindModel', () => { }); findTest('replace hello', (editor) => { - const findState = new FindReplaceState(); + const findState = disposables.add(new FindReplaceState()); findState.change({ searchString: 'hello', replaceString: 'hi', wholeWord: true }, false); - const findModel = new FindModelBoundToEditorModel(editor, findState); + const findModel = disposables.add(new FindModelBoundToEditorModel(editor, findState)); assertFindState( editor, @@ -1367,9 +1381,9 @@ suite('FindModel', () => { }); findTest('replace bla', (editor) => { - const findState = new FindReplaceState(); + const findState = disposables.add(new FindReplaceState()); findState.change({ searchString: 'bla', replaceString: 'ciao' }, false); - const findModel = new FindModelBoundToEditorModel(editor, findState); + const findModel = disposables.add(new FindModelBoundToEditorModel(editor, findState)); assertFindState( editor, @@ -1432,9 +1446,9 @@ suite('FindModel', () => { }); findTest('replaceAll hello', (editor) => { - const findState = new FindReplaceState(); + const findState = disposables.add(new FindReplaceState()); findState.change({ searchString: 'hello', replaceString: 'hi', wholeWord: true }, false); - const findModel = new FindModelBoundToEditorModel(editor, findState); + const findModel = disposables.add(new FindModelBoundToEditorModel(editor, findState)); assertFindState( editor, @@ -1480,9 +1494,9 @@ suite('FindModel', () => { }); findTest('replaceAll two spaces with one space', (editor) => { - const findState = new FindReplaceState(); + const findState = disposables.add(new FindReplaceState()); findState.change({ searchString: ' ', replaceString: ' ' }, false); - const findModel = new FindModelBoundToEditorModel(editor, findState); + const findModel = disposables.add(new FindModelBoundToEditorModel(editor, findState)); assertFindState( editor, @@ -1522,9 +1536,9 @@ suite('FindModel', () => { }); findTest('replaceAll bla', (editor) => { - const findState = new FindReplaceState(); + const findState = disposables.add(new FindReplaceState()); findState.change({ searchString: 'bla', replaceString: 'ciao' }, false); - const findModel = new FindModelBoundToEditorModel(editor, findState); + const findModel = disposables.add(new FindModelBoundToEditorModel(editor, findState)); assertFindState( editor, @@ -1551,9 +1565,9 @@ suite('FindModel', () => { }); findTest('replaceAll bla with \\t\\n', (editor) => { - const findState = new FindReplaceState(); + const findState = disposables.add(new FindReplaceState()); findState.change({ searchString: 'bla', replaceString: '<\\n\\t>', isRegex: true }, false); - const findModel = new FindModelBoundToEditorModel(editor, findState); + const findModel = disposables.add(new FindModelBoundToEditorModel(editor, findState)); assertFindState( editor, @@ -1583,9 +1597,9 @@ suite('FindModel', () => { }); findTest('issue #3516: "replace all" moves page/cursor/focus/scroll to the place of the last replacement', (editor) => { - const findState = new FindReplaceState(); + const findState = disposables.add(new FindReplaceState()); findState.change({ searchString: 'include', replaceString: 'bar' }, false); - const findModel = new FindModelBoundToEditorModel(editor, findState); + const findModel = disposables.add(new FindModelBoundToEditorModel(editor, findState)); assertFindState( editor, @@ -1613,9 +1627,9 @@ suite('FindModel', () => { }); findTest('listens to model content changes', (editor) => { - const findState = new FindReplaceState(); + const findState = disposables.add(new FindReplaceState()); findState.change({ searchString: 'hello', replaceString: 'hi', wholeWord: true }, false); - const findModel = new FindModelBoundToEditorModel(editor, findState); + const findModel = disposables.add(new FindModelBoundToEditorModel(editor, findState)); assertFindState( editor, @@ -1642,9 +1656,9 @@ suite('FindModel', () => { }); findTest('selectAllMatches', (editor) => { - const findState = new FindReplaceState(); + const findState = disposables.add(new FindReplaceState()); findState.change({ searchString: 'hello', replaceString: 'hi', wholeWord: true }, false); - const findModel = new FindModelBoundToEditorModel(editor, findState); + const findModel = disposables.add(new FindModelBoundToEditorModel(editor, findState)); assertFindState( editor, @@ -1684,9 +1698,9 @@ suite('FindModel', () => { }); findTest('issue #14143 selectAllMatches should maintain primary cursor if feasible', (editor) => { - const findState = new FindReplaceState(); + const findState = disposables.add(new FindReplaceState()); findState.change({ searchString: 'hello', replaceString: 'hi', wholeWord: true }, false); - const findModel = new FindModelBoundToEditorModel(editor, findState); + const findModel = disposables.add(new FindModelBoundToEditorModel(editor, findState)); assertFindState( editor, @@ -1730,9 +1744,9 @@ suite('FindModel', () => { }); findTest('issue #1914: NPE when there is only one find match', (editor) => { - const findState = new FindReplaceState(); + const findState = disposables.add(new FindReplaceState()); findState.change({ searchString: 'cool.h' }, false); - const findModel = new FindModelBoundToEditorModel(editor, findState); + const findModel = disposables.add(new FindModelBoundToEditorModel(editor, findState)); assertFindState( editor, @@ -1768,9 +1782,9 @@ suite('FindModel', () => { }); findTest('replace when search string has look ahed regex', (editor) => { - const findState = new FindReplaceState(); + const findState = disposables.add(new FindReplaceState()); findState.change({ searchString: 'hello(?=\\sworld)', replaceString: 'hi', isRegex: true }, false); - const findModel = new FindModelBoundToEditorModel(editor, findState); + const findModel = disposables.add(new FindModelBoundToEditorModel(editor, findState)); assertFindState( editor, @@ -1834,9 +1848,9 @@ suite('FindModel', () => { }); findTest('replace when search string has look ahed regex and cursor is at the last find match', (editor) => { - const findState = new FindReplaceState(); + const findState = disposables.add(new FindReplaceState()); findState.change({ searchString: 'hello(?=\\sworld)', replaceString: 'hi', isRegex: true }, false); - const findModel = new FindModelBoundToEditorModel(editor, findState); + const findModel = disposables.add(new FindModelBoundToEditorModel(editor, findState)); editor.trigger('mouse', CoreNavigationCommands.MoveTo.id, { position: new Position(8, 14) @@ -1905,9 +1919,9 @@ suite('FindModel', () => { }); findTest('replaceAll when search string has look ahed regex', (editor) => { - const findState = new FindReplaceState(); + const findState = disposables.add(new FindReplaceState()); findState.change({ searchString: 'hello(?=\\sworld)', replaceString: 'hi', isRegex: true }, false); - const findModel = new FindModelBoundToEditorModel(editor, findState); + const findModel = disposables.add(new FindModelBoundToEditorModel(editor, findState)); assertFindState( editor, @@ -1938,9 +1952,9 @@ suite('FindModel', () => { }); findTest('replace when search string has look ahed regex and replace string has capturing groups', (editor) => { - const findState = new FindReplaceState(); + const findState = disposables.add(new FindReplaceState()); findState.change({ searchString: 'hel(lo)(?=\\sworld)', replaceString: 'hi$1', isRegex: true }, false); - const findModel = new FindModelBoundToEditorModel(editor, findState); + const findModel = disposables.add(new FindModelBoundToEditorModel(editor, findState)); assertFindState( editor, @@ -2004,9 +2018,9 @@ suite('FindModel', () => { }); findTest('replaceAll when search string has look ahed regex and replace string has capturing groups', (editor) => { - const findState = new FindReplaceState(); + const findState = disposables.add(new FindReplaceState()); findState.change({ searchString: 'wo(rl)d(?=.*;$)', replaceString: 'gi$1', isRegex: true }, false); - const findModel = new FindModelBoundToEditorModel(editor, findState); + const findModel = disposables.add(new FindModelBoundToEditorModel(editor, findState)); assertFindState( editor, @@ -2039,9 +2053,9 @@ suite('FindModel', () => { }); findTest('replaceAll when search string is multiline and has look ahed regex and replace string has capturing groups', (editor) => { - const findState = new FindReplaceState(); + const findState = disposables.add(new FindReplaceState()); findState.change({ searchString: 'wo(rl)d(.*;\\n)(?=.*hello)', replaceString: 'gi$1$2', isRegex: true, matchCase: true }, false); - const findModel = new FindModelBoundToEditorModel(editor, findState); + const findModel = disposables.add(new FindModelBoundToEditorModel(editor, findState)); assertFindState( editor, @@ -2070,9 +2084,9 @@ suite('FindModel', () => { }); findTest('replaceAll preserving case', (editor) => { - const findState = new FindReplaceState(); + const findState = disposables.add(new FindReplaceState()); findState.change({ searchString: 'hello', replaceString: 'goodbye', isRegex: false, matchCase: false, preserveCase: true }, false); - const findModel = new FindModelBoundToEditorModel(editor, findState); + const findModel = disposables.add(new FindModelBoundToEditorModel(editor, findState)); assertFindState( editor, @@ -2106,9 +2120,9 @@ suite('FindModel', () => { }); findTest('issue #18711 replaceAll with empty string', (editor) => { - const findState = new FindReplaceState(); + const findState = disposables.add(new FindReplaceState()); findState.change({ searchString: 'hello', replaceString: '', wholeWord: true }, false); - const findModel = new FindModelBoundToEditorModel(editor, findState); + const findModel = disposables.add(new FindModelBoundToEditorModel(editor, findState)); assertFindState( editor, @@ -2143,9 +2157,9 @@ suite('FindModel', () => { initialText += 'line' + i + '\n'; } editor!.getModel()!.setValue(initialText); - const findState = new FindReplaceState(); + const findState = disposables.add(new FindReplaceState()); findState.change({ searchString: '^', replaceString: 'a ', isRegex: true }, false); - const findModel = new FindModelBoundToEditorModel(editor, findState); + const findModel = disposables.add(new FindModelBoundToEditorModel(editor, findState)); findModel.replaceAll(); @@ -2161,9 +2175,9 @@ suite('FindModel', () => { }); findTest('issue #19740 Find and replace capture group/backreference inserts `undefined` instead of empty string', (editor) => { - const findState = new FindReplaceState(); + const findState = disposables.add(new FindReplaceState()); findState.change({ searchString: 'hello(z)?', replaceString: 'hi$1', isRegex: true, matchCase: true }, false); - const findModel = new FindModelBoundToEditorModel(editor, findState); + const findModel = disposables.add(new FindModelBoundToEditorModel(editor, findState)); assertFindState( editor, @@ -2192,9 +2206,9 @@ suite('FindModel', () => { }); findTest('issue #27083. search scope works even if it is a single line', (editor) => { - const findState = new FindReplaceState(); + const findState = disposables.add(new FindReplaceState()); findState.change({ searchString: 'hello', wholeWord: true, searchScope: [new Range(7, 1, 8, 1)] }, false); - const findModel = new FindModelBoundToEditorModel(editor, findState); + const findModel = disposables.add(new FindModelBoundToEditorModel(editor, findState)); assertFindState( editor, @@ -2210,9 +2224,9 @@ suite('FindModel', () => { }); findTest('issue #3516: Control behavior of "Next" operations (not looping back to beginning)', (editor) => { - const findState = new FindReplaceState(); + const findState = disposables.add(new FindReplaceState()); findState.change({ searchString: 'hello', loop: false }, false); - const findModel = new FindModelBoundToEditorModel(editor, findState); + const findModel = disposables.add(new FindModelBoundToEditorModel(editor, findState)); assert.strictEqual(findState.matchesCount, 5); @@ -2290,9 +2304,9 @@ suite('FindModel', () => { }); findTest('issue #3516: Control behavior of "Next" operations (looping back to beginning)', (editor) => { - const findState = new FindReplaceState(); + const findState = disposables.add(new FindReplaceState()); findState.change({ searchString: 'hello' }, false); - const findModel = new FindModelBoundToEditorModel(editor, findState); + const findModel = disposables.add(new FindModelBoundToEditorModel(editor, findState)); assert.strictEqual(findState.matchesCount, 5); diff --git a/src/vs/editor/contrib/snippet/test/browser/snippetController2.old.test.ts b/src/vs/editor/contrib/snippet/test/browser/snippetController2.old.test.ts index 1fb079aef00..e0f11350e89 100644 --- a/src/vs/editor/contrib/snippet/test/browser/snippetController2.old.test.ts +++ b/src/vs/editor/contrib/snippet/test/browser/snippetController2.old.test.ts @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; import { mock } from 'vs/base/test/common/mock'; +import { ensureNoDisposablesAreLeakedInTestSuite } from 'vs/base/test/common/utils'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { Position } from 'vs/editor/common/core/position'; import { Selection } from 'vs/editor/common/core/selection'; @@ -19,11 +20,20 @@ import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace class TestSnippetController extends SnippetController2 { + private _testLanguageConfigurationService: TestLanguageConfigurationService; + constructor( editor: ICodeEditor, @IContextKeyService private readonly _contextKeyService: IContextKeyService ) { - super(editor, new NullLogService(), new LanguageFeaturesService(), _contextKeyService, new TestLanguageConfigurationService()); + const testLanguageConfigurationService = new TestLanguageConfigurationService(); + super(editor, new NullLogService(), new LanguageFeaturesService(), _contextKeyService, testLanguageConfigurationService); + this._testLanguageConfigurationService = testLanguageConfigurationService; + } + + override dispose(): void { + super.dispose(); + this._testLanguageConfigurationService.dispose(); } isInSnippetMode(): boolean { @@ -33,6 +43,8 @@ class TestSnippetController extends SnippetController2 { suite('SnippetController', () => { + ensureNoDisposablesAreLeakedInTestSuite(); + function snippetTest(cb: (editor: ITestCodeEditor, template: string, snippetController: TestSnippetController) => void, lines?: string[]): void { if (!lines) { diff --git a/src/vs/editor/standalone/browser/standaloneCodeEditorService.ts b/src/vs/editor/standalone/browser/standaloneCodeEditorService.ts index f5b83651667..fff134d4902 100644 --- a/src/vs/editor/standalone/browser/standaloneCodeEditorService.ts +++ b/src/vs/editor/standalone/browser/standaloneCodeEditorService.ts @@ -27,17 +27,17 @@ export class StandaloneCodeEditorService extends AbstractCodeEditorService { @IThemeService themeService: IThemeService, ) { super(themeService); - this.onCodeEditorAdd(() => this._checkContextKey()); - this.onCodeEditorRemove(() => this._checkContextKey()); + this._register(this.onCodeEditorAdd(() => this._checkContextKey())); + this._register(this.onCodeEditorRemove(() => this._checkContextKey())); this._editorIsOpen = contextKeyService.createKey('editorIsOpen', false); this._activeCodeEditor = null; - this.registerCodeEditorOpenHandler(async (input, source, sideBySide) => { + this._register(this.registerCodeEditorOpenHandler(async (input, source, sideBySide) => { if (!source) { return null; } return this.doOpenEditor(source, input); - }); + })); } private _checkContextKey(): void { diff --git a/src/vs/editor/standalone/browser/standaloneThemeService.ts b/src/vs/editor/standalone/browser/standaloneThemeService.ts index a391249e6e0..cac2e96a01f 100644 --- a/src/vs/editor/standalone/browser/standaloneThemeService.ts +++ b/src/vs/editor/standalone/browser/standaloneThemeService.ts @@ -244,7 +244,7 @@ export class StandaloneThemeService extends Disposable implements IStandaloneThe this._knownThemes.set(HC_BLACK_THEME_NAME, newBuiltInTheme(HC_BLACK_THEME_NAME)); this._knownThemes.set(HC_LIGHT_THEME_NAME, newBuiltInTheme(HC_LIGHT_THEME_NAME)); - const iconsStyleSheet = getIconsStyleSheet(this); + const iconsStyleSheet = this._register(getIconsStyleSheet(this)); this._codiconCSS = iconsStyleSheet.getCSS(); this._themeCSS = ''; @@ -255,10 +255,10 @@ export class StandaloneThemeService extends Disposable implements IStandaloneThe this.setTheme(VS_LIGHT_THEME_NAME); this._onOSSchemeChanged(); - iconsStyleSheet.onDidChange(() => { + this._register(iconsStyleSheet.onDidChange(() => { this._codiconCSS = iconsStyleSheet.getCSS(); this._updateCSS(); - }); + })); addMatchMediaChangeListener('(forced-colors: active)', () => { this._onOSSchemeChanged(); diff --git a/src/vs/editor/standalone/test/browser/standaloneServices.test.ts b/src/vs/editor/standalone/test/browser/standaloneServices.test.ts index 62a68ee7dd2..e716ea922d5 100644 --- a/src/vs/editor/standalone/test/browser/standaloneServices.test.ts +++ b/src/vs/editor/standalone/test/browser/standaloneServices.test.ts @@ -6,6 +6,7 @@ import * as assert from 'assert'; import { KeyCode } from 'vs/base/common/keyCodes'; import { DisposableStore } from 'vs/base/common/lifecycle'; +import { ensureNoDisposablesAreLeakedInTestSuite } from 'vs/base/test/common/utils'; import { StandaloneCodeEditorService } from 'vs/editor/standalone/browser/standaloneCodeEditorService'; import { StandaloneCommandService, StandaloneConfigurationService, StandaloneKeybindingService, StandaloneNotificationService } from 'vs/editor/standalone/browser/standaloneServices'; import { StandaloneThemeService } from 'vs/editor/standalone/browser/standaloneThemeService'; @@ -18,6 +19,8 @@ import { NullTelemetryService } from 'vs/platform/telemetry/common/telemetryUtil suite('StandaloneKeybindingService', () => { + ensureNoDisposablesAreLeakedInTestSuite(); + class TestStandaloneKeybindingService extends StandaloneKeybindingService { public testDispatch(e: IKeyboardEvent): void { super._dispatch(e, null!); diff --git a/src/vs/platform/remote/test/electron-sandbox/remoteAuthorityResolverService.test.ts b/src/vs/platform/remote/test/electron-sandbox/remoteAuthorityResolverService.test.ts index a4a7a964aa8..a5bacbb8c86 100644 --- a/src/vs/platform/remote/test/electron-sandbox/remoteAuthorityResolverService.test.ts +++ b/src/vs/platform/remote/test/electron-sandbox/remoteAuthorityResolverService.test.ts @@ -4,12 +4,16 @@ *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; +import { ensureNoDisposablesAreLeakedInTestSuite } from 'vs/base/test/common/utils'; import product from 'vs/platform/product/common/product'; import { IProductService } from 'vs/platform/product/common/productService'; import { RemoteAuthorityResolverError, RemoteAuthorityResolverErrorCode } from 'vs/platform/remote/common/remoteAuthorityResolver'; import { RemoteAuthorityResolverService } from 'vs/platform/remote/electron-sandbox/remoteAuthorityResolverService'; suite('RemoteAuthorityResolverService', () => { + + ensureNoDisposablesAreLeakedInTestSuite(); + test('issue #147318: RemoteAuthorityResolverError keeps the same type', async () => { const productService: IProductService = { _serviceBrand: undefined, ...product }; const service = new RemoteAuthorityResolverService(productService, undefined as any); @@ -21,5 +25,6 @@ suite('RemoteAuthorityResolverService', () => { } catch (err) { assert.strictEqual(RemoteAuthorityResolverError.isTemporarilyNotAvailable(err), true); } + service.dispose(); }); }); diff --git a/src/vs/platform/theme/browser/iconsStyleSheet.ts b/src/vs/platform/theme/browser/iconsStyleSheet.ts index fc788a234a7..6bfce5b466d 100644 --- a/src/vs/platform/theme/browser/iconsStyleSheet.ts +++ b/src/vs/platform/theme/browser/iconsStyleSheet.ts @@ -5,22 +5,28 @@ import { asCSSPropertyValue, asCSSUrl } from 'vs/base/browser/dom'; import { Emitter, Event } from 'vs/base/common/event'; +import { DisposableStore, IDisposable } from 'vs/base/common/lifecycle'; import { ThemeIcon } from 'vs/base/common/themables'; import { getIconRegistry, IconContribution, IconFontDefinition } from 'vs/platform/theme/common/iconRegistry'; import { IProductIconTheme, IThemeService } from 'vs/platform/theme/common/themeService'; -export interface IIconsStyleSheet { +export interface IIconsStyleSheet extends IDisposable { getCSS(): string; readonly onDidChange: Event; } export function getIconsStyleSheet(themeService: IThemeService | undefined): IIconsStyleSheet { - const onDidChangeEmmiter = new Emitter(); + const disposable = new DisposableStore(); + + const onDidChangeEmmiter = disposable.add(new Emitter()); const iconRegistry = getIconRegistry(); - iconRegistry.onDidChange(() => onDidChangeEmmiter.fire()); - themeService?.onDidProductIconThemeChange(() => onDidChangeEmmiter.fire()); + disposable.add(iconRegistry.onDidChange(() => onDidChangeEmmiter.fire())); + if (themeService) { + disposable.add(themeService.onDidProductIconThemeChange(() => onDidChangeEmmiter.fire())); + } return { + dispose: () => disposable.dispose(), onDidChange: onDidChangeEmmiter.event, getCSS() { const productIconTheme = themeService ? themeService.getProductIconTheme() : new UnthemedProductIconTheme(); diff --git a/src/vs/workbench/api/test/browser/mainThreadEditors.test.ts b/src/vs/workbench/api/test/browser/mainThreadEditors.test.ts index 7a9bf86bce9..71dd40df6d5 100644 --- a/src/vs/workbench/api/test/browser/mainThreadEditors.test.ts +++ b/src/vs/workbench/api/test/browser/mainThreadEditors.test.ts @@ -4,57 +4,58 @@ *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; -import { SingleProxyRPCProtocol } from 'vs/workbench/api/test/common/testRPCProtocol'; -import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService'; -import { ModelService } from 'vs/editor/common/services/modelService'; -import { TestCodeEditorService } from 'vs/editor/test/browser/editorTestServices'; -import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; -import { IWorkspaceTextEditDto } from 'vs/workbench/api/common/extHost.protocol'; -import { mock } from 'vs/base/test/common/mock'; import { Event } from 'vs/base/common/event'; +import { DisposableStore, IReference, ImmortalReference } from 'vs/base/common/lifecycle'; import { URI } from 'vs/base/common/uri'; -import { Range } from 'vs/editor/common/core/range'; -import { Position } from 'vs/editor/common/core/position'; -import { IModelService } from 'vs/editor/common/services/model'; -import { EditOperation } from 'vs/editor/common/core/editOperation'; -import { TestFileService, TestEditorService, TestEditorGroupsService, TestEnvironmentService, TestLifecycleService, TestWorkingCopyService } from 'vs/workbench/test/browser/workbenchTestServices'; -import { BulkEditService } from 'vs/workbench/contrib/bulkEdit/browser/bulkEditService'; -import { NullLogService, ILogService } from 'vs/platform/log/common/log'; -import { ITextModelService, IResolvedTextEditorModel } from 'vs/editor/common/services/resolverService'; -import { IReference, ImmortalReference, DisposableStore } from 'vs/base/common/lifecycle'; -import { LabelService } from 'vs/workbench/services/label/common/labelService'; -import { TestThemeService } from 'vs/platform/theme/test/common/testThemeService'; -import { IEditorWorkerService } from 'vs/editor/common/services/editorWorker'; -import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { mock } from 'vs/base/test/common/mock'; +import { ensureNoDisposablesAreLeakedInTestSuite } from 'vs/base/test/common/utils'; +import { IBulkEditService } from 'vs/editor/browser/services/bulkEditService'; import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; +import { EditOperation } from 'vs/editor/common/core/editOperation'; +import { Position } from 'vs/editor/common/core/position'; +import { Range } from 'vs/editor/common/core/range'; +import { ITextSnapshot } from 'vs/editor/common/model'; +import { IEditorWorkerService } from 'vs/editor/common/services/editorWorker'; +import { LanguageService } from 'vs/editor/common/services/languageService'; +import { IModelService } from 'vs/editor/common/services/model'; +import { ModelService } from 'vs/editor/common/services/modelService'; +import { IResolvedTextEditorModel, ITextModelService } from 'vs/editor/common/services/resolverService'; +import { TestCodeEditorService } from 'vs/editor/test/browser/editorTestServices'; +import { TestLanguageConfigurationService } from 'vs/editor/test/common/modes/testLanguageConfigurationService'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService'; +import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; +import { TestDialogService } from 'vs/platform/dialogs/test/common/testDialogService'; +import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { IFileService } from 'vs/platform/files/common/files'; +import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; +import { InstantiationService } from 'vs/platform/instantiation/common/instantiationService'; +import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; +import { ILabelService } from 'vs/platform/label/common/label'; +import { ILogService, NullLogService } from 'vs/platform/log/common/log'; +import { INotificationService } from 'vs/platform/notification/common/notification'; +import { TestNotificationService } from 'vs/platform/notification/test/common/testNotificationService'; +import { TestThemeService } from 'vs/platform/theme/test/common/testThemeService'; +import { IUndoRedoService } from 'vs/platform/undoRedo/common/undoRedo'; +import { UndoRedoService } from 'vs/platform/undoRedo/common/undoRedoService'; +import { IUriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentity'; +import { UriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentityService'; +import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; +import { MainThreadBulkEdits } from 'vs/workbench/api/browser/mainThreadBulkEdits'; +import { IWorkspaceTextEditDto } from 'vs/workbench/api/common/extHost.protocol'; +import { SingleProxyRPCProtocol } from 'vs/workbench/api/test/common/testRPCProtocol'; +import { BulkEditService } from 'vs/workbench/contrib/bulkEdit/browser/bulkEditService'; import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; -import { InstantiationService } from 'vs/platform/instantiation/common/instantiationService'; -import { IBulkEditService } from 'vs/editor/browser/services/bulkEditService'; -import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; -import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; -import { ILabelService } from 'vs/platform/label/common/label'; -import { IWorkingCopyFileService, IMoveOperation, IDeleteOperation, ICopyOperation, ICreateFileOperation, ICreateOperation } from 'vs/workbench/services/workingCopy/common/workingCopyFileService'; -import { UndoRedoService } from 'vs/platform/undoRedo/common/undoRedoService'; -import { TestDialogService } from 'vs/platform/dialogs/test/common/testDialogService'; -import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; -import { IUndoRedoService } from 'vs/platform/undoRedo/common/undoRedo'; -import { TestNotificationService } from 'vs/platform/notification/test/common/testNotificationService'; -import { INotificationService } from 'vs/platform/notification/common/notification'; -import { TestTextResourcePropertiesService, TestContextService } from 'vs/workbench/test/common/workbenchTestServices'; -import { IUriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentity'; -import { ITextSnapshot } from 'vs/editor/common/model'; +import { LabelService } from 'vs/workbench/services/label/common/labelService'; import { ILifecycleService } from 'vs/workbench/services/lifecycle/common/lifecycle'; -import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { IPaneCompositePartService } from 'vs/workbench/services/panecomposite/browser/panecomposite'; -import { TestLanguageConfigurationService } from 'vs/editor/test/common/modes/testLanguageConfigurationService'; -import { LanguageService } from 'vs/editor/common/services/languageService'; -import { MainThreadBulkEdits } from 'vs/workbench/api/browser/mainThreadBulkEdits'; +import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; +import { ICopyOperation, ICreateFileOperation, ICreateOperation, IDeleteOperation, IMoveOperation, IWorkingCopyFileService } from 'vs/workbench/services/workingCopy/common/workingCopyFileService'; import { IWorkingCopyService } from 'vs/workbench/services/workingCopy/common/workingCopyService'; -import { UriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentityService'; +import { TestEditorGroupsService, TestEditorService, TestEnvironmentService, TestFileService, TestLifecycleService, TestWorkingCopyService } from 'vs/workbench/test/browser/workbenchTestServices'; +import { TestContextService, TestTextResourcePropertiesService } from 'vs/workbench/test/common/workbenchTestServices'; suite('MainThreadEditors', () => { @@ -185,9 +186,11 @@ suite('MainThreadEditors', () => { disposables.dispose(); }); + ensureNoDisposablesAreLeakedInTestSuite(); + test(`applyWorkspaceEdit returns false if model is changed by user`, () => { - const model = modelService.createModel('something', null, resource); + const model = disposables.add(modelService.createModel('something', null, resource)); const workspaceResourceEdit: IWorkspaceTextEditDto = { resource: resource, @@ -208,7 +211,7 @@ suite('MainThreadEditors', () => { test(`issue #54773: applyWorkspaceEdit checks model version in race situation`, () => { - const model = modelService.createModel('something', null, resource); + const model = disposables.add(modelService.createModel('something', null, resource)); const workspaceResourceEdit1: IWorkspaceTextEditDto = { resource: resource, diff --git a/src/vs/workbench/services/extensions/test/browser/extensionService.test.ts b/src/vs/workbench/services/extensions/test/browser/extensionService.test.ts index f99c067f3a3..7bb517785af 100644 --- a/src/vs/workbench/services/extensions/test/browser/extensionService.test.ts +++ b/src/vs/workbench/services/extensions/test/browser/extensionService.test.ts @@ -7,6 +7,7 @@ import * as assert from 'assert'; import { Event } from 'vs/base/common/event'; import { DisposableStore } from 'vs/base/common/lifecycle'; import { mock } from 'vs/base/test/common/mock'; +import { ensureNoDisposablesAreLeakedInTestSuite } from 'vs/base/test/common/utils'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService'; import { TestDialogService } from 'vs/platform/dialogs/test/common/testDialogService'; @@ -49,6 +50,9 @@ import { TestEnvironmentService, TestFileService, TestLifecycleService, TestRemo import { TestContextService } from 'vs/workbench/test/common/workbenchTestServices'; suite('BrowserExtensionService', () => { + + ensureNoDisposablesAreLeakedInTestSuite(); + test('pickRunningLocation', () => { assert.deepStrictEqual(BrowserExtensionHostKindPicker.pickRunningLocation([], false, false, ExtensionRunningPreference.None), null); assert.deepStrictEqual(BrowserExtensionHostKindPicker.pickRunningLocation([], false, true, ExtensionRunningPreference.None), null); @@ -255,6 +259,8 @@ suite('ExtensionService', () => { disposables.dispose(); }); + ensureNoDisposablesAreLeakedInTestSuite(); + test('issue #152204: Remote extension host not disposed after closing vscode client', async () => { await extService.startExtensionHosts(); await extService.stopExtensionHosts('foo'); @@ -270,8 +276,8 @@ suite('ExtensionService', () => { test('Extension host not disposed when vetoed (sync)', async () => { await extService.startExtensionHosts(); - extService.onWillStop(e => e.veto(true, 'test 1')); - extService.onWillStop(e => e.veto(false, 'test 2')); + disposables.add(extService.onWillStop(e => e.veto(true, 'test 1'))); + disposables.add(extService.onWillStop(e => e.veto(false, 'test 2'))); await extService.stopExtensionHosts('foo'); assert.deepStrictEqual(extService.order, (['create 1', 'create 2', 'create 3'])); @@ -280,9 +286,9 @@ suite('ExtensionService', () => { test('Extension host not disposed when vetoed (async)', async () => { await extService.startExtensionHosts(); - extService.onWillStop(e => e.veto(false, 'test 1')); - extService.onWillStop(e => e.veto(Promise.resolve(true), 'test 2')); - extService.onWillStop(e => e.veto(Promise.resolve(false), 'test 3')); + disposables.add(extService.onWillStop(e => e.veto(false, 'test 1'))); + disposables.add(extService.onWillStop(e => e.veto(Promise.resolve(true), 'test 2'))); + disposables.add(extService.onWillStop(e => e.veto(Promise.resolve(false), 'test 3'))); await extService.stopExtensionHosts('foo'); assert.deepStrictEqual(extService.order, (['create 1', 'create 2', 'create 3'])); diff --git a/src/vs/workbench/services/extensions/test/common/extensionManifestPropertiesService.test.ts b/src/vs/workbench/services/extensions/test/common/extensionManifestPropertiesService.test.ts index 1924d01fe44..9cde0946333 100644 --- a/src/vs/workbench/services/extensions/test/common/extensionManifestPropertiesService.test.ts +++ b/src/vs/workbench/services/extensions/test/common/extensionManifestPropertiesService.test.ts @@ -4,20 +4,34 @@ *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; -import { IExtensionManifest, ExtensionUntrustedWorkspaceSupportType } from 'vs/platform/extensions/common/extensions'; -import { ExtensionManifestPropertiesService } from 'vs/workbench/services/extensions/common/extensionManifestPropertiesService'; -import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService'; -import { TestProductService, TestWorkspaceTrustEnablementService } from 'vs/workbench/test/common/workbenchTestServices'; -import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { IProductService } from 'vs/platform/product/common/productService'; +import { DisposableStore } from 'vs/base/common/lifecycle'; import { isWeb } from 'vs/base/common/platform'; -import { IWorkspaceTrustEnablementService } from 'vs/platform/workspace/common/workspaceTrust'; +import { ensureNoDisposablesAreLeakedInTestSuite } from 'vs/base/test/common/utils'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService'; +import { ExtensionUntrustedWorkspaceSupportType, IExtensionManifest } from 'vs/platform/extensions/common/extensions'; +import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock'; import { NullLogService } from 'vs/platform/log/common/log'; +import { IProductService } from 'vs/platform/product/common/productService'; +import { IWorkspaceTrustEnablementService } from 'vs/platform/workspace/common/workspaceTrust'; +import { ExtensionManifestPropertiesService } from 'vs/workbench/services/extensions/common/extensionManifestPropertiesService'; +import { TestProductService, TestWorkspaceTrustEnablementService } from 'vs/workbench/test/common/workbenchTestServices'; suite('ExtensionManifestPropertiesService - ExtensionKind', () => { - let testObject = new ExtensionManifestPropertiesService(TestProductService, new TestConfigurationService(), new TestWorkspaceTrustEnablementService(), new NullLogService()); + let disposables: DisposableStore; + let testObject: ExtensionManifestPropertiesService; + + setup(() => { + disposables = new DisposableStore(); + testObject = disposables.add(new ExtensionManifestPropertiesService(TestProductService, new TestConfigurationService(), new TestWorkspaceTrustEnablementService(), new NullLogService())); + }); + + teardown(() => { + disposables.dispose(); + }); + + ensureNoDisposablesAreLeakedInTestSuite(); test('declarative with extension dependencies', () => { assert.deepStrictEqual(testObject.getExtensionKind({ extensionDependencies: ['ext1'] }), isWeb ? ['workspace', 'web'] : ['workspace']); @@ -68,12 +82,12 @@ suite('ExtensionManifestPropertiesService - ExtensionKind', () => { }); test('opt out from web through settings even if it can run in web', () => { - testObject = new ExtensionManifestPropertiesService(TestProductService, new TestConfigurationService({ remote: { extensionKind: { 'pub.a': ['-web'] } } }), new TestWorkspaceTrustEnablementService(), new NullLogService()); + testObject = disposables.add(new ExtensionManifestPropertiesService(TestProductService, new TestConfigurationService({ remote: { extensionKind: { 'pub.a': ['-web'] } } }), new TestWorkspaceTrustEnablementService(), new NullLogService())); assert.deepStrictEqual(testObject.getExtensionKind({ browser: 'main.browser.js', publisher: 'pub', name: 'a' }), ['ui', 'workspace']); }); test('opt out from web and include only workspace through settings even if it can run in web', () => { - testObject = new ExtensionManifestPropertiesService(TestProductService, new TestConfigurationService({ remote: { extensionKind: { 'pub.a': ['-web', 'workspace'] } } }), new TestWorkspaceTrustEnablementService(), new NullLogService()); + testObject = disposables.add(new ExtensionManifestPropertiesService(TestProductService, new TestConfigurationService({ remote: { extensionKind: { 'pub.a': ['-web', 'workspace'] } } }), new TestWorkspaceTrustEnablementService(), new NullLogService())); assert.deepStrictEqual(testObject.getExtensionKind({ browser: 'main.browser.js', publisher: 'pub', name: 'a' }), ['workspace']); });