From 26b601577ee38526d7dd67edbfc90d1babbb22d2 Mon Sep 17 00:00:00 2001 From: Markis Taylor Date: Wed, 22 Dec 2021 14:09:37 -0500 Subject: [PATCH 1/8] Add show/hide coverage commands --- package.json | 16 +++++++++++++++- src/extension.ts | 49 +++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 61 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 7d9fc01..d2ed25a 100644 --- a/package.json +++ b/package.json @@ -59,7 +59,21 @@ "description": "Search location for lcov files" } } - } + }, + "activationEvents": [ + "onCommand:code-coverage.hide", + "onCommand:code-coverage.show" + ], + "commands": [ + { + "command": "code-coverage.hide", + "title": "Hide Code Coverage" + }, + { + "command": "code-coverage.show", + "title": "Show Code Coverage" + } + ] }, "eslintConfig": { "env": { diff --git a/src/extension.ts b/src/extension.ts index 3bf50cd..a734a3d 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -1,5 +1,6 @@ import { isAbsolute, join } from "path"; import { + commands, Diagnostic, DiagnosticSeverity, ExtensionContext, @@ -21,11 +22,26 @@ import { parse as parseLcov } from "./parse-lcov"; const DEFAULT_SEARCH_CRITERIA = "coverage/lcov*.info"; +export let onCommand: (cmd: string) => void = noop; + +export function deactivate() { + onCommand = noop; +} + export async function activate(context: ExtensionContext) { const packageInfo = require(join(context.extensionPath, "package.json")); const diagnostics = languages.createDiagnosticCollection("coverage"); const statusBar = window.createStatusBarItem(); + const hideCommand = commands.registerCommand( + `${packageInfo.name}.hide`, + onHideCoverage + ); + const showCommand = commands.registerCommand( + `${packageInfo.name}.show`, + onShowCoverage + ); const coverageByFile = new Map(); + let showCoverage = true; const config = workspace.getConfiguration("markiscodecoverage"); const configSearchCriteria = @@ -47,7 +63,7 @@ export async function activate(context: ExtensionContext) { } } - context.subscriptions.push(diagnostics, statusBar); + context.subscriptions.push(diagnostics, statusBar, showCommand, hideCommand); // Update status bar on changes to any open file workspace.onDidChangeTextDocument((e) => { @@ -67,8 +83,31 @@ export async function activate(context: ExtensionContext) { }); // Run the main routine at activation time as well - if (workspaceFolders) { - await Promise.all(workspaceFolders.map(findDiagnostics)); + await findDiagnosticsInWorkspace(); + + onCommand = (cmd: string) => { + switch (cmd) { + case `${packageInfo.name}.hide`: + return onHideCoverage(); + case `${packageInfo.name}.show`: + return onShowCoverage(); + } + }; + + function onHideCoverage() { + showCoverage = false; + diagnostics.clear(); + } + + function onShowCoverage() { + showCoverage = true; + findDiagnosticsInWorkspace(); + } + + async function findDiagnosticsInWorkspace() { + if (workspaceFolders) { + await Promise.all(workspaceFolders.map(findDiagnostics)); + } } // Finds VSCode diagnostics to display based on a coverage file specified by the search pattern in each workspace folder @@ -149,6 +188,8 @@ export async function activate(context: ExtensionContext) { ) { const currentFile = window.activeTextEditor?.document.uri.fsPath; const diagnosticsForFiles: Diagnostic[] = []; + if (!showCoverage) return diagnosticsForFiles; + for (const detail of details) { const line = detail.line - 1; if (detail.hit === 0) { @@ -171,3 +212,5 @@ export async function activate(context: ExtensionContext) { // exports - accessible to tests return { statusBar }; } + +function noop() {} From 62e83f3db310a98b86115baa75318f2dc89e443d Mon Sep 17 00:00:00 2001 From: Markis Taylor Date: Thu, 23 Dec 2021 16:08:23 -0500 Subject: [PATCH 2/8] Move `showCoverage` up higher in the callstack --- src/extension.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/extension.ts b/src/extension.ts index a734a3d..14a34d2 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -162,6 +162,8 @@ export async function activate(context: ExtensionContext) { coverages: CoverageCollection, workspaceFolder: string ) { + if (!showCoverage) return; // do nothing + for (const coverage of coverages) { if (coverage && coverage.lines && coverage.lines.details) { const fileName = !isAbsolute(coverage.file) @@ -188,7 +190,6 @@ export async function activate(context: ExtensionContext) { ) { const currentFile = window.activeTextEditor?.document.uri.fsPath; const diagnosticsForFiles: Diagnostic[] = []; - if (!showCoverage) return diagnosticsForFiles; for (const detail of details) { const line = detail.line - 1; From 9918094b4ba64e47e74961c71b7bb581c67c8f5f Mon Sep 17 00:00:00 2001 From: Markis Taylor Date: Thu, 23 Dec 2021 17:50:20 -0500 Subject: [PATCH 3/8] Add tests --- src/extension.ts | 14 +++++++------- test/suite/extension.test.ts | 21 ++++++++++++++++++--- 2 files changed, 25 insertions(+), 10 deletions(-) diff --git a/src/extension.ts b/src/extension.ts index 14a34d2..14dd19b 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -22,7 +22,7 @@ import { parse as parseLcov } from "./parse-lcov"; const DEFAULT_SEARCH_CRITERIA = "coverage/lcov*.info"; -export let onCommand: (cmd: string) => void = noop; +export let onCommand: (cmd: string) => Promise = noop; export function deactivate() { onCommand = noop; @@ -85,7 +85,7 @@ export async function activate(context: ExtensionContext) { // Run the main routine at activation time as well await findDiagnosticsInWorkspace(); - onCommand = (cmd: string) => { + onCommand = async function onCommand(cmd: string) { switch (cmd) { case `${packageInfo.name}.hide`: return onHideCoverage(); @@ -94,14 +94,14 @@ export async function activate(context: ExtensionContext) { } }; - function onHideCoverage() { + async function onHideCoverage() { showCoverage = false; diagnostics.clear(); } - function onShowCoverage() { + async function onShowCoverage() { showCoverage = true; - findDiagnosticsInWorkspace(); + await findDiagnosticsInWorkspace(); } async function findDiagnosticsInWorkspace() { @@ -211,7 +211,7 @@ export async function activate(context: ExtensionContext) { } // exports - accessible to tests - return { statusBar }; + return { onCommand, statusBar }; } -function noop() {} +async function noop() {} diff --git a/test/suite/extension.test.ts b/test/suite/extension.test.ts index 1a7cc42..9a78960 100644 --- a/test/suite/extension.test.ts +++ b/test/suite/extension.test.ts @@ -5,13 +5,13 @@ import { commands, extensions, languages, StatusBarItem, Uri, window, workspace suite('code-coverage', () => { const exampleWorkspace = join(__dirname, '../../../', 'example'); const exampleWorkspaceUri = Uri.file(exampleWorkspace); - const exampleIndexFile = join(exampleWorkspace, 'index.ts'); + const exampleIndexUri = Uri.file(join(exampleWorkspace, 'index.ts')); const extension = extensions.getExtension("markis.code-coverage"); setup(async () => { // Open the example workspace and open the example index file await commands.executeCommand('vscode.openFolder', exampleWorkspaceUri); - const doc = await workspace.openTextDocument(exampleIndexFile); + const doc = await workspace.openTextDocument(exampleIndexUri); await window.showTextDocument(doc); }); @@ -23,7 +23,7 @@ suite('code-coverage', () => { test('check diagnostics exist', async () => { // Check to see if the diagnostics exist for the example file // there should only be one line not covered, and so only one diagnostic should exist - const diagnostics = languages.getDiagnostics(Uri.file(exampleIndexFile)); + const diagnostics = languages.getDiagnostics(exampleIndexUri); assert.strictEqual(diagnostics.length, 1); assert.strictEqual(diagnostics[0].range.start.line, 5); }); @@ -35,4 +35,19 @@ suite('code-coverage', () => { assert.ok(statusBar.text); assert.ok(statusBar.text.includes('3/4')) }); + + test('test commands hide/show coverage', async () => { + const onCommand = extension?.exports.onCommand; + + // Ensure coverage exists + assert.strictEqual(languages.getDiagnostics(exampleIndexUri).length, 1); + + // Hide coverage + await onCommand('code-coverage.hide'); + assert.strictEqual(languages.getDiagnostics(exampleIndexUri).length, 0); + + // Show coverage + await onCommand('code-coverage.show'); + assert.strictEqual(languages.getDiagnostics(exampleIndexUri).length, 1); + }); }); From 92983f33a7df86698dbabddd4e7fad635eac3bde Mon Sep 17 00:00:00 2001 From: Markis Taylor Date: Thu, 23 Dec 2021 17:56:13 -0500 Subject: [PATCH 4/8] Increase timeouts --- test/suite/extension.test.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/suite/extension.test.ts b/test/suite/extension.test.ts index 9a78960..16c0df2 100644 --- a/test/suite/extension.test.ts +++ b/test/suite/extension.test.ts @@ -2,7 +2,9 @@ import * as assert from 'assert'; import { join } from 'path'; import { commands, extensions, languages, StatusBarItem, Uri, window, workspace } from 'vscode'; -suite('code-coverage', () => { +suite('code-coverage', function() { + this.timeout(30000); + const exampleWorkspace = join(__dirname, '../../../', 'example'); const exampleWorkspaceUri = Uri.file(exampleWorkspace); const exampleIndexUri = Uri.file(join(exampleWorkspace, 'index.ts')); From 35122a9b99dba3b3a0bd76418539954b0a42d149 Mon Sep 17 00:00:00 2001 From: Markis Taylor Date: Fri, 24 Dec 2021 10:42:44 -0500 Subject: [PATCH 5/8] Refactor tests --- src/extension.ts | 2 +- test/suite/extension.test.ts | 16 +++++++++------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/extension.ts b/src/extension.ts index 14dd19b..cbc6267 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -24,7 +24,7 @@ const DEFAULT_SEARCH_CRITERIA = "coverage/lcov*.info"; export let onCommand: (cmd: string) => Promise = noop; -export function deactivate() { +export async function deactivate() { onCommand = noop; } diff --git a/test/suite/extension.test.ts b/test/suite/extension.test.ts index 16c0df2..299bf28 100644 --- a/test/suite/extension.test.ts +++ b/test/suite/extension.test.ts @@ -1,20 +1,22 @@ import * as assert from 'assert'; import { join } from 'path'; -import { commands, extensions, languages, StatusBarItem, Uri, window, workspace } from 'vscode'; +import { commands, extensions, languages, StatusBarItem, Uri, window, workspace, Extension } from 'vscode'; suite('code-coverage', function() { - this.timeout(30000); - const exampleWorkspace = join(__dirname, '../../../', 'example'); const exampleWorkspaceUri = Uri.file(exampleWorkspace); const exampleIndexUri = Uri.file(join(exampleWorkspace, 'index.ts')); - const extension = extensions.getExtension("markis.code-coverage"); + let extension: Extension | undefined; + let onCommand: (cmd: string) => Promise | undefined; + setup(async () => { // Open the example workspace and open the example index file await commands.executeCommand('vscode.openFolder', exampleWorkspaceUri); const doc = await workspace.openTextDocument(exampleIndexUri); await window.showTextDocument(doc); + extension = extensions.getExtension("markis.code-coverage"); + onCommand = extension?.exports.onCommand; }); teardown(async () => { @@ -38,16 +40,16 @@ suite('code-coverage', function() { assert.ok(statusBar.text.includes('3/4')) }); - test('test commands hide/show coverage', async () => { - const onCommand = extension?.exports.onCommand; - + test('test commands hide coverage', async () => { // Ensure coverage exists assert.strictEqual(languages.getDiagnostics(exampleIndexUri).length, 1); // Hide coverage await onCommand('code-coverage.hide'); assert.strictEqual(languages.getDiagnostics(exampleIndexUri).length, 0); + }); + test('test commands show coverage', async () => { // Show coverage await onCommand('code-coverage.show'); assert.strictEqual(languages.getDiagnostics(exampleIndexUri).length, 1); From 94b2db6b110e69d3e08d7459284f7e53bc9d0780 Mon Sep 17 00:00:00 2001 From: Markis Taylor Date: Fri, 24 Dec 2021 10:54:52 -0500 Subject: [PATCH 6/8] PR comments --- src/extension.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/extension.ts b/src/extension.ts index cbc6267..d962e50 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -190,7 +190,6 @@ export async function activate(context: ExtensionContext) { ) { const currentFile = window.activeTextEditor?.document.uri.fsPath; const diagnosticsForFiles: Diagnostic[] = []; - for (const detail of details) { const line = detail.line - 1; if (detail.hit === 0) { From 475b624733e09185c7a30e72647b652ae152f4a2 Mon Sep 17 00:00:00 2001 From: Markis Taylor Date: Fri, 24 Dec 2021 10:58:59 -0500 Subject: [PATCH 7/8] Fix tests --- src/extension.ts | 6 +++--- test/suite/extension.test.ts | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/extension.ts b/src/extension.ts index d962e50..6e0195f 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -188,14 +188,14 @@ export async function activate(context: ExtensionContext) { details: LineCoverageInfo[], fileName: string ) { - const currentFile = window.activeTextEditor?.document.uri.fsPath; + const doc = window.activeTextEditor?.document; + const currentFile = doc?.uri.fsPath; const diagnosticsForFiles: Diagnostic[] = []; for (const detail of details) { const line = detail.line - 1; if (detail.hit === 0) { const range = - (currentFile === fileName && - window.activeTextEditor?.document.lineAt(line).range) || + (currentFile === fileName && doc?.lineAt(line).range) || new Range(new Position(line, 0), new Position(line, 1000)); diagnosticsForFiles.push( new Diagnostic( diff --git a/test/suite/extension.test.ts b/test/suite/extension.test.ts index 299bf28..ff84cd3 100644 --- a/test/suite/extension.test.ts +++ b/test/suite/extension.test.ts @@ -3,12 +3,12 @@ import { join } from 'path'; import { commands, extensions, languages, StatusBarItem, Uri, window, workspace, Extension } from 'vscode'; suite('code-coverage', function() { + this.timeout(10000); const exampleWorkspace = join(__dirname, '../../../', 'example'); const exampleWorkspaceUri = Uri.file(exampleWorkspace); const exampleIndexUri = Uri.file(join(exampleWorkspace, 'index.ts')); let extension: Extension | undefined; let onCommand: (cmd: string) => Promise | undefined; - setup(async () => { // Open the example workspace and open the example index file From b4b7a2086a6f0038eefb01019d0a73414b1987e4 Mon Sep 17 00:00:00 2001 From: Markis Taylor Date: Fri, 24 Dec 2021 11:21:10 -0500 Subject: [PATCH 8/8] Format tests scripts --- package.json | 8 +-- test/run-test.ts | 12 ++-- test/suite/extension.test.ts | 123 +++++++++++++++++++---------------- test/suite/index.ts | 56 ++++++++-------- 4 files changed, 105 insertions(+), 94 deletions(-) diff --git a/package.json b/package.json index d2ed25a..3af96e3 100644 --- a/package.json +++ b/package.json @@ -105,10 +105,10 @@ "vscode:prepublish": "tsc -p ./", "compile": "tsc -p ./", "compile:watch": "tsc -watch -p ./", - "preformat": "prettier --write src/**/*.ts", - "format": "eslint --fix src/**/*.ts", - "prelint": "prettier --check src/**/*.ts", - "lint": "eslint src/**/*.ts", + "preformat": "prettier --write src/**/*.ts test/**/*.ts", + "format": "eslint --fix src/**/*.ts test/**/*.ts", + "prelint": "prettier --check src/**/*.ts test/**/*.ts", + "lint": "eslint src/**/*.ts test/**/*.ts", "pretest": "npm run compile", "test": "node ./out/test/run-test.js" }, diff --git a/test/run-test.ts b/test/run-test.ts index cccf87d..2920435 100644 --- a/test/run-test.ts +++ b/test/run-test.ts @@ -1,24 +1,24 @@ -import * as path from 'path'; +import * as path from "path"; -import { runTests } from '@vscode/test-electron'; +import { runTests } from "@vscode/test-electron"; async function main() { try { // The folder containing the Extension Manifest package.json // Passed to `--extensionDevelopmentPath` - const extensionDevelopmentPath = path.resolve(__dirname, '../../../'); + const extensionDevelopmentPath = path.resolve(__dirname, "../../../"); // The path to the extension test runner script // Passed to --extensionTestsPath - const extensionTestsPath = path.resolve(__dirname, './suite/'); + const extensionTestsPath = path.resolve(__dirname, "./suite/"); // Download VS Code, unzip it and run the integration test await runTests({ extensionDevelopmentPath, extensionTestsPath }); } catch (err) { console.error(err); - console.error('Failed to run tests'); + console.error("Failed to run tests"); process.exit(1); } } -main(); \ No newline at end of file +main(); diff --git a/test/suite/extension.test.ts b/test/suite/extension.test.ts index ff84cd3..f97b3ea 100644 --- a/test/suite/extension.test.ts +++ b/test/suite/extension.test.ts @@ -1,57 +1,66 @@ -import * as assert from 'assert'; -import { join } from 'path'; -import { commands, extensions, languages, StatusBarItem, Uri, window, workspace, Extension } from 'vscode'; - -suite('code-coverage', function() { - this.timeout(10000); - const exampleWorkspace = join(__dirname, '../../../', 'example'); - const exampleWorkspaceUri = Uri.file(exampleWorkspace); - const exampleIndexUri = Uri.file(join(exampleWorkspace, 'index.ts')); - let extension: Extension | undefined; - let onCommand: (cmd: string) => Promise | undefined; - - setup(async () => { - // Open the example workspace and open the example index file - await commands.executeCommand('vscode.openFolder', exampleWorkspaceUri); - const doc = await workspace.openTextDocument(exampleIndexUri); - await window.showTextDocument(doc); - extension = extensions.getExtension("markis.code-coverage"); - onCommand = extension?.exports.onCommand; - }); - - teardown(async () => { - // All done, close the editor - commands.executeCommand('workbench.action.closeActiveEditor'); - }); - - test('check diagnostics exist', async () => { - // Check to see if the diagnostics exist for the example file - // there should only be one line not covered, and so only one diagnostic should exist - const diagnostics = languages.getDiagnostics(exampleIndexUri); - assert.strictEqual(diagnostics.length, 1); - assert.strictEqual(diagnostics[0].range.start.line, 5); - }); - - test('check status bar', async () => { - // Check to see if the status bar is updated correctly - // the example coverage should cover 3 out of 4 lines - "3/4" - const statusBar: StatusBarItem = extension?.exports.statusBar; - assert.ok(statusBar.text); - assert.ok(statusBar.text.includes('3/4')) - }); - - test('test commands hide coverage', async () => { - // Ensure coverage exists - assert.strictEqual(languages.getDiagnostics(exampleIndexUri).length, 1); - - // Hide coverage - await onCommand('code-coverage.hide'); - assert.strictEqual(languages.getDiagnostics(exampleIndexUri).length, 0); - }); - - test('test commands show coverage', async () => { - // Show coverage - await onCommand('code-coverage.show'); - assert.strictEqual(languages.getDiagnostics(exampleIndexUri).length, 1); - }); -}); +import * as assert from "assert"; +import { join } from "path"; +import { + commands, + extensions, + languages, + StatusBarItem, + Uri, + window, + workspace, + Extension, +} from "vscode"; + +suite("code-coverage", function () { + this.timeout(10000); + const exampleWorkspace = join(__dirname, "../../../", "example"); + const exampleWorkspaceUri = Uri.file(exampleWorkspace); + const exampleIndexUri = Uri.file(join(exampleWorkspace, "index.ts")); + let extension: Extension | undefined; + let onCommand: (cmd: string) => Promise | undefined; + + setup(async () => { + // Open the example workspace and open the example index file + await commands.executeCommand("vscode.openFolder", exampleWorkspaceUri); + const doc = await workspace.openTextDocument(exampleIndexUri); + await window.showTextDocument(doc); + extension = extensions.getExtension("markis.code-coverage"); + onCommand = extension?.exports.onCommand; + }); + + teardown(async () => { + // All done, close the editor + commands.executeCommand("workbench.action.closeActiveEditor"); + }); + + test("check diagnostics exist", async () => { + // Check to see if the diagnostics exist for the example file + // there should only be one line not covered, and so only one diagnostic should exist + const diagnostics = languages.getDiagnostics(exampleIndexUri); + assert.strictEqual(diagnostics.length, 1); + assert.strictEqual(diagnostics[0].range.start.line, 5); + }); + + test("check status bar", async () => { + // Check to see if the status bar is updated correctly + // the example coverage should cover 3 out of 4 lines - "3/4" + const statusBar: StatusBarItem = extension?.exports.statusBar; + assert.ok(statusBar.text); + assert.ok(statusBar.text.includes("3/4")); + }); + + test("test commands hide coverage", async () => { + // Ensure coverage exists + assert.strictEqual(languages.getDiagnostics(exampleIndexUri).length, 1); + + // Hide coverage + await onCommand("code-coverage.hide"); + assert.strictEqual(languages.getDiagnostics(exampleIndexUri).length, 0); + }); + + test("test commands show coverage", async () => { + // Show coverage + await onCommand("code-coverage.show"); + assert.strictEqual(languages.getDiagnostics(exampleIndexUri).length, 1); + }); +}); diff --git a/test/suite/index.ts b/test/suite/index.ts index 8cb6761..6e6baae 100644 --- a/test/suite/index.ts +++ b/test/suite/index.ts @@ -1,31 +1,33 @@ +import * as path from "path"; +import * as Mocha from "mocha"; +import * as glob from "glob"; -import * as path from 'path'; -import * as Mocha from 'mocha'; -import * as glob from 'glob'; +export function run( + testsRoot: string, + cb: (error: any, failures?: number) => void +): void { + // Create the mocha test + const mocha = new Mocha({ + ui: "tdd", + }); + mocha.useColors(true); -export function run(testsRoot: string, cb: (error: any, failures?: number) => void): void { - // Create the mocha test - const mocha = new Mocha({ - ui: 'tdd' - }); - mocha.useColors(true); + glob("**/**.test.js", { cwd: testsRoot }, (err, files) => { + if (err) { + return cb(err); + } - glob('**/**.test.js', { cwd: testsRoot }, (err, files) => { - if (err) { - return cb(err); - } + // Add files to the test suite + files.forEach((f) => mocha.addFile(path.resolve(testsRoot, f))); - // Add files to the test suite - files.forEach(f => mocha.addFile(path.resolve(testsRoot, f))); - - try { - // Run the mocha test - mocha.run(failures => { - cb(null, failures); - }); - } catch (err) { - console.error(err); - cb(err); - } - }); -} \ No newline at end of file + try { + // Run the mocha test + mocha.run((failures) => { + cb(null, failures); + }); + } catch (err) { + console.error(err); + cb(err); + } + }); +}