Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 19 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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": {
Expand Down Expand Up @@ -91,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"
},
Expand Down
57 changes: 50 additions & 7 deletions src/extension.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { isAbsolute, join } from "path";
import {
commands,
Diagnostic,
DiagnosticSeverity,
ExtensionContext,
Expand All @@ -21,11 +22,26 @@ import { parse as parseLcov } from "./parse-lcov";

const DEFAULT_SEARCH_CRITERIA = "coverage/lcov*.info";

export let onCommand: (cmd: string) => Promise<void> = noop;

export async 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<string, Coverage>();
let showCoverage = true;

const config = workspace.getConfiguration("markiscodecoverage");
const configSearchCriteria =
Expand All @@ -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) => {
Expand All @@ -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 = async function onCommand(cmd: string) {
switch (cmd) {
case `${packageInfo.name}.hide`:
return onHideCoverage();
case `${packageInfo.name}.show`:
return onShowCoverage();
}
};

async function onHideCoverage() {
showCoverage = false;
diagnostics.clear();
}

async function onShowCoverage() {
showCoverage = true;
await 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
Expand Down Expand Up @@ -123,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)
Expand All @@ -147,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(
Expand All @@ -169,5 +210,7 @@ export async function activate(context: ExtensionContext) {
}

// exports - accessible to tests
return { statusBar };
return { onCommand, statusBar };
}

async function noop() {}
12 changes: 6 additions & 6 deletions test/run-test.ts
Original file line number Diff line number Diff line change
@@ -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();
main();
104 changes: 66 additions & 38 deletions test/suite/extension.test.ts
Original file line number Diff line number Diff line change
@@ -1,38 +1,66 @@
import * as assert from 'assert';
import { join } from 'path';
import { commands, extensions, languages, StatusBarItem, Uri, window, workspace } from 'vscode';

suite('code-coverage', () => {
const exampleWorkspace = join(__dirname, '../../../', 'example');
const exampleWorkspaceUri = Uri.file(exampleWorkspace);
const exampleIndexFile = 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);
await window.showTextDocument(doc);
});

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(Uri.file(exampleIndexFile));
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'))
});
});
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<any> | undefined;
let onCommand: (cmd: string) => Promise<void> | 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);
});
});
56 changes: 29 additions & 27 deletions test/suite/index.ts
Original file line number Diff line number Diff line change
@@ -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);
}
});
}
try {
// Run the mocha test
mocha.run((failures) => {
cb(null, failures);
});
} catch (err) {
console.error(err);
cb(err);
}
});
}