From f4dd1d1351b0bebaa9ebb66694a5ba9efbd4bbc5 Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Mon, 17 Dec 2018 18:49:02 -0800 Subject: [PATCH] Search tree - fix tests and match actions --- .../test/common/instantiationServiceMock.ts | 10 +-- .../parts/search/browser/searchActions.ts | 3 - .../parts/search/browser/searchResultsView.ts | 16 ++-- .../parts/search/browser/searchView.ts | 6 +- .../search/test/browser/mockSearchTree.ts | 88 +++++++++++++++++++ .../search/test/browser/searchActions.test.ts | 22 ++--- .../search/test/browser/searchViewlet.test.ts | 84 +++++++++--------- 7 files changed, 155 insertions(+), 74 deletions(-) create mode 100644 src/vs/workbench/parts/search/test/browser/mockSearchTree.ts diff --git a/src/vs/platform/instantiation/test/common/instantiationServiceMock.ts b/src/vs/platform/instantiation/test/common/instantiationServiceMock.ts index deafa400dce..4d3c9ae0a4c 100644 --- a/src/vs/platform/instantiation/test/common/instantiationServiceMock.ts +++ b/src/vs/platform/instantiation/test/common/instantiationServiceMock.ts @@ -4,10 +4,9 @@ *--------------------------------------------------------------------------------------------*/ import * as sinon from 'sinon'; -import * as types from 'vs/base/common/types'; +import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; import { InstantiationService } from 'vs/platform/instantiation/common/instantiationService'; import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; -import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; interface IServiceMock { id: ServiceIdentifier; @@ -122,13 +121,6 @@ export class TestInstantiationService extends InstantiationService { } } -export function stubFunction(ctor: any, fnProperty: string, value: any): T | sinon.SinonStub { - let stub = sinon.createStubInstance(ctor); - stub[fnProperty].restore(); - sinon.stub(stub, fnProperty, types.isFunction(value) ? value : () => { return value; }); - return stub; -} - interface SinonOptions { mock?: boolean; stub?: boolean; diff --git a/src/vs/workbench/parts/search/browser/searchActions.ts b/src/vs/workbench/parts/search/browser/searchActions.ts index c4d8b500c6e..151bb3b002c 100644 --- a/src/vs/workbench/parts/search/browser/searchActions.ts +++ b/src/vs/workbench/parts/search/browser/searchActions.ts @@ -266,9 +266,6 @@ export class CollapseDeepestExpandedLevelAction extends Action { const searchView = getSearchView(this.viewletService, this.panelService); if (searchView) { const viewer = searchView.getControl(); - // if (viewer.getHighlight()) { - // return Promise.resolve(null); // Global action disabled if user is in edit mode from another action - // } /** * one level to collapse so collapse everything. If FolderMatch, check if there are visible grandchildren, diff --git a/src/vs/workbench/parts/search/browser/searchResultsView.ts b/src/vs/workbench/parts/search/browser/searchResultsView.ts index 30a94f6ef7f..200902371c4 100644 --- a/src/vs/workbench/parts/search/browser/searchResultsView.ts +++ b/src/vs/workbench/parts/search/browser/searchResultsView.ts @@ -27,7 +27,7 @@ import { attachBadgeStyler } from 'vs/platform/theme/common/styler'; import { IThemeService } from 'vs/platform/theme/common/themeService'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { FileLabel } from 'vs/workbench/browser/labels'; -import { RemoveAction, ReplaceAllAction, ReplaceAllInFolderAction } from 'vs/workbench/parts/search/browser/searchActions'; +import { RemoveAction, ReplaceAllAction, ReplaceAllInFolderAction, ReplaceAction } from 'vs/workbench/parts/search/browser/searchActions'; import { SearchView } from 'vs/workbench/parts/search/browser/searchView'; import { FileMatch, FileMatchOrMatch, FolderMatch, Match, RenderableMatch, searchMatchComparer, SearchModel, SearchResult } from 'vs/workbench/parts/search/common/searchModel'; @@ -85,8 +85,8 @@ export class FolderMatchRenderer extends Disposable implements ITreeRenderer, index: number, templateData: IMatchTemplate): void { diff --git a/src/vs/workbench/parts/search/browser/searchView.ts b/src/vs/workbench/parts/search/browser/searchView.ts index 9ad0bc99da3..37c57870c04 100644 --- a/src/vs/workbench/parts/search/browser/searchView.ts +++ b/src/vs/workbench/parts/search/browser/searchView.ts @@ -92,7 +92,7 @@ function createFileIterator(fileMatch: FileMatch): Iterator (>{ element: r })); } -function createIterator(match: FolderMatch | FileMatch | SearchResult, collapseResults: ISearchConfigurationProperties['collapseResults']): Iterator> { +export function createIterator(match: FolderMatch | FileMatch | SearchResult, collapseResults: ISearchConfigurationProperties['collapseResults']): Iterator> { return match instanceof SearchResult ? createResultIterator(match, collapseResults) : match instanceof FolderMatch ? createFolderIterator(match, collapseResults) : createFileIterator(match); @@ -574,9 +574,9 @@ export class SearchView extends Viewlet implements IViewlet, IPanel { this.resultsElement, delegate, [ - this._register(this.instantiationService.createInstance(FolderMatchRenderer, this, this.viewModel)), + this._register(this.instantiationService.createInstance(FolderMatchRenderer, this.viewModel, this)), this._register(this.instantiationService.createInstance(FileMatchRenderer, this.viewModel, this)), - this._register(this.instantiationService.createInstance(MatchRenderer, this.viewModel)), + this._register(this.instantiationService.createInstance(MatchRenderer, this.viewModel, this)), ], {}); diff --git a/src/vs/workbench/parts/search/test/browser/mockSearchTree.ts b/src/vs/workbench/parts/search/test/browser/mockSearchTree.ts new file mode 100644 index 00000000000..eb4a7517a69 --- /dev/null +++ b/src/vs/workbench/parts/search/test/browser/mockSearchTree.ts @@ -0,0 +1,88 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { ITreeNavigator } from 'vs/base/browser/ui/tree/tree'; +import { Emitter } from 'vs/base/common/event'; +import { IDisposable } from 'vs/base/common/lifecycle'; + +const someEvent = new Emitter().event; + +/** + * Add stub methods as needed + */ +export class MockObjectTree implements IDisposable { + + get onDidChangeFocus() { return someEvent; } + get onDidChangeSelection() { return someEvent; } + get onDidOpen() { return someEvent; } + + get onMouseClick() { return someEvent; } + get onMouseDblClick() { return someEvent; } + get onContextMenu() { return someEvent; } + + get onKeyDown() { return someEvent; } + get onKeyUp() { return someEvent; } + get onKeyPress() { return someEvent; } + + get onDidFocus() { return someEvent; } + get onDidBlur() { return someEvent; } + + get onDidChangeCollapseState() { return someEvent; } + get onDidChangeRenderNodeCount() { return someEvent; } + + get onDidDispose() { return someEvent; } + + constructor(private elements: any[]) { } + + domFocus(): void { } + + collapse(location: TRef, recursive: boolean = false): boolean { + return true; + } + + expand(location: TRef, recursive: boolean = false): boolean { + return true; + } + + navigate(start?: TRef): ITreeNavigator { + const startIdx = start ? this.elements.indexOf(start) : + undefined; + + return new ArrayNavigator(this.elements, startIdx); + } + + dispose(): void { + } +} + +class ArrayNavigator implements ITreeNavigator { + constructor(private elements: T[], private index = 0) { } + + current(): T | null { + return this.elements[this.index]; + } + + previous(): T | null { + return this.elements[--this.index]; + } + + parent(): T | null { + throw new Error('not implemented'); + } + + first(): T | null { + this.index = 0; + return this.elements[this.index]; + } + + last(): T | null { + this.index = this.elements.length - 1; + return this.elements[this.index]; + } + + next(): T | null { + return this.elements[++this.index]; + } +} diff --git a/src/vs/workbench/parts/search/test/browser/searchActions.test.ts b/src/vs/workbench/parts/search/test/browser/searchActions.test.ts index a445e1c6aed..97e21219a41 100644 --- a/src/vs/workbench/parts/search/test/browser/searchActions.test.ts +++ b/src/vs/workbench/parts/search/test/browser/searchActions.test.ts @@ -2,22 +2,22 @@ * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ + import * as assert from 'assert'; +import { Keybinding } from 'vs/base/common/keyCodes'; +import { OS } from 'vs/base/common/platform'; import { URI } from 'vs/base/common/uri'; -import { TestInstantiationService, stubFunction } from 'vs/platform/instantiation/test/common/instantiationServiceMock'; -import { Match, FileMatch, FileMatchOrMatch } from 'vs/workbench/parts/search/common/searchModel'; -import { ReplaceAction } from 'vs/workbench/parts/search/browser/searchActions'; -import { ArrayNavigator } from 'vs/base/common/iterator'; -import { IFileMatch } from 'vs/platform/search/common/search'; +import { IModelService } from 'vs/editor/common/services/modelService'; +import { ModelServiceImpl } from 'vs/editor/common/services/modelServiceImpl'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService'; -import { ModelServiceImpl } from 'vs/editor/common/services/modelServiceImpl'; -import { IModelService } from 'vs/editor/common/services/modelService'; -import { Tree } from 'vs/base/parts/tree/browser/treeImpl'; +import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { USLayoutResolvedKeybinding } from 'vs/platform/keybinding/common/usLayoutResolvedKeybinding'; -import { OS } from 'vs/base/common/platform'; -import { Keybinding } from 'vs/base/common/keyCodes'; +import { IFileMatch } from 'vs/platform/search/common/search'; +import { ReplaceAction } from 'vs/workbench/parts/search/browser/searchActions'; +import { FileMatch, FileMatchOrMatch, Match } from 'vs/workbench/parts/search/common/searchModel'; +import { MockObjectTree } from 'vs/workbench/parts/search/test/browser/mockSearchTree'; suite('Search Actions', () => { @@ -148,7 +148,7 @@ suite('Search Actions', () => { } function aTree(elements: FileMatchOrMatch[]): any { - return stubFunction(Tree, 'getNavigator', () => { return new ArrayNavigator(elements); }); + return new MockObjectTree(elements); } function stubModelService(instantiationService: TestInstantiationService): IModelService { diff --git a/src/vs/workbench/parts/search/test/browser/searchViewlet.test.ts b/src/vs/workbench/parts/search/test/browser/searchViewlet.test.ts index be02a771076..206449b8b9f 100644 --- a/src/vs/workbench/parts/search/test/browser/searchViewlet.test.ts +++ b/src/vs/workbench/parts/search/test/browser/searchViewlet.test.ts @@ -13,8 +13,11 @@ import { IFileMatch, ITextSearchMatch, OneLineRange, QueryType } from 'vs/platfo import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { TestWorkspace } from 'vs/platform/workspace/test/common/testWorkspace'; import { SearchSorter } from 'vs/workbench/parts/search/browser/searchResultsView'; -import { FileMatch, Match, SearchResult } from 'vs/workbench/parts/search/common/searchModel'; +import { FileMatch, Match, SearchResult, RenderableMatch } from 'vs/workbench/parts/search/common/searchModel'; import { TestContextService } from 'vs/workbench/test/workbenchTestServices'; +import { createIterator } from 'vs/workbench/parts/search/browser/searchView'; +import { ITreeElement } from 'vs/base/browser/ui/tree/tree'; +import { Iterator } from 'vs/base/common/iterator'; suite('Search - Viewlet', () => { let instantiation: TestInstantiationService; @@ -25,50 +28,49 @@ suite('Search - Viewlet', () => { instantiation.set(IWorkspaceContextService, new TestContextService(TestWorkspace)); }); - // test('Data Source', function () { - // let ds = instantiation.createInstance(SearchDataSource); - // let result: SearchResult = instantiation.createInstance(SearchResult, null); - // result.query = { - // type: QueryType.Text, - // contentPattern: { pattern: 'foo' }, - // folderQueries: [{ - // folder: uri.parse('file://c:/') - // }] - // }; + test('Data Source', function () { + let result: SearchResult = instantiation.createInstance(SearchResult, null); + result.query = { + type: QueryType.Text, + contentPattern: { pattern: 'foo' }, + folderQueries: [{ + folder: uri.parse('file://c:/') + }] + }; - // result.add([{ - // resource: uri.parse('file:///c:/foo'), - // results: [{ - // preview: { - // text: 'bar', - // matches: { - // startLineNumber: 0, - // startColumn: 0, - // endLineNumber: 0, - // endColumn: 1 - // } - // }, - // ranges: { - // startLineNumber: 1, - // startColumn: 0, - // endLineNumber: 1, - // endColumn: 1 - // } - // }] - // }]); + result.add([{ + resource: uri.parse('file:///c:/foo'), + results: [{ + preview: { + text: 'bar', + matches: { + startLineNumber: 0, + startColumn: 0, + endLineNumber: 0, + endColumn: 1 + } + }, + ranges: { + startLineNumber: 1, + startColumn: 0, + endLineNumber: 1, + endColumn: 1 + } + }] + }]); - // let fileMatch = result.matches()[0]; - // let lineMatch = fileMatch.matches()[0]; + let fileMatch = result.matches()[0]; + let lineMatch = fileMatch.matches()[0]; - // assert.equal(ds.getId(null, result), 'root'); - // assert.equal(ds.getId(null, fileMatch), 'file:///c%3A/foo'); - // assert.equal(ds.getId(null, lineMatch), 'file:///c%3A/foo>[2,1 -> 2,2]b'); + assert.equal(fileMatch.id(), 'file:///c%3A/foo'); + assert.equal(lineMatch.id(), 'file:///c%3A/foo>[2,1 -> 2,2]b'); - // assert(!ds.hasChildren(null, 'foo')); - // assert(ds.hasChildren(null, result)); - // assert(ds.hasChildren(null, fileMatch)); - // assert(!ds.hasChildren(null, lineMatch)); - // }); + const resultIterator = createIterator(result, 'auto'); + const first = resultIterator.next(); + + assert(!!first.value.children); + assert.equal((>>first.value.children).next().value.element.id(), 'file:///c%3A/foo>[2,1 -> 2,2]b'); + }); test('Sorter', () => { let fileMatch1 = aFileMatch('C:\\foo');