suite('SearchModel', () => {

	let instantiationService: TestInstantiationService;
	let restoreStubs: sinon.SinonStub[];

	const testSearchStats: IUncachedSearchStats = {
		fromCache: false,
		resultCount: 4,
		traversal: 'node',
		errors: [],
		fileWalkStartTime: 0,
		fileWalkResultTime: 1,
		directoriesWalked: 2,
		filesWalked: 3
	};

	const folderQueries: IFolderQuery[] = [
		{ folder: URI.parse('file://c:/') }
	];

	setup(() => {
		restoreStubs = [];
		instantiationService = new TestInstantiationService();
		instantiationService.stub(ITelemetryService, NullTelemetryService);
		instantiationService.stub(IModelService, stubModelService(instantiationService));
		instantiationService.stub(ISearchService, {});
		instantiationService.stub(ISearchService, 'search', PPromise.as({ results: [] }));
	});

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

	test('Search Model: Search adds to results', function () {
		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, folderQueries });

		let actual = testObject.searchResult.matches();

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

		let actuaMatches = actual[0].matches();
		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()));

		actuaMatches = actual[1].matches();
		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) {
		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);

		let testObject = instantiationService.createInstance(SearchModel);
		let result = testObject.search({ contentPattern: { pattern: 'somestring' }, type: 1, folderQueries });

		promise.progress(results[0]);
		promise.progress(results[1]);
		promise.complete({ results: [], stats: testSearchStats });

		result.done(() => {
			let actual = testObject.searchResult.matches();

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

			let actuaMatches = actual[0].matches();
			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()));

			actuaMatches = actual[1].matches();
			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 () {
		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 }));

		let testObject = instantiationService.createInstance(SearchModel);
		testObject.search({ contentPattern: { pattern: 'somestring' }, type: 1, folderQueries });

		assert.ok(target.calledOnce);
		const data = target.args[0];
		data[1].duration = -1;
		assert.deepEqual(['searchResultsShown', { count: 3, fileCount: 2, options: {}, duration: -1, useRipgrep: undefined }], data);
	});

	test('Search Model: Search reports timed telemetry on search when progress is not called', function (done) {
		let target2 = sinon.spy();
		stub(nullEvent, 'stop', target2);
		let target1 = sinon.stub().returns(nullEvent);
		instantiationService.stub(ITelemetryService, 'publicLog', target1);

		instantiationService.stub(ISearchService, 'search', PPromise.as({ results: [] }));

		let testObject = instantiationService.createInstance(SearchModel);
		const result = testObject.search({ contentPattern: { pattern: 'somestring' }, type: 1, folderQueries });

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

				done();
			});
		}, 0);
	});

	test('Search Model: Search reports timed telemetry on search when progress is called', function (done) {
		let target2 = sinon.spy();
		stub(nullEvent, 'stop', target2);
		let target1 = sinon.stub().returns(nullEvent);
		instantiationService.stub(ITelemetryService, 'publicLog', target1);

		let promise = new DeferredPPromise<ISearchComplete, ISearchProgressItem>();
		instantiationService.stub(ISearchService, 'search', promise);

		let testObject = instantiationService.createInstance(SearchModel);
		let result = testObject.search({ contentPattern: { pattern: 'somestring' }, type: 1, folderQueries });

		promise.progress(aRawMatch('file://c:/1', aLineMatch('some preview')));
		promise.complete({ results: [], stats: testSearchStats });

		setTimeout(() => {
			result.done(() => {
				assert.ok(target1.calledWith('searchResultsFirstRender'));
				assert.ok(target1.calledWith('searchResultsFinished'));
				// assert.equal(1, target2.callCount);

				done();
			});
		}, 0);
	});

	test('Search Model: Search reports timed telemetry on search when error is called', function (done) {
		let target2 = sinon.spy();
		stub(nullEvent, 'stop', target2);
		let target1 = sinon.stub().returns(nullEvent);
		instantiationService.stub(ITelemetryService, 'publicLog', target1);

		let promise = new DeferredPPromise<ISearchComplete, ISearchProgressItem>();
		instantiationService.stub(ISearchService, 'search', promise);

		let testObject = instantiationService.createInstance(SearchModel);
		let result = testObject.search({ contentPattern: { pattern: 'somestring' }, type: 1, folderQueries });

		promise.error('error');

		setTimeout(() => {
			result.done(() => { }, () => {
				assert.ok(target1.calledWith('searchResultsFirstRender'));
				assert.ok(target1.calledWith('searchResultsFinished'));
				// assert.ok(target2.calledOnce);

				done();
			});
		}, 0);
	});

	test('Search Model: Search reports timed telemetry on search when error is cancelled error', function (done) {
		let target2 = sinon.spy();
		stub(nullEvent, 'stop', target2);
		let target1 = sinon.stub().returns(nullEvent);
		instantiationService.stub(ITelemetryService, 'publicLog', target1);

		let promise = new DeferredPPromise<ISearchComplete, ISearchProgressItem>();
		instantiationService.stub(ISearchService, 'search', promise);

		let testObject = instantiationService.createInstance(SearchModel);
		let result = testObject.search({ contentPattern: { pattern: 'somestring' }, type: 1, folderQueries });

		promise.cancel();

		setTimeout(() => {
			result.done(() => { }, () => {
				assert.ok(target1.calledWith('searchResultsFirstRender'));
				assert.ok(target1.calledWith('searchResultsFinished'));
				// assert.ok(target2.calledOnce);
				done();
			});
		}, 0);
	});

	test('Search Model: Search results are cleared during search', function () {
		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, folderQueries });
		assert.ok(!testObject.searchResult.isEmpty());

		instantiationService.stub(ISearchService, 'search', new DeferredPPromise<ISearchComplete, ISearchProgressItem>());

		testObject.search({ contentPattern: { pattern: 'somestring' }, type: 1, folderQueries });
		assert.ok(testObject.searchResult.isEmpty());
	});

	test('Search Model: Previous search is cancelled when new search is called', function () {
		let target = sinon.spy();
		instantiationService.stub(ISearchService, 'search', new DeferredPPromise((c, e, p) => { }, target));
		let testObject: SearchModel = instantiationService.createInstance(SearchModel);

		testObject.search({ contentPattern: { pattern: 'somestring' }, type: 1, folderQueries });
		instantiationService.stub(ISearchService, 'search', new DeferredPPromise<ISearchComplete, ISearchProgressItem>());
		testObject.search({ contentPattern: { pattern: 'somestring' }, type: 1, folderQueries });

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

	test('getReplaceString returns proper replace string for regExpressions', function () {
		let results = [aRawMatch('file://c:/1', aLineMatch('preview 1', 1, [[1, 3], [4, 7]]))];
		instantiationService.stub(ISearchService, 'search', PPromise.as({ results: results }));

		let testObject: SearchModel = instantiationService.createInstance(SearchModel);
		testObject.search({ contentPattern: { pattern: 're' }, type: 1, folderQueries });
		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, folderQueries });
		match = testObject.searchResult.matches()[0].matches()[0];
		assert.equal('hello', match.replaceString);

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

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

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

	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 };
	}

	function stub(arg1: any, arg2: any, arg3: any): sinon.SinonStub {
		const stub = sinon.stub(arg1, arg2, arg3);
		restoreStubs.push(stub);
		return stub;
	}

	function stubModelService(instantiationService: TestInstantiationService): IModelService {
		instantiationService.stub(IConfigurationService, new TestConfigurationService());
		return instantiationService.createInstance(ModelServiceImpl);
	}

});
suite('Search Actions', () => {

	let instantiationService: TestInstantiationService;
	let counter: number;

	setup(() => {
		instantiationService = new TestInstantiationService();
		instantiationService.stub(IModelService, stubModelService(instantiationService));
		instantiationService.stub(IKeybindingService, {});
		instantiationService.stub(IKeybindingService, 'resolveKeybinding', (keybinding: Keybinding) => [new USLayoutResolvedKeybinding(keybinding, OS)]);
		instantiationService.stub(IKeybindingService, 'lookupKeybinding', (id: string) => null);
		counter = 0;
	});

	test('get next element to focus after removing a match when it has next sibling file', function () {
		let fileMatch1 = aFileMatch();
		let fileMatch2 = aFileMatch();
		let data = [fileMatch1, aMatch(fileMatch1), aMatch(fileMatch1), fileMatch2, aMatch(fileMatch2), aMatch(fileMatch2)];
		let tree = aTree(data);
		let target = data[2];
		let testObject: ReplaceAction = instantiationService.createInstance(ReplaceAction, tree, target, null);

		let actual = testObject.getElementToFocusAfterRemoved(tree, target);

		assert.equal(data[4], actual);
	});

	test('get next element to focus after removing a match when it does not have next sibling match', function () {
		let fileMatch1 = aFileMatch();
		let fileMatch2 = aFileMatch();
		let data = [fileMatch1, aMatch(fileMatch1), aMatch(fileMatch1), fileMatch2, aMatch(fileMatch2), aMatch(fileMatch2)];
		let tree = aTree(data);
		let target = data[5];
		let testObject: ReplaceAction = instantiationService.createInstance(ReplaceAction, tree, target, null);

		let actual = testObject.getElementToFocusAfterRemoved(tree, target);

		assert.equal(data[4], actual);
	});

	test('get next element to focus after removing a match when it does not have next sibling match and previous match is file match', function () {
		let fileMatch1 = aFileMatch();
		let fileMatch2 = aFileMatch();
		let data = [fileMatch1, aMatch(fileMatch1), aMatch(fileMatch1), fileMatch2, aMatch(fileMatch2)];
		let tree = aTree(data);
		let target = data[4];
		let testObject: ReplaceAction = instantiationService.createInstance(ReplaceAction, tree, target, null);

		let actual = testObject.getElementToFocusAfterRemoved(tree, target);

		assert.equal(data[2], actual);
	});

	test('get next element to focus after removing a match when it is the only match', function () {
		let fileMatch1 = aFileMatch();
		let data = [fileMatch1, aMatch(fileMatch1)];
		let tree = aTree(data);
		let target = data[1];
		let testObject: ReplaceAction = instantiationService.createInstance(ReplaceAction, tree, target, null);

		let actual = testObject.getElementToFocusAfterRemoved(tree, target);

		assert.equal(void 0, actual);
	});

	test('get next element to focus after removing a file match when it has next sibling', function () {
		let fileMatch1 = aFileMatch();
		let fileMatch2 = aFileMatch();
		let fileMatch3 = aFileMatch();
		let data = [fileMatch1, aMatch(fileMatch1), fileMatch2, aMatch(fileMatch2), fileMatch3, aMatch(fileMatch3)];
		let tree = aTree(data);
		let target = data[2];
		let testObject: ReplaceAction = instantiationService.createInstance(ReplaceAction, tree, target, null);

		let actual = testObject.getElementToFocusAfterRemoved(tree, target);

		assert.equal(data[4], actual);
	});

	test('get next element to focus after removing a file match when it has no next sibling', function () {
		let fileMatch1 = aFileMatch();
		let fileMatch2 = aFileMatch();
		let fileMatch3 = aFileMatch();
		let data = [fileMatch1, aMatch(fileMatch1), fileMatch2, aMatch(fileMatch2), fileMatch3, aMatch(fileMatch3)];
		let tree = aTree(data);
		let target = data[4];
		let testObject: ReplaceAction = instantiationService.createInstance(ReplaceAction, tree, target, null);

		let actual = testObject.getElementToFocusAfterRemoved(tree, target);

		assert.equal(data[3], actual);
	});

	test('get next element to focus after removing a file match when it is only match', function () {
		let fileMatch1 = aFileMatch();
		let data = [fileMatch1, aMatch(fileMatch1)];
		let tree = aTree(data);
		let target = data[0];
		let testObject: ReplaceAction = instantiationService.createInstance(ReplaceAction, tree, target, null);

		let actual = testObject.getElementToFocusAfterRemoved(tree, target);

		assert.equal(void 0, actual);
	});

	function aFileMatch(): FileMatch {
		let rawMatch: IFileMatch = {
			resource: URI.file('somepath' + ++counter),
			results: []
		};
		return instantiationService.createInstance(FileMatch, null, null, null, null, rawMatch);
	}

	function aMatch(fileMatch: FileMatch): Match {
		const line = ++counter;
		const ranges = {
			startLineNumber: line,
			startColumn: 0,
			endLineNumber: line,
			endColumn: 2
		};
		let match = new Match(fileMatch, {
			preview: {
				text: 'some match',
				matches: ranges
			},
			ranges
		});
		fileMatch.add(match);
		return match;
	}

	function aTree(elements: FileMatchOrMatch[]): any {
		return stubFunction(Tree, 'getNavigator', () => { return new ArrayNavigator(elements); });
	}

	function stubModelService(instantiationService: TestInstantiationService): IModelService {
		instantiationService.stub(IConfigurationService, new TestConfigurationService());
		return instantiationService.createInstance(ModelServiceImpl);
	}
});
	function stubModelService(instantiationService: TestInstantiationService): IModelService {
		instantiationService.stub(IConfigurationService, new TestConfigurationService());
		return instantiationService.createInstance(ModelServiceImpl);
	}
suite('Search - Viewlet', () => {
	let instantiation: TestInstantiationService;

	setup(() => {
		instantiation = new TestInstantiationService();
		instantiation.stub(IModelService, stubModelService(instantiation));
		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: 1, folderQueries: [{ folder: uri.parse('file://c:/') }] };
		result.add([{
			resource: uri.parse('file:///c:/foo'),
			lineMatches: [{ lineNumber: 1, preview: 'bar', offsetAndLengths: [[0, 1]] }]
		}]);

		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>1>0b');

		assert(!ds.hasChildren(null, 'foo'));
		assert(ds.hasChildren(null, result));
		assert(ds.hasChildren(null, fileMatch));
		assert(!ds.hasChildren(null, lineMatch));
	});

	test('Sorter', function () {
		let fileMatch1 = aFileMatch('C:\\foo');
		let fileMatch2 = aFileMatch('C:\\with\\path');
		let fileMatch3 = aFileMatch('C:\\with\\path\\foo');
		let lineMatch1 = new Match(fileMatch1, 'bar', 1, 1, 1);
		let lineMatch2 = new Match(fileMatch1, 'bar', 2, 1, 1);
		let lineMatch3 = new Match(fileMatch1, 'bar', 2, 1, 1);

		let s = new SearchSorter();

		assert(s.compare(null, fileMatch1, fileMatch2) < 0);
		assert(s.compare(null, fileMatch2, fileMatch1) > 0);
		assert(s.compare(null, fileMatch1, fileMatch1) === 0);
		assert(s.compare(null, fileMatch2, fileMatch3) < 0);

		assert(s.compare(null, lineMatch1, lineMatch2) < 0);
		assert(s.compare(null, lineMatch2, lineMatch1) > 0);
		assert(s.compare(null, lineMatch2, lineMatch3) === 0);
	});

	function aFileMatch(path: string, searchResult?: SearchResult, ...lineMatches: ILineMatch[]): FileMatch {
		let rawMatch: IFileMatch = {
			resource: uri.file('C:\\' + path),
			lineMatches: lineMatches
		};
		return instantiation.createInstance(FileMatch, null, null, searchResult, rawMatch);
	}

	function stubModelService(instantiationService: TestInstantiationService): IModelService {
		instantiationService.stub(IConfigurationService, new TestConfigurationService());
		return instantiationService.createInstance(ModelServiceImpl);
	}
});
	setup(() => {
		instantiation = new TestInstantiationService();
		instantiation.stub(IModelService, stubModelService(instantiation));
		instantiation.set(IWorkspaceContextService, new TestContextService(TestWorkspace));
	});
	setup(() => {
		instantiationService = new TestInstantiationService();
		instantiationService.stub(INotificationService, new TestNotificationService());
		instantiationService.stub(IHistoryService, new TestHistoryService());
	});
	setup(() => {
		instantiation = new TestInstantiationService();
		instantiation.stub(IModelService, stubModelService(instantiation));
	});
suite('SearchResult', () => {

	let instantiationService: TestInstantiationService;

	setup(() => {
		instantiationService = new TestInstantiationService();
		instantiationService.stub(ITelemetryService, NullTelemetryService);
		instantiationService.stub(IModelService, stubModelService(instantiationService));
		instantiationService.stubPromise(IReplaceService, {});
		instantiationService.stubPromise(IReplaceService, 'replace', null);
	});

	test('Line Match', function () {
		let fileMatch = aFileMatch('folder\\file.txt', null);
		let lineMatch = new Match(fileMatch, 'foo bar', 1, 0, 3);
		assert.equal(lineMatch.text(), 'foo bar');
		assert.equal(lineMatch.range().startLineNumber, 2);
		assert.equal(lineMatch.range().endLineNumber, 2);
		assert.equal(lineMatch.range().startColumn, 1);
		assert.equal(lineMatch.range().endColumn, 4);
		assert.equal('file:///c%3A/folder/file.txt>1>0foo', lineMatch.id());
	});

	test('Line Match - Remove', function () {
		let fileMatch = aFileMatch('folder\\file.txt', aSearchResult(), ...[{
			preview: 'foo bar',
			lineNumber: 1,
			offsetAndLengths: [[0, 3]]
		}]);
		let lineMatch = fileMatch.matches()[0];
		fileMatch.remove(lineMatch);
		assert.equal(fileMatch.matches().length, 0);
	});

	test('File Match', function () {
		let fileMatch = aFileMatch('folder\\file.txt');
		assert.equal(fileMatch.matches(), 0);
		assert.equal(fileMatch.resource().toString(), 'file:///c%3A/folder/file.txt');
		assert.equal(fileMatch.name(), 'file.txt');

		fileMatch = aFileMatch('file.txt');
		assert.equal(fileMatch.matches(), 0);
		assert.equal(fileMatch.resource().toString(), 'file:///c%3A/file.txt');
		assert.equal(fileMatch.name(), 'file.txt');
	});

	test('File Match: Select an existing match', function () {
		let testObject = aFileMatch('folder\\file.txt', aSearchResult(), ...[{
			preview: 'foo',
			lineNumber: 1,
			offsetAndLengths: [[0, 3]]
		}, {
			preview: 'bar',
			lineNumber: 1,
			offsetAndLengths: [[5, 3]]
		}]);

		testObject.setSelectedMatch(testObject.matches()[0]);

		assert.equal(testObject.matches()[0], testObject.getSelectedMatch());
	});

	test('File Match: Select non existing match', function () {
		let testObject = aFileMatch('folder\\file.txt', aSearchResult(), ...[{
			preview: 'foo',
			lineNumber: 1,
			offsetAndLengths: [[0, 3]]
		}, {
			preview: 'bar',
			lineNumber: 1,
			offsetAndLengths: [[5, 3]]
		}]);
		let target = testObject.matches()[0];
		testObject.remove(target);

		testObject.setSelectedMatch(target);

		assert.equal(undefined, testObject.getSelectedMatch());
	});

	test('File Match: isSelected return true for selected match', function () {
		let testObject = aFileMatch('folder\\file.txt', aSearchResult(), ...[{
			preview: 'foo',
			lineNumber: 1,
			offsetAndLengths: [[0, 3]]
		}, {
			preview: 'bar',
			lineNumber: 1,
			offsetAndLengths: [[5, 3]]
		}]);
		let target = testObject.matches()[0];
		testObject.setSelectedMatch(target);

		assert.ok(testObject.isMatchSelected(target));
	});

	test('File Match: isSelected return false for un-selected match', function () {
		let testObject = aFileMatch('folder\\file.txt', aSearchResult(), ...[{
			preview: 'foo',
			lineNumber: 1,
			offsetAndLengths: [[0, 3]]
		}, {
			preview: 'bar',
			lineNumber: 1,
			offsetAndLengths: [[5, 3]]
		}]);

		testObject.setSelectedMatch(testObject.matches()[0]);

		assert.ok(!testObject.isMatchSelected(testObject.matches()[1]));
	});

	test('File Match: unselect', function () {
		let testObject = aFileMatch('folder\\file.txt', aSearchResult(), ...[{
			preview: 'foo',
			lineNumber: 1,
			offsetAndLengths: [[0, 3]]
		}, {
			preview: 'bar',
			lineNumber: 1,
			offsetAndLengths: [[5, 3]]
		}]);

		testObject.setSelectedMatch(testObject.matches()[0]);
		testObject.setSelectedMatch(null);

		assert.equal(null, testObject.getSelectedMatch());
	});

	test('File Match: unselect when not selected', function () {
		let testObject = aFileMatch('folder\\file.txt', aSearchResult(), ...[{
			preview: 'foo',
			lineNumber: 1,
			offsetAndLengths: [[0, 3]]
		}, {
			preview: 'bar',
			lineNumber: 1,
			offsetAndLengths: [[5, 3]]
		}]);

		testObject.setSelectedMatch(null);

		assert.equal(null, testObject.getSelectedMatch());
	});

	test('Alle Drei Zusammen', function () {
		let searchResult = instantiationService.createInstance(SearchResult, null);
		let fileMatch = aFileMatch('far\\boo', searchResult);
		let lineMatch = new Match(fileMatch, 'foo bar', 1, 0, 3);

		assert(lineMatch.parent() === fileMatch);
		assert(fileMatch.parent() === searchResult);
	});

	test('Adding a raw match will add a file match with line matches', function () {
		let testObject = aSearchResult();
		let target = [aRawMatch('file://c:/', aLineMatch('preview 1', 1, [[1, 3], [4, 7]]), aLineMatch('preview 2'))];

		testObject.add(target);

		assert.equal(3, testObject.count());

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

		let actuaMatches = actual[0].matches();
		assert.equal(3, 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()));

		assert.equal('preview 2', actuaMatches[2].text());
		assert.ok(new Range(2, 1, 2, 2).equalsRange(actuaMatches[2].range()));
	});

	test('Adding multiple raw matches', function () {
		let testObject = aSearchResult();
		let target = [aRawMatch('file://c:/1', aLineMatch('preview 1', 1, [[1, 3], [4, 7]])), aRawMatch('file://c:/2', aLineMatch('preview 2'))];

		testObject.add(target);

		assert.equal(3, testObject.count());

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

		let actuaMatches = actual[0].matches();
		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()));

		actuaMatches = actual[1].matches();
		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('Dispose disposes matches', function () {
		let target1 = sinon.spy();
		let target2 = sinon.spy();

		let testObject = aSearchResult();
		testObject.add([aRawMatch('file://c:/1', aLineMatch('preview 1')), aRawMatch('file://c:/2', aLineMatch('preview 2'))]);

		testObject.matches()[0].onDispose(target1);
		testObject.matches()[1].onDispose(target2);

		testObject.dispose();

		assert.ok(testObject.isEmpty());
		assert.ok(target1.calledOnce);
		assert.ok(target2.calledOnce);
	});

	test('remove triggers change event', function () {
		let target = sinon.spy();
		let testObject = aSearchResult();
		testObject.add([aRawMatch('file://c:/1', aLineMatch('preview 1'))]);
		let objectRoRemove = testObject.matches()[0];
		testObject.onChange(target);

		testObject.remove(objectRoRemove);

		assert.ok(target.calledOnce);
		assert.deepEqual([{ elements: [objectRoRemove], removed: true }], target.args[0]);
	});

	test('remove triggers change event', function () {
		let target = sinon.spy();
		let testObject = aSearchResult();
		testObject.add([aRawMatch('file://c:/1', aLineMatch('preview 1'))]);
		let objectRoRemove = testObject.matches()[0];
		testObject.onChange(target);

		testObject.remove(objectRoRemove);

		assert.ok(target.calledOnce);
		assert.deepEqual([{ elements: [objectRoRemove], removed: true }], target.args[0]);
	});

	test('Removing all line matches and adding back will add file back to result', function () {
		let testObject = aSearchResult();
		testObject.add([aRawMatch('file://c:/1', aLineMatch('preview 1'))]);
		let target = testObject.matches()[0];
		let matchToRemove = target.matches()[0];
		target.remove(matchToRemove);

		assert.ok(testObject.isEmpty());
		target.add(matchToRemove, true);

		assert.equal(1, testObject.fileCount());
		assert.equal(target, testObject.matches()[0]);
	});

	test('replace should remove the file match', function () {
		instantiationService.stubPromise(IReplaceService, 'replace', null);
		let testObject = aSearchResult();
		testObject.add([aRawMatch('file://c:/1', aLineMatch('preview 1'))]);

		testObject.replace(testObject.matches()[0]);

		assert.ok(testObject.isEmpty());
	});

	test('replace should trigger the change event', function () {
		let target = sinon.spy();
		instantiationService.stubPromise(IReplaceService, 'replace', null);
		let testObject = aSearchResult();
		testObject.add([aRawMatch('file://c:/1', aLineMatch('preview 1'))]);
		testObject.onChange(target);
		let objectRoRemove = testObject.matches()[0];

		testObject.replace(objectRoRemove);

		assert.ok(target.calledOnce);
		assert.deepEqual([{ elements: [objectRoRemove], removed: true }], target.args[0]);
	});

	test('replaceAll should remove all file matches', function () {
		instantiationService.stubPromise(IReplaceService, 'replace', null);
		let testObject = aSearchResult();
		testObject.add([aRawMatch('file://c:/1', aLineMatch('preview 1')), aRawMatch('file://c:/2', aLineMatch('preview 2'))]);

		testObject.replaceAll(null);

		assert.ok(testObject.isEmpty());
	});

	//// ----- utils
	//function lineHasDecorations(model: editor.IModel, lineNumber: number, decorations: { start: number; end: number; }[]): void {
	//    let lineDecorations:typeof decorations = [];
	//    let decs = model.getLineDecorations(lineNumber);
	//    for (let i = 0, len = decs.length; i < len; i++) {
	//        lineDecorations.push({
	//            start: decs[i].range.startColumn,
	//            end: decs[i].range.endColumn
	//        });
	//    }
	//    assert.deepEqual(lineDecorations, decorations);
	//}
	//
	//function lineHasNoDecoration(model: editor.IModel, lineNumber: number): void {
	//    lineHasDecorations(model, lineNumber, []);
	//}
	//
	//function lineHasDecoration(model: editor.IModel, lineNumber: number, start: number, end: number): void {
	//    lineHasDecorations(model, lineNumber, [{
	//        start: start,
	//        end: end
	//    }]);
	//}
	//// ----- end utils
	//
	//test('Model Highlights', function () {
	//
	//    let fileMatch = instantiation.createInstance(FileMatch, null, toUri('folder\\file.txt'));
	//    fileMatch.add(new Match(fileMatch, 'line2', 1, 0, 2));
	//    fileMatch.connect();
	//    lineHasDecoration(oneModel, 2, 1, 3);
	//});
	//
	//test('Dispose', function () {
	//
	//    let fileMatch = instantiation.createInstance(FileMatch, null, toUri('folder\\file.txt'));
	//    fileMatch.add(new Match(fileMatch, 'line2', 1, 0, 2));
	//    fileMatch.connect();
	//    lineHasDecoration(oneModel, 2, 1, 3);
	//
	//    fileMatch.dispose();
	//    lineHasNoDecoration(oneModel, 2);
	//});

	function aFileMatch(path: string, searchResult?: SearchResult, ...lineMatches: ILineMatch[]): FileMatch {
		let rawMatch: IFileMatch = {
			resource: URI.file('C:\\' + path),
			lineMatches: lineMatches
		};
		return instantiationService.createInstance(FileMatch, null, searchResult, rawMatch);
	}

	function aSearchResult(): SearchResult {
		let searchModel = instantiationService.createInstance(SearchModel);
		return searchModel.searchResult;
	}

	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 };
	}

	function stubModelService(instantiationService: TestInstantiationService): IModelService {
		instantiationService.stub(IConfigurationService, new TestConfigurationService());
		return instantiationService.createInstance(ModelServiceImpl);
	}
});
	function aSearchResult(): SearchResult {
		let searchModel = instantiationService.createInstance(SearchModel);
		return searchModel.searchResult;
	}
Exemple #10
0
	function aSearchResult(): SearchResult {
		let searchModel = instantiationService.createInstance(SearchModel);
		searchModel.searchResult.query = { type: 1, folderQueries: [{ folder: URI.parse('file://c:/') }] };
		return searchModel.searchResult;
	}