searchModel.test.ts 11.5 KB
Newer Older
E
Erich Gamma 已提交
1 2 3 4 5 6 7
/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/
'use strict';

import * as assert from 'assert';
8 9 10 11 12 13
import * as sinon from 'sinon';
import { TestInstantiationService } from 'vs/test/utils/instantiationTestUtils';
import { DeferredPPromise } from 'vs/test/utils/promiseTestUtils';
import { PPromise } from 'vs/base/common/winjs.base';
import { nullEvent } from 'vs/base/common/timer';
import { SearchModel } from 'vs/workbench/parts/search/common/searchModel';
J
Johannes Rieken 已提交
14
import URI from 'vs/base/common/uri';
J
Joao Moreno 已提交
15
import { IFileMatch, ILineMatch, ISearchService, ISearchComplete, ISearchProgressItem, IUncachedSearchStats } from 'vs/platform/search/common/search';
16 17
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { Range } from 'vs/editor/common/core/range';
18 19
import { createMockModelService } from 'vs/test/utils/servicesTestUtils';
import { IModelService } from 'vs/editor/common/services/modelService';
20

21
suite('SearchModel', () => {
E
Erich Gamma 已提交
22

23 24
	let instantiationService: TestInstantiationService;
	let restoreStubs;
E
Erich Gamma 已提交
25

26 27 28
	const testSearchStats: IUncachedSearchStats = {
		fromCache: false,
		resultCount: 4,
C
Christof Marti 已提交
29 30
		traversal: 'node',
		errors: [],
C
chrmarti 已提交
31 32 33 34 35 36
		fileWalkStartTime: 0,
		fileWalkResultTime: 1,
		directoriesWalked: 2,
		filesWalked: 3
	};

E
Erich Gamma 已提交
37
	setup(() => {
J
Johannes Rieken 已提交
38 39
		restoreStubs = [];
		instantiationService = new TestInstantiationService();
40
		instantiationService.stub(ITelemetryService);
41
		instantiationService.stub(IModelService, createMockModelService(instantiationService));
42 43 44 45 46 47 48 49 50
	});

	teardown(() => {
		restoreStubs.forEach(element => {
			element.restore();
		});
	});

	test('Search Model: Search adds to results', function () {
J
Johannes Rieken 已提交
51 52
		let results = [aRawMatch('file://c:/1', aLineMatch('preview 1', 1, [[1, 3], [4, 7]])), aRawMatch('file://c:/2', aLineMatch('preview 2'))];
		instantiationService.stub(ISearchService, 'search', PPromise.as({ results: results }));
53

J
Johannes Rieken 已提交
54 55
		let testObject = instantiationService.createInstance(SearchModel);
		testObject.search({ contentPattern: { pattern: 'somestring' }, type: 1 });
56

J
Johannes Rieken 已提交
57
		let actual = testObject.searchResult.matches();
58 59 60 61

		assert.equal(2, actual.length);
		assert.equal('file://c:/1', actual[0].resource().toString());

J
Johannes Rieken 已提交
62
		let actuaMatches = actual[0].matches();
63 64 65 66 67 68
		assert.equal(2, actuaMatches.length);
		assert.equal('preview 1', actuaMatches[0].text());
		assert.ok(new Range(2, 2, 2, 5).equalsRange(actuaMatches[0].range()));
		assert.equal('preview 1', actuaMatches[1].text());
		assert.ok(new Range(2, 5, 2, 12).equalsRange(actuaMatches[1].range()));

J
Johannes Rieken 已提交
69
		actuaMatches = actual[1].matches();
70 71 72 73 74 75
		assert.equal(1, actuaMatches.length);
		assert.equal('preview 2', actuaMatches[0].text());
		assert.ok(new Range(2, 1, 2, 2).equalsRange(actuaMatches[0].range()));
	});

	test('Search Model: Search adds to results during progress', function (done) {
J
Johannes Rieken 已提交
76 77 78
		let results = [aRawMatch('file://c:/1', aLineMatch('preview 1', 1, [[1, 3], [4, 7]])), aRawMatch('file://c:/2', aLineMatch('preview 2'))];
		let promise = new DeferredPPromise<ISearchComplete, ISearchProgressItem>();
		instantiationService.stub(ISearchService, 'search', promise);
79

J
Johannes Rieken 已提交
80 81
		let testObject = instantiationService.createInstance(SearchModel);
		let result = testObject.search({ contentPattern: { pattern: 'somestring' }, type: 1 });
82 83 84

		promise.progress(results[0]);
		promise.progress(results[1]);
J
Johannes Rieken 已提交
85
		promise.complete({ results: [], stats: testSearchStats });
86 87

		result.done(() => {
J
Johannes Rieken 已提交
88
			let actual = testObject.searchResult.matches();
89 90 91 92

			assert.equal(2, actual.length);
			assert.equal('file://c:/1', actual[0].resource().toString());

J
Johannes Rieken 已提交
93
			let actuaMatches = actual[0].matches();
94 95 96 97 98 99
			assert.equal(2, actuaMatches.length);
			assert.equal('preview 1', actuaMatches[0].text());
			assert.ok(new Range(2, 2, 2, 5).equalsRange(actuaMatches[0].range()));
			assert.equal('preview 1', actuaMatches[1].text());
			assert.ok(new Range(2, 5, 2, 12).equalsRange(actuaMatches[1].range()));

J
Johannes Rieken 已提交
100
			actuaMatches = actual[1].matches();
101 102 103 104 105 106 107 108 109
			assert.equal(1, actuaMatches.length);
			assert.equal('preview 2', actuaMatches[0].text());
			assert.ok(new Range(2, 1, 2, 2).equalsRange(actuaMatches[0].range()));

			done();
		});
	});

	test('Search Model: Search reports telemetry on search completed', function () {
J
Johannes Rieken 已提交
110 111 112
		let target = instantiationService.spy(ITelemetryService, 'publicLog');
		let results = [aRawMatch('file://c:/1', aLineMatch('preview 1', 1, [[1, 3], [4, 7]])), aRawMatch('file://c:/2', aLineMatch('preview 2'))];
		instantiationService.stub(ISearchService, 'search', PPromise.as({ results: results }));
113

J
Johannes Rieken 已提交
114 115
		let testObject = instantiationService.createInstance(SearchModel);
		testObject.search({ contentPattern: { pattern: 'somestring' }, type: 1 });
116 117

		assert.ok(target.calledOnce);
118
		assert.deepEqual(['searchResultsShown', { count: 3, fileCount: 2, options: {}, duration: -1 }], target.args[0]);
119 120
	});

J
Joao Moreno 已提交
121
	test('Search Model: Search reports timed telemetry on search when progress is not called', function (done) {
J
Johannes Rieken 已提交
122
		let target2 = sinon.spy();
123
		stub(nullEvent, 'stop', target2);
J
Johannes Rieken 已提交
124
		let target1 = sinon.stub().returns(nullEvent);
J
Joao Moreno 已提交
125
		instantiationService.stub(ITelemetryService, 'publicLog', target1);
126

J
Johannes Rieken 已提交
127
		instantiationService.stub(ISearchService, 'search', PPromise.as({ results: [] }));
128

J
Johannes Rieken 已提交
129 130
		let testObject = instantiationService.createInstance(SearchModel);
		const result = testObject.search({ contentPattern: { pattern: 'somestring' }, type: 1 });
J
Joao Moreno 已提交
131 132 133 134 135

		setTimeout(() => {
			result.done(() => {
				assert.ok(target1.calledWith('searchResultsFirstRender'));
				assert.ok(target1.calledWith('searchResultsFinished'));
136

J
Joao Moreno 已提交
137 138 139
				done();
			});
		}, 0);
140 141 142
	});

	test('Search Model: Search reports timed telemetry on search when progress is called', function (done) {
J
Johannes Rieken 已提交
143
		let target2 = sinon.spy();
144
		stub(nullEvent, 'stop', target2);
J
Johannes Rieken 已提交
145
		let target1 = sinon.stub().returns(nullEvent);
J
Joao Moreno 已提交
146
		instantiationService.stub(ITelemetryService, 'publicLog', target1);
147

J
Johannes Rieken 已提交
148 149
		let promise = new DeferredPPromise<ISearchComplete, ISearchProgressItem>();
		instantiationService.stub(ISearchService, 'search', promise);
150

J
Johannes Rieken 已提交
151 152
		let testObject = instantiationService.createInstance(SearchModel);
		let result = testObject.search({ contentPattern: { pattern: 'somestring' }, type: 1 });
153 154

		promise.progress(aRawMatch('file://c:/1', aLineMatch('some preview')));
J
Johannes Rieken 已提交
155
		promise.complete({ results: [], stats: testSearchStats });
156

J
Joao Moreno 已提交
157 158 159 160 161
		setTimeout(() => {
			result.done(() => {
				assert.ok(target1.calledWith('searchResultsFirstRender'));
				assert.ok(target1.calledWith('searchResultsFinished'));
				// assert.equal(1, target2.callCount);
162

J
Joao Moreno 已提交
163 164 165
				done();
			});
		}, 0);
166 167 168
	});

	test('Search Model: Search reports timed telemetry on search when error is called', function (done) {
J
Johannes Rieken 已提交
169
		let target2 = sinon.spy();
170
		stub(nullEvent, 'stop', target2);
J
Johannes Rieken 已提交
171
		let target1 = sinon.stub().returns(nullEvent);
J
Joao Moreno 已提交
172
		instantiationService.stub(ITelemetryService, 'publicLog', target1);
173

J
Johannes Rieken 已提交
174 175
		let promise = new DeferredPPromise<ISearchComplete, ISearchProgressItem>();
		instantiationService.stub(ISearchService, 'search', promise);
176

J
Johannes Rieken 已提交
177 178
		let testObject = instantiationService.createInstance(SearchModel);
		let result = testObject.search({ contentPattern: { pattern: 'somestring' }, type: 1 });
179 180 181

		promise.error('error');

J
Joao Moreno 已提交
182
		setTimeout(() => {
J
Johannes Rieken 已提交
183
			result.done(() => { }, () => {
J
Joao Moreno 已提交
184 185 186
				assert.ok(target1.calledWith('searchResultsFirstRender'));
				assert.ok(target1.calledWith('searchResultsFinished'));
				// assert.ok(target2.calledOnce);
187

J
Joao Moreno 已提交
188 189 190
				done();
			});
		}, 0);
191 192 193
	});

	test('Search Model: Search reports timed telemetry on search when error is cancelled error', function (done) {
J
Johannes Rieken 已提交
194
		let target2 = sinon.spy();
195
		stub(nullEvent, 'stop', target2);
J
Johannes Rieken 已提交
196
		let target1 = sinon.stub().returns(nullEvent);
J
Joao Moreno 已提交
197
		instantiationService.stub(ITelemetryService, 'publicLog', target1);
198

J
Johannes Rieken 已提交
199 200
		let promise = new DeferredPPromise<ISearchComplete, ISearchProgressItem>();
		instantiationService.stub(ISearchService, 'search', promise);
201

J
Johannes Rieken 已提交
202 203
		let testObject = instantiationService.createInstance(SearchModel);
		let result = testObject.search({ contentPattern: { pattern: 'somestring' }, type: 1 });
204 205 206

		promise.cancel();

J
Joao Moreno 已提交
207
		setTimeout(() => {
J
Johannes Rieken 已提交
208
			result.done(() => { }, () => {
J
Joao Moreno 已提交
209 210 211 212 213 214
				assert.ok(target1.calledWith('searchResultsFirstRender'));
				assert.ok(target1.calledWith('searchResultsFinished'));
				// assert.ok(target2.calledOnce);
				done();
			});
		}, 0);
215 216 217
	});

	test('Search Model: Search results are cleared during search', function () {
J
Johannes Rieken 已提交
218 219 220 221
		let results = [aRawMatch('file://c:/1', aLineMatch('preview 1', 1, [[1, 3], [4, 7]])), aRawMatch('file://c:/2', aLineMatch('preview 2'))];
		instantiationService.stub(ISearchService, 'search', PPromise.as({ results: results }));
		let testObject: SearchModel = instantiationService.createInstance(SearchModel);
		testObject.search({ contentPattern: { pattern: 'somestring' }, type: 1 });
222 223
		assert.ok(!testObject.searchResult.isEmpty());

J
Johannes Rieken 已提交
224
		instantiationService.stub(ISearchService, 'search', new DeferredPPromise<ISearchComplete, ISearchProgressItem>());
225

J
Johannes Rieken 已提交
226
		testObject.search({ contentPattern: { pattern: 'somestring' }, type: 1 });
227 228 229 230
		assert.ok(testObject.searchResult.isEmpty());
	});

	test('Search Model: Previous search is cancelled when new search is called', function () {
J
Johannes Rieken 已提交
231 232 233
		let target = sinon.spy();
		instantiationService.stub(ISearchService, 'search', new DeferredPPromise((c, e, p) => { }, target));
		let testObject: SearchModel = instantiationService.createInstance(SearchModel);
234

J
Johannes Rieken 已提交
235 236 237
		testObject.search({ contentPattern: { pattern: 'somestring' }, type: 1 });
		instantiationService.stub(ISearchService, 'search', new DeferredPPromise<ISearchComplete, ISearchProgressItem>());
		testObject.search({ contentPattern: { pattern: 'somestring' }, type: 1 });
238 239 240 241

		assert.ok(target.calledOnce);
	});

S
Sandeep Somavarapu 已提交
242
	test('getReplaceString returns proper replace string for regExpressions', function () {
J
Johannes Rieken 已提交
243 244
		let results = [aRawMatch('file://c:/1', aLineMatch('preview 1', 1, [[1, 3], [4, 7]]))];
		instantiationService.stub(ISearchService, 'search', PPromise.as({ results: results }));
S
Sandeep Somavarapu 已提交
245

J
Johannes Rieken 已提交
246
		let testObject: SearchModel = instantiationService.createInstance(SearchModel);
S
Sandeep Somavarapu 已提交
247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269
		testObject.search({ contentPattern: { pattern: 're' }, type: 1 });
		testObject.replaceString = 'hello';
		let match = testObject.searchResult.matches()[0].matches()[0];
		assert.equal('hello', match.replaceString);

		testObject.search({ contentPattern: { pattern: 're', isRegExp: true }, type: 1 });
		match = testObject.searchResult.matches()[0].matches()[0];
		assert.equal('hello', match.replaceString);

		testObject.search({ contentPattern: { pattern: 're(?:vi)', isRegExp: true }, type: 1 });
		match = testObject.searchResult.matches()[0].matches()[0];
		assert.equal('hello', match.replaceString);

		testObject.search({ contentPattern: { pattern: 'r(e)(?:vi)', isRegExp: true }, type: 1 });
		match = testObject.searchResult.matches()[0].matches()[0];
		assert.equal('hello', match.replaceString);

		testObject.search({ contentPattern: { pattern: 'r(e)(?:vi)', isRegExp: true }, type: 1 });
		testObject.replaceString = 'hello$1';
		match = testObject.searchResult.matches()[0].matches()[0];
		assert.equal('helloe', match.replaceString);
	});

270 271 272 273 274 275 276 277
	function aRawMatch(resource: string, ...lineMatches: ILineMatch[]): IFileMatch {
		return { resource: URI.parse(resource), lineMatches };
	}

	function aLineMatch(preview: string, lineNumber: number = 1, offsetAndLengths: number[][] = [[0, 1]]): ILineMatch {
		return { preview, lineNumber, offsetAndLengths };
	}

J
Johannes Rieken 已提交
278 279
	function stub(arg1, arg2, arg3): sinon.SinonStub {
		const stub = sinon.stub(arg1, arg2, arg3);
280 281 282 283
		restoreStubs.push(stub);
		return stub;
	}

E
Erich Gamma 已提交
284
});