mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-17 02:51:36 -05:00
Load all data workspace projects directly from workspace (#15921)
* Load all projects directly from workspace * fixes * Remove relativity and fix tests * fix compile * PR comments * remove unused * distro
This commit is contained in:
@@ -1,66 +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 should from 'should';
|
||||
import * as TypeMoq from 'typemoq';
|
||||
import * as os from 'os';
|
||||
import * as path from 'path';
|
||||
import * as sinon from 'sinon';
|
||||
import * as utils from '../../common/utils';
|
||||
import * as constants from '../../common/constants';
|
||||
import { NewProjectDialog } from '../../dialogs/newProjectDialog';
|
||||
import { WorkspaceService } from '../../services/workspaceService';
|
||||
import { testProjectType } from '../testUtils';
|
||||
|
||||
suite('DialogBase - workspace validation', function (): void {
|
||||
// DialogBase is an abstract class, so we'll just use a NewProjectDialog to test the common base class functions
|
||||
let dialog: NewProjectDialog;
|
||||
|
||||
this.beforeEach(async () => {
|
||||
const workspaceServiceMock = TypeMoq.Mock.ofType<WorkspaceService>();
|
||||
workspaceServiceMock.setup(x => x.getAllProjectTypes()).returns(() => Promise.resolve([testProjectType]));
|
||||
|
||||
dialog = new NewProjectDialog(workspaceServiceMock.object);
|
||||
await dialog.open();
|
||||
|
||||
dialog.model.name = `TestProject_${new Date().getTime()}`;
|
||||
dialog.model.location = os.tmpdir();
|
||||
});
|
||||
|
||||
this.afterEach(() => {
|
||||
sinon.restore();
|
||||
});
|
||||
|
||||
test('Should validate new workspace location missing file extension', async function (): Promise<void> {
|
||||
dialog.workspaceInputBox!.value = 'test';
|
||||
await should(dialog.validateNewWorkspace(false)).be.rejectedWith(constants.WorkspaceFileInvalidError(dialog.workspaceInputBox!.value));
|
||||
});
|
||||
|
||||
test('Should validate new workspace location with invalid location', async function (): Promise<void> {
|
||||
// use invalid folder
|
||||
dialog.workspaceInputBox!.value = 'invalidLocation/test.code-workspace';
|
||||
await should(dialog.validateNewWorkspace(false)).be.rejectedWith(constants.WorkspaceParentDirectoryNotExistError(path.dirname(dialog.workspaceInputBox!.value)));
|
||||
});
|
||||
|
||||
test('Should validate new workspace location that already exists', async function (): Promise<void> {
|
||||
// use already existing workspace
|
||||
const fileExistStub = sinon.stub(utils, 'fileExist');
|
||||
fileExistStub.resolves(true);
|
||||
const existingWorkspaceFilePath = path.join(os.tmpdir(), `${dialog.model.name}.code-workspace`);
|
||||
dialog.workspaceInputBox!.value = existingWorkspaceFilePath;
|
||||
await should(dialog.validateNewWorkspace(false)).be.rejectedWith(constants.WorkspaceFileAlreadyExistsError(existingWorkspaceFilePath));
|
||||
});
|
||||
|
||||
test('Should validate new workspace location that is valid', async function (): Promise<void> {
|
||||
// same folder as the project should be valid even if the project folder isn't created yet
|
||||
dialog.workspaceInputBox!.value = path.join(dialog.model.location, dialog.model.name, 'test.code-workspace');
|
||||
await should(dialog.validateNewWorkspace(true)).not.be.rejected();
|
||||
|
||||
// a workspace not in the same folder as the project should also be valid
|
||||
dialog.workspaceInputBox!.value = path.join(os.tmpdir(), `TestWorkspace_${new Date().getTime()}.code-workspace`);
|
||||
await should(dialog.validateNewWorkspace(false)).not.be.rejected();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -7,7 +7,6 @@ import * as should from 'should';
|
||||
import * as TypeMoq from 'typemoq';
|
||||
import * as os from 'os';
|
||||
import * as path from 'path';
|
||||
import * as vscode from 'vscode';
|
||||
import * as sinon from 'sinon';
|
||||
import { promises as fs } from 'fs';
|
||||
import { NewProjectDialog } from '../../dialogs/newProjectDialog';
|
||||
@@ -28,7 +27,6 @@ suite('New Project Dialog', function (): void {
|
||||
|
||||
dialog.model.name = 'TestProject';
|
||||
dialog.model.location = '';
|
||||
dialog.workspaceInputBox!.value = 'test.code-workspace';
|
||||
should.equal(await dialog.validate(), false, 'Validation should fail because the parent directory does not exist');
|
||||
|
||||
// create a folder with the same name
|
||||
@@ -41,24 +39,5 @@ suite('New Project Dialog', function (): void {
|
||||
dialog.model.name = `TestProject_${new Date().getTime()}`;
|
||||
should.equal(await dialog.validate(), true, 'Validation should pass because name is unique and parent directory exists');
|
||||
});
|
||||
|
||||
|
||||
test('Should validate workspace in onComplete', async function (): Promise<void> {
|
||||
const workspaceServiceMock = TypeMoq.Mock.ofType<WorkspaceService>();
|
||||
workspaceServiceMock.setup(x => x.validateWorkspace()).returns(() => Promise.resolve(true));
|
||||
workspaceServiceMock.setup(x => x.getAllProjectTypes()).returns(() => Promise.resolve([testProjectType]));
|
||||
|
||||
const dialog = new NewProjectDialog(workspaceServiceMock.object);
|
||||
await dialog.open();
|
||||
|
||||
dialog.model.name = 'TestProject';
|
||||
dialog.model.location = '';
|
||||
should.doesNotThrow(async () => await dialog.onComplete());
|
||||
|
||||
workspaceServiceMock.setup(x => x.validateWorkspace()).throws(new Error('test error'));
|
||||
const spy = sinon.spy(vscode.window, 'showErrorMessage');
|
||||
should.doesNotThrow(async () => await dialog.onComplete(), 'Error should be caught');
|
||||
should(spy.calledOnce).be.true();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -12,23 +12,19 @@ import * as constants from '../../common/constants';
|
||||
import * as utils from '../../common/utils';
|
||||
import { WorkspaceService } from '../../services/workspaceService';
|
||||
import { OpenExistingDialog } from '../../dialogs/openExistingDialog';
|
||||
import { createProjectFile, generateUniqueProjectFilePath, generateUniqueWorkspaceFilePath, testProjectType } from '../testUtils';
|
||||
import { createProjectFile, generateUniqueProjectFilePath, testProjectType } from '../testUtils';
|
||||
|
||||
suite('Open Existing Dialog', function (): void {
|
||||
const mockExtensionContext = TypeMoq.Mock.ofType<vscode.ExtensionContext>();
|
||||
|
||||
this.afterEach(() => {
|
||||
sinon.restore();
|
||||
});
|
||||
|
||||
test('Should validate project file exists', async function (): Promise<void> {
|
||||
const workspaceServiceMock = TypeMoq.Mock.ofType<WorkspaceService>();
|
||||
const dialog = new OpenExistingDialog(workspaceServiceMock.object, mockExtensionContext.object);
|
||||
const dialog = new OpenExistingDialog(workspaceServiceMock.object);
|
||||
await dialog.open();
|
||||
|
||||
dialog.targetTypeRadioCardGroup?.updateProperty( 'selectedCardId', constants.Project);
|
||||
dialog.filePathTextBox!.value = 'nonExistentProjectFile';
|
||||
dialog.workspaceInputBox!.value = 'test.code-workspace';
|
||||
|
||||
const validateResult = await dialog.validate();
|
||||
|
||||
@@ -41,32 +37,12 @@ suite('Open Existing Dialog', function (): void {
|
||||
should.equal(await dialog.validate(), true, `Validation should pass because project file exists, but failed with: ${dialog.dialogObject.message.text}`);
|
||||
});
|
||||
|
||||
test('Should validate workspace file exists', async function (): Promise<void> {
|
||||
const workspaceServiceMock = TypeMoq.Mock.ofType<WorkspaceService>();
|
||||
const dialog = new OpenExistingDialog(workspaceServiceMock.object, mockExtensionContext.object);
|
||||
await dialog.open();
|
||||
|
||||
dialog.targetTypeRadioCardGroup?.updateProperty( 'selectedCardId', constants.Workspace);
|
||||
dialog.filePathTextBox!.value = 'nonExistentWorkspaceFile';
|
||||
const fileExistStub = sinon.stub(utils, 'fileExist').resolves(false);
|
||||
|
||||
const validateResult = await dialog.validate();
|
||||
const msg = constants.FileNotExistError('workspace', 'nonExistentWorkspaceFile');
|
||||
should.equal(dialog.dialogObject.message.text, msg);
|
||||
should.equal(validateResult, false, 'Validation should fail because workspace file does not exist, but passed');
|
||||
|
||||
// validation should pass if workspace file exists
|
||||
dialog.filePathTextBox!.value = generateUniqueWorkspaceFilePath();
|
||||
fileExistStub.resolves(true);
|
||||
should.equal(await dialog.validate(), true, `Validation should pass because workspace file exists, but failed with: ${dialog.dialogObject.message.text}`);
|
||||
});
|
||||
|
||||
test('Should validate workspace git clone location', async function (): Promise<void> {
|
||||
const workspaceServiceMock = TypeMoq.Mock.ofType<WorkspaceService>();
|
||||
const dialog = new OpenExistingDialog(workspaceServiceMock.object, mockExtensionContext.object);
|
||||
const dialog = new OpenExistingDialog(workspaceServiceMock.object);
|
||||
await dialog.open();
|
||||
|
||||
dialog.targetTypeRadioCardGroup?.updateProperty( 'selectedCardId', constants.Workspace);
|
||||
dialog.localRadioButton!.checked = false;
|
||||
dialog.remoteGitRepoRadioButton!.checked = true;
|
||||
dialog.localClonePathTextBox!.value = 'invalidLocation';
|
||||
@@ -74,7 +50,7 @@ suite('Open Existing Dialog', function (): void {
|
||||
|
||||
const validateResult = await dialog.validate();
|
||||
const msg = constants.CloneParentDirectoryNotExistError(dialog.localClonePathTextBox!.value);
|
||||
should.equal(dialog.dialogObject.message.text, msg);
|
||||
should.equal(dialog.dialogObject.message.text, msg, 'Dialog message should be correct');
|
||||
should.equal(validateResult, false, 'Validation should fail because clone directory does not exist, but passed');
|
||||
|
||||
// validation should pass if directory exists
|
||||
@@ -83,58 +59,22 @@ suite('Open Existing Dialog', function (): void {
|
||||
should.equal(await dialog.validate(), true, `Validation should pass because clone directory exists, but failed with: ${dialog.dialogObject.message.text}`);
|
||||
});
|
||||
|
||||
test('Should validate workspace in onComplete when opening project', async function (): Promise<void> {
|
||||
const workspaceServiceMock = TypeMoq.Mock.ofType<WorkspaceService>();
|
||||
workspaceServiceMock.setup(x => x.validateWorkspace()).returns(() => Promise.resolve(true));
|
||||
workspaceServiceMock.setup(x => x.addProjectsToWorkspace(TypeMoq.It.isAny())).returns(() => Promise.resolve());
|
||||
|
||||
const dialog = new OpenExistingDialog(workspaceServiceMock.object, mockExtensionContext.object);
|
||||
await dialog.open();
|
||||
|
||||
dialog.filePathTextBox!.value = generateUniqueProjectFilePath('testproj');
|
||||
should.doesNotThrow(async () => await dialog.onComplete());
|
||||
|
||||
workspaceServiceMock.setup(x => x.validateWorkspace()).throws(new Error('test error'));
|
||||
const spy = sinon.spy(vscode.window, 'showErrorMessage');
|
||||
should.doesNotThrow(async () => await dialog.onComplete(), 'Error should be caught');
|
||||
should(spy.calledOnce).be.true();
|
||||
});
|
||||
|
||||
test('workspace browse', async function (): Promise<void> {
|
||||
const workspaceServiceMock = TypeMoq.Mock.ofType<WorkspaceService>();
|
||||
sinon.stub(vscode.window, 'showOpenDialog').returns(Promise.resolve([]));
|
||||
|
||||
const dialog = new OpenExistingDialog(workspaceServiceMock.object, mockExtensionContext.object);
|
||||
await dialog.open();
|
||||
should.equal(dialog.filePathTextBox!.value, '');
|
||||
await dialog.workspaceBrowse();
|
||||
should.equal(dialog.filePathTextBox!.value, '', 'Workspace file should not be set when no file is selected');
|
||||
|
||||
sinon.restore();
|
||||
const workspaceFile = vscode.Uri.file(generateUniqueWorkspaceFilePath());
|
||||
sinon.stub(vscode.window, 'showOpenDialog').returns(Promise.resolve([workspaceFile]));
|
||||
await dialog.workspaceBrowse();
|
||||
should.equal(dialog.filePathTextBox!.value, workspaceFile.fsPath, 'Workspace file should get set');
|
||||
should.equal(dialog.filePathTextBox?.value, workspaceFile.fsPath);
|
||||
});
|
||||
|
||||
test('project browse', async function (): Promise<void> {
|
||||
const workspaceServiceMock = TypeMoq.Mock.ofType<WorkspaceService>();
|
||||
workspaceServiceMock.setup(x => x.getAllProjectTypes()).returns(() => Promise.resolve([testProjectType]));
|
||||
sinon.stub(vscode.window, 'showOpenDialog').returns(Promise.resolve([]));
|
||||
|
||||
const dialog = new OpenExistingDialog(workspaceServiceMock.object, mockExtensionContext.object);
|
||||
const dialog = new OpenExistingDialog(workspaceServiceMock.object);
|
||||
await dialog.open();
|
||||
should.equal(dialog.filePathTextBox!.value, '');
|
||||
should.equal(dialog.filePathTextBox!.value ?? '', '', 'Project file should initially be empty');
|
||||
await dialog.projectBrowse();
|
||||
should.equal(dialog.filePathTextBox!.value, '', 'Project file should not be set when no file is selected');
|
||||
should.equal(dialog.filePathTextBox!.value ?? '', '', 'Project file should not be set when no file is selected');
|
||||
|
||||
sinon.restore();
|
||||
const projectFile = vscode.Uri.file(generateUniqueProjectFilePath('testproj'));
|
||||
sinon.stub(vscode.window, 'showOpenDialog').returns(Promise.resolve([projectFile]));
|
||||
await dialog.projectBrowse();
|
||||
should.equal(dialog.filePathTextBox!.value, projectFile.fsPath, 'Project file should be set');
|
||||
should.equal(dialog.filePathTextBox?.value, projectFile.fsPath);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -23,9 +23,6 @@ export function createProjectProvider(projectTypes: IProjectType[], projectActio
|
||||
const treeDataProvider = new MockTreeDataProvider();
|
||||
const projectProvider: IProjectProvider = {
|
||||
supportedProjectTypes: projectTypes,
|
||||
RemoveProject: (projectFile: vscode.Uri): Promise<void> => {
|
||||
return Promise.resolve();
|
||||
},
|
||||
getProjectTreeDataProvider: (projectFile: vscode.Uri): Promise<vscode.TreeDataProvider<any>> => {
|
||||
return Promise.resolve(treeDataProvider);
|
||||
},
|
||||
|
||||
@@ -31,7 +31,3 @@ export async function createProjectFile(fileExt: string, contents?: string): Pro
|
||||
export function generateUniqueProjectFilePath(fileExt: string): string {
|
||||
return path.join(os.tmpdir(), `TestProject_${new Date().getTime()}.${fileExt}`);
|
||||
}
|
||||
|
||||
export function generateUniqueWorkspaceFilePath(): string {
|
||||
return path.join(os.tmpdir(), `TestWorkspace_${new Date().getTime()}.code-workspace`);
|
||||
}
|
||||
|
||||
@@ -1,21 +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 'mocha';
|
||||
import * as os from 'os';
|
||||
import * as path from 'path';
|
||||
import should = require('should');
|
||||
import { calculateRelativity } from '../common/telemetry';
|
||||
|
||||
suite('Utilities Tests', function (): void {
|
||||
test('test CalculateRelativity', async () => {
|
||||
const root = os.platform() === 'win32' ? 'Z:\\' : '/';
|
||||
const workspacePath = path.join(root, 'Source', 'Workspace', 'qwerty.code-workspace');
|
||||
|
||||
should.equal(calculateRelativity(path.join(root, 'Source', 'Workspace', 'qwerty.sqlproj'), workspacePath), 'sameFolder');
|
||||
should.equal(calculateRelativity(path.join(root, 'Source', 'Workspace', 'qwerty', 'asdfg', 'qwerty.sqlproj'), workspacePath), 'directAncestor');
|
||||
should.equal(calculateRelativity(path.join(root, 'Users', 'BillG', 'qwerty.sqlproj'), workspacePath), 'other');
|
||||
});
|
||||
});
|
||||
@@ -5,42 +5,13 @@
|
||||
|
||||
import 'mocha';
|
||||
import * as vscode from 'vscode';
|
||||
import * as azdata from 'azdata';
|
||||
import * as sinon from 'sinon';
|
||||
import * as should from 'should';
|
||||
import * as path from 'path';
|
||||
import * as TypeMoq from 'typemoq';
|
||||
import * as constants from '../common/constants';
|
||||
import * as utils from '../common/utils';
|
||||
import { WorkspaceService } from '../services/workspaceService';
|
||||
import { ProjectProviderRegistry } from '../common/projectProviderRegistry';
|
||||
import { createProjectProvider } from './projectProviderRegistry.test';
|
||||
|
||||
const DefaultWorkspaceFilePath = '/test/folder/ws.code-workspace';
|
||||
|
||||
/**
|
||||
* Create a stub for vscode.workspace.workspaceFile
|
||||
* @param workspaceFilePath The workspace file to return
|
||||
*/
|
||||
function stubWorkspaceFile(workspaceFilePath: string | undefined): sinon.SinonStub {
|
||||
return sinon.stub(vscode.workspace, 'workspaceFile').value(workspaceFilePath ? vscode.Uri.file(workspaceFilePath) : undefined);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a stub for vscode.workspace.getConfiguration
|
||||
* @param returnValue the configuration value to return
|
||||
*/
|
||||
function stubGetConfigurationValue(getStub?: sinon.SinonStub, updateStub?: sinon.SinonStub): sinon.SinonStub {
|
||||
return sinon.stub(vscode.workspace, 'getConfiguration').returns({
|
||||
get: (configurationName: string) => {
|
||||
return getStub!(configurationName);
|
||||
},
|
||||
update: (section: string, value: any, configurationTarget?: vscode.ConfigurationTarget | boolean, overrideInLanguage?: boolean) => {
|
||||
updateStub!(section, value, configurationTarget);
|
||||
}
|
||||
} as vscode.WorkspaceConfiguration);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a stub for vscode.extensions.all
|
||||
* @param extensions extensions to return
|
||||
@@ -64,41 +35,29 @@ function createMockExtension(id: string, isActive: boolean, projectTypes: string
|
||||
};
|
||||
}
|
||||
|
||||
interface ExtensionGlobalMemento extends vscode.Memento {
|
||||
setKeysForSync(keys: string[]): void;
|
||||
}
|
||||
|
||||
suite('WorkspaceService Tests', function (): void {
|
||||
const mockExtensionContext = TypeMoq.Mock.ofType<vscode.ExtensionContext>();
|
||||
const mockGlobalState = TypeMoq.Mock.ofType<ExtensionGlobalMemento>();
|
||||
mockGlobalState.setup(x => x.update(TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => Promise.resolve());
|
||||
mockExtensionContext.setup(x => x.globalState).returns(() => mockGlobalState.object);
|
||||
|
||||
const service = new WorkspaceService(mockExtensionContext.object);
|
||||
suite('WorkspaceService', function (): void {
|
||||
let service = new WorkspaceService();
|
||||
|
||||
this.afterEach(() => {
|
||||
sinon.restore();
|
||||
});
|
||||
|
||||
test('test getProjectsInWorkspace', async () => {
|
||||
test('getProjectsInWorkspace', async () => {
|
||||
// No workspace is loaded
|
||||
stubWorkspaceFile(undefined);
|
||||
let projects = await service.getProjectsInWorkspace();
|
||||
should.strictEqual(projects.length, 0, 'no projects should be returned when no workspace is loaded');
|
||||
|
||||
// from this point on, workspace is loaded
|
||||
stubWorkspaceFile(DefaultWorkspaceFilePath);
|
||||
|
||||
// No projects are present in the workspace file
|
||||
const getConfigurationStub = stubGetConfigurationValue(sinon.stub().returns([]));
|
||||
const workspaceFoldersStub = sinon.stub(vscode.workspace, 'workspaceFolders').value([]);
|
||||
projects = await service.getProjectsInWorkspace();
|
||||
should.strictEqual(projects.length, 0, 'no projects should be returned when projects are present in the workspace file');
|
||||
getConfigurationStub.restore();
|
||||
workspaceFoldersStub.restore();
|
||||
|
||||
// Projects are present
|
||||
stubGetConfigurationValue(sinon.stub().returns(['abc.sqlproj', 'folder1/abc1.sqlproj', 'folder2/abc2.sqlproj']));
|
||||
sinon.stub(vscode.workspace, 'workspaceFolders').value([{ uri: vscode.Uri.file('')}]);
|
||||
sinon.stub(service, 'getAllProjectsInFolder').resolves([vscode.Uri.file('/test/folder/abc.sqlproj'), vscode.Uri.file('/test/folder/folder1/abc1.sqlproj'), vscode.Uri.file('/test/folder/folder2/abc2.sqlproj')]);
|
||||
projects = await service.getProjectsInWorkspace();
|
||||
should.strictEqual(projects.length, 3, 'there should be 2 projects');
|
||||
should.strictEqual(projects.length, 3, 'there should be 3 projects');
|
||||
const project1 = vscode.Uri.file('/test/folder/abc.sqlproj');
|
||||
const project2 = vscode.Uri.file('/test/folder/folder1/abc1.sqlproj');
|
||||
const project3 = vscode.Uri.file('/test/folder/folder2/abc2.sqlproj');
|
||||
@@ -107,7 +66,7 @@ suite('WorkspaceService Tests', function (): void {
|
||||
should.strictEqual(projects[2].path, project3.path);
|
||||
});
|
||||
|
||||
test('test getAllProjectTypes', async () => {
|
||||
test('getAllProjectTypes', async () => {
|
||||
// extensions that are already activated
|
||||
const extension1 = createMockExtension('ext1', true, ['csproj']); // with projects contribution
|
||||
const extension2 = createMockExtension('ext2', true, []); // with empty projects contribution
|
||||
@@ -219,7 +178,7 @@ suite('WorkspaceService Tests', function (): void {
|
||||
should.strictEqual(consoleErrorStub.calledOnce, true, 'Logger.error should be called once');
|
||||
});
|
||||
|
||||
test('test getProjectProvider', async () => {
|
||||
test('getProjectProvider', async () => {
|
||||
const extension1 = createMockExtension('ext1', true, ['csproj']);
|
||||
const extension2 = createMockExtension('ext2', false, ['sqlproj']);
|
||||
const extension3 = createMockExtension('ext3', false, ['dbproj']);
|
||||
@@ -297,147 +256,64 @@ suite('WorkspaceService Tests', function (): void {
|
||||
should.strictEqual(extension3.activationStub.notCalled, true, 'the ext3.activate() should not have been called for csproj');
|
||||
});
|
||||
|
||||
test('test addProjectsToWorkspace', async () => {
|
||||
const processPath = (original: string): string => {
|
||||
return original.replace(/\//g, path.sep);
|
||||
};
|
||||
stubWorkspaceFile(DefaultWorkspaceFilePath);
|
||||
const updateConfigurationStub = sinon.stub();
|
||||
const getConfigurationStub = sinon.stub().returns([processPath('folder1/proj2.sqlproj')]);
|
||||
test('addProjectsToWorkspace', async () => {
|
||||
sinon.stub(service, 'getProjectsInWorkspace').resolves([vscode.Uri.file('folder/folder1/proj2.sqlproj')]);
|
||||
const onWorkspaceProjectsChangedStub = sinon.stub();
|
||||
const showInformationMessageStub = sinon.stub(vscode.window, 'showInformationMessage');
|
||||
const onWorkspaceProjectsChangedDisposable = service.onDidWorkspaceProjectsChange(() => {
|
||||
onWorkspaceProjectsChangedStub();
|
||||
});
|
||||
stubGetConfigurationValue(getConfigurationStub, updateConfigurationStub);
|
||||
const asRelativeStub = sinon.stub(vscode.workspace, 'asRelativePath');
|
||||
sinon.stub(vscode.workspace, 'workspaceFolders').value(['.']);
|
||||
asRelativeStub.onFirstCall().returns(`proj1.sqlproj`);
|
||||
asRelativeStub.onSecondCall().returns(processPath('/test/other/proj3.sqlproj'));
|
||||
asRelativeStub.onSecondCall().returns('other/proj3.sqlproj');
|
||||
const updateWorkspaceFoldersStub = sinon.stub(vscode.workspace, 'updateWorkspaceFolders');
|
||||
await service.addProjectsToWorkspace([
|
||||
vscode.Uri.file('/test/folder/proj1.sqlproj'), // within the workspace folder
|
||||
vscode.Uri.file('/test/folder/folder1/proj2.sqlproj'), //already exists
|
||||
vscode.Uri.file('/test/other/proj3.sqlproj') // outside of workspace folder
|
||||
vscode.Uri.file('folder/proj1.sqlproj'), // within the workspace folder
|
||||
vscode.Uri.file('folder/folder1/proj2.sqlproj'), //already exists
|
||||
vscode.Uri.file('other/proj3.sqlproj') // new workspace folder
|
||||
]);
|
||||
should.strictEqual(updateConfigurationStub.calledOnce, true, 'update configuration should have been called once');
|
||||
should.strictEqual(updateWorkspaceFoldersStub.calledOnce, true, 'updateWorkspaceFolders should have been called once');
|
||||
should.strictEqual(showInformationMessageStub.calledOnce, true, 'showInformationMessage should be called once');
|
||||
should(showInformationMessageStub.calledWith(constants.ProjectAlreadyOpened(processPath('/test/folder/folder1/proj2.sqlproj')))).be.true(`showInformationMessage not called with expected message '${constants.ProjectAlreadyOpened(processPath('/test/folder/folder1/proj2.sqlproj'))}' Actual '${showInformationMessageStub.getCall(0).args[0]}'`);
|
||||
should.strictEqual(updateConfigurationStub.calledWith('projects', sinon.match.array.deepEquals([
|
||||
processPath('folder1/proj2.sqlproj'),
|
||||
processPath('proj1.sqlproj'),
|
||||
processPath('../other/proj3.sqlproj')
|
||||
]), vscode.ConfigurationTarget.Workspace), true, 'updateConfiguration parameters does not match expectation');
|
||||
should.strictEqual(updateWorkspaceFoldersStub.calledWith(1, null, sinon.match((arg) => {
|
||||
return arg.uri.path === '/test/other';
|
||||
const expectedProjPath = vscode.Uri.file('folder/folder1/proj2.sqlproj').fsPath;
|
||||
should(showInformationMessageStub.calledWith(constants.ProjectAlreadyOpened(expectedProjPath))).be.true(`showInformationMessage not called with expected message '${constants.ProjectAlreadyOpened(expectedProjPath)}' Actual '${showInformationMessageStub.getCall(0).args[0]}'`);
|
||||
should.strictEqual(updateWorkspaceFoldersStub.calledWith(1, undefined, sinon.match((arg) => {
|
||||
return arg.uri.path === vscode.Uri.file('other').path;
|
||||
})), true, 'updateWorkspaceFolder parameters does not match expectation');
|
||||
should.strictEqual(onWorkspaceProjectsChangedStub.calledOnce, true, 'the onDidWorkspaceProjectsChange event should have been fired');
|
||||
onWorkspaceProjectsChangedDisposable.dispose();
|
||||
});
|
||||
|
||||
test('test addProjectsToWorkspace when no workspace open', async () => {
|
||||
stubWorkspaceFile(undefined);
|
||||
test('addProjectsToWorkspace when no workspace open', async () => {
|
||||
const onWorkspaceProjectsChangedStub = sinon.stub();
|
||||
const onWorkspaceProjectsChangedDisposable = service.onDidWorkspaceProjectsChange(() => {
|
||||
onWorkspaceProjectsChangedStub();
|
||||
});
|
||||
const createWorkspaceStub = sinon.stub(azdata.workspace, 'createAndEnterWorkspace').resolves(undefined);
|
||||
const updateWorkspaceFoldersStub = sinon.stub(vscode.workspace, 'updateWorkspaceFolders').returns(true);
|
||||
|
||||
await service.addProjectsToWorkspace([
|
||||
vscode.Uri.file('/test/folder/proj1.sqlproj')
|
||||
]);
|
||||
|
||||
should.strictEqual(createWorkspaceStub.calledOnce, true, 'createAndEnterWorkspace should have been called once');
|
||||
should.strictEqual(onWorkspaceProjectsChangedStub.notCalled, true, 'the onDidWorkspaceProjectsChange event should not have been fired');
|
||||
should.strictEqual(onWorkspaceProjectsChangedStub.calledOnce, true, 'the onDidWorkspaceProjectsChange event should have been fired');
|
||||
should.strictEqual(updateWorkspaceFoldersStub.calledOnce, true, 'updateWorkspaceFolders should have been called');
|
||||
onWorkspaceProjectsChangedDisposable.dispose();
|
||||
});
|
||||
|
||||
test('test addProjectsToWorkspace when untitled workspace is open', async () => {
|
||||
stubWorkspaceFile(undefined);
|
||||
test('addProjectsToWorkspace when untitled workspace is open', async () => {
|
||||
sinon.stub(service, 'getProjectsInWorkspace').resolves([]);
|
||||
const onWorkspaceProjectsChangedStub = sinon.stub();
|
||||
const onWorkspaceProjectsChangedDisposable = service.onDidWorkspaceProjectsChange(() => {
|
||||
onWorkspaceProjectsChangedStub();
|
||||
});
|
||||
const saveWorkspaceStub = sinon.stub(azdata.workspace, 'saveAndEnterWorkspace').resolves(undefined);
|
||||
sinon.stub(utils, 'isCurrentWorkspaceUntitled').returns(true);
|
||||
sinon.stub(vscode.workspace, 'workspaceFolders').value(['folder1']);
|
||||
|
||||
sinon.replaceGetter(vscode.workspace, 'workspaceFolders', () => [{ uri: vscode.Uri.file('folder1'), name: '', index: 0}]);
|
||||
const updateWorkspaceFoldersStub = sinon.stub(vscode.workspace, 'updateWorkspaceFolders').returns(true);
|
||||
await service.addProjectsToWorkspace([
|
||||
vscode.Uri.file('/test/folder/proj1.sqlproj')
|
||||
]);
|
||||
|
||||
should.strictEqual(saveWorkspaceStub.calledOnce, true, 'saveAndEnterWorkspace should have been called once');
|
||||
should.strictEqual(onWorkspaceProjectsChangedStub.notCalled, true, 'the onDidWorkspaceProjectsChange event should not have been fired');
|
||||
onWorkspaceProjectsChangedDisposable.dispose();
|
||||
});
|
||||
|
||||
test('test loadTempProjects', async () => {
|
||||
const processPath = (original: string): string => {
|
||||
return original.replace(/\//g, path.sep);
|
||||
};
|
||||
stubWorkspaceFile('/test/folder/proj1.code-workspace');
|
||||
const updateConfigurationStub = sinon.stub();
|
||||
const getConfigurationStub = sinon.stub().returns([processPath('folder1/proj2.sqlproj')]);
|
||||
const onWorkspaceProjectsChangedStub = sinon.stub();
|
||||
const onWorkspaceProjectsChangedDisposable = service.onDidWorkspaceProjectsChange(() => {
|
||||
onWorkspaceProjectsChangedStub();
|
||||
});
|
||||
stubGetConfigurationValue(getConfigurationStub, updateConfigurationStub);
|
||||
sinon.stub(azdata.workspace, 'createAndEnterWorkspace').resolves(undefined);
|
||||
sinon.stub(vscode.workspace, 'workspaceFolders').value(['folder1']);
|
||||
mockGlobalState.setup(x => x.get(TypeMoq.It.isAny())).returns(() => [processPath('folder1/proj2.sqlproj')]);
|
||||
|
||||
await service.loadTempProjects();
|
||||
|
||||
should.strictEqual(onWorkspaceProjectsChangedStub.calledOnce, true, 'the onDidWorkspaceProjectsChange event should have been fired');
|
||||
should.strictEqual(updateWorkspaceFoldersStub.calledOnce, true, 'updateWorkspaceFolders should have been called');
|
||||
onWorkspaceProjectsChangedDisposable.dispose();
|
||||
});
|
||||
|
||||
test('test removeProject', async () => {
|
||||
const processPath = (original: string): string => {
|
||||
return original.replace(/\//g, path.sep);
|
||||
};
|
||||
stubWorkspaceFile(DefaultWorkspaceFilePath);
|
||||
const updateConfigurationStub = sinon.stub();
|
||||
const getConfigurationStub = sinon.stub().returns([processPath('folder1/proj2.sqlproj'), processPath('folder2/proj3.sqlproj')]);
|
||||
const onWorkspaceProjectsChangedStub = sinon.stub();
|
||||
const onWorkspaceProjectsChangedDisposable = service.onDidWorkspaceProjectsChange(() => {
|
||||
onWorkspaceProjectsChangedStub();
|
||||
});
|
||||
stubGetConfigurationValue(getConfigurationStub, updateConfigurationStub);
|
||||
await service.removeProject(vscode.Uri.file('/test/folder/folder1/proj2.sqlproj'));
|
||||
should.strictEqual(updateConfigurationStub.calledWith('projects', sinon.match.array.deepEquals([
|
||||
processPath('folder2/proj3.sqlproj')
|
||||
]), vscode.ConfigurationTarget.Workspace), true, 'updateConfiguration parameters does not match expectation for remove project');
|
||||
should.strictEqual(onWorkspaceProjectsChangedStub.calledOnce, true, 'the onDidWorkspaceProjectsChange event should have been fired');
|
||||
onWorkspaceProjectsChangedDisposable.dispose();
|
||||
});
|
||||
|
||||
test('test checkForProjectsNotAddedToWorkspace', async () => {
|
||||
const previousSetting = await vscode.workspace.getConfiguration(constants.projectsConfigurationKey)[constants.showNotAddedProjectsMessageKey];
|
||||
await vscode.workspace.getConfiguration(constants.projectsConfigurationKey).update(constants.showNotAddedProjectsMessageKey, true, true);
|
||||
|
||||
sinon.stub(service, 'getProjectsInWorkspace').returns([vscode.Uri.file('abc.sqlproj'), vscode.Uri.file('folder1/abc1.sqlproj')]);
|
||||
sinon.stub(vscode.workspace, 'workspaceFolders').value([{ uri: vscode.Uri.file('.') }]);
|
||||
sinon.stub(service, 'getAllProjectTypes').resolves([{
|
||||
projectFileExtension: 'sqlproj',
|
||||
id: 'sql project',
|
||||
displayName: 'sql project',
|
||||
description: '',
|
||||
icon: ''
|
||||
}]);
|
||||
const infoMessageStub = sinon.stub(vscode.window, 'showInformationMessage').resolves(<any>constants.DoNotAskAgain);
|
||||
const getProjectsInwWorkspaceFolderStub = sinon.stub(service, 'getAllProjectsInFolder').resolves([vscode.Uri.file('abc.sqlproj').fsPath, vscode.Uri.file('folder1/abc1.sqlproj').fsPath]);
|
||||
|
||||
await service.checkForProjectsNotAddedToWorkspace();
|
||||
should(infoMessageStub.notCalled).be.true('Should not have found projects not added to workspace');
|
||||
|
||||
// add a project to the workspace folder not added to the workspace yet
|
||||
getProjectsInwWorkspaceFolderStub.resolves([vscode.Uri.file('abc.sqlproj').fsPath, vscode.Uri.file('folder1/abc1.sqlproj').fsPath, vscode.Uri.file('folder2/abc2.sqlproj').fsPath]);
|
||||
await service.checkForProjectsNotAddedToWorkspace();
|
||||
should(infoMessageStub.calledOnce).be.true('Should have found a project that was not added to the workspace');
|
||||
|
||||
await vscode.workspace.getConfiguration(constants.projectsConfigurationKey).update(constants.showNotAddedProjectsMessageKey, previousSetting, true);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -7,23 +7,13 @@ import { IDashboardTable, IProjectProvider, WorkspaceTreeItem } from 'dataworksp
|
||||
import 'mocha';
|
||||
import * as should from 'should';
|
||||
import * as sinon from 'sinon';
|
||||
import * as TypeMoq from 'typemoq';
|
||||
import * as vscode from 'vscode';
|
||||
import { WorkspaceTreeDataProvider } from '../common/workspaceTreeDataProvider';
|
||||
import { WorkspaceService } from '../services/workspaceService';
|
||||
import { MockTreeDataProvider } from './projectProviderRegistry.test';
|
||||
|
||||
interface ExtensionGlobalMemento extends vscode.Memento {
|
||||
setKeysForSync(keys: string[]): void;
|
||||
}
|
||||
|
||||
suite('workspaceTreeDataProvider Tests', function (): void {
|
||||
const mockExtensionContext = TypeMoq.Mock.ofType<vscode.ExtensionContext>();
|
||||
const mockGlobalState = TypeMoq.Mock.ofType<ExtensionGlobalMemento>();
|
||||
mockGlobalState.setup(x => x.update(TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => Promise.resolve());
|
||||
mockExtensionContext.setup(x => x.globalState).returns(() => mockGlobalState.object);
|
||||
|
||||
const workspaceService = new WorkspaceService(mockExtensionContext.object);
|
||||
const workspaceService = new WorkspaceService();
|
||||
const treeProvider = new WorkspaceTreeDataProvider(workspaceService);
|
||||
|
||||
this.afterEach(() => {
|
||||
@@ -63,7 +53,7 @@ suite('workspaceTreeDataProvider Tests', function (): void {
|
||||
};
|
||||
const children = await treeProvider.getChildren(element);
|
||||
should.strictEqual(children.length, 0, 'children count should be 0');
|
||||
should.strictEqual(getChildrenStub.calledWithExactly('obj1'), true, 'getChildren parameter should be obj1')
|
||||
should.strictEqual(getChildrenStub.calledWithExactly('obj1'), true, 'getChildren parameter should be obj1');
|
||||
});
|
||||
|
||||
test('test getChildren() for root element', async () => {
|
||||
@@ -82,9 +72,6 @@ suite('workspaceTreeDataProvider Tests', function (): void {
|
||||
displayName: 'sql project',
|
||||
description: ''
|
||||
}],
|
||||
RemoveProject: (projectFile: vscode.Uri): Promise<void> => {
|
||||
return Promise.resolve();
|
||||
},
|
||||
getProjectTreeDataProvider: (projectFile: vscode.Uri): Promise<vscode.TreeDataProvider<any>> => {
|
||||
return Promise.resolve(treeDataProvider);
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user