Skip to content

Commit

Permalink
Fix new result pane column behavior (#582)
Browse files Browse the repository at this point in the history
* adding wrapper functions

* added configuration option for splitPaneSelection

* changed to switch statement

* moved helper functions into sqloutputcontentprovider

* adding test and uncommenting out some of the sqloutputtests

* small test fix

* cleaning up output test file

* updated to enum

* addressing issues

* fixed test verbage
  • Loading branch information
Raymondd authored Jan 7, 2017
1 parent ccc7eb2 commit 597fe49
Show file tree
Hide file tree
Showing 6 changed files with 238 additions and 112 deletions.
11 changes: 10 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -441,8 +441,17 @@
"type": "boolean",
"description": "[Optional] Configuration options for copying multi-line results from the Results View",
"default": true
},
"mssql.splitPaneSelection": {
"type": "string",
"description": "[Optional] Configuration options for which column new result panes should open in",
"default": "next",
"enum": [
"next",
"current",
"end"
]
}

}
}
},
Expand Down
58 changes: 52 additions & 6 deletions src/models/SqlOutputContentProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -313,16 +313,15 @@ export class SqlOutputContentProvider implements vscode.TextDocumentContentProvi
let paneTitle = Utils.formatString(Constants.titleResultsPane, queryRunner.title);
// Always run this command even if just updating to avoid a bug - tfs 8686842

// Find any URIs which match the one we are about to display
let resultPaneURIMatch = vscode.workspace.textDocuments.find(tDoc => tDoc.uri.toString() === resultsUri);

// Check if the results window already exists
if (resultPaneURIMatch !== undefined) {
// Implicity Use existsing results window by not providing an pane
if (this.doesResultPaneExist(resultsUri)) {
// Implicity Use existing results window by not providing a pane
vscode.commands.executeCommand('vscode.previewHtml', resultsUri, paneTitle);
} else {
// A fresh results window should always start in the second pane
vscode.commands.executeCommand('vscode.previewHtml', resultsUri, vscode.ViewColumn.Two, paneTitle);
// Wrapper tells us where the new results pane should be placed
let viewColumn = this.newResultPaneViewColumn();
vscode.commands.executeCommand('vscode.previewHtml', resultsUri, viewColumn, paneTitle);
}
}

Expand Down Expand Up @@ -535,4 +534,51 @@ export class SqlOutputContentProvider implements vscode.TextDocumentContentProvi
}
return path.join(os.tmpdir(), columnName + '_' + String(Math.floor( Date.now() / 1000)) + String(process.pid) + '.' + linkType);
}

/**
* Returns whether or not a result pane with the same URI exists
* @param The string value of a Uri.
* @return boolean true if pane exists
* public for testing purposes
*/
public doesResultPaneExist(resultsUri: string): boolean {
let resultPaneURIMatch = this._vscodeWrapper.textDocuments.find(tDoc => tDoc.uri.toString() === resultsUri);
return (resultPaneURIMatch !== undefined);
}

/**
* Returns which column should be used for a new result pane
* @return ViewColumn to be used
* public for testing purposes
*/
public newResultPaneViewColumn(): vscode.ViewColumn {
// Find configuration options
let config = this._vscodeWrapper.getConfiguration(Constants.extensionConfigSectionName);
let splitPaneSelection = config[Constants.configSplitPaneSelection];
let viewColumn: vscode.ViewColumn;


switch (splitPaneSelection) {
case 'current' :
viewColumn = this._vscodeWrapper.activeTextEditor.viewColumn;
break;
case 'end' :
viewColumn = vscode.ViewColumn.Three;
break;
// default case where splitPaneSelection is next or anything else
default :
if (this._vscodeWrapper.activeTextEditor.viewColumn === vscode.ViewColumn.One) {
viewColumn = vscode.ViewColumn.Two;
} else {
viewColumn = vscode.ViewColumn.Three;
};
}

return viewColumn;
}

// Exposing the wrapper for testing purposes
public setVscodeWrapper(wrapper: VscodeWrapper): void {
this._vscodeWrapper = wrapper;
}
}
1 change: 1 addition & 0 deletions src/models/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ export const configSaveAsJson = 'saveAsJson';
export const configRecentConnections = 'recentConnections';
export const configMaxRecentConnections = 'maxRecentConnections';
export const configCopyRemoveNewLine = 'copyRemoveNewLine';
export const configSplitPaneSelection = 'splitPaneSelection';


// localizable strings
Expand Down
3 changes: 1 addition & 2 deletions test/resources/results.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@
"B": "APPLE",
"ROWID": "77CB1B42-4AD7-408E-8881-C7E8E33E7295"
}
],
"executionPlanXml": ""
]
}
]
260 changes: 158 additions & 102 deletions test/sqlOutputContentProvider.test.ts
Original file line number Diff line number Diff line change
@@ -1,105 +1,161 @@
// The module 'assert' provides assertion methods from node
// import assert = require('assert');
// import * as vscode from 'vscode';
'use strict';

// You can import and use all API from the 'vscode' module
// as well as import your extension to test it
// import { SqlOutputContentProvider } from '../src/models/sqlOutputContentProvider';
// import LocalWebService from '../src/controllers/localWebService';
// import Interfaces = require('../src/models/interfaces');
// import Constants = require('../src/models/constants');
// let results = require('./resources/results.json');
// let messages = require('./resources/messages.json');
// let metadata = [
// {
// "columnsUri":"/" + Constants.outputContentTypeColumns+ "?id=0",
// "rowsUri":"/" + Constants.outputContentTypeRows + "?id=0"
// }
// ]

// let fs = require('fs');
// let request = require('request');

// class TextContext implements vscode.ExtensionContext {
// subscriptions: { dispose(): any }[];
// workspaceState: vscode.Memento;
// globalState: vscode.Memento;
// extensionPath: string;
// asAbsolutePath(relativePath: string): string {
// return '';
// }

// constructor(path: string) {
// this.extensionPath = path;
// }
// }


// suite('SqlOutputProvider Tests', () => {

// let contentProvider: SqlOutputContentProvider;
// let path: string;
// let port: string;
// let file = '/out/test/resources/sqlTest.sql';

// function openSQLFile(): Thenable<void> {
// return vscode.workspace.openTextDocument(vscode.Uri.parse('file:' + path + file)).then( document => {
// vscode.window.showTextDocument(document);
// });
// }

// setup(() => {
// path = vscode.extensions.getExtension('microsoft.vscode-mssql').extensionPath;
// contentProvider = new SqlOutputContentProvider(new TextContext(path));
// port = LocalWebService._servicePort;
// return openSQLFile();
// });

// test("Initial Server Responses", () => {
// let uri = contentProvider.updateContent(messages, results);
// let url = 'http://localhost:' + port + '/' + Interfaces.ContentTypes[Interfaces.ContentType.Root] + '?uri=' + uri;
// let htmlbuf = fs.readFileSync(path +'/src/views/htmlcontent/sqlOutput.ejs')
// htmlbuf = htmlbuf.toString();
// htmlbuf = htmlbuf.replace('<%=uri%>', uri);
// return request.get(url, function(err, res, body){
// assert.equal(res.statusCode, 200);
// assert.equal(htmlbuf.toString(), body);
// });
// });

// test("Correctly Delievers MetaData", () => {
// let uri = contentProvider.updateContent(messages, results);
// let url = 'http://localhost:' + port + '/' + Interfaces.ContentTypes[Interfaces.ContentType.ResultsetsMeta] + '?uri=' + uri;
// return request.get(url, function(err, res, body){
// assert.equal(res.statusCode, 200);
// assert.equal(body, JSON.stringify(metadata));
// });
// });

// test("Correctly Delievers Messages", () => {
// let uri = contentProvider.updateContent(messages, results);
// let url = 'http://localhost:' + port + '/' + Interfaces.ContentTypes[Interfaces.ContentType.Messages] + '?uri=' + uri;
// return request.get(url, function(err, res, body){
// assert.equal(res.statusCode, 200);
// assert.equal(body, JSON.stringify(messages));
// });
// });

// test("Correctly Delivers Columns", () => {
// let uri = contentProvider.updateContent(messages, results);
// let url = 'http://localhost:' + port + '/' + Interfaces.ContentTypes[Interfaces.ContentType.Columns] + '?id=0&uri=' + uri;
// return request.get(url, function(err, res, body){
// assert.equal(res.statusCode, 200);
// assert.equal(body, JSON.stringify(results[0].columns));
// });
// });

// test("Correctly Delievers Rows", () => {
// let uri = contentProvider.updateContent(messages, results);
// let url = 'http://localhost:' + port + '/' + Interfaces.ContentTypes[Interfaces.ContentType.Rows] + '?id=0&uri=' + uri;
// return request.get(url,(err, res, body) => {
// assert.equal(res.statusCode, 200);
// assert.equal(body, JSON.stringify(results[0].rows));
// });
// });
// });
import { SqlOutputContentProvider } from '../src/models/SqlOutputContentProvider';
import VscodeWrapper from '../src/controllers/vscodeWrapper';
import StatusView from '../src/views/statusView';
import * as stubs from './stubs';
import Constants = require('../src/models/constants');
import vscode = require('vscode');
import * as TypeMoq from 'typemoq';
import assert = require('assert');

suite('SqlOutputProvider Tests', () => {
let vscodeWrapper: TypeMoq.Mock<VscodeWrapper>;
let contentProvider: SqlOutputContentProvider;
let context: TypeMoq.Mock<vscode.ExtensionContext>;
let statusView: TypeMoq.Mock<StatusView>;

setup(() => {
vscodeWrapper = TypeMoq.Mock.ofType(VscodeWrapper);
context = TypeMoq.Mock.ofType(stubs.TestExtensionContext);
context.object.extensionPath = '';
statusView = TypeMoq.Mock.ofType(StatusView);
contentProvider = new SqlOutputContentProvider(context.object, statusView.object);
contentProvider.setVscodeWrapper(vscodeWrapper.object);

});

test('Correctly outputs the new result pane view column', done => {
function setSplitPaneSelectionConfig(value: string): void {
let configResult: {[key: string]: any} = {};
configResult[Constants.configSplitPaneSelection] = value;
let config = stubs.createWorkspaceConfiguration(configResult);
vscodeWrapper.setup(x => x.getConfiguration(TypeMoq.It.isAny()))
.returns(x => {
return config;
});
}

function setCurrentEditorColumn(column: number): void {
vscodeWrapper.setup(x => x.activeTextEditor)
.returns(x => {
let editor: vscode.TextEditor = new stubs.TestTextEditor();
editor.viewColumn = column;
return editor;
});
}

class Case {
position: number;
config: string;
expectedColumn: number;
}

let cases: Case[] = [
{position: 1, config: 'next', expectedColumn: 2},
{position: 2, config: 'next', expectedColumn: 3},
{position: 3, config: 'next', expectedColumn: 3},
{position: 1, config: 'current', expectedColumn: 1},
{position: 2, config: 'current', expectedColumn: 2},
{position: 3, config: 'current', expectedColumn: 3},
{position: 1, config: 'end', expectedColumn: 3},
{position: 2, config: 'end', expectedColumn: 3},
{position: 3, config: 'end', expectedColumn: 3}
];

try {
cases.forEach((c: Case) => {
setSplitPaneSelectionConfig(c.config);
setCurrentEditorColumn(c.position);

let resultColumn = contentProvider.newResultPaneViewColumn();
assert.equal(resultColumn, c.expectedColumn);
});

done();
} catch (err) {
done(new Error(err));
}
});

});


// TODO: rewrite all the outputprovider handle tests (old ones kept for reference)
// Tracked by issue #584
/*
// Imports used by previous tests
import LocalWebService from '../src/controllers/localWebService';
import Interfaces = require('../src/models/interfaces');
let results = require('./resources/results.json');
let messages = require('./resources/messages.json');
const pd = require('pretty-data').pd;
const fs = require('fs');
let request = require('request');
let metadata = [
{
'columnsUri': '/' + Constants.outputContentTypeColumns + '?id=0',
'rowsUri': '/' + Constants.outputContentTypeRows + '?id=0'
}
]
// Old Decleration area
// let port: string;
// let file = '/out/test/resources/sqlTest.sql';
// let path: string;
// Old Setup Area
// port = LocalWebService._servicePort;
// path = vscode.extensions.getExtension('microsoft.vscode-mssql').extensionPath;
test("Initial Server Responses", () => {
let uri = contentProvider.updateContent(messages, results);
let url = 'http://localhost:' + port + '/' + Interfaces.ContentTypes[Interfaces.ContentType.Root] + '?uri=' + uri;
let htmlbuf = fs.readFileSync(path +'/src/views/htmlcontent/sqlOutput.ejs')
htmlbuf = htmlbuf.toString();
htmlbuf = htmlbuf.replace('<%=uri%>', uri);
return request.get(url, function(err, res, body){
assert.equal(res.statusCode, 200);
assert.equal(htmlbuf.toString(), body);
});
});
test("Correctly Delievers MetaData", () => {
let uri = contentProvider.updateContent(messages, results);
let url = 'http://localhost:' + port + '/' + Interfaces.ContentTypes[Interfaces.ContentType.ResultsetsMeta] + '?uri=' + uri;
return request.get(url, function(err, res, body){
assert.equal(res.statusCode, 200);
assert.equal(body, JSON.stringify(metadata));
});
});
test("Correctly Delievers Messages", () => {
let uri = contentProvider.updateContent(messages, results);
let url = 'http://localhost:' + port + '/' + Interfaces.ContentTypes[Interfaces.ContentType.Messages] + '?uri=' + uri;
return request.get(url, function(err, res, body){
assert.equal(res.statusCode, 200);
assert.equal(body, JSON.stringify(messages));
});
});
test("Correctly Delivers Columns", () => {
let uri = contentProvider.updateContent(messages, results);
let url = 'http://localhost:' + port + '/' + Interfaces.ContentTypes[Interfaces.ContentType.Columns] + '?id=0&uri=' + uri;
return request.get(url, function(err, res, body){
assert.equal(res.statusCode, 200);
assert.equal(body, JSON.stringify(results[0].columns));
});
});
test("Correctly Delievers Rows", () => {
let uri = contentProvider.updateContent(messages, results);
let url = 'http://localhost:' + port + '/' + Interfaces.ContentTypes[Interfaces.ContentType.Rows] + '?id=0&uri=' + uri;
return request.get(url,(err, res, body) => {
assert.equal(res.statusCode, 200);
assert.equal(body, JSON.stringify(results[0].rows));
});
});
*/
Loading

0 comments on commit 597fe49

Please sign in to comment.