From 4ec2147af5870e2a22f8b8c62ef3484faa5b4c70 Mon Sep 17 00:00:00 2001 From: Josh Wong Date: Mon, 2 Jan 2017 22:55:03 +1100 Subject: [PATCH] Add additional tests and refactored query function --- .vscode/launch.json | 2 +- src/jmespathMain.ts | 3 +- src/jmespathQuery.ts | 19 ++--- test/data/empty.json | 0 test/data/locations.json | 8 ++ test/jmespathQuery.test.ts | 146 +++++++++++++++++++++++++++++++++++++ 6 files changed, 167 insertions(+), 11 deletions(-) create mode 100644 test/data/empty.json create mode 100644 test/data/locations.json create mode 100644 test/jmespathQuery.test.ts diff --git a/.vscode/launch.json b/.vscode/launch.json index c696e43..187f75d 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -20,7 +20,7 @@ "type": "extensionHost", "request": "launch", "runtimeExecutable": "${execPath}", - "args": ["--extensionDevelopmentPath=${workspaceRoot}", "--extensionTestsPath=${workspaceRoot}/out/test" ], + "args": ["--extensionDevelopmentPath=${workspaceRoot}", "--extensionTestsPath=${workspaceRoot}/out/test", "--new-window" ], "stopOnEntry": false, "sourceMaps": true, "outFiles": [ diff --git a/src/jmespathMain.ts b/src/jmespathMain.ts index d5705a6..6b75603 100644 --- a/src/jmespathMain.ts +++ b/src/jmespathMain.ts @@ -7,7 +7,8 @@ export function activate(context: vscode.ExtensionContext) { context.subscriptions.push( vscode.commands.registerTextEditorCommand("jmespath.query", (textEditor: vscode.TextEditor, edit: vscode.TextEditorEdit) => { - queryJson(context); + let outputChannel = vscode.window.createOutputChannel("JMESPath Output"); + queryJson(context, outputChannel); } ) ); diff --git a/src/jmespathQuery.ts b/src/jmespathQuery.ts index 5fe3a8b..84e6e52 100644 --- a/src/jmespathQuery.ts +++ b/src/jmespathQuery.ts @@ -1,14 +1,14 @@ +"use strict"; + import * as vscode from "vscode"; let jmespath = require("jmespath"); -let outputChannel = vscode.window.createOutputChannel("JMESPath Output"); - -export function queryJson(context: vscode.ExtensionContext) { +export function queryJson(context: vscode.ExtensionContext, outputChannel: vscode.OutputChannel): PromiseLike { let editor = vscode.window.activeTextEditor; if (editor.document.languageId !== "json") { vscode.window.showInformationMessage("Please open a JSON document."); - return; + return Promise.resolve(); } let options: vscode.InputBoxOptions = { @@ -16,9 +16,10 @@ export function queryJson(context: vscode.ExtensionContext) { placeHolder: "JMESPath expression" }; - vscode.window.showInputBox(options).then((expression) => { - if (expression.trim().length === 0) { - return; + return vscode.window.showInputBox(options).then((expression) => { + if (expression === undefined || expression.trim().length === 0) { + vscode.window.showInformationMessage("Please enter a valid JMESPath expression."); + return Promise.resolve(); } try { @@ -26,7 +27,7 @@ export function queryJson(context: vscode.ExtensionContext) { } catch (e) { vscode.window.showErrorMessage(`${e.message}`); - return; + return Promise.resolve(); } let data = vscode.window.activeTextEditor.document.getText(); @@ -39,7 +40,7 @@ export function queryJson(context: vscode.ExtensionContext) { outputChannel.show(); } catch (e) { vscode.window.showErrorMessage(`${e.message}`); - return; + return Promise.resolve(); } }); } diff --git a/test/data/empty.json b/test/data/empty.json new file mode 100644 index 0000000..e69de29 diff --git a/test/data/locations.json b/test/data/locations.json new file mode 100644 index 0000000..227a78a --- /dev/null +++ b/test/data/locations.json @@ -0,0 +1,8 @@ +{ + "locations": [ + {"name": "Seattle", "state": "WA"}, + {"name": "New York", "state": "NY"}, + {"name": "Bellevue", "state": "WA"}, + {"name": "Olympia", "state": "WA"} + ] +} diff --git a/test/jmespathQuery.test.ts b/test/jmespathQuery.test.ts new file mode 100644 index 0000000..8560503 --- /dev/null +++ b/test/jmespathQuery.test.ts @@ -0,0 +1,146 @@ +"use strict"; + +import * as vscode from "vscode"; +import * as path from "path"; +import * as jmespathQuery from "../src/jmespathQuery"; +import * as assert from "assert"; +import * as sinon from "sinon"; +import chai = require("chai"); + +let expect = chai.expect; +let jmespath = require("jmespath"); + +let testDataPath = path.join(__dirname, "..", "..", "test", "data"); +let testJsonFile = path.join(testDataPath, "locations.json"); +let emptyJsonFile = path.join(testDataPath, "empty.json"); + +describe("jmespathQuery", () => { + + describe("#queryJson()", () => { + let context: vscode.ExtensionContext; + let sandbox: sinon.SinonSandbox; + let showInputBox: sinon.SinonStub; + let showInformationMessage: sinon.SinonStub; + let showErrorMessage: sinon.SinonStub; + let jmespathCompile: sinon.SinonStub; + + let createOutputChannel: sinon.SinonStub; + let outputChannel: vscode.OutputChannel, outputBuffer; + + beforeEach(() => { + context = { + subscriptions: [], + workspaceState: null, + globalState: null, + extensionPath: null, + asAbsolutePath: sinon.stub() + }; + + sandbox = sinon.sandbox.create(); + + showInformationMessage = sandbox.stub(vscode.window, "showInformationMessage"); + showErrorMessage = sandbox.stub(vscode.window, "showErrorMessage"); + createOutputChannel = sandbox.stub(vscode.window, "createOutputChannel"); + + outputBuffer = ""; + outputChannel = { + name: "TestOutputChannel", + append: (output: string) => { + outputBuffer = output; + }, + appendLine: sandbox.stub(), + clear: sandbox.stub(), + show: sandbox.stub(), + hide: sandbox.stub(), + dispose: sandbox.stub() + }; + createOutputChannel.withArgs(sinon.match.any).returns(outputChannel); + }); + + afterEach(() => { + sandbox.restore(); + }); + + it("active document is not JSON -- display info message", () => { + return jmespathQuery.queryJson(context, outputChannel) + .then(() => { + expect(showInformationMessage.called).to.be.true; + }); + }); + + it("empty expression entered -- display info message", () => { + jmespathCompile = sandbox.stub(jmespath, "compile"); + + let emptyExpression = ""; + showInputBox = sandbox.stub(vscode.window, "showInputBox"); + showInputBox.withArgs(sinon.match.any).returns(Promise.resolve(emptyExpression)); + + return vscode.workspace.openTextDocument(testJsonFile) + .then((document) => { + return vscode.window.showTextDocument(document); + }) + .then((editor) => { + return jmespathQuery.queryJson(context, outputChannel); + }) + .then(() => { + expect(showInformationMessage.called).to.be.true; + expect(jmespathCompile.called).to.not.be.true; + }); + }); + + it("invalid expression entered -- display error message", () => { + let invalidExpression = "locations[?state=='WA'"; // invalid jmespath expression + showInputBox = sandbox.stub(vscode.window, "showInputBox"); + showInputBox.withArgs(sinon.match.any).returns(Promise.resolve(invalidExpression)); + + return vscode.workspace.openTextDocument(testJsonFile) + .then((document) => { + return vscode.window.showTextDocument(document); + }) + .then((editor) => { + return jmespathQuery.queryJson(context, outputChannel); + }) + .then(() => { + expect(showErrorMessage.called).to.be.true; + }); + }); + + it("valid jmespath expression -- display results in output channel", () => { + let expression = "locations[?state=='WA'].name | sort(@)"; + showInputBox = sandbox.stub(vscode.window, "showInputBox"); + showInputBox.withArgs(sinon.match.any).returns(Promise.resolve(expression)); + + let expectedOutput = JSON.stringify([ "Bellevue", "Olympia", "Seattle" ], null, " "); + + return vscode.workspace.openTextDocument(testJsonFile) + .then((document) => { + return vscode.window.showTextDocument(document); + }) + .then((editor) => { + return jmespathQuery.queryJson(context, outputChannel); + }) + .then(() => { + expect(expectedOutput).to.equal(outputBuffer); + expect((outputChannel.show).called).to.be.true; + }); + }); + + it("empty json document -- display error message", () => { + let expression = "locations[?state=='WA'].name"; + showInputBox = sandbox.stub(vscode.window, "showInputBox"); + showInputBox.withArgs(sinon.match.any).returns(Promise.resolve(expression)); + + return vscode.workspace.openTextDocument(emptyJsonFile) + .then((document) => { + return vscode.window.showTextDocument(document); + }) + .then((editor) => { + return jmespathQuery.queryJson(context, outputChannel); + }) + .then(() => { + expect(showErrorMessage.called).to.be.true; + }); + }); + }); + +});