UNPKG

2.68 kBPlain TextView Raw
1import { MutantResult, MutantStatus, MutantRunPlan, MutantTestPlan, PlanKind } from '@stryker-mutator/api/core';
2import { DryRunCompletedEvent, MutationTestingPlanReadyEvent, Reporter, RunTiming } from '@stryker-mutator/api/report';
3
4import { Timer } from '../utils/timer.js';
5
6export abstract class ProgressKeeper implements Reporter {
7 private timer!: Timer;
8 private timing!: RunTiming;
9 private ticksByMutantId!: Map<string, number>;
10 protected progress = {
11 survived: 0,
12 timedOut: 0,
13 tested: 0,
14 mutants: 0,
15 total: 0,
16 ticks: 0,
17 };
18
19 public onDryRunCompleted({ timing }: DryRunCompletedEvent): void {
20 this.timing = timing;
21 }
22
23 /**
24 * An event emitted when the mutant test plan is calculated.
25 * @param event The mutant test plan ready event
26 */
27 public onMutationTestingPlanReady({ mutantPlans }: MutationTestingPlanReadyEvent): void {
28 this.timer = new Timer();
29 this.ticksByMutantId = new Map(
30 mutantPlans.filter(isRunPlan).map(({ netTime, mutant, runOptions }) => {
31 let ticks = netTime;
32 if (runOptions.reloadEnvironment) {
33 ticks += this.timing.overhead;
34 }
35 return [mutant.id, ticks];
36 })
37 );
38 this.progress.mutants = this.ticksByMutantId.size;
39 this.progress.total = [...this.ticksByMutantId.values()].reduce((acc, n) => acc + n, 0);
40 }
41
42 public onMutantTested(result: MutantResult): number {
43 const ticks = this.ticksByMutantId.get(result.id);
44 if (ticks !== undefined) {
45 this.progress.tested++;
46 this.progress.ticks += this.ticksByMutantId.get(result.id) ?? 0;
47 if (result.status === MutantStatus.Survived) {
48 this.progress.survived++;
49 }
50 if (result.status === MutantStatus.Timeout) {
51 this.progress.timedOut++;
52 }
53 }
54 return ticks ?? 0;
55 }
56
57 protected getElapsedTime(): string {
58 return this.formatTime(this.timer.elapsedSeconds());
59 }
60
61 protected getEtc(): string {
62 const totalSecondsLeft = Math.floor((this.timer.elapsedSeconds() / this.progress.ticks) * (this.progress.total - this.progress.ticks));
63
64 if (isFinite(totalSecondsLeft) && totalSecondsLeft > 0) {
65 return this.formatTime(totalSecondsLeft);
66 } else {
67 return 'n/a';
68 }
69 }
70
71 private formatTime(timeInSeconds: number) {
72 const hours = Math.floor(timeInSeconds / 3600);
73
74 const minutes = Math.floor((timeInSeconds % 3600) / 60);
75
76 return hours > 0 // conditional time formatting
77 ? `~${hours}h ${minutes}m`
78 : minutes > 0
79 ? `~${minutes}m`
80 : '<1m';
81 }
82}
83
84function isRunPlan(mutantPlan: MutantTestPlan): mutantPlan is MutantRunPlan {
85 return mutantPlan.plan === PlanKind.Run;
86}