Add more SsmsMin interactions (#5267)

* Add support for more SsmsMin property dialogs and the Generate Script Wizard. Also fixed bug with ExtHostObjectExplorerNode getParent function

* Localize package.json entries

* Fix localization tokens

* Address PR comments

* Fix regex and getParent
This commit is contained in:
Charles Gagnon
2019-04-30 16:10:11 -07:00
committed by GitHub
parent 64416e05c1
commit 97cab22e00
8 changed files with 511 additions and 100 deletions

View File

@@ -0,0 +1,68 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as azdata from 'azdata';
import * as vscode from 'vscode';
/**
* Helper stub class for mocking ExtHostObjectExplorerNode
*/
export class ExtHostObjectExplorerNodeStub implements azdata.objectexplorer.ObjectExplorerNode {
// Stub properties
private parent: azdata.objectexplorer.ObjectExplorerNode;
// Base properties
public connectionId: string;
public nodePath: string;
public nodeType: string;
public nodeSubType: string;
public nodeStatus: string;
public label: string;
public isLeaf: boolean;
public metadata: azdata.ObjectMetadata;
public errorMessage: string;
constructor(nodeName: string, nodeSchema: string, nodeType, parent: azdata.objectexplorer.ObjectExplorerNode) {
this.parent = parent;
this.nodeType = nodeType;
this.metadata = { metadataType: undefined, metadataTypeName: undefined, name: nodeName, schema: nodeSchema, urn: undefined };
}
isExpanded(): Thenable<boolean> {
throw new Error('Method not implemented');
}
setExpandedState(expandedState: vscode.TreeItemCollapsibleState): Thenable<void> {
throw new Error('Method not implemented');
}
setSelected(selected: boolean, clearOtherSelections: boolean = undefined): Thenable<void> {
throw new Error('Method not implemented');
}
getChildren(): Thenable<azdata.objectexplorer.ObjectExplorerNode[]> {
throw new Error('Method not implemented');
}
getParent(): Thenable<azdata.objectexplorer.ObjectExplorerNode> {
return Promise.resolve(this.parent);
}
refresh(): Thenable<void> {
throw new Error('Method not implemented');
}
/**
*
* @param nodeName Helperfunction to create a node that is a child of this one
* @param nodeSchema The schema to give the child node
* @param nodeType The type of node this should be
*/
createChild(nodeName: string, nodeSchema: string, nodeType: string): ExtHostObjectExplorerNodeStub {
return new ExtHostObjectExplorerNodeStub(nodeName, nodeSchema, nodeType, this);
}
}

View File

@@ -8,11 +8,13 @@
import * as should from 'should';
import 'mocha';
import * as extensionMain from '../main';
import { buildSsmsMinCommandArgs, buildUrn, LaunchSsmsDialogParams } from '../main';
import { doubleEscapeSingleQuotes, backEscapeDoubleQuotes } from '../utils';
import { ExtHostObjectExplorerNodeStub } from './stubs';
describe('buildSsmsMinCommandArgs Method Tests', () => {
it('Should be built correctly with all params and UseAAD as false', function (): void {
let params: extensionMain.LaunchSsmsDialogParams = {
const params: LaunchSsmsDialogParams = {
action: 'myAction',
server: 'myServer',
database: 'myDatabase',
@@ -21,12 +23,12 @@ describe('buildSsmsMinCommandArgs Method Tests', () => {
useAad: false,
urn: 'Server\\Database\\Table'
};
let args = extensionMain.buildSsmsMinCommandArgs(params);
const args = buildSsmsMinCommandArgs(params);
should(args).equal('-a "myAction" -S "myServer" -D "myDatabase" -U "user" -u "Server\\Database\\Table"');
});
it('Should be built correctly with all params and UseAAD as true', function (): void {
let params: extensionMain.LaunchSsmsDialogParams = {
const params: LaunchSsmsDialogParams = {
action: 'myAction',
server: 'myServer',
database: 'myDatabase',
@@ -35,13 +37,13 @@ describe('buildSsmsMinCommandArgs Method Tests', () => {
useAad: true,
urn: 'Server\\Database\\Table'
};
let args = extensionMain.buildSsmsMinCommandArgs(params);
const args = buildSsmsMinCommandArgs(params);
// User is omitted since UseAAD is true
should(args).equal('-a "myAction" -S "myServer" -D "myDatabase" -G -u "Server\\Database\\Table"');
});
it('Should be built correctly and names escaped correctly', function (): void {
let params: extensionMain.LaunchSsmsDialogParams = {
const params: LaunchSsmsDialogParams = {
action: 'myAction\'"/\\[]tricky',
server: 'myServer\'"/\\[]tricky',
database: 'myDatabase\'"/\\[]tricky',
@@ -50,18 +52,87 @@ describe('buildSsmsMinCommandArgs Method Tests', () => {
useAad: true,
urn: 'Server\\Database[\'myDatabase\'\'"/\\[]tricky\']\\Table["myTable\'""/\\[]tricky"]'
};
let args = extensionMain.buildSsmsMinCommandArgs(params);
const args = buildSsmsMinCommandArgs(params);
// User is omitted since UseAAD is true
should(args).equal('-a "myAction\'\\"/\\[]tricky" -S "myServer\'\\"/\\[]tricky" -D "myDatabase\'\\"/\\[]tricky" -G -u "Server\\Database[\'myDatabase\'\'\\"/\\[]tricky\']\\Table[\\"myTable\'\\"\\"/\\[]tricky\\"]"');
});
it('Should be built correctly with only action and server', function (): void {
let params: extensionMain.LaunchSsmsDialogParams = {
const params: LaunchSsmsDialogParams = {
action: 'myAction',
server: 'myServer'
};
let args = extensionMain.buildSsmsMinCommandArgs(params);
const args = buildSsmsMinCommandArgs(params);
should(args).equal('-a "myAction" -S "myServer"');
});
});
const serverName = 'My\'Server';
const escapedServerName = doubleEscapeSingleQuotes(serverName);
const dbName = 'My\'Db';
const escapedDbName = doubleEscapeSingleQuotes(dbName);
const dbSchema = 'db\'sch';
const escapedDbSchema = doubleEscapeSingleQuotes(dbSchema);
const tableName = 'My\'Table';
const escapedTableName = doubleEscapeSingleQuotes(tableName);
const tableSchema = 'tbl\'sch';
const escapedTableSchema = doubleEscapeSingleQuotes(tableSchema);
describe('buildUrn Method Tests', () => {
it('Urn should be correct with just server', async function (): Promise<void> {
should(await buildUrn(serverName, undefined)).equal(`Server[@Name=\'${escapedServerName}\']`);
});
it('Urn should be correct with Server and only Databases folder', async function (): Promise<void> {
const leafNode: ExtHostObjectExplorerNodeStub =
new ExtHostObjectExplorerNodeStub('Databases', undefined, 'Folder', undefined);
should(await buildUrn(serverName, leafNode)).equal(`Server[@Name='${escapedServerName}']`);
});
it('Urn should be correct with Server and Database node', async function (): Promise<void> {
const leafNode: ExtHostObjectExplorerNodeStub =
new ExtHostObjectExplorerNodeStub('Databases', undefined, 'Folder', undefined)
.createChild(dbName, dbSchema, 'Database');
should(await buildUrn(serverName, leafNode)).equal(
`Server[@Name='${escapedServerName}']/Database[@Name='${escapedDbName}' and @Schema='${escapedDbSchema}']`);
});
it('Urn should be correct with Multiple levels of Nodes', async function (): Promise<void> {
const rootNode: ExtHostObjectExplorerNodeStub =
new ExtHostObjectExplorerNodeStub('Databases', undefined, 'Folder', undefined)
.createChild(dbName, dbSchema, 'Database')
.createChild('Tables', undefined, 'Folder')
.createChild(tableName, tableSchema, 'Table');
should(await buildUrn(serverName, rootNode)).equal(
`Server[@Name='${escapedServerName}']/Database[@Name='${escapedDbName}' and @Schema='${escapedDbSchema}']/Table[@Name='${escapedTableName}' and @Schema='${escapedTableSchema}']`);
});
});
describe('doubleEscapeSingleQuotes Method Tests', () => {
it('Should return original string if no single quotes', function (): void {
const testString: string = 'MyTestString';
const ret = doubleEscapeSingleQuotes(testString);
should(ret).equal(testString);
});
it('Should return escaped original string if it contains single quotes', function (): void {
const testString: string = 'MyTestString\'\'WithQuotes';
const ret = doubleEscapeSingleQuotes(testString);
should(ret).equal('MyTestString\'\'\'\'WithQuotes');
});
});
describe('backEscapeDoubleQuotes Method Tests', () => {
it('Should return original string if no double quotes', function (): void {
const testString: string = 'MyTestString';
const ret = backEscapeDoubleQuotes(testString);
should(ret).equal(testString);
});
it('Should return escaped original string if it contains double quotes', function (): void {
const testString: string = 'MyTestString\"\"WithQuotes';
const ret = backEscapeDoubleQuotes(testString);
should(ret).equal('MyTestString\\"\\"WithQuotes');
});
});