mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-17 02:51:36 -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(
|
constructor(
|
||||||
private notebookInput: NotebookInput,
|
private notebookInput: NotebookInput,
|
||||||
@IInstantiationService private readonly instantiationService: IInstantiationService) {
|
@IInstantiationService private readonly instantiationService: IInstantiationService) {
|
||||||
|
|||||||
@@ -494,13 +494,18 @@ export class NotebookFindModel extends Disposable implements INotebookFindModel
|
|||||||
this._findArray = new Array<NotebookRange>();
|
this._findArray = new Array<NotebookRange>();
|
||||||
this._onFindCountChange.fire(this._findArray.length);
|
this._onFindCountChange.fire(this._findArray.length);
|
||||||
if (exp) {
|
if (exp) {
|
||||||
return new Promise<NotebookRange>((resolve) => {
|
for (let i = 0; i < this.notebookModel.cells.length; i++) {
|
||||||
const disp = this.onFindCountChange(e => {
|
const item = this.notebookModel.cells[i];
|
||||||
resolve(this._findArray[this._findIndex]);
|
const result = this.searchFn(item, exp, maxMatches);
|
||||||
disp.dispose();
|
if (result) {
|
||||||
});
|
this._findArray.push(...result);
|
||||||
this._startSearch(exp, maxMatches);
|
this._onFindCountChange.fire(this._findArray.length);
|
||||||
});
|
if (maxMatches > 0 && this._findArray.length === maxMatches) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Promise.resolve(this._findArray[this._findIndex]);
|
||||||
} else {
|
} else {
|
||||||
return Promise.reject(new Error('no expression'));
|
return Promise.reject(new Error('no expression'));
|
||||||
}
|
}
|
||||||
@@ -518,51 +523,41 @@ export class NotebookFindModel extends Disposable implements INotebookFindModel
|
|||||||
return this.findArray;
|
return this.findArray;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _startSearch(exp: string, maxMatches: number = 0): void {
|
private searchFn(cell: ICellModel, exp: string, maxMatches?: number): NotebookRange[] {
|
||||||
let searchFn = (cell: ICellModel, exp: string): NotebookRange[] => {
|
let findResults: NotebookRange[] = [];
|
||||||
let findResults: NotebookRange[] = [];
|
let cellVal = cell.cellType === 'markdown' ? this.cleanUpCellSource(cell.source) : cell.source;
|
||||||
let cellVal = cell.cellType === 'markdown' ? this.cleanUpCellSource(cell.source) : cell.source;
|
let index: number;
|
||||||
let index: number;
|
let start: number;
|
||||||
let start: number;
|
let end: number;
|
||||||
let end: number;
|
if (cellVal) {
|
||||||
if (cellVal) {
|
if (typeof cellVal === 'string') {
|
||||||
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;
|
index = 0;
|
||||||
while (cellVal.substr(index).toLocaleLowerCase().indexOf(exp.toLocaleLowerCase()) > -1) {
|
let cellValFormatted = cell.cellType === 'markdown' ? this.cleanMarkdownLinks(cellVal[j]) : cellVal[j];
|
||||||
start = cellVal.substr(index).toLocaleLowerCase().indexOf(exp.toLocaleLowerCase()) + index;
|
while (cellValFormatted.substr(index).toLocaleLowerCase().indexOf(exp.toLocaleLowerCase()) > -1) {
|
||||||
|
start = cellValFormatted.substr(index).toLocaleLowerCase().indexOf(exp.toLocaleLowerCase()) + index + 1;
|
||||||
end = start + exp.length;
|
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);
|
findResults = findResults.concat(range);
|
||||||
index = end;
|
index = end;
|
||||||
}
|
}
|
||||||
} else {
|
if (findResults.length >= maxMatches) {
|
||||||
for (let j = 0; j < cellVal.length; j++) {
|
break;
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
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
|
// 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