update to finalize api

This commit is contained in:
Connor Peet
2024-03-27 11:29:31 -07:00
parent be3ef98e19
commit 1e6b9bb2cb
4 changed files with 28 additions and 226 deletions

View File

@ -18,7 +18,7 @@
"typescript": "^5.3.2"
},
"engines": {
"vscode": "^1.68.0"
"vscode": "^1.88.0"
}
},
"node_modules/@eslint-community/eslint-utils": {

View File

@ -7,11 +7,8 @@
"private": true,
"license": "MIT",
"repository": "https://github.com/Microsoft/vscode-extension-samples",
"enabledApiProposals": [
"testCoverage"
],
"engines": {
"vscode": "^1.68.0"
"vscode": "^1.88.0"
},
"categories": [
"Other"
@ -25,7 +22,7 @@
"compile": "tsc -p ./",
"lint": "eslint \"src/**/*.ts\"",
"watch": "tsc -watch -p ./",
"download-api": "dts main && dts dev",
"download-api": "dts main",
"postinstall": "npm run download-api"
},
"devDependencies": {

View File

@ -96,27 +96,15 @@ export async function activate(context: vscode.ExtensionContext) {
const fileCoverage = coveredLines.get(test.uri!.toString());
const lineInfo = fileCoverage?.[lineNo];
if (lineInfo) {
lineInfo.executionCount++;
(lineInfo.executed as number)++;
}
run.appendOutput(`Completed ${test.id}\r\n`);
}
run.coverageProvider = {
provideFileCoverage() {
const coverage: vscode.FileCoverage[] = [];
for (const [uri, statements] of coveredLines) {
coverage.push(
vscode.FileCoverage.fromDetails(
vscode.Uri.parse(uri),
statements.filter((s): s is vscode.StatementCoverage => !!s)
)
);
}
return coverage;
},
};
for (const [uri, statements] of coveredLines) {
run.addCoverage(new MarkdownFileCoverage(uri, statements));
}
run.end();
};
@ -128,7 +116,15 @@ export async function activate(context: vscode.ExtensionContext) {
await Promise.all(getWorkspaceTestPatterns().map(({ pattern }) => findInitialFiles(ctrl, pattern)));
};
ctrl.createRunProfile('Run Tests', vscode.TestRunProfileKind.Run, runHandler, true, undefined, true);
const profile = ctrl.createRunProfile('Run Tests', vscode.TestRunProfileKind.Run, runHandler, true, undefined, true);
profile.loadDetailedCoverage = async (_testRun, coverage) => {
if (coverage instanceof MarkdownFileCoverage) {
return coverage.coveredLines.filter((l): l is vscode.StatementCoverage => !!l);
}
return [];
};
ctrl.resolveHandler = async item => {
if (!item) {
@ -226,3 +222,15 @@ function startWatchingWorkspace(controller: vscode.TestController, fileChangedEm
return watcher;
});
}
class MarkdownFileCoverage extends vscode.FileCoverage {
constructor(uri: string, public readonly coveredLines: (vscode.StatementCoverage | undefined)[]) {
super(vscode.Uri.parse(uri), new vscode.TestCoverageCount(0, 0));
for (const line of coveredLines) {
if (line) {
this.statementCoverage.covered += line.executed ? 1 : 0;
this.statementCoverage.total++;
}
}
}
}

View File

@ -1,203 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
declare module 'vscode' {
// https://github.com/microsoft/vscode/issues/123713
export interface TestRun {
/**
* Test coverage provider for this result. An extension can defer setting
* this until after a run is complete and coverage is available.
*/
coverageProvider?: TestCoverageProvider;
// ...
}
/**
* Provides information about test coverage for a test result.
* Methods on the provider will not be called until the test run is complete
*/
export interface TestCoverageProvider<T extends FileCoverage = FileCoverage> {
/**
* Returns coverage information for all files involved in the test run.
* @param token A cancellation token.
* @return Coverage metadata for all files involved in the test.
*/
provideFileCoverage(token: CancellationToken): ProviderResult<T[]>;
/**
* Give a FileCoverage to fill in more data, namely {@link FileCoverage.detailedCoverage}.
* The editor will only resolve a FileCoverage once, and only if detailedCoverage
* is undefined.
*
* @param coverage A coverage object obtained from {@link provideFileCoverage}
* @param token A cancellation token.
* @return The resolved file coverage, or a thenable that resolves to one. It
* is OK to return the given `coverage`. When no result is returned, the
* given `coverage` will be used.
*/
resolveFileCoverage?(coverage: T, token: CancellationToken): ProviderResult<T>;
}
/**
* A class that contains information about a covered resource. A count can
* be give for lines, branches, and functions in a file.
*/
export class CoveredCount {
/**
* Number of items covered in the file.
*/
covered: number;
/**
* Total number of covered items in the file.
*/
total: number;
/**
* @param covered Value for {@link CovereredCount.covered}
* @param total Value for {@link CovereredCount.total}
*/
constructor(covered: number, total: number);
}
/**
* Contains coverage metadata for a file.
*/
export class FileCoverage {
/**
* File URI.
*/
readonly uri: Uri;
/**
* Statement coverage information. If the reporter does not provide statement
* coverage information, this can instead be used to represent line coverage.
*/
statementCoverage: CoveredCount;
/**
* Branch coverage information.
*/
branchCoverage?: CoveredCount;
/**
* Function coverage information.
*/
functionCoverage?: CoveredCount;
/**
* Detailed, per-statement coverage. If this is undefined, the editor will
* call {@link TestCoverageProvider.resolveFileCoverage} when necessary.
*/
detailedCoverage?: DetailedCoverage[];
/**
* Creates a {@link FileCoverage} instance with counts filled in from
* the coverage details.
* @param uri Covered file URI
* @param detailed Detailed coverage information
*/
static fromDetails(uri: Uri, details: readonly DetailedCoverage[]): FileCoverage;
/**
* @param uri Covered file URI
* @param statementCoverage Statement coverage information. If the reporter
* does not provide statement coverage information, this can instead be
* used to represent line coverage.
* @param branchCoverage Branch coverage information
* @param functionCoverage Function coverage information
*/
constructor(
uri: Uri,
statementCoverage: CoveredCount,
branchCoverage?: CoveredCount,
functionCoverage?: CoveredCount,
);
}
/**
* Contains coverage information for a single statement or line.
*/
export class StatementCoverage {
/**
* The number of times this statement was executed. If zero, the
* statement will be marked as un-covered.
*/
executionCount: number;
/**
* Statement location.
*/
location: Position | Range;
/**
* Coverage from branches of this line or statement. If it's not a
* conditional, this will be empty.
*/
branches: BranchCoverage[];
/**
* @param location The statement position.
* @param executionCount The number of times this statement was
* executed. If zero, the statement will be marked as un-covered.
* @param branches Coverage from branches of this line. If it's not a
* conditional, this should be omitted.
*/
constructor(executionCount: number, location: Position | Range, branches?: BranchCoverage[]);
}
/**
* Contains coverage information for a branch of a {@link StatementCoverage}.
*/
export class BranchCoverage {
/**
* The number of times this branch was executed. If zero, the
* branch will be marked as un-covered.
*/
executionCount: number;
/**
* Branch location.
*/
location?: Position | Range;
/**
* @param executionCount The number of times this branch was executed.
* @param location The branch position.
*/
constructor(executionCount: number, location?: Position | Range);
}
/**
* Contains coverage information for a function or method.
*/
export class FunctionCoverage {
/**
* Name of the function or method.
*/
name: string;
/**
* The number of times this function was executed. If zero, the
* function will be marked as un-covered.
*/
executionCount: number;
/**
* Function location.
*/
location: Position | Range;
/**
* @param executionCount The number of times this function was executed.
* @param location The function position.
*/
constructor(name: string, executionCount: number, location: Position | Range);
}
export type DetailedCoverage = StatementCoverage | FunctionCoverage;
}