mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-01-23 17:23:02 -05:00
Tests/notebook find tests (#8827)
* updates to existing book tests * notebookFindModal tests * remove commented code * undo book test changes * undo book test changes * resolve the find array * additional tests
This commit is contained in:
@@ -462,7 +462,7 @@ export abstract class NotebookInput extends EditorInput {
|
||||
}
|
||||
}
|
||||
|
||||
class NotebookEditorContentManager implements IContentManager {
|
||||
export class NotebookEditorContentManager implements IContentManager {
|
||||
constructor(
|
||||
private notebookInput: NotebookInput,
|
||||
@IInstantiationService private readonly instantiationService: IInstantiationService) {
|
||||
|
||||
@@ -494,13 +494,18 @@ export class NotebookFindModel extends Disposable implements INotebookFindModel
|
||||
this._findArray = new Array<NotebookRange>();
|
||||
this._onFindCountChange.fire(this._findArray.length);
|
||||
if (exp) {
|
||||
return new Promise<NotebookRange>((resolve) => {
|
||||
const disp = this.onFindCountChange(e => {
|
||||
resolve(this._findArray[this._findIndex]);
|
||||
disp.dispose();
|
||||
});
|
||||
this._startSearch(exp, maxMatches);
|
||||
});
|
||||
for (let i = 0; i < this.notebookModel.cells.length; i++) {
|
||||
const item = this.notebookModel.cells[i];
|
||||
const result = this.searchFn(item, exp, maxMatches);
|
||||
if (result) {
|
||||
this._findArray.push(...result);
|
||||
this._onFindCountChange.fire(this._findArray.length);
|
||||
if (maxMatches > 0 && this._findArray.length === maxMatches) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return Promise.resolve(this._findArray[this._findIndex]);
|
||||
} else {
|
||||
return Promise.reject(new Error('no expression'));
|
||||
}
|
||||
@@ -518,51 +523,41 @@ export class NotebookFindModel extends Disposable implements INotebookFindModel
|
||||
return this.findArray;
|
||||
}
|
||||
|
||||
private _startSearch(exp: string, maxMatches: number = 0): void {
|
||||
let searchFn = (cell: ICellModel, exp: string): NotebookRange[] => {
|
||||
let findResults: NotebookRange[] = [];
|
||||
let cellVal = cell.cellType === 'markdown' ? this.cleanUpCellSource(cell.source) : cell.source;
|
||||
let index: number;
|
||||
let start: number;
|
||||
let end: number;
|
||||
if (cellVal) {
|
||||
if (typeof cellVal === 'string') {
|
||||
private searchFn(cell: ICellModel, exp: string, maxMatches?: number): NotebookRange[] {
|
||||
let findResults: NotebookRange[] = [];
|
||||
let cellVal = cell.cellType === 'markdown' ? this.cleanUpCellSource(cell.source) : cell.source;
|
||||
let index: number;
|
||||
let start: number;
|
||||
let end: number;
|
||||
if (cellVal) {
|
||||
if (typeof cellVal === 'string') {
|
||||
index = 0;
|
||||
while (cellVal.substr(index).toLocaleLowerCase().indexOf(exp.toLocaleLowerCase()) > -1) {
|
||||
start = cellVal.substr(index).toLocaleLowerCase().indexOf(exp.toLocaleLowerCase()) + index;
|
||||
end = start + exp.length;
|
||||
let range = new NotebookRange(cell, 0, start, 0, end);
|
||||
findResults = findResults.concat(range);
|
||||
index = end;
|
||||
}
|
||||
} else {
|
||||
for (let j = 0; j < cellVal.length; j++) {
|
||||
index = 0;
|
||||
while (cellVal.substr(index).toLocaleLowerCase().indexOf(exp.toLocaleLowerCase()) > -1) {
|
||||
start = cellVal.substr(index).toLocaleLowerCase().indexOf(exp.toLocaleLowerCase()) + index;
|
||||
let cellValFormatted = cell.cellType === 'markdown' ? this.cleanMarkdownLinks(cellVal[j]) : cellVal[j];
|
||||
while (cellValFormatted.substr(index).toLocaleLowerCase().indexOf(exp.toLocaleLowerCase()) > -1) {
|
||||
start = cellValFormatted.substr(index).toLocaleLowerCase().indexOf(exp.toLocaleLowerCase()) + index + 1;
|
||||
end = start + exp.length;
|
||||
let range = new NotebookRange(cell, 0, start, 0, end);
|
||||
// lineNumber: j+1 since notebook editors aren't zero indexed.
|
||||
let range = new NotebookRange(cell, j + 1, start, j + 1, end);
|
||||
findResults = findResults.concat(range);
|
||||
index = end;
|
||||
}
|
||||
} else {
|
||||
for (let j = 0; j < cellVal.length; j++) {
|
||||
index = 0;
|
||||
let cellValFormatted = cell.cellType === 'markdown' ? this.cleanMarkdownLinks(cellVal[j]) : cellVal[j];
|
||||
while (cellValFormatted.substr(index).toLocaleLowerCase().indexOf(exp.toLocaleLowerCase()) > -1) {
|
||||
start = cellValFormatted.substr(index).toLocaleLowerCase().indexOf(exp.toLocaleLowerCase()) + index + 1;
|
||||
end = start + exp.length;
|
||||
// lineNumber: j+1 since notebook editors aren't zero indexed.
|
||||
let range = new NotebookRange(cell, j + 1, start, j + 1, end);
|
||||
findResults = findResults.concat(range);
|
||||
index = end;
|
||||
}
|
||||
if (findResults.length >= maxMatches) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return findResults;
|
||||
};
|
||||
for (let i = 0; i < this.notebookModel.cells.length; i++) {
|
||||
const item = this.notebookModel.cells[i];
|
||||
const result = searchFn!(item, exp);
|
||||
if (result) {
|
||||
this._findArray = this._findArray.concat(result);
|
||||
this._onFindCountChange.fire(this._findArray.length);
|
||||
if (maxMatches > 0 && this._findArray.length === maxMatches) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return findResults;
|
||||
}
|
||||
|
||||
// In markdown links are defined as [Link Text](https://url/of/the/text). when searching for text we shouldn't
|
||||
|
||||
@@ -0,0 +1,203 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import * as TypeMoq from 'typemoq';
|
||||
import { nb } from 'azdata';
|
||||
import * as assert from 'assert';
|
||||
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { NotebookManagerStub } from 'sql/workbench/contrib/notebook/test/stubs';
|
||||
import { CellTypes } from 'sql/workbench/contrib/notebook/common/models/contracts';
|
||||
import { IClientSession, INotebookModelOptions } from 'sql/workbench/contrib/notebook/browser/models/modelInterfaces';
|
||||
import { NotebookModel } from 'sql/workbench/contrib/notebook/browser/models/notebookModel';
|
||||
import { NullLogService } from 'vs/platform/log/common/log';
|
||||
import { NotebookFindModel } from 'sql/workbench/contrib/notebook/find/notebookFindModel';
|
||||
import { TestConnectionManagementService } from 'sql/platform/connection/test/common/testConnectionManagementService';
|
||||
import { Deferred } from 'sql/base/common/promise';
|
||||
import { ModelFactory } from 'sql/workbench/contrib/notebook/browser/models/modelFactory';
|
||||
import { ICapabilitiesService } from 'sql/platform/capabilities/common/capabilitiesService';
|
||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { TestNotificationService } from 'vs/platform/notification/test/common/testNotificationService';
|
||||
import { Memento } from 'vs/workbench/common/memento';
|
||||
import { TestCapabilitiesService } from 'sql/platform/capabilities/test/common/testCapabilitiesService';
|
||||
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
|
||||
import { InstantiationService } from 'vs/platform/instantiation/common/instantiationService';
|
||||
import { ClientSession } from 'sql/workbench/contrib/notebook/browser/models/clientSession';
|
||||
import { TestStorageService } from 'vs/workbench/test/workbenchTestServices';
|
||||
import { NotebookRange } from 'sql/workbench/contrib/notebook/find/notebookFindDecorations';
|
||||
import { NotebookEditorContentManager } from 'sql/workbench/contrib/notebook/browser/models/notebookInput';
|
||||
|
||||
let expectedNotebookContent: nb.INotebookContents = {
|
||||
cells: [{
|
||||
cell_type: CellTypes.Code,
|
||||
source: 'insert into t1 values (c1, c2) \ninsert into markdown values (*hello worls*)',
|
||||
metadata: { language: 'python' },
|
||||
execution_count: 1
|
||||
}, {
|
||||
cell_type: CellTypes.Markdown,
|
||||
source: 'I am *markdown*',
|
||||
metadata: { language: 'python' },
|
||||
execution_count: 1
|
||||
}],
|
||||
metadata: {
|
||||
kernelspec: {
|
||||
name: 'mssql',
|
||||
language: 'sql'
|
||||
}
|
||||
},
|
||||
nbformat: 4,
|
||||
nbformat_minor: 5
|
||||
};
|
||||
|
||||
let defaultUri = URI.file('/some/path.ipynb');
|
||||
let max_find_count = 3;
|
||||
let mockClientSession: TypeMoq.Mock<IClientSession>;
|
||||
let sessionReady: Deferred<void>;
|
||||
let mockModelFactory: TypeMoq.Mock<ModelFactory>;
|
||||
let notificationService: TypeMoq.Mock<INotificationService>;
|
||||
let capabilitiesService: TypeMoq.Mock<ICapabilitiesService>;
|
||||
let instantiationService: IInstantiationService;
|
||||
let serviceCollection = new ServiceCollection();
|
||||
|
||||
suite('Notebook Find Model', function (): void {
|
||||
|
||||
let notebookManagers = [new NotebookManagerStub()];
|
||||
let memento: TypeMoq.Mock<Memento>;
|
||||
let queryConnectionService: TypeMoq.Mock<TestConnectionManagementService>;
|
||||
let defaultModelOptions: INotebookModelOptions;
|
||||
const logService = new NullLogService();
|
||||
let model: NotebookModel;
|
||||
|
||||
setup(async () => {
|
||||
sessionReady = new Deferred<void>();
|
||||
notificationService = TypeMoq.Mock.ofType(TestNotificationService, TypeMoq.MockBehavior.Loose);
|
||||
capabilitiesService = TypeMoq.Mock.ofType(TestCapabilitiesService);
|
||||
memento = TypeMoq.Mock.ofType(Memento, TypeMoq.MockBehavior.Loose, '');
|
||||
memento.setup(x => x.getMemento(TypeMoq.It.isAny())).returns(() => void 0);
|
||||
queryConnectionService = TypeMoq.Mock.ofType(TestConnectionManagementService, TypeMoq.MockBehavior.Loose, memento.object, undefined, new TestStorageService());
|
||||
queryConnectionService.callBase = true;
|
||||
|
||||
instantiationService = new InstantiationService(serviceCollection, true);
|
||||
defaultModelOptions = {
|
||||
notebookUri: defaultUri,
|
||||
factory: new ModelFactory(instantiationService),
|
||||
notebookManagers,
|
||||
contentManager: undefined,
|
||||
notificationService: notificationService.object,
|
||||
connectionService: queryConnectionService.object,
|
||||
providerId: 'SQL',
|
||||
cellMagicMapper: undefined,
|
||||
defaultKernel: undefined,
|
||||
layoutChanged: undefined,
|
||||
capabilitiesService: capabilitiesService.object
|
||||
};
|
||||
mockClientSession = TypeMoq.Mock.ofType(ClientSession, undefined, defaultModelOptions);
|
||||
mockClientSession.setup(c => c.initialize()).returns(() => {
|
||||
return Promise.resolve();
|
||||
});
|
||||
mockClientSession.setup(c => c.ready).returns(() => sessionReady.promise);
|
||||
mockModelFactory = TypeMoq.Mock.ofType(ModelFactory);
|
||||
mockModelFactory.callBase = true;
|
||||
mockModelFactory.setup(f => f.createClientSession(TypeMoq.It.isAny())).returns(() => {
|
||||
return mockClientSession.object;
|
||||
});
|
||||
|
||||
await initNotebookModel(expectedNotebookContent);
|
||||
});
|
||||
|
||||
test('Should find results in the notebook', async function (): Promise<void> {
|
||||
//initialize find
|
||||
let notebookFindModel = new NotebookFindModel(model);
|
||||
await notebookFindModel.find('markdown', max_find_count);
|
||||
|
||||
assert(notebookFindModel.findMatches, new Error('Find in notebook failed.'));
|
||||
assert.equal(notebookFindModel.findMatches.length, 2, 'Find couldnt find all occurances');
|
||||
});
|
||||
|
||||
test('Should not find results in the notebook', async function (): Promise<void> {
|
||||
//initialize find
|
||||
let notebookFindModel = new NotebookFindModel(model);
|
||||
await notebookFindModel.find('notFound', max_find_count);
|
||||
|
||||
assert.equal(notebookFindModel.findMatches.length, 0, 'Find failed');
|
||||
});
|
||||
|
||||
test('Should match find result ranges', async function (): Promise<void> {
|
||||
let notebookFindModel = new NotebookFindModel(model);
|
||||
await notebookFindModel.find('markdown', max_find_count);
|
||||
|
||||
let expectedFindRange1 = new NotebookRange(model.cells[0], 2, 13, 2, 21);
|
||||
assert.deepEqual(notebookFindModel.findMatches[0].range, expectedFindRange1, 'Find in markdown range is wrong :\n' + JSON.stringify(expectedFindRange1) + '\n ' + JSON.stringify(notebookFindModel.findMatches[0].range));
|
||||
|
||||
let expectedFindRange2 = new NotebookRange(model.cells[1], 1, 6, 1, 14);
|
||||
assert.deepEqual(notebookFindModel.findMatches[1].range, expectedFindRange2, 'Find in markdown range is wrong :\n' + JSON.stringify(expectedFindRange2) + '\n ' + JSON.stringify(notebookFindModel.findMatches[1].range));
|
||||
});
|
||||
|
||||
test('Should ignore hyperlink markdown data and find correctly', async function (): Promise<void> {
|
||||
let markdownContent: nb.INotebookContents = {
|
||||
cells: [{
|
||||
cell_type: CellTypes.Markdown,
|
||||
source: 'I am markdown link: [best link ever](https://url/of/the/best-link-ever)',
|
||||
metadata: { language: 'python' },
|
||||
execution_count: 1
|
||||
}],
|
||||
metadata: {
|
||||
kernelspec: {
|
||||
name: 'mssql',
|
||||
language: 'sql'
|
||||
}
|
||||
},
|
||||
nbformat: 4,
|
||||
nbformat_minor: 5
|
||||
};
|
||||
await initNotebookModel(markdownContent);
|
||||
|
||||
let notebookFindModel = new NotebookFindModel(model);
|
||||
await notebookFindModel.find('best', max_find_count);
|
||||
|
||||
assert.equal(notebookFindModel.findMatches.length, 1, 'Find failed on markdown link');
|
||||
|
||||
let expectedFindRange1 = new NotebookRange(model.cells[0], 1, 21, 1, 25);
|
||||
assert.deepEqual(notebookFindModel.findMatches[0].range, expectedFindRange1, 'Find in markdown range is wrong :\n' + JSON.stringify(expectedFindRange1) + '\n ' + JSON.stringify(notebookFindModel.findMatches[0].range));
|
||||
|
||||
});
|
||||
|
||||
test('Should not find more than max results in the notebook', async function (): Promise<void> {
|
||||
let codeContent: nb.INotebookContents = {
|
||||
cells: [{
|
||||
cell_type: CellTypes.Code,
|
||||
source: ['import x', 'x.init()', 'x.show()', 'x.analyze()'],
|
||||
metadata: { language: 'python' },
|
||||
execution_count: 1
|
||||
}],
|
||||
metadata: {
|
||||
kernelspec: {
|
||||
name: 'python',
|
||||
language: 'python'
|
||||
}
|
||||
},
|
||||
nbformat: 4,
|
||||
nbformat_minor: 5
|
||||
};
|
||||
await initNotebookModel(codeContent);
|
||||
//initialize find
|
||||
let notebookFindModel = new NotebookFindModel(model);
|
||||
await notebookFindModel.find('x', max_find_count);
|
||||
|
||||
assert.equal(notebookFindModel.findMatches.length, 3, 'Find failed');
|
||||
});
|
||||
|
||||
async function initNotebookModel(contents: nb.INotebookContents): Promise<void> {
|
||||
let mockContentManager = TypeMoq.Mock.ofType(NotebookEditorContentManager);
|
||||
mockContentManager.setup(c => c.loadContent()).returns(() => Promise.resolve(contents));
|
||||
defaultModelOptions.contentManager = mockContentManager.object;
|
||||
// Initialize the model
|
||||
model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, undefined);
|
||||
await model.loadContents();
|
||||
await model.requestModelLoad();
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user