Add tests for Open Notebook Folder functionality. (#10056)

This commit is contained in:
Cory Rivera
2020-04-17 16:27:00 -07:00
committed by GitHub
parent 6200075624
commit 67b6f6ffcd
3 changed files with 110 additions and 85 deletions

View File

@@ -79,15 +79,10 @@ export class BookTreeViewProvider implements vscode.TreeDataProvider<BookTreeIte
trustBook(bookTreeItem?: BookTreeItem): void {
let bookPathToTrust = bookTreeItem ? bookTreeItem.root : this.currentBook?.bookPath;
if (bookPathToTrust) {
let trustChanged = this._bookTrustManager.setBookAsTrusted(bookPathToTrust);
if (trustChanged) {
let notebookDocuments = this._apiWrapper.getNotebookDocuments();
if (notebookDocuments) {
// update trust state of opened items
notebookDocuments.forEach(document => {
@@ -114,7 +109,7 @@ export class BookTreeViewProvider implements vscode.TreeDataProvider<BookTreeIte
if (existingBook?.bookItems.length > 0) {
this.currentBook = existingBook;
} else {
await this.createAndAddBookModel(bookPath, isNotebook);
await this.createAndAddBookModel(bookPath, !!isNotebook);
let bookViewer = vscode.window.createTreeView(this.viewId, { showCollapseAll: true, treeDataProvider: this });
this.currentBook = this.books.find(book => book.bookPath === bookPath);
bookViewer.reveal(this.currentBook.bookItems[0], { expand: vscode.TreeItemCollapsibleState.Expanded, focus: true, select: true });
@@ -370,7 +365,7 @@ export class BookTreeViewProvider implements vscode.TreeDataProvider<BookTreeIte
}
}
private async loadNotebooksInFolder(folderPath: string) {
public async loadNotebooksInFolder(folderPath: string) {
let bookCollection = await this.getNotebooksInTree(folderPath);
for (let i = 0; i < bookCollection.bookPaths.length; i++) {
await this.openBook(bookCollection.bookPaths[i], undefined, false);
@@ -456,7 +451,6 @@ export class BookTreeViewProvider implements vscode.TreeDataProvider<BookTreeIte
}
}
getParent(element?: BookTreeItem): vscode.ProviderResult<BookTreeItem> {
if (element) {
let parentPath;
@@ -488,7 +482,6 @@ export class BookTreeViewProvider implements vscode.TreeDataProvider<BookTreeIte
return untitledFileName;
}
//Confirmation message dialog
private async confirmReplace(): Promise<boolean> {
return await this.prompter.promptSingle<boolean>(<IQuestion>{

View File

@@ -1,74 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as fs from 'fs-extra';
import * as nls from 'vscode-nls';
const localize = nls.loadMessageBundle();
import * as constants from '../common/constants';
export enum SettingType {
String,
Number,
Boolean,
Set
}
export class ISetting {
key: string;
value: string | number | boolean;
type: SettingType;
}
export class JupyterSettingWriter {
private settings: ISetting[] = [];
constructor(private baseFile: string) {
}
public addSetting(setting: ISetting): void {
this.settings.push(setting);
}
public async writeSettings(targetFile: string): Promise<void> {
let settings = await this.printSettings();
await fs.writeFile(targetFile, settings);
}
public async printSettings(): Promise<string> {
let content = '';
let newLine = process.platform === constants.winPlatform ? '\r\n' : '\n';
if (this.baseFile) {
let sourceContents = await fs.readFile(this.baseFile);
content += sourceContents.toString();
}
for (let setting of this.settings) {
content += newLine;
content += this.printSetting(setting);
}
return content;
}
private printSetting(setting: ISetting): string {
let value: string;
switch (setting.type) {
case SettingType.Boolean:
value = setting.value ? 'True' : 'False';
break;
case SettingType.String:
value = `'${setting.value}'`;
break;
case SettingType.Number:
value = `${setting.value}`;
break;
case SettingType.Set:
value = `set([${setting.value}])`;
break;
default:
throw new Error(localize('UnexpectedSettingType', "Unexpected setting type {0}", setting.type));
}
return `c.${setting.key} = ${value}`;
}
}

View File

@@ -12,12 +12,13 @@ import * as rimraf from 'rimraf';
import * as os from 'os';
import * as uuid from 'uuid';
import { BookTreeViewProvider } from '../../book/bookTreeView';
import { BookTreeItem } from '../../book/bookTreeItem';
import { BookTreeItem, BookTreeItemType } from '../../book/bookTreeItem';
import { promisify } from 'util';
import { MockExtensionContext } from '../common/stubs';
import { exists } from '../../common/utils';
import { AppContext } from '../../common/appContext';
import { ApiWrapper } from '../../common/apiWrapper';
import { BookModel } from '../../book/bookModel';
import { BookTrustManager } from '../../book/bookTrustManager';
export interface IExpectedBookItem {
@@ -43,7 +44,6 @@ export function equalBookItems(book: BookTreeItem, expectedBook: IExpectedBookIt
}
describe('BookTreeViewProviderTests', function () {
describe('BookTreeViewProvider', () => {
let mockExtensionContext: vscode.ExtensionContext;
@@ -449,4 +449,110 @@ describe('BookTreeViewProviderTests', function () {
}
});
});
describe('BookTreeViewProvider.openNotebookFolder', function (): void {
let rootFolderPath: string;
let bookFolderPath: string;
let bookTitle: string;
let notebookFolderPath: string;
let tableOfContentsFile: string;
let standaloneNotebookTitle: string;
let standaloneNotebookFile: string;
let bookTreeViewProvider: BookTreeViewProvider;
let appContext: AppContext;
this.beforeAll(async () => {
rootFolderPath = path.join(os.tmpdir(), `BookFolderTest_${uuid.v4()}`);
bookFolderPath = path.join(rootFolderPath, 'BookTestData');
let dataFolderPath = path.join(bookFolderPath, '_data');
let contentFolderPath = path.join(bookFolderPath, 'content');
let configFile = path.join(bookFolderPath, '_config.yml');
tableOfContentsFile = path.join(dataFolderPath, 'toc.yml');
let bookNotebookFile = path.join(contentFolderPath, 'notebook1.ipynb');
notebookFolderPath = path.join(rootFolderPath, 'NotebookTestData');
standaloneNotebookTitle = 'notebook2';
standaloneNotebookFile = path.join(notebookFolderPath, `${standaloneNotebookTitle}.ipynb`);
await fs.mkdir(rootFolderPath);
await fs.mkdir(bookFolderPath);
await fs.mkdir(dataFolderPath);
await fs.mkdir(contentFolderPath);
await fs.mkdir(notebookFolderPath);
bookTitle = 'Test Book';
await fs.writeFile(configFile, `title: ${bookTitle}`);
await fs.writeFile(tableOfContentsFile, '- title: Notebook1\n url: /notebook1');
await fs.writeFile(bookNotebookFile, '');
await fs.writeFile(standaloneNotebookFile, '');
const mockExtensionContext = new MockExtensionContext();
appContext = new AppContext(mockExtensionContext, new ApiWrapper());
bookTreeViewProvider = new BookTreeViewProvider(appContext.apiWrapper, [], mockExtensionContext, false, 'bookTreeView');
let errorCase = new Promise((resolve, reject) => setTimeout(() => resolve(), 5000));
await Promise.race([bookTreeViewProvider.initialized, errorCase.then(() => { throw new Error('BookTreeViewProvider did not initialize in time'); })]);
appContext = new AppContext(undefined, new ApiWrapper());
});
it('should include books and notebooks when opening parent folder', async () => {
await bookTreeViewProvider.loadNotebooksInFolder(rootFolderPath);
should(bookTreeViewProvider.books.length).equal(2, 'Should have loaded a book and a notebook');
validateIsBook(bookTreeViewProvider.books[0]);
validateIsNotebook(bookTreeViewProvider.books[1]);
});
it('should include only books when opening books folder', async () => {
await bookTreeViewProvider.loadNotebooksInFolder(bookFolderPath);
should(bookTreeViewProvider.books.length).equal(1, 'Should have loaded only one book');
validateIsBook(bookTreeViewProvider.books[0]);
});
it('should include only notebooks when opening notebooks folder', async () => {
await bookTreeViewProvider.loadNotebooksInFolder(notebookFolderPath);
should(bookTreeViewProvider.books.length).equal(1, 'Should have loaded only one notebook');
validateIsNotebook(bookTreeViewProvider.books[0]);
});
this.afterEach(async function (): Promise<void> {
let bookItems = await bookTreeViewProvider.getChildren();
await Promise.all(bookItems.map(bookItem => bookTreeViewProvider.closeBook(bookItem)));
});
this.afterAll(async function (): Promise<void> {
if (await exists(rootFolderPath)) {
await promisify(rimraf)(rootFolderPath);
}
});
let validateIsBook = (book: BookModel) => {
should(book.isNotebook).be.false();
should(book.bookItems.length).equal(1);
let bookItem = book.bookItems[0];
let bookDetails = bookItem.book;
should(bookDetails.type).equal(BookTreeItemType.Book);
should(bookDetails.title).equal(bookTitle);
should(bookDetails.contentPath).equal(tableOfContentsFile.replace(/\\/g, '/'));
should(bookDetails.root).equal(bookFolderPath.replace(/\\/g, '/'));
should(bookDetails.tableOfContents.sections).not.equal(undefined);
should(bookDetails.page).not.equal(undefined);
};
let validateIsNotebook = (book: BookModel) => {
should(book.isNotebook).be.true();
should(book.bookItems.length).equal(1);
let bookItem = book.bookItems[0];
should(book.getAllNotebooks().get(vscode.Uri.file(standaloneNotebookFile).fsPath)).equal(bookItem);
let bookDetails = bookItem.book;
should(bookDetails.type).equal(BookTreeItemType.Notebook);
should(bookDetails.title).equal(standaloneNotebookTitle);
should(bookDetails.contentPath).equal(standaloneNotebookFile.replace(/\\/g, '/'));
should(bookDetails.root).equal(notebookFolderPath.replace(/\\/g, '/'));
should(bookDetails.tableOfContents.sections).equal(undefined);
should(bookDetails.page.sections).equal(undefined);
};
});
});