Skip to content

Commit

Permalink
Stub TestCoverage API (#13631)
Browse files Browse the repository at this point in the history
contributed on behalf of STMicroelectronics

Signed-off-by: Remi Schnekenburger <[email protected]>
  • Loading branch information
rschnekenbu authored Apr 24, 2024
1 parent 1578d2d commit 845b291
Show file tree
Hide file tree
Showing 5 changed files with 280 additions and 2 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
## not yet released

- [scm] added support for dirty diff peek view [#13104](https://github.com/eclipse-theia/theia/pull/13104)
- [test] stub VS Code `Test Coverage` API [#13631](https://github.com/eclipse-theia/theia/pull/13631)

<a name="breaking_changes_not_yet_released">[Breaking Changes:](#breaking_changes_not_yet_released)</a>
- [scm] revised some of the dirty diff related types [#13104](https://github.com/eclipse-theia/theia/pull/13104)
Expand Down
14 changes: 12 additions & 2 deletions packages/plugin-ext/src/plugin/plugin-context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,12 @@ import {
TerminalOutputAnchor,
TerminalQuickFixTerminalCommand,
TerminalQuickFixOpener,
TestResultState
TestResultState,
BranchCoverage,
DeclarationCoverage,
FileCoverage,
StatementCoverage,
TestCoverageCount
} from './types-impl';
import { AuthenticationExtImpl } from './authentication-ext';
import { SymbolKind } from '../common/plugin-api-rpc-model';
Expand Down Expand Up @@ -1402,7 +1407,12 @@ export function createAPIFactory(
TerminalQuickFixTerminalCommand,
TerminalQuickFixOpener,
EditSessionIdentityMatch,
TestResultState
TestResultState,
BranchCoverage,
DeclarationCoverage,
FileCoverage,
StatementCoverage,
TestCoverageCount
};
};
}
Expand Down
5 changes: 5 additions & 0 deletions packages/plugin-ext/src/plugin/tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,8 @@ class TestRun implements theia.TestRun {
onDidEnd: Event<void> = this.onDidEndEmitter.event;
private onWillFlushEmitter = new Emitter<void>();
onWillFlush: Event<void> = this.onWillFlushEmitter.event;
private onDidDisposeEmitter = new Emitter<void>();
onDidDispose: Event<void> = this.onDidDisposeEmitter.event;

readonly id: string;
private testStateDeltas = new Map<theia.TestItem, TestStateChangeDTO>();
Expand Down Expand Up @@ -293,6 +295,9 @@ class TestRun implements theia.TestRun {
this.proxy.$notifyTestRunEnded(this.controller.id, this.id);
}

/** @stubbed */
addCoverage(fileCoverage: theia.FileCoverage): void { }

private checkNotEnded(test: theia.TestItem): boolean {
if (this.ended) {
console.warn(`Setting the state of test "${test.id}" is a no - op after the run ends.`);
Expand Down
66 changes: 66 additions & 0 deletions packages/plugin-ext/src/plugin/types-impl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3330,6 +3330,72 @@ export class TestMessage implements theia.TestMessage {
constructor(public message: string | theia.MarkdownString) { }
}

@es5ClassCompat
export class TestCoverageCount {
constructor( public covered: number, public total: number) { }
}

@es5ClassCompat
export class FileCoverage {

detailedCoverage?: theia.FileCoverageDetail[];

static fromDetails(uri: theia.Uri, details: theia.FileCoverageDetail[]): FileCoverage {
const statements = new TestCoverageCount(0, 0);
const branches = new TestCoverageCount(0, 0);
const decl = new TestCoverageCount(0, 0);

for (const detail of details) {
if (detail instanceof StatementCoverage) {
statements.total += 1;
statements.covered += detail.executed ? 1 : 0;

for (const branch of detail.branches) {
branches.total += 1;
branches.covered += branch.executed ? 1 : 0;
}
} else {
decl.total += 1;
decl.covered += detail.executed ? 1 : 0;
}
}

const coverage = new FileCoverage(
uri,
statements,
branches.total > 0 ? branches : undefined,
decl.total > 0 ? decl : undefined,
);

coverage.detailedCoverage = details;

return coverage;
}

constructor(
public uri: theia.Uri,
public statementCoverage: TestCoverageCount,
public branchCoverage?: TestCoverageCount,
public declarationCoverage?: TestCoverageCount,
) { }
}

@es5ClassCompat
export class StatementCoverage implements theia.StatementCoverage {
constructor(public executed: number | boolean, public location: Position | Range, public branches: BranchCoverage[] = []) { }
}

export class BranchCoverage implements theia.BranchCoverage {
constructor(public executed: number | boolean, public location?: Position | Range, public label?: string) { }
}

@es5ClassCompat
export class DeclarationCoverage implements theia.DeclarationCoverage {
constructor(public name: string, public executed: number | boolean, public location: Position | Range) { }
}

export type FileCoverageDetail = StatementCoverage | DeclarationCoverage;

@es5ClassCompat
export class TimelineItem {
timestamp: number;
Expand Down
196 changes: 196 additions & 0 deletions packages/plugin/src/theia.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16035,6 +16035,18 @@ export module '@theia/plugin' {
*/
runHandler: (request: TestRunRequest, token: CancellationToken) => Thenable<void> | void;

/**
* An extension-provided function that provides detailed statement and
* function-level coverage for a file. The editor will call this when more
* detail is needed for a file, such as when it's opened in an editor or
* expanded in the **Test Coverage** view.
*
* The {@link FileCoverage} object passed to this function is the same instance
* emitted on {@link TestRun.addCoverage} calls associated with this profile.
* @stubbed
*/
loadDetailedCoverage?: (testRun: TestRun, fileCoverage: FileCoverage, token: CancellationToken) => Thenable<FileCoverageDetail[]>;

/**
* Deletes the run profile.
*/
Expand Down Expand Up @@ -16314,11 +16326,23 @@ export module '@theia/plugin' {
*/
appendOutput(output: string, location?: Location, test?: TestItem): void;

/**
* Adds coverage for a file in the run.
* @stubbed
*/
addCoverage(fileCoverage: FileCoverage): void;

/**
* Signals the end of the test run. Any tests included in the run whose
* states have not been updated will have their state reset.
*/
end(): void;

/**
* An event fired when the editor is no longer interested in data
* associated with the test run.
*/
onDidDispose: Event<void>;
}

/**
Expand Down Expand Up @@ -16527,6 +16551,178 @@ export module '@theia/plugin' {
*/
constructor(message: string | MarkdownString);
}

/**
* A class that contains information about a covered resource. A count can
* be give for lines, branches, and declarations in a file.
*/
export class TestCoverageCount {
/**
* Number of items covered in the file.
*/
covered: number;
/**
* Total number of covered items in the file.
*/
total: number;

/**
* @param covered Value for {@link TestCoverageCount.covered}
* @param total Value for {@link TestCoverageCount.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: TestCoverageCount;

/**
* Branch coverage information.
*/
branchCoverage?: TestCoverageCount;

/**
* Declaration coverage information. Depending on the reporter and
* language, this may be types such as functions, methods, or namespaces.
*/
declarationCoverage?: TestCoverageCount;

/**
* 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 FileCoverageDetail[]): 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 declarationCoverage Declaration coverage information
*/
constructor(
uri: Uri,
statementCoverage: TestCoverageCount,
branchCoverage?: TestCoverageCount,
declarationCoverage?: TestCoverageCount,
);
}

/**
* Contains coverage information for a single statement or line.
*/
export class StatementCoverage {
/**
* The number of times this statement was executed, or a boolean indicating
* whether it was executed if the exact count is unknown. If zero or false,
* the statement will be marked as un-covered.
*/
executed: number | boolean;

/**
* 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 executed The number of times this statement was executed, or a
* boolean indicating whether it was executed if the exact count is
* unknown. If zero or false, 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(executed: number | boolean, 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, or a boolean indicating
* whether it was executed if the exact count is unknown. If zero or false,
* the branch will be marked as un-covered.
*/
executed: number | boolean;

/**
* Branch location.
*/
location?: Position | Range;

/**
* Label for the branch, used in the context of "the ${label} branch was
* not taken," for example.
*/
label?: string;

/**
* @param executed The number of times this branch was executed, or a
* boolean indicating whether it was executed if the exact count is
* unknown. If zero or false, the branch will be marked as un-covered.
* @param location The branch position.
*/
constructor(executed: number | boolean, location?: Position | Range, label?: string);
}

/**
* Contains coverage information for a declaration. Depending on the reporter
* and language, this may be types such as functions, methods, or namespaces.
*/
export class DeclarationCoverage {
/**
* Name of the declaration.
*/
name: string;

/**
* The number of times this declaration was executed, or a boolean
* indicating whether it was executed if the exact count is unknown. If
* zero or false, the declaration will be marked as un-covered.
*/
executed: number | boolean;

/**
* Declaration location.
*/
location: Position | Range;

/**
* @param executed The number of times this declaration was executed, or a
* boolean indicating whether it was executed if the exact count is
* unknown. If zero or false, the declaration will be marked as un-covered.
* @param location The declaration position.
*/
constructor(name: string, executed: number | boolean, location: Position | Range);
}

/**
* Coverage details returned from {@link TestRunProfile.loadDetailedCoverage}.
*/
export type FileCoverageDetail = StatementCoverage | DeclarationCoverage;

/**
* Thenable is a common denominator between ES6 promises, Q, jquery.Deferred, WinJS.Promise,
* and others. This API makes no assumption about what promise library is being used which
Expand Down

0 comments on commit 845b291

Please sign in to comment.