From d173b27117ade43e86a991643207532e338e7907 Mon Sep 17 00:00:00 2001 From: Nico Jansen Date: Thu, 11 Mar 2021 21:35:20 +0100 Subject: [PATCH] feat(reporter api): unify reporter api with mutation-testing-elements (#2798) This change brings the `Reporter` API more in line with the schema of [`mutation-testing-elements`](https://github.com/stryker-mutator/mutation-testing-elements). It also adds the metrics result to the `onMutationTestReportReady` for convenience. | Old | New | |-|-| | `MutantStatus.TimedOut` | `MutantStatus.Timeout` | | `mutant.coveredByTests` (boolean) | `mutant.coveredBy` (array, an empty array means not covered) | | `mutant.testFilter` (array) | `mutant.coveredBy` | | `mutant.testFilter` (undefined) | `mutant.static` (true/false) | | `mutant.runAllTests` (boolean) | `mutant.static` (true/false) | | `mutant.errorMessage`, `mutant.ignoreReason` | `mutant.statusReason` | | `mutant.nrOfTestsRan` | `mutant.testsCompleted` | | `mutant.id` (number) | `mutant.id` (string) | | `MatchedMutant` | `MutantTestCoverage` (name change) | This has also a small impact on the `TestRunner` API, because the `Mutant` is used there as well. BREAKING CHANGE: Changes to `Reporter` and `TestRunner` plugin API of Stryker Fixes #2766 --- e2e/package-lock.json | 14 +- e2e/package.json | 2 +- e2e/test/coverage-analysis/verify/verify.ts | 6 +- .../karma-webpack-with-ts/package-lock.json | 14 +- e2e/test/karma-webpack-with-ts/package.json | 4 +- packages/api/package.json | 3 +- packages/api/src/core/index.ts | 7 +- packages/api/src/core/instrument.ts | 2 +- packages/api/src/core/mutant-coverage.ts | 5 +- packages/api/src/core/mutant.ts | 43 +- packages/api/src/report/index.ts | 12 - packages/api/src/report/matched-mutant.ts | 30 - packages/api/src/report/mutant-result.ts | 41 - packages/api/src/report/mutant-status.ts | 44 - packages/api/src/report/reporter.ts | 20 +- packages/api/src/test-runner/test-result.ts | 2 +- packages/api/test/unit/plugin/plugins.spec.ts | 2 +- packages/core/package.json | 4 +- .../child-proxy/child-process-proxy-worker.ts | 2 +- .../src/child-proxy/child-process-proxy.ts | 4 +- packages/core/src/input/index.ts | 2 + .../src/mutants/find-mutant-test-coverage.ts | 91 +- .../core/src/process/1-prepare-executor.ts | 2 +- .../src/process/4-mutation-test-executor.ts | 36 +- .../core/src/reporters/broadcast-reporter.ts | 22 +- .../core/src/reporters/clear-text-reporter.ts | 126 +- .../dashboard-reporter/dashboard-reporter.ts | 14 +- .../reporters/dashboard-reporter/report.ts | 4 +- packages/core/src/reporters/dots-reporter.ts | 6 +- .../src/reporters/event-recorder-reporter.ts | 12 +- .../core/src/reporters/html/html-reporter.ts | 8 +- .../src/reporters/html/report-template.ts | 4 +- packages/core/src/reporters/json-reporter.ts | 8 +- .../reporters/mutation-test-report-helper.ts | 207 +- .../progress-append-only-reporter.ts | 4 +- .../core/src/reporters/progress-keeper.ts | 17 +- .../core/src/reporters/progress-reporter.ts | 4 +- packages/core/src/stryker-cli.ts | 4 +- packages/core/src/stryker.ts | 3 +- .../src/test-runner/command-test-runner.ts | 6 +- packages/core/src/utils/mutant-utils.ts | 51 - packages/core/src/utils/object-utils.ts | 20 - packages/core/src/utils/string-utils.ts | 23 + packages/core/test/helpers/producers.ts | 11 - .../command-test-runner.it.spec.ts | 4 +- .../reporters/html/simple-report.ts | 8 +- .../child-proxy/child-process-proxy.spec.ts | 9 +- .../child-proxy/child-process-worker.spec.ts | 2 +- .../mutants/find-mutant-test-coverage.spec.ts | 116 +- .../unit/process/1-prepare-executor.spec.ts | 3 +- .../2-mutant-instrumenter-executor.spec.ts | 2 +- .../process/4-mutation-test-executor.spec.ts | 56 +- .../unit/reporters/broadcast-reporter.spec.ts | 67 +- .../reporters/clear-text-reporter.spec.ts | 171 +- .../dashboard-reporter.spec.ts | 19 +- .../test/unit/reporters/dots-reporter.spec.ts | 6 +- .../unit/reporters/html/html-reporter.spec.ts | 8 +- .../test/unit/reporters/json-reporter.spec.ts | 6 +- .../mutation-test-report-helper.spec.ts | 512 ++-- .../progress-append-only-reporter.spec.ts | 6 +- .../unit/reporters/progress-reporter.spec.ts | 111 +- packages/core/test/unit/stryker.spec.ts | 3 +- .../test-runner/command-test-runner.spec.ts | 4 +- packages/core/tsconfig.src.json | 4 +- packages/instrumenter/src/mutant.ts | 7 +- .../src/transformers/mutant-collector.ts | 2 +- .../instrumenter/src/util/syntax-helpers.ts | 8 +- .../instrumenter/test/helpers/factories.ts | 2 +- .../integration/transformers.it.spec.ts.snap | 2511 ++++++++--------- .../expression-mutant-placer.spec.ts | 14 +- .../statement-mutant-placer.spec.ts | 16 +- .../switch-case-mutant-placer.spec.ts | 20 +- .../instrumenter/test/unit/mutant.spec.ts | 33 +- .../transformers/mutant-collector.spec.ts | 4 +- .../instrumenter/app.component.ts.out.snap | 4 +- .../instrumenter/html-sample.html.out.snap | 8 +- .../instrumenter/ignore.js.out.snap | 6 +- .../instrumenter/js-sample.js.out.snap | 8 +- .../instrumenter/lit-html-sample.ts.out.snap | 114 +- .../instrumenter/shebang.js.out.snap | 4 +- .../instrumenter/super-call.ts.out.snap | 4 +- .../instrumenter/switch-case.js.out.snap | 18 +- .../instrumenter/ts-sample.ts.out.snap | 22 +- .../instrumenter/vue-sample.vue.out.snap | 30 +- .../jasmine-init-instrumented.it.spec.ts | 8 +- .../test/unit/jasmine-test-runner.spec.ts | 10 +- .../lib/jasmine_examples/Player.js | 36 +- .../lib/jasmine_examples/Song.js | 8 +- .../react-scripts-ts-jest-config-loader.ts | 45 + .../integration/coverage-analysis.it.spec.ts | 8 +- .../integration/jest-test-runner.it.spec.ts | 12 +- ...eact-scripts-ts-jest-config-loader.spec.ts | 75 + .../test/unit/jest-test-runner.spec.ts | 8 +- .../src/Add.js | 44 +- .../src/Circle.js | 16 +- .../jasmine2-node-instrumented/src/Add.js | 34 +- .../jasmine2-node-instrumented/src/Circle.js | 14 +- .../karma-plugins/test-hooks-middleware.ts | 2 +- .../test/integration/instrumented.it.spec.ts | 28 +- .../test-hooks-middleware.spec.ts | 6 +- .../testResources/instrumented/src/Add.js | 34 +- .../testResources/instrumented/src/Circle.js | 14 +- .../sample-project-instrumented.it.spec.ts | 10 +- .../test/unit/mocha-test-runner.spec.ts | 4 +- .../sample-project-instrumented/MyMath.js | 40 +- packages/test-helpers/package.json | 2 +- packages/test-helpers/src/factory.ts | 133 +- 107 files changed, 2672 insertions(+), 2817 deletions(-) delete mode 100644 packages/api/src/report/matched-mutant.ts delete mode 100644 packages/api/src/report/mutant-result.ts delete mode 100644 packages/api/src/report/mutant-status.ts create mode 100644 packages/core/src/input/index.ts delete mode 100644 packages/core/src/utils/mutant-utils.ts create mode 100644 packages/core/src/utils/string-utils.ts create mode 100644 packages/jest-runner/src/config-loaders/react-scripts-ts-jest-config-loader.ts create mode 100644 packages/jest-runner/test/unit/config-loaders/react-scripts-ts-jest-config-loader.spec.ts diff --git a/e2e/package-lock.json b/e2e/package-lock.json index 7d6be68ac6..70e3d22e30 100644 --- a/e2e/package-lock.json +++ b/e2e/package-lock.json @@ -8895,18 +8895,18 @@ } }, "mutation-testing-metrics": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/mutation-testing-metrics/-/mutation-testing-metrics-1.5.2.tgz", - "integrity": "sha512-KRMBf1tRNh1snwt+5rZu4Le+dgam+GSX+39WfzJG9k55f/+isRn4hv3dhC4Vl/XdlJ29/Z0dTSe7ZFsWBTABUA==", + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/mutation-testing-metrics/-/mutation-testing-metrics-1.6.2.tgz", + "integrity": "sha512-Rhmp/Mvs27RKTJO2cIzViiPN76ERR3CGVNlBZsM0sbdnbIaTuvISlEHFuIZHEQl/+zySX9Z+h/k/b47JxOskiA==", "dev": true, "requires": { - "mutation-testing-report-schema": "^1.5.2" + "mutation-testing-report-schema": "^1.6.0" } }, "mutation-testing-report-schema": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/mutation-testing-report-schema/-/mutation-testing-report-schema-1.5.2.tgz", - "integrity": "sha512-ad90c42vMHa0S4ZZ3e5oZOzGAWg4G8JWto9MrmDkrwInf/Dq+Q8FupCOOTqed0V9FTWqv4sl5arRlYEbedW6Ww==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mutation-testing-report-schema/-/mutation-testing-report-schema-1.6.0.tgz", + "integrity": "sha512-aQlE9Tx7X1MoW2592miQSxPk3oll2GjVCE+0bYWIoSfe9UAKp3TSULd8IDHDXhDgQ4QNSGUARhCObMz3XhNXEw==", "dev": true }, "mz": { diff --git a/e2e/package.json b/e2e/package.json index cfe46a7963..7d8d61acdd 100644 --- a/e2e/package.json +++ b/e2e/package.json @@ -31,7 +31,7 @@ "link-parent-bin": "^2.0.0", "load-grunt-tasks": "~5.1.0", "mocha": "~8.2.0", - "mutation-testing-metrics": "~1.5.2", + "mutation-testing-metrics": "~1.6.2", "rxjs": "~6.5.3", "semver": "~6.3.0", "ts-jest": "~26.3.0", diff --git a/e2e/test/coverage-analysis/verify/verify.ts b/e2e/test/coverage-analysis/verify/verify.ts index 36d9a95ca2..82e652aeb2 100644 --- a/e2e/test/coverage-analysis/verify/verify.ts +++ b/e2e/test/coverage-analysis/verify/verify.ts @@ -59,7 +59,7 @@ describe('Coverage analysis', () => { const stryker = new Stryker(strykerOptions); // Act - const testsRan = (await stryker.runMutationTest()).reduce((a, b) => a + b.nrOfTestsRan, 0); + const testsRan = (await stryker.runMutationTest()).reduce((a, b) => a + (b.testsCompleted ?? 0), 0); // Assert const metricsResult = calculateMetrics(CoverageAnalysisReporter.instance?.report.files); @@ -79,7 +79,7 @@ describe('Coverage analysis', () => { const stryker = new Stryker(strykerOptions); // Act - const testsRan = (await stryker.runMutationTest()).reduce((a, b) => a + b.nrOfTestsRan, 0); + const testsRan = (await stryker.runMutationTest()).reduce((a, b) => a + (b.testsCompleted ?? 0), 0); // Assert const metricsResult = calculateMetrics(CoverageAnalysisReporter.instance?.report.files); @@ -99,7 +99,7 @@ describe('Coverage analysis', () => { const stryker = new Stryker(strykerOptions); // Act - const testsRan = (await stryker.runMutationTest()).reduce((a, b) => a + b.nrOfTestsRan, 0); + const testsRan = (await stryker.runMutationTest()).reduce((a, b) => a + (b.testsCompleted ?? 0), 0); // Assert const metricsResult = calculateMetrics(CoverageAnalysisReporter.instance?.report.files); diff --git a/e2e/test/karma-webpack-with-ts/package-lock.json b/e2e/test/karma-webpack-with-ts/package-lock.json index baa6c30fb4..9530e8f9b0 100644 --- a/e2e/test/karma-webpack-with-ts/package-lock.json +++ b/e2e/test/karma-webpack-with-ts/package-lock.json @@ -23,17 +23,17 @@ "integrity": "sha512-GSJHHXMGLZDzTRq59IUfL9FCdAlGfqNp/dEa7k7aBaaWD+JKaCjsAk9KYm2V12ItonVaYx2dprN66Zdm1AuBTQ==" }, "mutation-testing-metrics": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/mutation-testing-metrics/-/mutation-testing-metrics-1.5.2.tgz", - "integrity": "sha512-KRMBf1tRNh1snwt+5rZu4Le+dgam+GSX+39WfzJG9k55f/+isRn4hv3dhC4Vl/XdlJ29/Z0dTSe7ZFsWBTABUA==", + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/mutation-testing-metrics/-/mutation-testing-metrics-1.6.2.tgz", + "integrity": "sha512-Rhmp/Mvs27RKTJO2cIzViiPN76ERR3CGVNlBZsM0sbdnbIaTuvISlEHFuIZHEQl/+zySX9Z+h/k/b47JxOskiA==", "requires": { - "mutation-testing-report-schema": "^1.5.2" + "mutation-testing-report-schema": "^1.6.0" } }, "mutation-testing-report-schema": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/mutation-testing-report-schema/-/mutation-testing-report-schema-1.5.2.tgz", - "integrity": "sha512-ad90c42vMHa0S4ZZ3e5oZOzGAWg4G8JWto9MrmDkrwInf/Dq+Q8FupCOOTqed0V9FTWqv4sl5arRlYEbedW6Ww==" + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mutation-testing-report-schema/-/mutation-testing-report-schema-1.6.0.tgz", + "integrity": "sha512-aQlE9Tx7X1MoW2592miQSxPk3oll2GjVCE+0bYWIoSfe9UAKp3TSULd8IDHDXhDgQ4QNSGUARhCObMz3XhNXEw==" } } } diff --git a/e2e/test/karma-webpack-with-ts/package.json b/e2e/test/karma-webpack-with-ts/package.json index 5fbca1acb8..1f022191c6 100644 --- a/e2e/test/karma-webpack-with-ts/package.json +++ b/e2e/test/karma-webpack-with-ts/package.json @@ -8,8 +8,8 @@ }, "dependencies": { "lit-element": "~2.3.1", - "mutation-testing-metrics": "~1.5.2", - "mutation-testing-report-schema": "~1.5.2" + "mutation-testing-metrics": "~1.6.2", + "mutation-testing-report-schema": "~1.6.0" }, "devDependencies": { "@types/webpack-env": "~1.15.2" diff --git a/packages/api/package.json b/packages/api/package.json index 0a8e181e47..bdf3cb926f 100644 --- a/packages/api/package.json +++ b/packages/api/package.json @@ -38,7 +38,8 @@ "node": ">=10" }, "dependencies": { - "mutation-testing-report-schema": "~1.5.2", + "mutation-testing-report-schema": "~1.6.0", + "mutation-testing-metrics": "~1.6.2", "surrial": "~2.0.2", "tslib": "~2.1.0" }, diff --git a/packages/api/src/core/index.ts b/packages/api/src/core/index.ts index 4ef67d5724..cfe270ca40 100644 --- a/packages/api/src/core/index.ts +++ b/packages/api/src/core/index.ts @@ -2,10 +2,15 @@ export { File } from './file'; export { Position } from './position'; export { Location } from './location'; export { Range } from './range'; -export { Mutant } from './mutant'; +export * from './mutant'; export * from '../../src-generated/stryker-core'; export * from './report-types'; export * from './stryker-options-schema'; export * from './partial-stryker-options'; export * from './instrument'; export * from './mutant-coverage'; + +/** + * Re-export all members from "mutation-testing-report-schema" under the `schema` key + */ +export * as schema from 'mutation-testing-report-schema'; diff --git a/packages/api/src/core/instrument.ts b/packages/api/src/core/instrument.ts index 3463f72d0a..6153c5f4ec 100644 --- a/packages/api/src/core/instrument.ts +++ b/packages/api/src/core/instrument.ts @@ -12,7 +12,7 @@ export const INSTRUMENTER_CONSTANTS = Object.freeze({ } as const); export interface InstrumenterContext { - activeMutant?: number; + activeMutant?: string; currentTestId?: string; mutantCoverage?: MutantCoverage; } diff --git a/packages/api/src/core/mutant-coverage.ts b/packages/api/src/core/mutant-coverage.ts index c0a2834be8..a62a727501 100644 --- a/packages/api/src/core/mutant-coverage.ts +++ b/packages/api/src/core/mutant-coverage.ts @@ -5,4 +5,7 @@ export interface MutantCoverage { export type CoveragePerTestId = Record; -export type CoverageData = Record; +/** + * Keys are mutant ids, the numbers are the amount of times it was hit. + */ +export type CoverageData = Record; diff --git a/packages/api/src/core/mutant.ts b/packages/api/src/core/mutant.ts index 42ab40c2f4..a79faeb1b9 100644 --- a/packages/api/src/core/mutant.ts +++ b/packages/api/src/core/mutant.ts @@ -1,36 +1,43 @@ +import * as schema from 'mutation-testing-report-schema'; + import { Range } from './range'; -import { Location } from './location'; + +export { MutantStatus } from 'mutation-testing-report-schema'; + +// We're reusing the `MutantResult` interface here to acquire uniformity. /** - * Represents a mutant + * Represents a mutant in its initial state. */ -export interface Mutant { - /** - * The id of the mutant. Unique within a run. - */ - id: number; - /** - * The name of the mutator that generated this mutant. - */ - mutatorName: string; +export interface Mutant extends Pick { /** * The file name from which this mutant originated */ fileName: string; /** * The range of this mutant (from/to within the file) + * deprecate? */ range: Range; /** - * The line number/column location of this mutant - */ - location: Location; - /** - * The replacement (actual mutated code) + * Actual mutation that has been applied. */ replacement: string; /** - * If the mutant was ignored during generation, the reason for ignoring it, otherwise `undefined` + * The status if a mutant if known. This should be undefined for a mutant that still needs testing. */ - ignoreReason?: string; + status?: schema.MutantStatus; } + +/** + * Represents a mutant in its matched-with-the-tests state, ready to be tested. + */ +export type MutantTestCoverage = Mutant & + Pick & { + estimatedNetTime: number; + }; + +/** + * Represents a mutant in its final state, ready to be reported. + */ +export type MutantResult = Mutant & schema.MutantResult; diff --git a/packages/api/src/report/index.ts b/packages/api/src/report/index.ts index 79074321bd..79b8b0ab06 100644 --- a/packages/api/src/report/index.ts +++ b/packages/api/src/report/index.ts @@ -1,14 +1,2 @@ -import * as mutationTestReportSchema from 'mutation-testing-report-schema'; - export { Reporter } from './reporter'; -export * from './mutant-result'; -export { MutantStatus } from './mutant-status'; export { SourceFile } from './source-file'; -export { MatchedMutant } from './matched-mutant'; -export { - /** - * Types exported directly from mutation-testing-schema - * @see https://github.com/stryker-mutator/mutation-testing-elements/tree/master/packages/mutation-testing-report-schema - */ - mutationTestReportSchema, -}; diff --git a/packages/api/src/report/matched-mutant.ts b/packages/api/src/report/matched-mutant.ts deleted file mode 100644 index fa2aa8925b..0000000000 --- a/packages/api/src/report/matched-mutant.ts +++ /dev/null @@ -1,30 +0,0 @@ -export interface MatchedMutant { - /** - * The ID of the mutant - */ - readonly id: string; - /** - * The Mutator name - */ - readonly mutatorName: string; - /** - * Whether or not all tests will run for this mutant - */ - readonly runAllTests: boolean; - /** - * If not all tests will run for this mutant, this array will contain the ids of the tests that will run. - */ - readonly testFilter: string[] | undefined; - /** - * The time spent on the tests that will run in initial test run - */ - readonly timeSpentScopedTests: number; - /** - * The file name that contains the mutant - */ - readonly fileName: string; - /** - * The replacement code to be inserted - */ - readonly replacement: string; -} diff --git a/packages/api/src/report/mutant-result.ts b/packages/api/src/report/mutant-result.ts deleted file mode 100644 index 9c8cbae420..0000000000 --- a/packages/api/src/report/mutant-result.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { Location, Range } from '../core'; - -import { MutantStatus } from './mutant-status'; - -export interface BaseMutantResult { - id: string; - fileName: string; - mutatorName: string; - replacement: string; - originalLines: string; - mutatedLines: string; - nrOfTestsRan: number; - location: Location; - range: Range; -} - -export interface KilledMutantResult extends BaseMutantResult { - status: MutantStatus.Killed; - killedBy: string; -} - -export interface InvalidMutantResult extends BaseMutantResult { - status: MutantStatus.CompileError | MutantStatus.RuntimeError; - errorMessage: string; -} - -export interface IgnoredMutantResult extends BaseMutantResult { - status: MutantStatus.Ignored; - ignoreReason: string; -} - -export interface UndetectedMutantResult extends BaseMutantResult { - status: MutantStatus.NoCoverage | MutantStatus.Survived; - testFilter: string[] | undefined; -} - -export interface TimeoutMutantResult extends BaseMutantResult { - status: MutantStatus.TimedOut; -} - -export type MutantResult = IgnoredMutantResult | InvalidMutantResult | KilledMutantResult | TimeoutMutantResult | UndetectedMutantResult; diff --git a/packages/api/src/report/mutant-status.ts b/packages/api/src/report/mutant-status.ts deleted file mode 100644 index 61bb8527bf..0000000000 --- a/packages/api/src/report/mutant-status.ts +++ /dev/null @@ -1,44 +0,0 @@ -export enum MutantStatus { - /** - * The status of a survived mutant, because it was not covered by any test. - */ - NoCoverage, - - /** - * The status of a killed mutant. - */ - Killed, - - /** - * The status of a survived mutant. - */ - Survived, - - /** - * The status of a timed out mutant. - */ - TimedOut, - - /** - * The status of a mutant of which the tests resulted in a runtime error. - * @example - * ```javascript - * const fs = require('f' - 's'); // mutated code - * ``` - */ - RuntimeError, - - /** - * The status of a mutant which could not be compiled. - * @example - * ```typescript - * const foo = 'foo' - 'bar'; // mutated code - * ``` - */ - CompileError, - - /** - * The status of a mutant that is ignored. For example, by user configuration. - */ - Ignored, -} diff --git a/packages/api/src/report/reporter.ts b/packages/api/src/report/reporter.ts index 39db07bf5c..64e5ed8e14 100644 --- a/packages/api/src/report/reporter.ts +++ b/packages/api/src/report/reporter.ts @@ -1,7 +1,7 @@ -import { MutationTestResult } from 'mutation-testing-report-schema'; +import { MutationTestMetricsResult } from 'mutation-testing-metrics'; + +import { MutantResult, MutantTestCoverage, schema } from '../core'; -import { MatchedMutant } from './matched-mutant'; -import { MutantResult } from './mutant-result'; import { SourceFile } from './source-file'; /** @@ -12,38 +12,38 @@ export interface Reporter { * Called when a source file was loaded * @param file The immutable source file */ - onSourceFileRead?(file: SourceFile): void; + onSourceFileRead?(file: Readonly): void; /** * Called when all source files were loaded * @param files The immutable source files */ - onAllSourceFilesRead?(files: SourceFile[]): void; + onAllSourceFilesRead?(files: ReadonlyArray>): void; /** * Called when mutants are matched with tests * @param results The immutable array of mutants */ - onAllMutantsMatchedWithTests?(results: readonly MatchedMutant[]): void; + onAllMutantsMatchedWithTests?(results: ReadonlyArray>): void; /** * Called when a mutant was tested * @param result The immutable result */ - onMutantTested?(result: MutantResult): void; + onMutantTested?(result: Readonly): void; /** * Called when all mutants were tested * @param results The immutable results */ - onAllMutantsTested?(results: MutantResult[]): void; + onAllMutantsTested?(results: ReadonlyArray>): void; /** * Called when mutation testing is done * @param report the mutation test result that is valid according to the mutation-testing-report-schema (json schema) * @see https://github.com/stryker-mutator/mutation-testing-elements/tree/master/packages/mutation-testing-report-schema#mutation-testing-elements-schema */ - onMutationTestReportReady?(report: MutationTestResult): void; + onMutationTestReportReady?(report: Readonly, metrics: Readonly): void; /** * Called when stryker wants to quit @@ -51,5 +51,5 @@ export interface Reporter { * Stryker will not close until the promise is either resolved or rejected. * @return a promise which will resolve when the reporter is done reporting */ - wrapUp?(): Promise | Promise | void; + wrapUp?(): Promise | void; } diff --git a/packages/api/src/test-runner/test-result.ts b/packages/api/src/test-runner/test-result.ts index e7f286ad1a..19e4f10834 100644 --- a/packages/api/src/test-runner/test-result.ts +++ b/packages/api/src/test-runner/test-result.ts @@ -3,7 +3,7 @@ import { TestStatus } from './test-status'; /** * Indicates the result of a single test */ -interface BaseTestResult { +export interface BaseTestResult { /** * The id of this test. Can be the name if the test runner doesn't have an 'id' */ diff --git a/packages/api/test/unit/plugin/plugins.spec.ts b/packages/api/test/unit/plugin/plugins.spec.ts index f856418c5a..4f20e3d0f7 100644 --- a/packages/api/test/unit/plugin/plugins.spec.ts +++ b/packages/api/test/unit/plugin/plugins.spec.ts @@ -2,7 +2,7 @@ import { expect } from 'chai'; import { tokens, commonTokens, PluginKind, declareClassPlugin, declareFactoryPlugin } from '../../../src/plugin'; import { Logger } from '../../../logging'; -import { MutantResult } from '../../../report'; +import { MutantResult } from '../../../core'; describe('plugins', () => { describe(declareClassPlugin.name, () => { diff --git a/packages/core/package.json b/packages/core/package.json index 6734d5229e..bcd4415fc6 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -71,8 +71,8 @@ "log4js": "~6.2.1", "minimatch": "~3.0.4", "mkdirp": "~1.0.3", - "mutation-testing-elements": "~1.5.2", - "mutation-testing-metrics": "~1.5.2", + "mutation-testing-elements": "~1.6.2", + "mutation-testing-metrics": "~1.6.2", "npm-run-path": "~4.0.1", "progress": "~2.0.0", "rimraf": "~3.0.0", diff --git a/packages/core/src/child-proxy/child-process-proxy-worker.ts b/packages/core/src/child-proxy/child-process-proxy-worker.ts index 25edc49ca6..5f49e0f06e 100644 --- a/packages/core/src/child-proxy/child-process-proxy-worker.ts +++ b/packages/core/src/child-proxy/child-process-proxy-worker.ts @@ -6,7 +6,7 @@ import { getLogger, Logger } from 'log4js'; import { buildChildProcessInjector } from '../di'; import { LogConfigurator } from '../logging'; -import { deserialize, serialize } from '../utils/object-utils'; +import { deserialize, serialize } from '../utils/string-utils'; import { autoStart, CallMessage, ParentMessage, ParentMessageKind, WorkerMessage, WorkerMessageKind, InitMessage } from './message-protocol'; diff --git a/packages/core/src/child-proxy/child-process-proxy.ts b/packages/core/src/child-proxy/child-process-proxy.ts index 6eb020ca31..de95145a83 100644 --- a/packages/core/src/child-proxy/child-process-proxy.ts +++ b/packages/core/src/child-proxy/child-process-proxy.ts @@ -8,9 +8,11 @@ import { getLogger } from 'log4js'; import { Disposable, InjectableClass, InjectionToken } from 'typed-inject'; import { LoggingClientContext } from '../logging'; -import { deserialize, kill, padLeft, serialize } from '../utils/object-utils'; +import { kill } from '../utils/object-utils'; import { StringBuilder } from '../utils/string-builder'; +import { deserialize, padLeft, serialize } from '../utils/string-utils'; + import { ChildProcessCrashedError } from './child-process-crashed-error'; import { autoStart, ParentMessage, ParentMessageKind, WorkerMessage, WorkerMessageKind } from './message-protocol'; import { OutOfMemoryError } from './out-of-memory-error'; diff --git a/packages/core/src/input/index.ts b/packages/core/src/input/index.ts new file mode 100644 index 0000000000..fe45b919a7 --- /dev/null +++ b/packages/core/src/input/index.ts @@ -0,0 +1,2 @@ +export { InputFileCollection } from './input-file-collection'; +export { InputFileResolver } from './input-file-resolver'; diff --git a/packages/core/src/mutants/find-mutant-test-coverage.ts b/packages/core/src/mutants/find-mutant-test-coverage.ts index 01cfdf7c24..0f2fae51e5 100644 --- a/packages/core/src/mutants/find-mutant-test-coverage.ts +++ b/packages/core/src/mutants/find-mutant-test-coverage.ts @@ -1,21 +1,12 @@ import { CompleteDryRunResult, TestResult } from '@stryker-mutator/api/test-runner'; -import { Mutant, CoveragePerTestId } from '@stryker-mutator/api/core'; +import { Mutant, CoveragePerTestId, MutantTestCoverage } from '@stryker-mutator/api/core'; import { commonTokens, tokens } from '@stryker-mutator/api/plugin'; -import { MatchedMutant } from '@stryker-mutator/api/report'; - import { Logger } from '@stryker-mutator/api/logging'; import { coreTokens } from '../di'; import { StrictReporter } from '../reporters/strict-reporter'; -export interface MutantTestCoverage { - estimatedNetTime: number; - coveredByTests: boolean; - testFilter?: string[]; - mutant: Mutant; -} - findMutantTestCoverage.inject = tokens(coreTokens.dryRunResult, coreTokens.mutants, coreTokens.reporter, commonTokens.logger); export function findMutantTestCoverage( dryRunResult: CompleteDryRunResult, @@ -24,64 +15,57 @@ export function findMutantTestCoverage( logger: Logger ): MutantTestCoverage[] { const mutantTestCoverage = mapToMutantTestCoverage(dryRunResult, mutants, logger); - reporter.onAllMutantsMatchedWithTests(mutantTestCoverage.map(toMatchedMutant)); + reporter.onAllMutantsMatchedWithTests(mutantTestCoverage); return mutantTestCoverage; } -function toMatchedMutant({ mutant, testFilter, coveredByTests, estimatedNetTime }: MutantTestCoverage): MatchedMutant { - return { - fileName: mutant.fileName, - id: mutant.id.toString(), - mutatorName: mutant.mutatorName, - replacement: mutant.replacement, - runAllTests: !testFilter && coveredByTests, - testFilter: testFilter, - timeSpentScopedTests: estimatedNetTime, - }; -} - -function mapToMutantTestCoverage(dryRunResult: CompleteDryRunResult, mutants: readonly Mutant[], logger: Logger) { +function mapToMutantTestCoverage(dryRunResult: CompleteDryRunResult, mutants: readonly Mutant[], logger: Logger): MutantTestCoverage[] { const testsByMutantId = findTestsByMutant(dryRunResult.mutantCoverage?.perTest, dryRunResult.tests, logger); const timeSpentAllTests = calculateTotalTime(dryRunResult.tests); - const mutantCoverage = mutants.map((mutant) => { - if (mutant.ignoreReason !== undefined) { - return { - mutant, - estimatedNetTime: 0, - coveredByTests: false, - }; - } else if (!dryRunResult.mutantCoverage || dryRunResult.mutantCoverage.static[mutant.id] > 0) { - return { - mutant, - estimatedNetTime: timeSpentAllTests, - testFilter: undefined, - coveredByTests: true, - }; - } else { - const tests = testsByMutantId.get(mutant.id); - if (tests && tests.size > 0) { + const mutantCoverage = mutants.map( + (mutant): MutantTestCoverage => { + if (mutant.status) { return { - mutant, - estimatedNetTime: calculateTotalTime(tests), - testFilter: toTestIds(tests), - coveredByTests: true, + ...mutant, + static: false, + estimatedNetTime: 0, }; - } else { + } else if (!dryRunResult.mutantCoverage || dryRunResult.mutantCoverage.static[mutant.id] > 0) { + // When there is static coverage for this mutant, it is a static mutant. return { - mutant, - estimatedNetTime: 0, - testFilter: undefined, - coveredByTests: false, + ...mutant, + estimatedNetTime: timeSpentAllTests, + coveredBy: undefined, + static: true, }; + } else { + // If no static coverage, but there is test coverage, it is a non-static, covered mutant + const tests = testsByMutantId.get(mutant.id); + if (tests && tests.size > 0) { + return { + ...mutant, + estimatedNetTime: calculateTotalTime(tests), + coveredBy: toTestIds(tests), + static: false, + }; + } else { + // Otherwise it is has no coverage + return { + ...mutant, + estimatedNetTime: 0, + coveredBy: [], + static: false, + }; + } } } - }); + ); return mutantCoverage; } function findTestsByMutant(coveragePerTest: CoveragePerTestId | undefined, allTests: TestResult[], logger: Logger) { - const testsByMutantId = new Map>(); + const testsByMutantId = new Map>(); coveragePerTest && Object.entries(coveragePerTest).forEach(([testId, mutantCoverage]) => { const foundTest = allTests.find((test) => test.id === testId); @@ -91,9 +75,8 @@ function findTestsByMutant(coveragePerTest: CoveragePerTestId | undefined, allTe ); return; } - Object.entries(mutantCoverage).forEach(([mutantIdAsString, count]) => { + Object.entries(mutantCoverage).forEach(([mutantId, count]) => { if (count) { - const mutantId = parseInt(mutantIdAsString, 10); let tests = testsByMutantId.get(mutantId); if (!tests) { tests = new Set(); diff --git a/packages/core/src/process/1-prepare-executor.ts b/packages/core/src/process/1-prepare-executor.ts index e5ff696555..83d7637136 100644 --- a/packages/core/src/process/1-prepare-executor.ts +++ b/packages/core/src/process/1-prepare-executor.ts @@ -3,7 +3,7 @@ import { commonTokens, Injector, tokens } from '@stryker-mutator/api/plugin'; import { LogConfigurator } from '../logging'; import { buildMainInjector, coreTokens, CliOptionsProvider } from '../di'; -import { InputFileResolver } from '../input/input-file-resolver'; +import { InputFileResolver } from '../input'; import { ConfigError } from '../errors'; import { MutantInstrumenterContext } from '.'; diff --git a/packages/core/src/process/4-mutation-test-executor.ts b/packages/core/src/process/4-mutation-test-executor.ts index 6b9df150c3..2172aa5880 100644 --- a/packages/core/src/process/4-mutation-test-executor.ts +++ b/packages/core/src/process/4-mutation-test-executor.ts @@ -1,8 +1,7 @@ import { from, partition, merge, Observable } from 'rxjs'; import { toArray, map, tap, shareReplay } from 'rxjs/operators'; import { tokens, commonTokens } from '@stryker-mutator/api/plugin'; -import { StrykerOptions } from '@stryker-mutator/api/core'; -import { MutantResult } from '@stryker-mutator/api/report'; +import { MutantTestCoverage, MutantResult, StrykerOptions, MutantStatus } from '@stryker-mutator/api/core'; import { MutantRunOptions, TestRunner } from '@stryker-mutator/api/test-runner'; import { Logger } from '@stryker-mutator/api/logging'; import { I } from '@stryker-mutator/util'; @@ -10,7 +9,6 @@ import { CheckStatus, Checker, CheckResult, PassedCheckResult } from '@stryker-m import { coreTokens } from '../di'; import { StrictReporter } from '../reporters/strict-reporter'; -import { MutantTestCoverage } from '../mutants/find-mutant-test-coverage'; import { MutationTestReportHelper } from '../reporters/mutation-test-report-helper'; import { Timer } from '../utils/timer'; import { Pool, ConcurrencyTokenProvider } from '../concurrent'; @@ -67,21 +65,26 @@ export class MutationTestExecutor { } private executeIgnore(input$: Observable) { - const [notIgnoredMutant$, ignoredMutant$] = partition(input$.pipe(shareReplay()), ({ mutant }) => mutant.ignoreReason === undefined); - const ignoredResult$ = ignoredMutant$.pipe(map(({ mutant }) => this.mutationTestReportHelper.reportMutantIgnored(mutant))); + const [ignoredMutant$, notIgnoredMutant$] = partition(input$.pipe(shareReplay()), (mutant) => mutant.status === MutantStatus.Ignored); + const ignoredResult$ = ignoredMutant$.pipe(map((mutant) => this.mutationTestReportHelper.reportMutantStatus(mutant, MutantStatus.Ignored))); return { ignoredResult$, notIgnoredMutant$ }; } private executeNoCoverage(input$: Observable) { - const [coveredMutant$, noCoverageMatchedMutant$] = partition(input$.pipe(shareReplay()), (matchedMutant) => matchedMutant.coveredByTests); - const noCoverageResult$ = noCoverageMatchedMutant$.pipe(map(({ mutant }) => this.mutationTestReportHelper.reportNoCoverage(mutant))); + const [noCoverageMatchedMutant$, coveredMutant$] = partition( + input$.pipe(shareReplay()), + (mutant) => !mutant.static && (mutant.coveredBy?.length ?? 0) === 0 + ); + const noCoverageResult$ = noCoverageMatchedMutant$.pipe( + map((mutant) => this.mutationTestReportHelper.reportMutantStatus(mutant, MutantStatus.NoCoverage)) + ); return { noCoverageResult$, coveredMutant$ }; } private executeCheck(input$: Observable) { const checkTask$ = this.checkerPool .schedule(input$, async (checker, mutant) => { - const checkResult = await checker.check(mutant.mutant); + const checkResult = await checker.check(mutant); return { checkResult, mutant, @@ -101,10 +104,7 @@ export class MutationTestExecutor { const [passedCheckResult$, failedCheckResult$] = partition(checkTask$, ({ checkResult }) => checkResult.status === CheckStatus.Passed); const checkResult$ = failedCheckResult$.pipe( map((failedMutant) => - this.mutationTestReportHelper.reportCheckFailed( - failedMutant.mutant.mutant, - failedMutant.checkResult as Exclude - ) + this.mutationTestReportHelper.reportCheckFailed(failedMutant.mutant, failedMutant.checkResult as Exclude) ) ); const passedMutant$ = passedCheckResult$.pipe(map(({ mutant }) => mutant)); @@ -119,13 +119,13 @@ export class MutationTestExecutor { }); } - private createMutantRunOptions(mutant: MutantTestCoverage): MutantRunOptions { - const timeout = this.options.timeoutFactor * mutant.estimatedNetTime + this.options.timeoutMS + this.timeOverheadMS; + private createMutantRunOptions(activeMutant: MutantTestCoverage): MutantRunOptions { + const timeout = this.options.timeoutFactor * activeMutant.estimatedNetTime + this.options.timeoutMS + this.timeOverheadMS; return { - activeMutant: mutant.mutant, - timeout: timeout, - testFilter: mutant.testFilter, - sandboxFileName: this.sandbox.sandboxFileFor(mutant.mutant.fileName), + activeMutant, + timeout, + testFilter: activeMutant.coveredBy, + sandboxFileName: this.sandbox.sandboxFileFor(activeMutant.fileName), }; } diff --git a/packages/core/src/reporters/broadcast-reporter.ts b/packages/core/src/reporters/broadcast-reporter.ts index 6e3ac5b3fd..8378fb48d3 100644 --- a/packages/core/src/reporters/broadcast-reporter.ts +++ b/packages/core/src/reporters/broadcast-reporter.ts @@ -1,7 +1,8 @@ -import { StrykerOptions } from '@stryker-mutator/api/core'; +import { MutantTestCoverage, MutantResult, schema, StrykerOptions } from '@stryker-mutator/api/core'; import { Logger } from '@stryker-mutator/api/logging'; import { commonTokens, PluginKind } from '@stryker-mutator/api/plugin'; -import { MatchedMutant, MutantResult, mutationTestReportSchema, Reporter, SourceFile } from '@stryker-mutator/api/report'; +import { Reporter, SourceFile } from '@stryker-mutator/api/report'; +import { MutationTestMetricsResult } from 'mutation-testing-metrics'; import { tokens } from 'typed-inject'; import { coreTokens } from '../di'; @@ -42,13 +43,12 @@ export class BroadcastReporter implements StrictReporter { } } - private broadcast(methodName: keyof Reporter, eventArgs: any): Promise { + private broadcast(methodName: TMethod, ...eventArgs: Parameters[TMethod]>): Promise { return Promise.all( - Object.keys(this.reporters).map(async (reporterName) => { - const reporter = this.reporters[reporterName]; - if (typeof reporter[methodName] === 'function') { + Object.entries(this.reporters).map(async ([reporterName, reporter]) => { + if (reporter[methodName]) { try { - await (reporter[methodName] as any)(eventArgs); + await (reporter[methodName] as (...args: Parameters[TMethod]>) => Promise | void)!(...eventArgs); } catch (error) { this.handleError(error, methodName, reporterName); } @@ -65,7 +65,7 @@ export class BroadcastReporter implements StrictReporter { this.broadcast('onAllSourceFilesRead', files); } - public onAllMutantsMatchedWithTests(results: readonly MatchedMutant[]): void { + public onAllMutantsMatchedWithTests(results: readonly MutantTestCoverage[]): void { this.broadcast('onAllMutantsMatchedWithTests', results); } @@ -77,12 +77,12 @@ export class BroadcastReporter implements StrictReporter { this.broadcast('onAllMutantsTested', results); } - public onMutationTestReportReady(report: mutationTestReportSchema.MutationTestResult): void { - this.broadcast('onMutationTestReportReady', report); + public onMutationTestReportReady(report: schema.MutationTestResult, metrics: MutationTestMetricsResult): void { + this.broadcast('onMutationTestReportReady', report, metrics); } public async wrapUp(): Promise { - await this.broadcast('wrapUp', undefined); + await this.broadcast('wrapUp'); } private handleError(error: Error, methodName: string, reporterName: string) { diff --git a/packages/core/src/reporters/clear-text-reporter.ts b/packages/core/src/reporters/clear-text-reporter.ts index c5890ff1b8..5e1406d2eb 100644 --- a/packages/core/src/reporters/clear-text-reporter.ts +++ b/packages/core/src/reporters/clear-text-reporter.ts @@ -1,15 +1,19 @@ import os from 'os'; import chalk from 'chalk'; -import { Position, StrykerOptions } from '@stryker-mutator/api/core'; +import { schema, Position, StrykerOptions } from '@stryker-mutator/api/core'; import { Logger } from '@stryker-mutator/api/logging'; import { commonTokens } from '@stryker-mutator/api/plugin'; -import { MutantResult, MutantStatus, mutationTestReportSchema, Reporter, UndetectedMutantResult } from '@stryker-mutator/api/report'; -import { calculateMetrics } from 'mutation-testing-metrics'; +import { Reporter } from '@stryker-mutator/api/report'; +import { MetricsResult, MutantModel, TestModel, MutationTestMetricsResult } from 'mutation-testing-metrics'; import { tokens } from 'typed-inject'; +import { plural } from '../utils/string-utils'; + import { ClearTextScoreTable } from './clear-text-score-table'; +const { MutantStatus } = schema; + export class ClearTextReporter implements Reporter { public static inject = tokens(commonTokens.logger, commonTokens.options); constructor(private readonly log: Logger, private readonly options: StrykerOptions) { @@ -28,7 +32,12 @@ export class ClearTextReporter implements Reporter { } } - public onAllMutantsTested(mutantResults: MutantResult[]): void { + public onMutationTestReportReady(_report: schema.MutationTestResult, metrics: MutationTestMetricsResult): void { + this.reportAllMutants(metrics); + this.writeLine(new ClearTextScoreTable(metrics.systemUnderTestMetrics, this.options.thresholds).draw()); + } + + private reportAllMutants({ systemUnderTestMetrics }: MutationTestMetricsResult): void { this.writeLine(); let totalTests = 0; @@ -36,47 +45,61 @@ export class ClearTextReporter implements Reporter { const logDebugFn = (input: string) => this.log.debug(input); const writeLineFn = (input: string) => this.writeLine(input); - mutantResults.forEach((result) => { - totalTests += result.nrOfTestsRan; - switch (result.status) { - case MutantStatus.Killed: - case MutantStatus.TimedOut: - case MutantStatus.RuntimeError: - case MutantStatus.CompileError: - this.logMutantResult(result, logDebugFn); - break; - case MutantStatus.Survived: - case MutantStatus.NoCoverage: - this.logMutantResult(result, writeLineFn); - break; - default: - } - }); - this.writeLine(`Ran ${(totalTests / mutantResults.length).toFixed(2)} tests per mutant on average.`); + const reportMutants = (metrics: MetricsResult[]) => { + metrics.forEach((child) => { + child.file?.mutants.forEach((result) => { + totalTests += result.testsCompleted ?? 0; + switch (result.status) { + case MutantStatus.Killed: + case MutantStatus.Timeout: + case MutantStatus.RuntimeError: + case MutantStatus.CompileError: + this.reportMutantResult(result, logDebugFn); + break; + case MutantStatus.Survived: + case MutantStatus.NoCoverage: + this.reportMutantResult(result, writeLineFn); + break; + default: + } + }); + reportMutants(child.childResults); + }); + }; + reportMutants(systemUnderTestMetrics.childResults); + this.writeLine(`Ran ${(totalTests / systemUnderTestMetrics.metrics.totalMutants).toFixed(2)} tests per mutant on average.`); } - private logMutantResult(result: MutantResult, logImplementation: (input: string) => void): void { + private reportMutantResult(result: MutantModel, logImplementation: (input: string) => void): void { logImplementation(`#${result.id}. [${MutantStatus[result.status]}] ${result.mutatorName}`); logImplementation(this.colorSourceFileAndLocation(result.fileName, result.location.start)); - result.originalLines.split('\n').forEach((line) => { - logImplementation(chalk.red('- ' + line)); - }); - result.mutatedLines.split('\n').forEach((line) => { - logImplementation(chalk.green('+ ' + line)); - }); - logImplementation(''); + result + .getOriginalLines() + .split('\n') + .filter(Boolean) + .forEach((line) => { + logImplementation(chalk.red('- ' + line)); + }); + result + .getMutatedLines() + .split('\n') + .filter(Boolean) + .forEach((line) => { + logImplementation(chalk.green('+ ' + line)); + }); if (result.status === MutantStatus.Survived) { - if (this.options.coverageAnalysis === 'perTest' && result.testFilter) { - this.logExecutedTests(result, logImplementation); - } else { + if (result.static) { logImplementation('Ran all tests for this mutant.'); + } else if (result.coveredByTests) { + this.logExecutedTests(result.coveredByTests, logImplementation); } - } else if (result.status === MutantStatus.Killed) { - logImplementation(`Killed by: ${result.killedBy}`); + } else if (result.status === MutantStatus.Killed && result.killedByTests && result.killedByTests.length) { + logImplementation(`Killed by: ${result.killedByTests[0].name}`); } else if (result.status === MutantStatus.RuntimeError || result.status === MutantStatus.CompileError) { - logImplementation(`Error message: ${result.errorMessage}`); + logImplementation(`Error message: ${result.statusReason}`); } + logImplementation(''); } private colorSourceFileAndLocation(fileName: string, position: Position): string { @@ -87,34 +110,23 @@ export class ClearTextReporter implements Reporter { return [chalk.cyan(fileName), chalk.yellow(`${position.line}`), chalk.yellow(`${position.column}`)].join(':'); } - private logExecutedTests(result: UndetectedMutantResult, logImplementation: (input: string) => void) { + private logExecutedTests(tests: TestModel[], logImplementation: (input: string) => void) { if (!this.options.clearTextReporter.logTests) { return; } - if (result.nrOfTestsRan > 0) { - const { maxTestsToLog } = this.options.clearTextReporter; + const testCount = Math.min(this.options.clearTextReporter.maxTestsToLog, tests.length); - if (maxTestsToLog > 0) { - logImplementation('Tests ran:'); - for (let i = 0; i < maxTestsToLog; i++) { - if (i > result.testFilter!.length - 1) { - break; - } - logImplementation(` ${result.testFilter![i]}`); - } - const diff = result.testFilter!.length - maxTestsToLog; - if (diff > 0) { - const plural = diff === 1 ? '' : 's'; - logImplementation(` and ${diff} more test${plural}!`); - } - logImplementation(''); + if (testCount > 0) { + logImplementation('Tests ran:'); + tests.slice(0, testCount).forEach((test) => { + logImplementation(` ${test.name}`); + }); + const diff = tests.length - this.options.clearTextReporter.maxTestsToLog; + if (diff > 0) { + logImplementation(` and ${diff} more test${plural(diff)}!`); } + logImplementation(''); } } - - public onMutationTestReportReady(report: mutationTestReportSchema.MutationTestResult): void { - const metricsResult = calculateMetrics(report.files); - this.writeLine(new ClearTextScoreTable(metricsResult, this.options.thresholds).draw()); - } } diff --git a/packages/core/src/reporters/dashboard-reporter/dashboard-reporter.ts b/packages/core/src/reporters/dashboard-reporter/dashboard-reporter.ts index 65df2ef0b5..9b5a3e52bb 100644 --- a/packages/core/src/reporters/dashboard-reporter/dashboard-reporter.ts +++ b/packages/core/src/reporters/dashboard-reporter/dashboard-reporter.ts @@ -1,8 +1,8 @@ -import { StrykerOptions, ReportType } from '@stryker-mutator/api/core'; +import { StrykerOptions, ReportType, schema } from '@stryker-mutator/api/core'; import { Logger } from '@stryker-mutator/api/logging'; import { commonTokens, tokens } from '@stryker-mutator/api/plugin'; -import { mutationTestReportSchema, Reporter } from '@stryker-mutator/api/report'; -import { calculateMetrics } from 'mutation-testing-metrics'; +import { Reporter } from '@stryker-mutator/api/report'; +import { MutationTestMetricsResult } from 'mutation-testing-metrics'; import { CIProvider } from '../ci/provider'; @@ -27,11 +27,11 @@ export class DashboardReporter implements Reporter { private onGoingWork: Promise | undefined; - public onMutationTestReportReady(result: mutationTestReportSchema.MutationTestResult): void { + public onMutationTestReportReady(result: schema.MutationTestResult, metrics: MutationTestMetricsResult): void { this.onGoingWork = (async () => { const { projectName, version, moduleName } = this.getContextFromEnvironment(); if (projectName && version) { - await this.update(this.toReport(result), projectName, version, moduleName); + await this.update(this.toReport(result, metrics), projectName, version, moduleName); } else { this.log.info( 'The report was not send to the dashboard. The dashboard.project and/or dashboard.version values were missing and not detected to be running on a build server.' @@ -44,12 +44,12 @@ export class DashboardReporter implements Reporter { await this.onGoingWork; } - private toReport(result: mutationTestReportSchema.MutationTestResult): Report { + private toReport(result: schema.MutationTestResult, metrics: MutationTestMetricsResult): Report { if (this.options.dashboard.reportType === ReportType.Full) { return result; } else { return { - mutationScore: calculateMetrics(result.files).metrics.mutationScore, + mutationScore: metrics.systemUnderTestMetrics.metrics.mutationScore, }; } } diff --git a/packages/core/src/reporters/dashboard-reporter/report.ts b/packages/core/src/reporters/dashboard-reporter/report.ts index 6abf439fb3..2cb5d6fe08 100644 --- a/packages/core/src/reporters/dashboard-reporter/report.ts +++ b/packages/core/src/reporters/dashboard-reporter/report.ts @@ -1,6 +1,6 @@ -import { mutationTestReportSchema } from '@stryker-mutator/api/report'; +import { schema } from '@stryker-mutator/api/core'; export interface MutationScoreOnlyReport { mutationScore: number; } -export type Report = MutationScoreOnlyReport | mutationTestReportSchema.MutationTestResult; +export type Report = MutationScoreOnlyReport | schema.MutationTestResult; diff --git a/packages/core/src/reporters/dots-reporter.ts b/packages/core/src/reporters/dots-reporter.ts index 59783fa4c7..ae8bee8b60 100644 --- a/packages/core/src/reporters/dots-reporter.ts +++ b/packages/core/src/reporters/dots-reporter.ts @@ -1,8 +1,8 @@ import os from 'os'; -import { MutantResult, MutantStatus, Reporter } from '@stryker-mutator/api/report'; - import chalk from 'chalk'; +import { Reporter } from '@stryker-mutator/api/report'; +import { MutantResult, MutantStatus } from '@stryker-mutator/api/core'; export class DotsReporter implements Reporter { public onMutantTested(result: MutantResult): void { @@ -11,7 +11,7 @@ export class DotsReporter implements Reporter { case MutantStatus.Killed: toLog = '.'; break; - case MutantStatus.TimedOut: + case MutantStatus.Timeout: toLog = chalk.yellow('T'); break; case MutantStatus.Survived: diff --git a/packages/core/src/reporters/event-recorder-reporter.ts b/packages/core/src/reporters/event-recorder-reporter.ts index 4be8f5981b..be285ad9d3 100644 --- a/packages/core/src/reporters/event-recorder-reporter.ts +++ b/packages/core/src/reporters/event-recorder-reporter.ts @@ -1,10 +1,10 @@ import path from 'path'; import { promises as fsPromises } from 'fs'; -import { StrykerOptions } from '@stryker-mutator/api/core'; +import { MutantResult, MutantTestCoverage, schema, StrykerOptions } from '@stryker-mutator/api/core'; import { Logger } from '@stryker-mutator/api/logging'; import { commonTokens, tokens } from '@stryker-mutator/api/plugin'; -import { MatchedMutant, MutantResult, mutationTestReportSchema, Reporter, SourceFile } from '@stryker-mutator/api/report'; +import { Reporter, SourceFile } from '@stryker-mutator/api/report'; import { cleanFolder } from '../utils/file-utils'; @@ -49,7 +49,7 @@ export class EventRecorderReporter implements StrictReporter { this.work('onAllSourceFilesRead', files); } - public onAllMutantsMatchedWithTests(results: readonly MatchedMutant[]): void { + public onAllMutantsMatchedWithTests(results: MutantTestCoverage[]): void { this.work('onAllMutantsMatchedWithTests', results); } @@ -57,7 +57,7 @@ export class EventRecorderReporter implements StrictReporter { this.work('onMutantTested', result); } - public onMutationTestReportReady(report: mutationTestReportSchema.MutationTestResult): void { + public onMutationTestReportReady(report: schema.MutationTestResult): void { this.work('onMutationTestReportReady', report); } @@ -65,8 +65,8 @@ export class EventRecorderReporter implements StrictReporter { this.work('onAllMutantsTested', results); } - public async wrapUp(): Promise { + public async wrapUp(): Promise { await this.createBaseFolderTask; - return Promise.all(this.allWork); + await Promise.all(this.allWork); } } diff --git a/packages/core/src/reporters/html/html-reporter.ts b/packages/core/src/reporters/html/html-reporter.ts index 7c653ef0d3..a9c1474664 100644 --- a/packages/core/src/reporters/html/html-reporter.ts +++ b/packages/core/src/reporters/html/html-reporter.ts @@ -1,10 +1,10 @@ import path from 'path'; import fileUrl from 'file-url'; -import { StrykerOptions } from '@stryker-mutator/api/core'; +import { schema, StrykerOptions } from '@stryker-mutator/api/core'; import { Logger } from '@stryker-mutator/api/logging'; import { commonTokens, tokens } from '@stryker-mutator/api/plugin'; -import { mutationTestReportSchema, Reporter } from '@stryker-mutator/api/report'; +import { Reporter } from '@stryker-mutator/api/report'; import * as ReporterUtil from '../reporter-util'; @@ -21,7 +21,7 @@ export class HtmlReporter implements Reporter { public static readonly inject = tokens(commonTokens.options, commonTokens.logger); - public onMutationTestReportReady(report: mutationTestReportSchema.MutationTestResult): void { + public onMutationTestReportReady(report: schema.MutationTestResult): void { this.mainPromise = this.generateReport(report); } @@ -29,7 +29,7 @@ export class HtmlReporter implements Reporter { return this.mainPromise; } - private async generateReport(report: mutationTestReportSchema.MutationTestResult) { + private async generateReport(report: schema.MutationTestResult) { const indexFileName = path.resolve(this.baseDir, 'index.html'); const singleFile = await reportTemplate(report); await this.cleanBaseFolder(); diff --git a/packages/core/src/reporters/html/report-template.ts b/packages/core/src/reporters/html/report-template.ts index b87ac12445..62f6e50cf5 100644 --- a/packages/core/src/reporters/html/report-template.ts +++ b/packages/core/src/reporters/html/report-template.ts @@ -1,11 +1,11 @@ import { readFile } from 'fs'; import { promisify } from 'util'; -import { mutationTestReportSchema } from '@stryker-mutator/api/report'; +import { schema } from '@stryker-mutator/api/core'; const promisedReadFile = promisify(readFile); -export async function reportTemplate(report: mutationTestReportSchema.MutationTestResult): Promise { +export async function reportTemplate(report: schema.MutationTestResult): Promise { const scriptContent = await promisedReadFile(require.resolve('mutation-testing-elements/dist/mutation-test-elements.js'), 'utf-8'); return ` diff --git a/packages/core/src/reporters/json-reporter.ts b/packages/core/src/reporters/json-reporter.ts index ef9a9cbd92..45a804e9e2 100644 --- a/packages/core/src/reporters/json-reporter.ts +++ b/packages/core/src/reporters/json-reporter.ts @@ -1,9 +1,9 @@ import path from 'path'; -import { StrykerOptions } from '@stryker-mutator/api/core'; +import { schema, StrykerOptions } from '@stryker-mutator/api/core'; import { Logger } from '@stryker-mutator/api/logging'; import { commonTokens, tokens } from '@stryker-mutator/api/plugin'; -import { mutationTestReportSchema, Reporter } from '@stryker-mutator/api/report'; +import { Reporter } from '@stryker-mutator/api/report'; import fileUrl from 'file-url'; @@ -19,7 +19,7 @@ export class JsonReporter implements Reporter { public static readonly inject = tokens(commonTokens.options, commonTokens.logger); - public onMutationTestReportReady(report: mutationTestReportSchema.MutationTestResult): void { + public onMutationTestReportReady(report: schema.MutationTestResult): void { this.mainPromise = this.generateReport(report); } @@ -27,7 +27,7 @@ export class JsonReporter implements Reporter { return this.mainPromise; } - private async generateReport(report: mutationTestReportSchema.MutationTestResult) { + private async generateReport(report: schema.MutationTestResult) { const filePath = path.normalize(this.options.jsonReporter.fileName); this.log.debug(`Using relative path ${filePath}`); await ReporterUtil.writeFile(path.resolve(filePath), JSON.stringify(report, null, INDENTION_LEVEL)); diff --git a/packages/core/src/reporters/mutation-test-report-helper.ts b/packages/core/src/reporters/mutation-test-report-helper.ts index f66d1a068d..df40543674 100644 --- a/packages/core/src/reporters/mutation-test-report-helper.ts +++ b/packages/core/src/reporters/mutation-test-report-helper.ts @@ -1,106 +1,83 @@ import path from 'path'; -import { Location, Position, StrykerOptions, Mutant } from '@stryker-mutator/api/core'; +import { Location, Position, StrykerOptions, Mutant, MutantTestCoverage, MutantResult, schema, MutantStatus } from '@stryker-mutator/api/core'; import { Logger } from '@stryker-mutator/api/logging'; import { commonTokens, tokens } from '@stryker-mutator/api/plugin'; -import { - MutantResult, - MutantStatus, - mutationTestReportSchema, - Reporter, - TimeoutMutantResult, - InvalidMutantResult, - BaseMutantResult, - UndetectedMutantResult, - KilledMutantResult, - IgnoredMutantResult, -} from '@stryker-mutator/api/report'; +import { Reporter } from '@stryker-mutator/api/report'; import { normalizeWhitespaces } from '@stryker-mutator/util'; -import { calculateMetrics } from 'mutation-testing-metrics'; -import { CompleteDryRunResult, MutantRunResult, MutantRunStatus } from '@stryker-mutator/api/test-runner'; +import { calculateMutationTestMetrics, MutationTestMetricsResult } from 'mutation-testing-metrics'; +import { CompleteDryRunResult, MutantRunResult, MutantRunStatus, TestResult } from '@stryker-mutator/api/test-runner'; import { CheckStatus, PassedCheckResult, CheckResult } from '@stryker-mutator/api/check'; import { coreTokens } from '../di'; import { InputFileCollection } from '../input/input-file-collection'; import { setExitCode } from '../utils/object-utils'; -import { MutantTestCoverage } from '../mutants/find-mutant-test-coverage'; -import { mutatedLines, originalLines } from '../utils/mutant-utils'; /** * A helper class to convert and report mutants that survived or get killed */ export class MutationTestReportHelper { - private readonly testNamesById: Map; - public static inject = tokens(coreTokens.reporter, commonTokens.options, coreTokens.inputFiles, commonTokens.logger, coreTokens.dryRunResult); + constructor( private readonly reporter: Required, private readonly options: StrykerOptions, private readonly inputFiles: InputFileCollection, private readonly log: Logger, private readonly dryRunResult: CompleteDryRunResult - ) { - this.testNamesById = new Map(this.dryRunResult.tests.map((test) => [test.id, test.name])); - } + ) {} public reportCheckFailed(mutant: Mutant, checkResult: Exclude): MutantResult { - return this.reportOne(mutant, { + return this.reportOne({ + ...mutant, status: this.checkStatusToResultStatus(checkResult.status), - errorMessage: checkResult.reason, + statusReason: checkResult.reason, }); } - public reportNoCoverage(mutant: Mutant): MutantResult { - return this.reportOne(mutant, { status: MutantStatus.NoCoverage, testFilter: [] }); - } - - public reportMutantIgnored(mutant: Mutant): MutantResult { - return this.reportOne(mutant, { status: MutantStatus.Ignored, ignoreReason: mutant.ignoreReason! }); + public reportMutantStatus(mutant: MutantTestCoverage, status: MutantStatus): MutantResult { + return this.reportOne({ + ...mutant, + status, + }); } - public reportMutantRunResult(mutantWithTestCoverage: MutantTestCoverage, result: MutantRunResult): MutantResult { - const { mutant, testFilter } = mutantWithTestCoverage; + public reportMutantRunResult(mutant: MutantTestCoverage, result: MutantRunResult): MutantResult { switch (result.status) { case MutantRunStatus.Error: - return this.reportOne(mutant, { status: MutantStatus.RuntimeError, errorMessage: result.errorMessage }); + return this.reportOne({ + ...mutant, + status: MutantStatus.RuntimeError, + statusReason: result.errorMessage, + }); case MutantRunStatus.Killed: - return this.reportOne(mutant, { + return this.reportOne({ + ...mutant, status: MutantStatus.Killed, - nrOfTestsRan: result.nrOfTests, - killedBy: this.testNamesById.get(result.killedBy)!, + testsCompleted: result.nrOfTests, + killedBy: [result.killedBy], + statusReason: result.failureMessage, }); case MutantRunStatus.Timeout: - return this.reportOne(mutant, { status: MutantStatus.TimedOut }); + return this.reportOne({ + ...mutant, + status: MutantStatus.Timeout, + }); case MutantRunStatus.Survived: - return this.reportOne(mutant, { + return this.reportOne({ + ...mutant, status: MutantStatus.Survived, - nrOfTestsRan: result.nrOfTests, - testFilter: testFilter ? this.dryRunResult.tests.filter((t) => testFilter.includes(t.id)).map((t) => t.name) : undefined, + testsCompleted: result.nrOfTests, }); } } - private reportOne(mutant: Mutant, additionalFields: Omit & { nrOfTestsRan?: number }) { - const originalFileTextContent = this.inputFiles.filesToMutate.find((fileToMutate) => fileToMutate.name === mutant.fileName)!.textContent; - - const mutantResult = { - id: mutant.id.toString(), - location: mutant.location, - mutatedLines: mutatedLines(originalFileTextContent, mutant), - mutatorName: mutant.mutatorName, - originalLines: originalLines(originalFileTextContent, mutant), - range: mutant.range, - replacement: mutant.replacement, - fileName: mutant.fileName, - nrOfTestsRan: 0, - ...additionalFields, - } as MutantResult; - this.reporter.onMutantTested(mutantResult); - - return mutantResult; + private reportOne(result: MutantResult): MutantResult { + this.reporter.onMutantTested(result); + return result; } - private checkStatusToResultStatus(status: Exclude): MutantStatus.CompileError { + private checkStatusToResultStatus(status: Exclude): MutantStatus { switch (status) { case CheckStatus.CompileError: return MutantStatus.CompileError; @@ -109,17 +86,18 @@ export class MutationTestReportHelper { public reportAll(results: MutantResult[]): void { const report = this.mutationTestReport(results); + const metrics = calculateMutationTestMetrics(report); this.reporter.onAllMutantsTested(results); - this.reporter.onMutationTestReportReady(report); - this.determineExitCode(report); + this.reporter.onMutationTestReportReady(report, metrics); + this.determineExitCode(metrics); } - private determineExitCode(report: mutationTestReportSchema.MutationTestResult) { - const { metrics } = calculateMetrics(report.files); + private determineExitCode(metrics: MutationTestMetricsResult) { + const mutationScore = metrics.systemUnderTestMetrics.metrics.mutationScore; const breaking = this.options.thresholds.break; - const formattedScore = metrics.mutationScore.toFixed(2); + const formattedScore = mutationScore.toFixed(2); if (typeof breaking === 'number') { - if (metrics.mutationScore < breaking) { + if (mutationScore < breaking) { this.log.error(`Final mutation score ${formattedScore} under breaking threshold ${breaking}, setting exit code to 1 (failure).`); this.log.info('(improve mutation score or set `thresholds.break = null` to prevent this error in the future)'); setExitCode(1); @@ -133,26 +111,39 @@ export class MutationTestReportHelper { } } - private mutationTestReport(results: readonly MutantResult[]): mutationTestReportSchema.MutationTestResult { + private mutationTestReport(results: readonly MutantResult[]): schema.MutationTestResult { + // Mocha, jest and karma use test titles as test ids. + // This can mean a lot of duplicate strings in the json report. + // Therefore we remap the test ids here to numbers. + const testIdMap = new Map(this.dryRunResult.tests.map((test, index) => [test.id, index.toString()])); + const remapTestId = (id: string): string => testIdMap.get(id) ?? id; + const remapTestIds = (ids: string[] | undefined): string[] | undefined => ids?.map(remapTestId); + return { - files: this.toFileResults(results), + files: this.toFileResults(results, remapTestIds), schemaVersion: '1.0', thresholds: this.options.thresholds, + testFiles: this.toTestFiles(remapTestId), }; } - private toFileResults(results: readonly MutantResult[]): mutationTestReportSchema.FileResultDictionary { - const resultDictionary: mutationTestReportSchema.FileResultDictionary = Object.create(null); + private toFileResults( + results: readonly MutantResult[], + remapTestIds: (ids: string[] | undefined) => string[] | undefined + ): schema.FileResultDictionary { + const resultDictionary: schema.FileResultDictionary = Object.create(null); + results.forEach((mutantResult) => { const fileResult = resultDictionary[mutantResult.fileName]; + const mutant = this.toMutantResult(mutantResult, remapTestIds); if (fileResult) { - fileResult.mutants.push(this.toMutantResult(mutantResult)); + fileResult.mutants.push(mutant); } else { const sourceFile = this.inputFiles.files.find((file) => file.name === mutantResult.fileName); if (sourceFile) { resultDictionary[mutantResult.fileName] = { language: this.determineLanguage(sourceFile.name), - mutants: [this.toMutantResult(mutantResult)], + mutants: [mutant], source: sourceFile.textContent, }; } else { @@ -166,7 +157,22 @@ export class MutationTestReportHelper { return resultDictionary; } - public determineLanguage(name: string): string { + private toTestFiles(remapTestId: (id: string) => string): schema.TestFileDefinitionDictionary { + return { + '': { + tests: this.dryRunResult.tests.map((test) => this.toTestDefinition(test, remapTestId)), + }, + }; + } + + private toTestDefinition(test: TestResult, remapTestId: (id: string) => string): schema.TestDefinition { + return { + id: remapTestId(test.id), + name: test.name, + }; + } + + private determineLanguage(name: string): string { const ext = path.extname(name).toLowerCase(); switch (ext) { case '.ts': @@ -180,68 +186,27 @@ export class MutationTestReportHelper { } } - private toMutantResult(mutantResult: MutantResult): mutationTestReportSchema.MutantResult { + private toMutantResult(mutantResult: MutantResult, remapTestIds: (ids: string[] | undefined) => string[] | undefined): schema.MutantResult { + const { range, fileName, location, killedBy, coveredBy, ...apiMutant } = mutantResult; return { - id: mutantResult.id, - location: this.toLocation(mutantResult.location), - mutatorName: mutantResult.mutatorName, - replacement: mutantResult.replacement, - status: this.toStatus(mutantResult.status), - description: this.describe(mutantResult), + ...apiMutant, + killedBy: remapTestIds(killedBy), + coveredBy: remapTestIds(coveredBy), + location: this.toLocation(location), }; } - private toLocation(location: Location): mutationTestReportSchema.Location { + private toLocation(location: Location): schema.Location { return { end: this.toPosition(location.end), start: this.toPosition(location.start), }; } - private toPosition(pos: Position): mutationTestReportSchema.Position { + private toPosition(pos: Position): schema.Position { return { column: pos.column + 1, // convert from 0-based to 1-based line: pos.line + 1, }; } - - private toStatus(status: MutantStatus): mutationTestReportSchema.MutantStatus { - switch (status) { - case MutantStatus.Killed: - return mutationTestReportSchema.MutantStatus.Killed; - case MutantStatus.NoCoverage: - return mutationTestReportSchema.MutantStatus.NoCoverage; - case MutantStatus.RuntimeError: - return mutationTestReportSchema.MutantStatus.RuntimeError; - case MutantStatus.Survived: - return mutationTestReportSchema.MutantStatus.Survived; - case MutantStatus.TimedOut: - return mutationTestReportSchema.MutantStatus.Timeout; - case MutantStatus.CompileError: - return mutationTestReportSchema.MutantStatus.CompileError; - case MutantStatus.Ignored: - return mutationTestReportSchema.MutantStatus.Ignored; - default: - this.logUnsupportedMutantStatus(status); - return mutationTestReportSchema.MutantStatus.RuntimeError; - } - } - - private describe(mutantResult: MutantResult): string | undefined { - switch (mutantResult.status) { - case MutantStatus.Ignored: - return `Ignore reason: ${mutantResult.ignoreReason}`; - case MutantStatus.Killed: - return `Killed by: ${mutantResult.killedBy}`; - case MutantStatus.CompileError: - case MutantStatus.RuntimeError: - return `Error message: ${mutantResult.errorMessage}`; - default: - return undefined; - } - } - - private logUnsupportedMutantStatus(status: never) { - this.log.warn('Unable to convert "%s" to a MutantStatus', status); - } } diff --git a/packages/core/src/reporters/progress-append-only-reporter.ts b/packages/core/src/reporters/progress-append-only-reporter.ts index 58040a21e9..00b63d5632 100644 --- a/packages/core/src/reporters/progress-append-only-reporter.ts +++ b/packages/core/src/reporters/progress-append-only-reporter.ts @@ -1,13 +1,13 @@ import os from 'os'; -import { MatchedMutant } from '@stryker-mutator/api/report'; +import { MutantTestCoverage } from '@stryker-mutator/api/core'; import { ProgressKeeper } from './progress-keeper'; export class ProgressAppendOnlyReporter extends ProgressKeeper { private intervalReference?: NodeJS.Timer; - public onAllMutantsMatchedWithTests(matchedMutants: readonly MatchedMutant[]): void { + public onAllMutantsMatchedWithTests(matchedMutants: readonly MutantTestCoverage[]): void { super.onAllMutantsMatchedWithTests(matchedMutants); if (matchedMutants.length) { this.intervalReference = setInterval(() => this.render(), 10000); diff --git a/packages/core/src/reporters/progress-keeper.ts b/packages/core/src/reporters/progress-keeper.ts index 0065838ff7..d4cb0ca559 100644 --- a/packages/core/src/reporters/progress-keeper.ts +++ b/packages/core/src/reporters/progress-keeper.ts @@ -1,10 +1,14 @@ -import { MatchedMutant, MutantResult, Reporter, MutantStatus } from '@stryker-mutator/api/report'; +import { MutantResult, MutantStatus, MutantTestCoverage } from '@stryker-mutator/api/core'; +import { Reporter } from '@stryker-mutator/api/report'; import { Timer } from '../utils/timer'; +function mutantHasCoverage(mutant: Pick) { + return !!mutant.static || !!mutant.coveredBy?.length; +} + export abstract class ProgressKeeper implements Reporter { private timer!: Timer; - private mutantIdsWithoutCoverage!: string[]; protected progress = { survived: 0, timedOut: 0, @@ -12,20 +16,19 @@ export abstract class ProgressKeeper implements Reporter { total: 0, }; - public onAllMutantsMatchedWithTests(matchedMutants: readonly MatchedMutant[]): void { + public onAllMutantsMatchedWithTests(mutants: readonly MutantTestCoverage[]): void { this.timer = new Timer(); - this.mutantIdsWithoutCoverage = matchedMutants.filter((m) => !m.runAllTests && !m.testFilter?.length).map((m) => m.id); - this.progress.total = matchedMutants.length - this.mutantIdsWithoutCoverage.length; + this.progress.total = mutants.filter(mutantHasCoverage).length; } public onMutantTested(result: MutantResult): void { - if (!this.mutantIdsWithoutCoverage.some((id) => result.id === id)) { + if (mutantHasCoverage(result)) { this.progress.tested++; } if (result.status === MutantStatus.Survived) { this.progress.survived++; } - if (result.status === MutantStatus.TimedOut) { + if (result.status === MutantStatus.Timeout) { this.progress.timedOut++; } } diff --git a/packages/core/src/reporters/progress-reporter.ts b/packages/core/src/reporters/progress-reporter.ts index 3e19ae1bb9..525fe67287 100644 --- a/packages/core/src/reporters/progress-reporter.ts +++ b/packages/core/src/reporters/progress-reporter.ts @@ -1,4 +1,4 @@ -import { MatchedMutant, MutantResult } from '@stryker-mutator/api/report'; +import { MutantTestCoverage, MutantResult } from '@stryker-mutator/api/core'; import { ProgressBar } from './progress-bar'; import { ProgressKeeper } from './progress-keeper'; @@ -6,7 +6,7 @@ import { ProgressKeeper } from './progress-keeper'; export class ProgressBarReporter extends ProgressKeeper { private progressBar?: ProgressBar; - public onAllMutantsMatchedWithTests(matchedMutants: readonly MatchedMutant[]): void { + public onAllMutantsMatchedWithTests(matchedMutants: MutantTestCoverage[]): void { super.onAllMutantsMatchedWithTests(matchedMutants); const progressBarContent = 'Mutation testing [:bar] :percent (elapsed: :et, remaining: :etc) :tested/:total tested (:survived survived, :timedOut timed out)'; diff --git a/packages/core/src/stryker-cli.ts b/packages/core/src/stryker-cli.ts index 109c3a332b..2435b99ca5 100644 --- a/packages/core/src/stryker-cli.ts +++ b/packages/core/src/stryker-cli.ts @@ -1,7 +1,5 @@ import commander from 'commander'; -import { DashboardOptions, ALL_REPORT_TYPES, PartialStrykerOptions } from '@stryker-mutator/api/core'; - -import { MutantResult } from '@stryker-mutator/api/report'; +import { MutantResult, DashboardOptions, ALL_REPORT_TYPES, PartialStrykerOptions } from '@stryker-mutator/api/core'; import { initializerFactory } from './initializer'; import { LogConfigurator } from './logging'; diff --git a/packages/core/src/stryker.ts b/packages/core/src/stryker.ts index 1654cc17ef..63373a5402 100644 --- a/packages/core/src/stryker.ts +++ b/packages/core/src/stryker.ts @@ -1,5 +1,4 @@ -import { PartialStrykerOptions } from '@stryker-mutator/api/core'; -import { MutantResult } from '@stryker-mutator/api/report'; +import { MutantResult, PartialStrykerOptions } from '@stryker-mutator/api/core'; import { createInjector } from 'typed-inject'; import { commonTokens } from '@stryker-mutator/api/plugin'; diff --git a/packages/core/src/test-runner/command-test-runner.ts b/packages/core/src/test-runner/command-test-runner.ts index 0563dca0aa..a3d1aea23c 100644 --- a/packages/core/src/test-runner/command-test-runner.ts +++ b/packages/core/src/test-runner/command-test-runner.ts @@ -61,14 +61,12 @@ export class CommandTestRunner implements TestRunner { return toMutantRunResult(result); } - private run({ activeMutantId }: { activeMutantId?: number }): Promise { + private run({ activeMutantId }: { activeMutantId?: string }): Promise { return new Promise((res, rej) => { const timerInstance = new Timer(); const output: Array = []; const env = - activeMutantId === undefined - ? process.env - : { ...process.env, [INSTRUMENTER_CONSTANTS.ACTIVE_MUTANT_ENV_VARIABLE]: activeMutantId.toString() }; + activeMutantId === undefined ? process.env : { ...process.env, [INSTRUMENTER_CONSTANTS.ACTIVE_MUTANT_ENV_VARIABLE]: activeMutantId }; const childProcess = exec(this.settings.command, { cwd: this.workingDir, env }); childProcess.on('error', (error) => { kill(childProcess.pid) diff --git a/packages/core/src/utils/mutant-utils.ts b/packages/core/src/utils/mutant-utils.ts deleted file mode 100644 index 188c823cf4..0000000000 --- a/packages/core/src/utils/mutant-utils.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { Mutant } from '@stryker-mutator/api/core'; - -const enum CharacterCodes { - MaxAsciiCharacter = 0x7f, - LineFeed = 0x0a, // \n - CarriageReturn = 0x0d, // \r - LineSeparator = 0x2028, - ParagraphSeparator = 0x2029, -} - -export function isLineBreak(ch: number): boolean { - // ES5 7.3: - // The ECMAScript line terminator characters are listed in Table 3. - // Table 3: Line Terminator Characters - // Code Unit Value Name Formal Name - // \u000A Line Feed - // \u000D Carriage Return - // \u2028 Line separator - // \u2029 Paragraph separator - // Only the characters in Table 3 are treated as line terminators. Other new line or line - // breaking characters are treated as white space but not as line terminators. - - return ( - ch === CharacterCodes.LineFeed || - ch === CharacterCodes.CarriageReturn || - ch === CharacterCodes.LineSeparator || - ch === CharacterCodes.ParagraphSeparator - ); -} - -export function originalLines(originalText: string, mutant: Mutant): string { - const [startIndex, endIndex] = getMutationLineIndexes(originalText, mutant); - return originalText.substring(startIndex, endIndex); -} - -function getMutationLineIndexes(originalText: string, mutant: Mutant): [number, number] { - let startIndexLines = mutant.range[0]; - let endIndexLines = mutant.range[1]; - while (startIndexLines > 0 && !isLineBreak(originalText.charCodeAt(startIndexLines - 1))) { - startIndexLines--; - } - while (endIndexLines < originalText.length && !isLineBreak(originalText.charCodeAt(endIndexLines))) { - endIndexLines++; - } - return [startIndexLines, endIndexLines]; -} - -export function mutatedLines(originalText: string, mutant: Mutant): string { - const [startIndex, endIndex] = getMutationLineIndexes(originalText, mutant); - return `${originalText.substring(startIndex, mutant.range[0])}${mutant.replacement}${originalText.substring(mutant.range[1], endIndex)}`; -} diff --git a/packages/core/src/utils/object-utils.ts b/packages/core/src/utils/object-utils.ts index 14599854fa..0a080d8a80 100644 --- a/packages/core/src/utils/object-utils.ts +++ b/packages/core/src/utils/object-utils.ts @@ -2,15 +2,6 @@ import treeKill from 'tree-kill'; import { StrykerError, KnownKeys } from '@stryker-mutator/util'; import { WarningOptions } from '@stryker-mutator/api/core'; -export { serialize, deserialize } from 'surrial'; - -export function wrapInClosure(codeFragment: string): string { - return ` - (function (window) { - ${codeFragment} - })((Function('return this'))());`; -} - /** * A wrapper around `process.env` (for testability) */ @@ -49,10 +40,6 @@ export function setExitCode(n: number): void { process.exitCode = n; } -export function base64Decode(base64EncodedString: string): string { - return Buffer.from(base64EncodedString, 'base64').toString('utf8'); -} - export function kill(pid: number): Promise { return new Promise((res, rej) => { treeKill(pid, 'SIGKILL', (err?: Error & { code?: number }) => { @@ -71,13 +58,6 @@ export function kill(pid: number): Promise { }); } -export function padLeft(input: string): string { - return input - .split('\n') - .map((str) => '\t' + str) - .join('\n'); -} - /** * Creates a random integer number. * @returns A random integer. diff --git a/packages/core/src/utils/string-utils.ts b/packages/core/src/utils/string-utils.ts new file mode 100644 index 0000000000..d66149d7ce --- /dev/null +++ b/packages/core/src/utils/string-utils.ts @@ -0,0 +1,23 @@ +export { serialize, deserialize } from 'surrial'; + +export function wrapInClosure(codeFragment: string): string { + return ` + (function (window) { + ${codeFragment} + })((Function('return this'))());`; +} + +export function padLeft(input: string): string { + return input + .split('\n') + .map((str) => '\t' + str) + .join('\n'); +} + +export function plural(items: number): string { + if (items > 1) { + return 's'; + } else { + return ''; + } +} diff --git a/packages/core/test/helpers/producers.ts b/packages/core/test/helpers/producers.ts index b4ee836ed2..01f6c6167e 100644 --- a/packages/core/test/helpers/producers.ts +++ b/packages/core/test/helpers/producers.ts @@ -1,14 +1,12 @@ import { CpuInfo } from 'os'; import { ClearTextReporterOptions } from '@stryker-mutator/api/core'; -import { factory } from '@stryker-mutator/test-helpers'; import { Logger } from 'log4js'; import sinon from 'sinon'; import { ReplaySubject } from 'rxjs'; import { TestRunner } from '@stryker-mutator/api/test-runner'; import { Checker } from '@stryker-mutator/api/check'; -import { MutantTestCoverage } from '../../src/mutants/find-mutant-test-coverage'; import { Pool, ConcurrencyTokenProvider } from '../../src/concurrent'; export type Mutable = { @@ -65,15 +63,6 @@ export function createCheckerPoolMock(): sinon.SinonStubbedInstance): MutantTestCoverage { - return { - coveredByTests: true, - mutant: factory.mutant(), - estimatedNetTime: 10, - ...overrides, - }; -} - export const logger = (): Mock => { return { _log: sinon.stub(), diff --git a/packages/core/test/integration/command-test-runner/command-test-runner.it.spec.ts b/packages/core/test/integration/command-test-runner/command-test-runner.it.spec.ts index b3f2fa82f1..4a8d2a951b 100644 --- a/packages/core/test/integration/command-test-runner/command-test-runner.it.spec.ts +++ b/packages/core/test/integration/command-test-runner/command-test-runner.it.spec.ts @@ -54,12 +54,12 @@ describe(`${CommandTestRunner.name} integration`, () => { describe(CommandTestRunner.prototype.mutantRun.name, () => { it('should report mutant as survived if the process exits with 0', async () => { const sut = createSut({ command: 'npm run mutant' }); - const result = await sut.mutantRun({ activeMutant: factory.mutant({ id: 41 }) }); + const result = await sut.mutantRun({ activeMutant: factory.mutant({ id: '41' }) }); assertions.expectSurvived(result); }); it('should report mutant as killed if the process exits with 1', async () => { const sut = createSut({ command: 'npm run mutant' }); - const result = await sut.mutantRun({ activeMutant: factory.mutant({ id: 42 /* 42 should fail */ }) }); + const result = await sut.mutantRun({ activeMutant: factory.mutant({ id: '42' /* 42 should fail */ }) }); assertions.expectKilled(result); expect(result.killedBy).eq('all'); }); diff --git a/packages/core/test/integration/reporters/html/simple-report.ts b/packages/core/test/integration/reporters/html/simple-report.ts index 16d6703720..a8ba1bf705 100644 --- a/packages/core/test/integration/reporters/html/simple-report.ts +++ b/packages/core/test/integration/reporters/html/simple-report.ts @@ -1,6 +1,6 @@ -import { mutationTestReportSchema } from '@stryker-mutator/api/report'; +import { MutantStatus, schema } from '@stryker-mutator/api/core'; -export const simpleReport: mutationTestReportSchema.MutationTestResult = { +export const simpleReport: schema.MutationTestResult = { files: { 'test.js': { language: 'javascript', @@ -19,7 +19,7 @@ export const simpleReport: mutationTestReportSchema.MutationTestResult = { }, mutatorName: 'String Literal', replacement: '""', - status: mutationTestReportSchema.MutantStatus.Survived, + status: MutantStatus.Survived, }, { id: '1', @@ -35,7 +35,7 @@ export const simpleReport: mutationTestReportSchema.MutationTestResult = { }, mutatorName: 'Arithmetic Operator', replacement: '-', - status: mutationTestReportSchema.MutantStatus.Survived, + status: MutantStatus.Survived, }, ], source: '"use strict";\nfunction add(a, b) {\n return a + b;\n}', diff --git a/packages/core/test/unit/child-proxy/child-process-proxy.spec.ts b/packages/core/test/unit/child-proxy/child-process-proxy.spec.ts index b419da8689..15bb5729d8 100644 --- a/packages/core/test/unit/child-proxy/child-process-proxy.spec.ts +++ b/packages/core/test/unit/child-proxy/child-process-proxy.spec.ts @@ -19,6 +19,7 @@ import { WorkerMessageKind, } from '../../../src/child-proxy/message-protocol'; import { LoggingClientContext } from '../../../src/logging'; +import * as stringUtils from '../../../src/utils/string-utils'; import * as objectUtils from '../../../src/utils/object-utils'; import { OutOfMemoryError } from '../../../src/child-proxy/out-of-memory-error'; import { currentLogMock } from '../../helpers/log-mock'; @@ -91,7 +92,7 @@ describe(ChildProcessProxy.name, () => { }); // Assert - expect(childProcessMock.send).calledWith(objectUtils.serialize(expectedMessage)); + expect(childProcessMock.send).calledWith(stringUtils.serialize(expectedMessage)); }); it('should log the exec arguments and require name', () => { @@ -225,7 +226,7 @@ describe(ChildProcessProxy.name, () => { // Assert expect(result).eq('ack'); - expect(childProcessMock.send).calledWith(objectUtils.serialize(expectedWorkerMessage)); + expect(childProcessMock.send).calledWith(stringUtils.serialize(expectedWorkerMessage)); }); }); @@ -237,7 +238,7 @@ describe(ChildProcessProxy.name, () => { it('should send a dispose message', async () => { await actDispose(); const expectedWorkerMessage: DisposeMessage = { kind: WorkerMessageKind.Dispose }; - expect(childProcessMock.send).calledWith(objectUtils.serialize(expectedWorkerMessage)); + expect(childProcessMock.send).calledWith(stringUtils.serialize(expectedWorkerMessage)); }); it('should kill the child process', async () => { @@ -280,7 +281,7 @@ describe(ChildProcessProxy.name, () => { }); function receiveMessage(workerResponse: ParentMessage) { - childProcessMock.emit('message', objectUtils.serialize(workerResponse)); + childProcessMock.emit('message', stringUtils.serialize(workerResponse)); } }); diff --git a/packages/core/test/unit/child-proxy/child-process-worker.spec.ts b/packages/core/test/unit/child-proxy/child-process-worker.spec.ts index a571b6fdd3..b70a77a70f 100644 --- a/packages/core/test/unit/child-proxy/child-process-worker.spec.ts +++ b/packages/core/test/unit/child-proxy/child-process-worker.spec.ts @@ -18,7 +18,7 @@ import { } from '../../../src/child-proxy/message-protocol'; import * as di from '../../../src/di'; import { LogConfigurator, LoggingClientContext } from '../../../src/logging'; -import { serialize } from '../../../src/utils/object-utils'; +import { serialize } from '../../../src/utils/string-utils'; import { currentLogMock } from '../../helpers/log-mock'; import { Mock } from '../../helpers/producers'; diff --git a/packages/core/test/unit/mutants/find-mutant-test-coverage.spec.ts b/packages/core/test/unit/mutants/find-mutant-test-coverage.spec.ts index 33e486991a..5bf141a79f 100644 --- a/packages/core/test/unit/mutants/find-mutant-test-coverage.spec.ts +++ b/packages/core/test/unit/mutants/find-mutant-test-coverage.spec.ts @@ -2,10 +2,10 @@ import sinon from 'sinon'; import { expect } from 'chai'; import { factory, testInjector } from '@stryker-mutator/test-helpers'; import { CompleteDryRunResult } from '@stryker-mutator/api/test-runner'; -import { Mutant } from '@stryker-mutator/api/core'; -import { Reporter, MatchedMutant } from '@stryker-mutator/api/report'; +import { Mutant, MutantStatus, MutantTestCoverage } from '@stryker-mutator/api/core'; +import { Reporter } from '@stryker-mutator/api/report'; -import { findMutantTestCoverage as sut, MutantTestCoverage } from '../../../src/mutants/find-mutant-test-coverage'; +import { findMutantTestCoverage as sut } from '../../../src/mutants/find-mutant-test-coverage'; import { coreTokens } from '../../../src/di'; describe(sut.name, () => { @@ -24,22 +24,34 @@ describe(sut.name, () => { } it('should not match ignored mutants to any tests', () => { - const mutant = factory.mutant({ id: 2, ignoreReason: 'foo should ignore' }); + const mutant = factory.mutant({ id: '2', status: MutantStatus.Ignored, statusReason: 'foo should ignore' }); const dryRunResult = factory.completeDryRunResult({ mutantCoverage: { static: {}, perTest: { '1': { 2: 2 } } } }); // Act const result = act(dryRunResult, [mutant]); // Assert - const expected: MutantTestCoverage[] = [{ mutant, estimatedNetTime: 0, coveredByTests: false }]; + const expected: MutantTestCoverage[] = [{ ...mutant, estimatedNetTime: 0, static: false }]; + expect(result).deep.eq(expected); + }); + + it('should mark mutant as "NoCoverage" when there is coverage data, but none for the specific mutant', () => { + const mutant = factory.mutant({ id: '3' }); + const dryRunResult = factory.completeDryRunResult({ mutantCoverage: { static: {}, perTest: { '1': { 2: 2 } } } }); + + // Act + const result = act(dryRunResult, [mutant]); + + // Assert + const expected: MutantTestCoverage[] = [{ ...mutant, estimatedNetTime: 0, static: false, coveredBy: [] }]; expect(result).deep.eq(expected); }); describe('without mutant coverage data', () => { - it('should disable test filtering', () => { + it('should mark mutants as "static"', () => { // Arrange - const mutant1 = factory.mutant({ id: 1 }); - const mutant2 = factory.mutant({ id: 2 }); + const mutant1 = factory.mutant({ id: '1' }); + const mutant2 = factory.mutant({ id: '2' }); const mutants = [mutant1, mutant2]; const dryRunResult = factory.completeDryRunResult({ mutantCoverage: undefined }); @@ -48,15 +60,15 @@ describe(sut.name, () => { // Assert const expected: MutantTestCoverage[] = [ - { mutant: mutant1, estimatedNetTime: 0, testFilter: undefined, coveredByTests: true }, - { mutant: mutant2, estimatedNetTime: 0, testFilter: undefined, coveredByTests: true }, + { ...mutant1, estimatedNetTime: 0, coveredBy: undefined, static: true }, + { ...mutant2, estimatedNetTime: 0, coveredBy: undefined, static: true }, ]; expect(result).deep.eq(expected); }); it('should calculate estimatedNetTime as the sum of all tests', () => { // Arrange - const mutant1 = factory.mutant({ id: 1 }); + const mutant1 = factory.mutant({ id: '1' }); const mutants = [mutant1]; const dryRunResult = factory.completeDryRunResult({ tests: [factory.successTestResult({ timeSpentMs: 20 }), factory.successTestResult({ timeSpentMs: 22 })], @@ -73,8 +85,8 @@ describe(sut.name, () => { it('should report onAllMutantsMatchedWithTests', () => { // Arrange const mutants = [ - factory.mutant({ id: 1, fileName: 'foo.js', mutatorName: 'fooMutator', replacement: '<=' }), - factory.mutant({ id: 2, fileName: 'bar.js', mutatorName: 'barMutator', replacement: '{}' }), + factory.mutant({ id: '1', fileName: 'foo.js', mutatorName: 'fooMutator', replacement: '<=', range: [0, 1] }), + factory.mutant({ id: '2', fileName: 'bar.js', mutatorName: 'barMutator', replacement: '{}', range: [2, 3] }), ]; const dryRunResult = factory.completeDryRunResult({ tests: [factory.successTestResult({ timeSpentMs: 20 }), factory.successTestResult({ timeSpentMs: 22 })], @@ -86,23 +98,23 @@ describe(sut.name, () => { // Assert expect(reporterMock.onAllMutantsMatchedWithTests).calledWithExactly([ - factory.matchedMutant({ + factory.mutantTestCoverage({ id: '1', fileName: 'foo.js', mutatorName: 'fooMutator', replacement: '<=', - runAllTests: true, - testFilter: undefined, - timeSpentScopedTests: 42, + static: true, + estimatedNetTime: 42, + range: [0, 1], }), - factory.matchedMutant({ + factory.mutantTestCoverage({ id: '2', fileName: 'bar.js', mutatorName: 'barMutator', replacement: '{}', - runAllTests: true, - testFilter: undefined, - timeSpentScopedTests: 42, + static: true, + estimatedNetTime: 42, + range: [2, 3], }), ]); }); @@ -111,7 +123,7 @@ describe(sut.name, () => { describe('with static coverage', () => { it('should disable test filtering', () => { // Arrange - const mutant = factory.mutant({ id: 1 }); + const mutant = factory.mutant({ id: '1' }); const mutants = [mutant]; const dryRunResult = factory.completeDryRunResult({ tests: [factory.successTestResult({ id: 'spec1', timeSpentMs: 0 })], @@ -122,13 +134,13 @@ describe(sut.name, () => { const result = act(dryRunResult, mutants); // Assert - const expected: MutantTestCoverage[] = [{ mutant, estimatedNetTime: 0, testFilter: undefined, coveredByTests: true }]; + const expected: MutantTestCoverage[] = [{ ...mutant, estimatedNetTime: 0, static: true, coveredBy: undefined }]; expect(result).deep.eq(expected); }); it('should calculate estimatedNetTime as the sum of all tests', () => { // Arrange - const mutant = factory.mutant({ id: 1 }); + const mutant = factory.mutant({ id: '1' }); const mutants = [mutant]; const dryRunResult = factory.completeDryRunResult({ tests: [factory.successTestResult({ id: 'spec1', timeSpentMs: 20 }), factory.successTestResult({ id: 'spec1', timeSpentMs: 22 })], @@ -142,27 +154,27 @@ describe(sut.name, () => { expect(result[0].estimatedNetTime).eq(42); }); - it('should report onAllMutantsMatchedWithTests with correct `runAllTests` value', () => { + it('should report onAllMutantsMatchedWithTests with correct `static` value', () => { // Arrange - const mutants = [factory.mutant({ id: 1 }), factory.mutant({ id: 2 })]; + const mutants = [factory.mutant({ id: '1' }), factory.mutant({ id: '2' })]; const dryRunResult = factory.completeDryRunResult({ tests: [factory.successTestResult()], - mutantCoverage: { static: { 1: 1 }, perTest: {} }, + mutantCoverage: { static: { 1: 1 }, perTest: {} }, // mutant 2 has no coverage }); // Act act(dryRunResult, mutants); // Assert - const expectedFirstMatch: Partial = { + const expectedFirstMatch: Partial = { id: '1', - runAllTests: true, - testFilter: undefined, + static: true, + coveredBy: undefined, }; - const expectedSecondMatch: Partial = { + const expectedSecondMatch: Partial = { id: '2', - runAllTests: false, - testFilter: undefined, + static: false, + coveredBy: [], }; expect(reporterMock.onAllMutantsMatchedWithTests).calledWithMatch([sinon.match(expectedFirstMatch), sinon.match(expectedSecondMatch)]); }); @@ -171,8 +183,8 @@ describe(sut.name, () => { describe('with perTest coverage', () => { it('should enable test filtering for covered tests', () => { // Arrange - const mutant1 = factory.mutant({ id: 1 }); - const mutant2 = factory.mutant({ id: 2 }); + const mutant1 = factory.mutant({ id: '1' }); + const mutant2 = factory.mutant({ id: '2' }); const mutants = [mutant1, mutant2]; const dryRunResult = factory.completeDryRunResult({ tests: [factory.successTestResult({ id: 'spec1', timeSpentMs: 0 }), factory.successTestResult({ id: 'spec2', timeSpentMs: 0 })], @@ -184,16 +196,16 @@ describe(sut.name, () => { // Assert const expected: MutantTestCoverage[] = [ - { mutant: mutant1, estimatedNetTime: 0, testFilter: ['spec1'], coveredByTests: true }, - { mutant: mutant2, estimatedNetTime: 0, testFilter: ['spec2'], coveredByTests: true }, + { ...mutant1, estimatedNetTime: 0, coveredBy: ['spec1'], static: false }, + { ...mutant2, estimatedNetTime: 0, coveredBy: ['spec2'], static: false }, ]; expect(result).deep.eq(expected); }); it('should calculate estimatedNetTime as the sum of covered tests', () => { // Arrange - const mutant1 = factory.mutant({ id: 1 }); - const mutant2 = factory.mutant({ id: 2 }); + const mutant1 = factory.mutant({ id: '1' }); + const mutant2 = factory.mutant({ id: '2' }); const mutants = [mutant1, mutant2]; const dryRunResult = factory.completeDryRunResult({ tests: [ @@ -208,13 +220,13 @@ describe(sut.name, () => { const actualMatches = act(dryRunResult, mutants); // Assert - expect(actualMatches.find((mutant) => mutant.mutant.id === 1)?.estimatedNetTime).eq(42); // spec1 + spec3 - expect(actualMatches.find((mutant) => mutant.mutant.id === 2)?.estimatedNetTime).eq(10); // spec2 + expect(actualMatches.find((mutant) => mutant.id === '1')?.estimatedNetTime).eq(42); // spec1 + spec3 + expect(actualMatches.find((mutant) => mutant.id === '2')?.estimatedNetTime).eq(10); // spec2 }); it('should report onAllMutantsMatchedWithTests with correct `testFilter` value', () => { // Arrange - const mutants = [factory.mutant({ id: 1 }), factory.mutant({ id: 2 })]; + const mutants = [factory.mutant({ id: '1' }), factory.mutant({ id: '2' })]; const dryRunResult = factory.completeDryRunResult({ tests: [factory.successTestResult({ id: 'spec1', timeSpentMs: 0 }), factory.successTestResult({ id: 'spec2', timeSpentMs: 0 })], mutantCoverage: { static: { 1: 0 }, perTest: { spec1: { 1: 1 }, spec2: { 1: 0, 2: 1 } } }, @@ -224,23 +236,23 @@ describe(sut.name, () => { act(dryRunResult, mutants); // Assert - const expectedFirstMatch: Partial = { + const expectedFirstMatch: Partial = { id: '1', - runAllTests: false, - testFilter: ['spec1'], + static: false, + coveredBy: ['spec1'], }; - const expectedSecondMatch: Partial = { + const expectedSecondMatch: Partial = { id: '2', - runAllTests: false, - testFilter: ['spec2'], + static: false, + coveredBy: ['spec2'], }; expect(reporterMock.onAllMutantsMatchedWithTests).calledWithMatch([sinon.match(expectedFirstMatch), sinon.match(expectedSecondMatch)]); }); it('should allow for non-existing tests (#2485)', () => { // Arrange - const mutant1 = factory.mutant({ id: 1 }); - const mutant2 = factory.mutant({ id: 2 }); + const mutant1 = factory.mutant({ id: '1' }); + const mutant2 = factory.mutant({ id: '2' }); const mutants = [mutant1, mutant2]; const dryRunResult = factory.completeDryRunResult({ tests: [factory.successTestResult({ id: 'spec1', timeSpentMs: 20 })], // test result for spec2 is missing @@ -251,8 +263,8 @@ describe(sut.name, () => { const actualMatches = act(dryRunResult, mutants); // Assert - expect(actualMatches.find((mutant) => mutant.mutant.id === 1)?.testFilter).deep.eq(['spec1']); - expect(actualMatches.find((mutant) => mutant.mutant.id === 2)?.coveredByTests).deep.eq(false); + expect(actualMatches.find((mutant) => mutant.id === '1')?.coveredBy).deep.eq(['spec1']); + expect(actualMatches.find((mutant) => mutant.id === '2')?.coveredBy).lengthOf(0); expect(testInjector.logger.debug).calledWith( 'Found test with id "spec2" in coverage data, but not in the test results of the dry run. Not taking coverage data for this test into account' ); diff --git a/packages/core/test/unit/process/1-prepare-executor.spec.ts b/packages/core/test/unit/process/1-prepare-executor.spec.ts index f958caac25..acd1540455 100644 --- a/packages/core/test/unit/process/1-prepare-executor.spec.ts +++ b/packages/core/test/unit/process/1-prepare-executor.spec.ts @@ -11,8 +11,7 @@ import { coreTokens } from '../../../src/di'; import { LogConfigurator, LoggingClientContext } from '../../../src/logging'; import * as buildMainInjectorModule from '../../../src/di/build-main-injector'; import { Timer } from '../../../src/utils/timer'; -import { InputFileResolver } from '../../../src/input/input-file-resolver'; -import { InputFileCollection } from '../../../src/input/input-file-collection'; +import { InputFileResolver, InputFileCollection } from '../../../src/input'; import { TemporaryDirectory } from '../../../src/utils/temporary-directory'; import { ConfigError } from '../../../src/errors'; diff --git a/packages/core/test/unit/process/2-mutant-instrumenter-executor.spec.ts b/packages/core/test/unit/process/2-mutant-instrumenter-executor.spec.ts index db4c4cfcac..f779396e69 100644 --- a/packages/core/test/unit/process/2-mutant-instrumenter-executor.spec.ts +++ b/packages/core/test/unit/process/2-mutant-instrumenter-executor.spec.ts @@ -39,7 +39,7 @@ describe(MutantInstrumenterExecutor.name, () => { instrumentResult = { files: [mutatedFile], - mutants: [factory.mutant({ id: 1, replacement: 'bar' })], + mutants: [factory.mutant({ id: '1', replacement: 'bar' })], }; sandboxMock = sinon.createStubInstance(Sandbox); instrumenterMock = sinon.createStubInstance(Instrumenter); diff --git a/packages/core/test/unit/process/4-mutation-test-executor.spec.ts b/packages/core/test/unit/process/4-mutation-test-executor.spec.ts index 2674a0a4a0..1b2ede9f18 100644 --- a/packages/core/test/unit/process/4-mutation-test-executor.spec.ts +++ b/packages/core/test/unit/process/4-mutation-test-executor.spec.ts @@ -6,13 +6,12 @@ import { TestRunner, MutantRunOptions, MutantRunResult, MutantRunStatus } from ' import { Checker, CheckResult, CheckStatus } from '@stryker-mutator/api/check'; import { mergeMap } from 'rxjs/operators'; import { Observable } from 'rxjs'; -import { Mutant } from '@stryker-mutator/api/core'; +import { Mutant, MutantStatus, MutantTestCoverage } from '@stryker-mutator/api/core'; import { I, Task } from '@stryker-mutator/util'; import { MutationTestExecutor } from '../../../src/process'; import { coreTokens } from '../../../src/di'; -import { createTestRunnerPoolMock, createMutantTestCoverage, createCheckerPoolMock } from '../../helpers/producers'; -import { MutantTestCoverage } from '../../../src/mutants/find-mutant-test-coverage'; +import { createTestRunnerPoolMock, createCheckerPoolMock } from '../../helpers/producers'; import { MutationTestReportHelper } from '../../../src/reporters/mutation-test-report-helper'; import { Timer } from '../../../src/utils/timer'; import { ConcurrencyTokenProvider, Pool } from '../../../src/concurrent'; @@ -73,24 +72,22 @@ describe(MutationTestExecutor.name, () => { it('should schedule mutants to be tested', async () => { // Arrange arrangeScenario(); - const mutant1 = factory.mutant({ id: 1 }); - const mutant2 = factory.mutant({ id: 2 }); - mutants.push(createMutantTestCoverage({ mutant: mutant1 })); - mutants.push(createMutantTestCoverage({ mutant: mutant2 })); + mutants.push(factory.mutantTestCoverage({ id: '1', static: true })); + mutants.push(factory.mutantTestCoverage({ id: '2', coveredBy: ['1'] })); // Act await sut.execute(); // Assert expect(testRunnerPoolMock.schedule).calledOnce; - expect(testRunner.mutantRun).calledWithMatch({ activeMutant: mutant1 }); - expect(testRunner.mutantRun).calledWithMatch({ activeMutant: mutant2 }); + expect(testRunner.mutantRun).calledWithMatch({ activeMutant: mutants[0] }); + expect(testRunner.mutantRun).calledWithMatch({ activeMutant: mutants[1] }); }); it('should short circuit ignored mutants (not check them or run them)', async () => { // Arrange - mutants.push(createMutantTestCoverage({ mutant: factory.mutant({ id: 1, ignoreReason: '1 is ignored' }) })); - mutants.push(createMutantTestCoverage({ mutant: factory.mutant({ id: 2, ignoreReason: '2 is ignored' }) })); + mutants.push(factory.mutantTestCoverage({ id: '1', status: MutantStatus.Ignored, statusReason: '1 is ignored' })); + mutants.push(factory.mutantTestCoverage({ id: '2', status: MutantStatus.Ignored, statusReason: '2 is ignored' })); // Act const actualResults = await sut.execute(); @@ -104,24 +101,22 @@ describe(MutationTestExecutor.name, () => { it('should check the mutants before running them', async () => { // Arrange arrangeScenario(); - const mutant1 = factory.mutant({ id: 1 }); - const mutant2 = factory.mutant({ id: 2 }); - mutants.push(createMutantTestCoverage({ mutant: mutant1 })); - mutants.push(createMutantTestCoverage({ mutant: mutant2 })); + mutants.push(factory.mutantTestCoverage({ id: '1' })); + mutants.push(factory.mutantTestCoverage({ id: '2' })); // Act await sut.execute(); // Assert expect(checker.check).calledTwice; - expect(checker.check).calledWithMatch(mutant1); - expect(checker.check).calledWithMatch(mutant2); + expect(checker.check).calledWithMatch(mutants[0]); + expect(checker.check).calledWithMatch(mutants[1]); }); it('should calculate timeout correctly', async () => { // Arrange arrangeScenario(); - mutants.push(createMutantTestCoverage({ mutant: factory.mutant({ id: 1 }), estimatedNetTime: 10 })); + mutants.push(factory.mutantTestCoverage({ id: '1', estimatedNetTime: 10, coveredBy: ['1'] })); testInjector.options.timeoutFactor = 1.5; testInjector.options.timeoutMS = 27; @@ -137,7 +132,7 @@ describe(MutationTestExecutor.name, () => { // Arrange arrangeScenario(); const expectedTestFilter = ['spec1', 'foo', 'bar']; - mutants.push(createMutantTestCoverage({ testFilter: expectedTestFilter })); + mutants.push(factory.mutantTestCoverage({ coveredBy: expectedTestFilter })); testInjector.options.timeoutFactor = 1.5; testInjector.options.timeoutMS = 27; @@ -154,7 +149,7 @@ describe(MutationTestExecutor.name, () => { arrangeScenario(); const expectedTestFilter = ['spec1', 'foo', 'bar']; sandboxMock.sandboxFileFor.returns('.stryker-tmp/sandbox1234/src/foo.js'); - mutants.push(createMutantTestCoverage({ testFilter: expectedTestFilter, mutant: factory.mutant({ fileName: 'src/foo.js' }) })); + mutants.push(factory.mutantTestCoverage({ coveredBy: expectedTestFilter, fileName: 'src/foo.js' })); testInjector.options.timeoutFactor = 1.5; testInjector.options.timeoutMS = 27; @@ -170,8 +165,7 @@ describe(MutationTestExecutor.name, () => { it('should not run mutants that are uncovered by tests', async () => { // Arrange arrangeScenario(); - const mutant1 = factory.mutant({ id: 1 }); - mutants.push(createMutantTestCoverage({ mutant: mutant1, coveredByTests: false })); + mutants.push(factory.mutantTestCoverage({ id: '1', coveredBy: undefined, static: false })); // Act await sut.execute(); @@ -183,35 +177,33 @@ describe(MutationTestExecutor.name, () => { it('should report an ignored mutant as `Ignored`', async () => { // Arrange arrangeScenario(); - const mutant = factory.mutant({ id: 1, ignoreReason: '1 is ignored' }); - mutants.push(createMutantTestCoverage({ mutant, coveredByTests: false })); + mutants.push(factory.mutantTestCoverage({ id: '1', status: MutantStatus.Ignored, statusReason: '1 is ignored' })); // Act await sut.execute(); // Assert - expect(mutationTestReportCalculatorMock.reportMutantIgnored).calledWithExactly(mutant); + expect(mutationTestReportCalculatorMock.reportMutantStatus).calledWithExactly(mutants[0], MutantStatus.Ignored); }); it('should report an uncovered mutant with `NoCoverage`', async () => { // Arrange arrangeScenario(); - const mutant = factory.mutant({ id: 1 }); - mutants.push(createMutantTestCoverage({ mutant: factory.mutant({ id: 1 }), coveredByTests: false })); + mutants.push(factory.mutantTestCoverage({ id: '1', coveredBy: undefined, status: MutantStatus.NoCoverage })); // Act await sut.execute(); // Assert - expect(mutationTestReportCalculatorMock.reportNoCoverage).calledWithExactly(mutant); + expect(mutationTestReportCalculatorMock.reportMutantStatus).calledWithExactly(mutants[0], MutantStatus.NoCoverage); }); it('should report non-passed check results as "checkFailed"', async () => { // Arrange - const mutant = factory.mutant({ id: 1 }); + const mutant = factory.mutantTestCoverage({ id: '1' }); const failedCheckResult = factory.checkResult({ reason: 'Cannot find foo() of `undefined`', status: CheckStatus.CompileError }); checker.check.resolves(failedCheckResult); - mutants.push(createMutantTestCoverage({ mutant })); + mutants.push(mutant); // Act await sut.execute(); @@ -222,7 +214,7 @@ describe(MutationTestExecutor.name, () => { it('should free checker resources after checking stage is complete', async () => { // Arrange - mutants.push(createMutantTestCoverage({ mutant: factory.mutant({ id: 1 }) })); + mutants.push(factory.mutantTestCoverage({ id: '1' })); const checkTask = new Task(); const testRunnerTask = new Task(); testRunner.mutantRun.returns(testRunnerTask.promise); @@ -240,7 +232,7 @@ describe(MutationTestExecutor.name, () => { it('should report mutant run results', async () => { // Arrange - const mutant = createMutantTestCoverage(); + const mutant = factory.mutantTestCoverage({ static: true }); const mutantRunResult = factory.killedMutantRunResult({ status: MutantRunStatus.Killed }); mutants.push(mutant); arrangeScenario({ mutantRunResult }); diff --git a/packages/core/test/unit/reporters/broadcast-reporter.spec.ts b/packages/core/test/unit/reporters/broadcast-reporter.spec.ts index 38f33d0637..9d84a17dcb 100644 --- a/packages/core/test/unit/reporters/broadcast-reporter.spec.ts +++ b/packages/core/test/unit/reporters/broadcast-reporter.spec.ts @@ -8,7 +8,7 @@ import { coreTokens } from '../../../src/di'; import { PluginCreator } from '../../../src/di/plugin-creator'; import { BroadcastReporter } from '../../../src/reporters/broadcast-reporter'; -describe('BroadcastReporter', () => { +describe(BroadcastReporter.name, () => { let sut: BroadcastReporter; let rep1: sinon.SinonStubbedInstance>; let rep2: sinon.SinonStubbedInstance>; @@ -68,13 +68,31 @@ describe('BroadcastReporter', () => { }); }); - describe('when created', () => { + describe('with 2 reporters', () => { beforeEach(() => { sut = createSut(); }); - it('should forward all events', () => { - actArrangeAssertAllEvents(); + it('should forward "onSourceFileRead"', () => { + actAssertShouldForward('onSourceFileRead', factory.sourceFile()); + }); + it('should forward "onAllSourceFilesRead"', () => { + actAssertShouldForward('onAllSourceFilesRead', [factory.sourceFile()]); + }); + it('should forward "onAllMutantsMatchedWithTests"', () => { + actAssertShouldForward('onAllMutantsMatchedWithTests', [factory.mutantTestCoverage()]); + }); + it('should forward "onMutantTested"', () => { + actAssertShouldForward('onMutantTested', factory.mutantResult()); + }); + it('should forward "onAllMutantsTested"', () => { + actAssertShouldForward('onAllMutantsTested', [factory.mutantResult()]); + }); + it('should forward "onMutationTestReportReady"', () => { + actAssertShouldForward('onMutationTestReportReady', factory.mutationTestReportSchemaMutationTestResult(), factory.mutationTestMetricsResult()); + }); + it('should forward "wrapUp"', () => { + actAssertShouldForward('wrapUp'); }); describe('when "wrapUp" returns promises', () => { @@ -128,8 +146,30 @@ describe('BroadcastReporter', () => { factory.ALL_REPORTER_EVENTS.forEach((eventName) => rep1[eventName].throws(actualError)); }); - it('should still broadcast to other reporters', () => { - actArrangeAssertAllEvents(); + it('should still broadcast "onSourceFileRead"', () => { + actAssertShouldForward('onSourceFileRead', factory.sourceFile()); + }); + it('should still broadcast "onAllSourceFilesRead"', () => { + actAssertShouldForward('onAllSourceFilesRead', [factory.sourceFile()]); + }); + it('should still broadcast "onAllMutantsMatchedWithTests"', () => { + actAssertShouldForward('onAllMutantsMatchedWithTests', [factory.mutantTestCoverage()]); + }); + it('should still broadcast "onMutantTested"', () => { + actAssertShouldForward('onMutantTested', factory.mutantResult()); + }); + it('should still broadcast "onAllMutantsTested"', () => { + actAssertShouldForward('onAllMutantsTested', [factory.mutantResult()]); + }); + it('should still broadcast "onMutationTestReportReady"', () => { + actAssertShouldForward( + 'onMutationTestReportReady', + factory.mutationTestReportSchemaMutationTestResult(), + factory.mutationTestMetricsResult() + ); + }); + it('should still broadcast "wrapUp"', () => { + actAssertShouldForward('wrapUp'); }); it('should log each error', () => { @@ -147,15 +187,6 @@ describe('BroadcastReporter', () => { .injectClass(BroadcastReporter); } - function actArrangeAssertAllEvents() { - factory.ALL_REPORTER_EVENTS.forEach((eventName) => { - const eventData = eventName === 'wrapUp' ? undefined : eventName; - (sut as any)[eventName](eventName); - expect(rep1[eventName]).calledWith(eventData); - expect(rep2[eventName]).calledWith(eventData); - }); - } - function captureTTY() { isTTY = process.stdout.isTTY; } @@ -167,4 +198,10 @@ describe('BroadcastReporter', () => { function setTTY(val: boolean) { process.stdout.isTTY = val; } + + function actAssertShouldForward(method: TMethod, ...input: Parameters[TMethod]>) { + (sut[method] as (...args: Parameters[TMethod]>) => Promise | void)(...input); + expect(rep1[method]).calledWithExactly(...input); + expect(rep2[method]).calledWithExactly(...input); + } }); diff --git a/packages/core/test/unit/reporters/clear-text-reporter.spec.ts b/packages/core/test/unit/reporters/clear-text-reporter.spec.ts index 8af7220da1..10be9d4949 100644 --- a/packages/core/test/unit/reporters/clear-text-reporter.spec.ts +++ b/packages/core/test/unit/reporters/clear-text-reporter.spec.ts @@ -1,12 +1,14 @@ import os from 'os'; -import { mutationTestReportSchema, MutantStatus } from '@stryker-mutator/api/report'; +import { MutantStatus, schema } from '@stryker-mutator/api/core'; import { testInjector, factory } from '@stryker-mutator/test-helpers'; import { expect } from 'chai'; import sinon from 'sinon'; import chalk from 'chalk'; +import { calculateMutationTestMetrics } from 'mutation-testing-metrics'; + import { ClearTextReporter } from '../../../src/reporters/clear-text-reporter'; describe(ClearTextReporter.name, () => { @@ -18,12 +20,42 @@ describe(ClearTextReporter.name, () => { sut = testInjector.injector.injectClass(ClearTextReporter); }); - describe('onMutationTestReportReady', () => { + describe(ClearTextReporter.prototype.onMutationTestReportReady.name, () => { + let report: schema.MutationTestResult; + let mutant: schema.MutantResult; + + beforeEach(() => { + mutant = factory.mutationTestReportSchemaMutantResult({ + id: '1', + location: { start: { line: 2, column: 1 }, end: { line: 2, column: 4 } }, + replacement: 'bar', + mutatorName: 'Math', + }); + report = factory.mutationTestReportSchemaMutationTestResult({ + files: { + 'foo.js': factory.mutationTestReportSchemaFileResult({ + source: '\nfoo\n', + mutants: [mutant], + }), + }, + testFiles: { + 'foo.spec.js': factory.mutationTestReportSchemaTestFile({ + tests: [ + factory.mutationTestReportSchemaTestDefinition({ id: '1', name: 'foo should be bar' }), + factory.mutationTestReportSchemaTestDefinition({ id: '2', name: 'bar should be baz' }), + factory.mutationTestReportSchemaTestDefinition({ id: '3', name: 'baz should be qux' }), + factory.mutationTestReportSchemaTestDefinition({ id: '4', name: 'qux should be quux' }), + factory.mutationTestReportSchemaTestDefinition({ id: '5', name: 'quux should be corge' }), + ], + }), + }, + }); + }); + it('should report the clear text table with correct values', () => { testInjector.options.coverageAnalysis = 'all'; - sut = testInjector.injector.injectClass(ClearTextReporter); - sut.onMutationTestReportReady({ + act({ files: { 'src/file.js': { language: 'js', @@ -33,7 +65,7 @@ describe(ClearTextReporter.name, () => { location: { start: { line: 0, column: 0 }, end: { line: 0, column: 0 } }, mutatorName: 'Block', replacement: '{}', - status: mutationTestReportSchema.MutantStatus.Killed, + status: MutantStatus.Killed, }, ], source: 'console.log("hello world!")', @@ -43,7 +75,7 @@ describe(ClearTextReporter.name, () => { thresholds: factory.mutationScoreThresholds({}), }); - const serializedTable: string = stdoutStub.getCall(0).args[0]; + const serializedTable: string = stdoutStub.getCalls().pop()!.args[0]; const rows = serializedTable.split(os.EOL); expect(rows).to.deep.eq([ '----------|---------|----------|-----------|------------|----------|---------|', @@ -59,9 +91,9 @@ describe(ClearTextReporter.name, () => { it('should not color score if `allowConsoleColors` config is false', () => { testInjector.options.allowConsoleColors = false; chalk.level = 1; + sut = testInjector.injector.injectClass(ClearTextReporter); // recreate, `allowConsoleColors` is read in constructor - sut = testInjector.injector.injectClass(ClearTextReporter); - sut.onMutationTestReportReady({ + act({ files: {}, schemaVersion: '1.0', thresholds: factory.mutationScoreThresholds({}), @@ -69,30 +101,21 @@ describe(ClearTextReporter.name, () => { expect(chalk.level).to.eq(0); }); - }); - describe('onAllMutantsTested', () => { it('should report a killed mutant to debug', async () => { - sut.onAllMutantsTested([ - factory.killedMutantResult({ id: '1', mutatorName: 'Math', killedBy: 'foo should be bar', originalLines: 'foo', mutatedLines: 'bar' }), - ]); + mutant.status = MutantStatus.Killed; + mutant.killedBy = ['1']; + act(report); expect(testInjector.logger.debug).calledWithMatch(sinon.match('1. [Killed] Math')); expect(testInjector.logger.debug).calledWith(`${chalk.red('- foo')}`); expect(testInjector.logger.debug).calledWith(`${chalk.green('+ bar')}`); expect(testInjector.logger.debug).calledWith('Killed by: foo should be bar'); }); - it('should report a transpileError mutant to debug', async () => { - sut.onAllMutantsTested([ - factory.invalidMutantResult({ - id: '1', - mutatorName: 'Math', - errorMessage: 'could not call bar of undefined', - status: MutantStatus.CompileError, - originalLines: 'foo', - mutatedLines: 'bar', - }), - ]); + it('should report a CompileError mutant to debug', async () => { + mutant.status = MutantStatus.CompileError; + mutant.statusReason = 'could not call bar of undefined'; + act(report); expect(testInjector.logger.debug).calledWithMatch(sinon.match('1. [CompileError] Math')); expect(testInjector.logger.debug).calledWith(`${chalk.red('- foo')}`); expect(testInjector.logger.debug).calledWith(`${chalk.green('+ bar')}`); @@ -100,116 +123,96 @@ describe(ClearTextReporter.name, () => { }); it('should report a NoCoverage mutant to stdout', async () => { - sut.onAllMutantsTested([ - factory.undetectedMutantResult({ - id: '1', - mutatorName: 'Math', - status: MutantStatus.NoCoverage, - originalLines: 'foo', - mutatedLines: 'bar', - }), - ]); + mutant.status = MutantStatus.NoCoverage; + act(report); expect(stdoutStub).calledWithMatch(sinon.match('1. [NoCoverage] Math')); expect(stdoutStub).calledWith(`${chalk.red('- foo')}${os.EOL}`); expect(stdoutStub).calledWith(`${chalk.green('+ bar')}${os.EOL}`); }); it('should report a Survived mutant to stdout', async () => { - sut.onAllMutantsTested([factory.undetectedMutantResult({ id: '42', mutatorName: 'Math', status: MutantStatus.Survived })]); - expect(stdoutStub).calledWithMatch(sinon.match('42. [Survived] Math')); + mutant.status = MutantStatus.Survived; + act(report); + expect(stdoutStub).calledWithMatch(sinon.match('1. [Survived] Math')); }); it('should report a Timeout mutant to stdout', async () => { - sut.onAllMutantsTested([factory.timeoutMutantResult({ id: '42', mutatorName: 'Math', status: MutantStatus.TimedOut })]); - expect(testInjector.logger.debug).calledWithMatch(sinon.match('42. [TimedOut] Math')); + mutant.status = MutantStatus.Timeout; + act(report); + expect(testInjector.logger.debug).calledWithMatch(sinon.match('1. [Timeout] Math')); }); it('should report the tests ran for a Survived mutant to stdout for "perTest" coverage analysis', async () => { - testInjector.options.coverageAnalysis = 'perTest'; - sut.onAllMutantsTested([ - factory.undetectedMutantResult({ - status: MutantStatus.Survived, - testFilter: ['foo should be bar', 'baz should be qux', 'quux should be corge'], - }), - ]); + mutant.coveredBy = ['1', '2', '3']; + mutant.status = MutantStatus.Survived; + act(report); expect(stdoutStub).calledWithExactly(`Tests ran:${os.EOL}`); expect(stdoutStub).calledWithExactly(` foo should be bar${os.EOL}`); + expect(stdoutStub).calledWithExactly(` bar should be baz${os.EOL}`); expect(stdoutStub).calledWithExactly(` baz should be qux${os.EOL}`); - expect(stdoutStub).calledWithExactly(` quux should be corge${os.EOL}`); }); it('should report the max tests to log and however many more tests', async () => { - testInjector.options.coverageAnalysis = 'perTest'; testInjector.options.clearTextReporter.maxTestsToLog = 2; - sut.onAllMutantsTested([ - factory.undetectedMutantResult({ - status: MutantStatus.Survived, - testFilter: ['foo should be bar', 'baz should be qux', 'quux should be corge'], - }), - ]); + mutant.coveredBy = ['1', '2', '3']; + mutant.status = MutantStatus.Survived; + act(report); expect(stdoutStub).calledWithExactly(`Tests ran:${os.EOL}`); expect(stdoutStub).calledWithExactly(` foo should be bar${os.EOL}`); - expect(stdoutStub).calledWithExactly(` baz should be qux${os.EOL}`); - expect(stdoutStub).not.calledWithMatch(sinon.match('quux should be corge')); + expect(stdoutStub).calledWithExactly(` bar should be baz${os.EOL}`); + expect(stdoutStub).not.calledWithMatch(sinon.match('baz should be qux')); expect(stdoutStub).calledWithExactly(` and 1 more test!${os.EOL}`); }); - it('should report that all tests have ran for a mutant when coverage analysis when testFilter is not defined', async () => { - testInjector.options.coverageAnalysis = 'perTest'; + it('should report that all tests have ran for a surviving mutant that is static', async () => { testInjector.options.clearTextReporter.maxTestsToLog = 2; - sut.onAllMutantsTested([ - factory.undetectedMutantResult({ - status: MutantStatus.Survived, - testFilter: undefined, - }), - ]); + mutant.static = true; + mutant.status = MutantStatus.Survived; + act(report); expect(stdoutStub).calledWithExactly(`Ran all tests for this mutant.${os.EOL}`); }); it('should not log individual ran tests when logTests is not true', () => { - testInjector.options.coverageAnalysis = 'perTest'; testInjector.options.clearTextReporter.logTests = false; - sut.onAllMutantsTested([factory.undetectedMutantResult({ status: MutantStatus.Survived, testFilter: ['foo should be bar'] })]); + mutant.coveredBy = ['1', '2', '3']; + mutant.status = MutantStatus.Survived; + act(report); expect(process.stdout.write).not.calledWithMatch(sinon.match('Tests ran: ')); expect(process.stdout.write).not.calledWithMatch(sinon.match('foo should be bar')); expect(process.stdout.write).not.calledWithMatch(sinon.match('Ran all tests for this mutant.')); }); - it('should report that all tests have ran for a mutant when coverage analysis = "all"', async () => { - testInjector.options.coverageAnalysis = 'all'; - sut.onAllMutantsTested([factory.undetectedMutantResult({ status: MutantStatus.Survived, testFilter: [] })]); - expect(stdoutStub).calledWithExactly(`Ran all tests for this mutant.${os.EOL}`); - }); - it('should correctly report tests run per mutant on avg', () => { - sut.onAllMutantsTested([ - factory.undetectedMutantResult({ nrOfTestsRan: 4 }), - factory.killedMutantResult({ nrOfTestsRan: 5 }), - factory.undetectedMutantResult({ nrOfTestsRan: 1 }), - ]); + mutant.testsCompleted = 4; + report.files['foo.js'].mutants.push(factory.mutationTestReportSchemaMutantResult({ testsCompleted: 5 })); + report.files['foo.js'].mutants.push(factory.mutationTestReportSchemaMutantResult({ testsCompleted: 1 })); + act(report); + expect(stdoutStub).calledWithExactly(`Ran 3.33 tests per mutant on average.${os.EOL}`); }); it('should log source file location', () => { - testInjector.options.coverageAnalysis = 'perTest'; - - sut.onAllMutantsTested([factory.undetectedMutantResult({ fileName: 'foo.js', location: factory.location({ start: { line: 4, column: 6 } }) })]); + mutant.status = MutantStatus.Survived; + mutant.location.start = { line: 4, column: 6 }; + act(report); expect(stdoutStub).to.have.been.calledWithMatch(sinon.match(`${chalk.cyan('foo.js')}:${chalk.yellow('4')}:${chalk.yellow('6')}`)); }); it('should log source file names without colored text when clearTextReporter is not false and allowConsoleColors is false', () => { - testInjector.options.coverageAnalysis = 'perTest'; testInjector.options.allowConsoleColors = false; + mutant.status = MutantStatus.Survived; + mutant.location.start = { line: 4, column: 6 }; // Recreate, color setting is set in constructor sut = testInjector.injector.injectClass(ClearTextReporter); + act(report); - sut.onAllMutantsTested([ - factory.killedMutantResult({ fileName: 'sourceFile.ts', location: factory.location({ start: { line: 1, column: 2 } }) }), - ]); - - expect(testInjector.logger.debug).calledWithMatch(sinon.match('sourceFile.ts:1:2')); + expect(stdoutStub).calledWithMatch(sinon.match('foo.js:4:6')); }); }); + + function act(report: schema.MutationTestResult) { + sut.onMutationTestReportReady(report, calculateMutationTestMetrics(report)); + } }); diff --git a/packages/core/test/unit/reporters/dashboard-reporter/dashboard-reporter.spec.ts b/packages/core/test/unit/reporters/dashboard-reporter/dashboard-reporter.spec.ts index fba48cb037..d6af26b167 100644 --- a/packages/core/test/unit/reporters/dashboard-reporter/dashboard-reporter.spec.ts +++ b/packages/core/test/unit/reporters/dashboard-reporter/dashboard-reporter.spec.ts @@ -1,8 +1,9 @@ -import { mutationTestReportSchema } from '@stryker-mutator/api/report'; import { testInjector, factory } from '@stryker-mutator/test-helpers'; import { expect } from 'chai'; import sinon from 'sinon'; -import { ReportType } from '@stryker-mutator/api/core'; +import { MutantStatus, ReportType, schema } from '@stryker-mutator/api/core'; + +import { calculateMutationTestMetrics } from 'mutation-testing-metrics'; import { CIProvider } from '../../../../src/reporters/ci/provider'; import { DashboardReporter } from '../../../../src/reporters/dashboard-reporter/dashboard-reporter'; @@ -78,10 +79,10 @@ describe(DashboardReporter.name, () => { files: { 'a.js': factory.mutationTestReportSchemaFileResult({ mutants: [ - factory.mutationTestReportSchemaMutantResult({ status: mutationTestReportSchema.MutantStatus.Killed }), - factory.mutationTestReportSchemaMutantResult({ status: mutationTestReportSchema.MutantStatus.Killed }), - factory.mutationTestReportSchemaMutantResult({ status: mutationTestReportSchema.MutantStatus.Killed }), - factory.mutationTestReportSchemaMutantResult({ status: mutationTestReportSchema.MutantStatus.Survived }), + factory.mutationTestReportSchemaMutantResult({ status: MutantStatus.Killed }), + factory.mutationTestReportSchemaMutantResult({ status: MutantStatus.Killed }), + factory.mutationTestReportSchemaMutantResult({ status: MutantStatus.Killed }), + factory.mutationTestReportSchemaMutantResult({ status: MutantStatus.Survived }), ], }), }, @@ -108,7 +109,7 @@ describe(DashboardReporter.name, () => { const sut = createSut(null); // Act - sut.onMutationTestReportReady(factory.mutationTestReportSchemaMutationTestResult()); + sut.onMutationTestReportReady(factory.mutationTestReportSchemaMutationTestResult(), factory.mutationTestMetricsResult()); await sut.wrapUp(); // Assert @@ -118,9 +119,9 @@ describe(DashboardReporter.name, () => { ); }); - async function act(result: mutationTestReportSchema.MutationTestResult) { + async function act(result: schema.MutationTestResult) { const sut = createSut(); - sut.onMutationTestReportReady(result); + sut.onMutationTestReportReady(result, calculateMutationTestMetrics(result)); await sut.wrapUp(); } }); diff --git a/packages/core/test/unit/reporters/dots-reporter.spec.ts b/packages/core/test/unit/reporters/dots-reporter.spec.ts index 7bb7f4ccb5..7a8ae65bea 100644 --- a/packages/core/test/unit/reporters/dots-reporter.spec.ts +++ b/packages/core/test/unit/reporters/dots-reporter.spec.ts @@ -1,10 +1,10 @@ import os from 'os'; -import { MutantStatus } from '@stryker-mutator/api/report'; -import { factory } from '@stryker-mutator/test-helpers'; import { expect } from 'chai'; import sinon from 'sinon'; import chalk from 'chalk'; +import { MutantStatus } from '@stryker-mutator/api/core'; +import { factory } from '@stryker-mutator/test-helpers'; import { DotsReporter } from '../../../src/reporters/dots-reporter'; @@ -30,7 +30,7 @@ describe(DotsReporter.name, () => { }); it('should log "S" when status is Survived', () => { - sut.onMutantTested(factory.undetectedMutantResult({ status: MutantStatus.Survived })); + sut.onMutantTested(factory.mutantResult({ status: MutantStatus.Survived })); expect(process.stdout.write).to.have.been.calledWith(chalk.bold.red('S')); }); }); diff --git a/packages/core/test/unit/reporters/html/html-reporter.spec.ts b/packages/core/test/unit/reporters/html/html-reporter.spec.ts index 651bf420a6..36d693a37a 100644 --- a/packages/core/test/unit/reporters/html/html-reporter.spec.ts +++ b/packages/core/test/unit/reporters/html/html-reporter.spec.ts @@ -1,9 +1,9 @@ import path from 'path'; -import { mutationTestReportSchema } from '@stryker-mutator/api/report'; -import { testInjector } from '@stryker-mutator/test-helpers'; import { expect } from 'chai'; import sinon from 'sinon'; +import { testInjector } from '@stryker-mutator/test-helpers'; +import { schema } from '@stryker-mutator/api/core'; import { HtmlReporter } from '../../../../src/reporters/html/html-reporter'; import * as ReporterUtil from '../../../../src/reporters/reporter-util'; @@ -49,7 +49,7 @@ describe(HtmlReporter.name, () => { }); it('should write the mutation report in the index file', async () => { - const report: mutationTestReportSchema.MutationTestResult = { + const report: schema.MutationTestResult = { files: { 'foo.js': { language: 'js', @@ -69,7 +69,7 @@ describe(HtmlReporter.name, () => { }); it('should escape HTML tags in the mutation testing report.', async () => { - const report: mutationTestReportSchema.MutationTestResult = { + const report: schema.MutationTestResult = { files: { 'index.html': { language: 'html', diff --git a/packages/core/test/unit/reporters/json-reporter.spec.ts b/packages/core/test/unit/reporters/json-reporter.spec.ts index 816ded7ccf..2a36438287 100644 --- a/packages/core/test/unit/reporters/json-reporter.spec.ts +++ b/packages/core/test/unit/reporters/json-reporter.spec.ts @@ -1,9 +1,9 @@ import path from 'path'; -import { mutationTestReportSchema } from '@stryker-mutator/api/report'; -import { testInjector } from '@stryker-mutator/test-helpers'; import { expect } from 'chai'; import sinon from 'sinon'; +import { testInjector } from '@stryker-mutator/test-helpers'; +import { schema } from '@stryker-mutator/api/core'; import { JsonReporter } from '../../../src/reporters/json-reporter'; import * as JsonReporterUtil from '../../../src/reporters/reporter-util'; @@ -37,7 +37,7 @@ describe(JsonReporter.name, () => { }); it('should write the mutation report to disk', async () => { - const report: mutationTestReportSchema.MutationTestResult = { + const report: schema.MutationTestResult = { files: {}, schemaVersion: '1.0', thresholds: { diff --git a/packages/core/test/unit/reporters/mutation-test-report-helper.spec.ts b/packages/core/test/unit/reporters/mutation-test-report-helper.spec.ts index 6069568ec9..be0cb35131 100644 --- a/packages/core/test/unit/reporters/mutation-test-report-helper.spec.ts +++ b/packages/core/test/unit/reporters/mutation-test-report-helper.spec.ts @@ -1,26 +1,17 @@ import sinon from 'sinon'; -import { File, Location, Range } from '@stryker-mutator/api/core'; -import { - MutantResult, - MutantStatus, - mutationTestReportSchema, - Reporter, - InvalidMutantResult, - UndetectedMutantResult, - KilledMutantResult, - TimeoutMutantResult, - IgnoredMutantResult, -} from '@stryker-mutator/api/report'; +import { File, Location, MutantResult, MutantStatus, Range, schema } from '@stryker-mutator/api/core'; +import { Reporter } from '@stryker-mutator/api/report'; import { factory, testInjector } from '@stryker-mutator/test-helpers'; import { expect } from 'chai'; import { CompleteDryRunResult } from '@stryker-mutator/api/test-runner'; import { CheckStatus } from '@stryker-mutator/api/check'; +import { calculateMutationTestMetrics } from 'mutation-testing-metrics'; + import { coreTokens } from '../../../src/di'; import { InputFileCollection } from '../../../src/input/input-file-collection'; import { MutationTestReportHelper } from '../../../src/reporters/mutation-test-report-helper'; import * as objectUtils from '../../../src/utils/object-utils'; -import { createMutantTestCoverage } from '../../helpers/producers'; describe(MutationTestReportHelper.name, () => { let reporterMock: sinon.SinonStubbedInstance>; @@ -36,8 +27,9 @@ describe(MutationTestReportHelper.name, () => { inputFiles = { files, filesToMutate: [], - // eslint-disable-next-line @typescript-eslint/no-empty-function - logFiles: () => {}, + logFiles: () => { + // idle + }, }; dryRunResult = factory.completeDryRunResult(); }); @@ -73,16 +65,16 @@ describe(MutationTestReportHelper.name, () => { }); it('should copy thresholds', () => { - const actualReport = actReportAll(); + const [actualReport] = actReportAll(); expect(actualReport.thresholds).eq(testInjector.options.thresholds); }); it('should set correct schema version', () => { - const actualReport = actReportAll(); + const [actualReport] = actReportAll(); expect(actualReport.schemaVersion).eq('1.0'); }); - it('should correctly map file properties', () => { + it('should correctly map system under test file properties', () => { // Arrange files.push(new File('foo.js', 'foo content')); files.push(new File('bar.html', 'bar content')); @@ -92,7 +84,7 @@ describe(MutationTestReportHelper.name, () => { const inputMutants = files.map((file) => factory.killedMutantResult({ fileName: file.name })); // Act - const actualReport = actReportAll(inputMutants); + const [actualReport] = actReportAll(inputMutants); // Assert expect(Object.keys(actualReport.files)).lengthOf(5); @@ -103,33 +95,63 @@ describe(MutationTestReportHelper.name, () => { expect(actualReport.files['corge.tsx']).include({ language: 'typescript', source: 'corge content' }); }); + it('should report the tests in `testFiles`', () => { + // Arrange + dryRunResult.tests.push( + factory.testResult({ id: 'spec1', name: 'dog should not eat dog' }), + factory.testResult({ id: 'spec2', name: 'dog should chase its own tail' }) + ); + + // Act + const [actualReport] = actReportAll([]); + + // Assert + const expected: schema.TestFileDefinitionDictionary = { + ['']: { + tests: [ + { id: '0', name: 'dog should not eat dog' }, + { id: '1', name: 'dog should chase its own tail' }, + ], + }, + }; + expect(actualReport.testFiles).deep.eq(expected); + }); + it('should correctly map basic MutantResult properties', () => { // Arrange + const killedMutantResult: MutantResult = { + id: '1', + mutatorName: 'Foo', + replacement: 'foo replacement', + fileName: 'foo.js', + description: 'this is mutant foo', + duration: 42, + location: factory.location(), + range: [1, 2], + static: true, + statusReason: 'smacked on the head', + testsCompleted: 32, + status: MutantStatus.Killed, + }; const inputMutants = [ - factory.killedMutantResult({ - id: '1', - mutatorName: 'Foo', - replacement: 'foo replacement', - fileName: 'foo.js', - status: MutantStatus.Killed, - }), - factory.undetectedMutantResult({ + killedMutantResult, + factory.mutantResult({ fileName: 'bar.js', status: MutantStatus.NoCoverage, }), - factory.invalidMutantResult({ + factory.mutantResult({ fileName: 'baz.js', status: MutantStatus.RuntimeError, }), - factory.undetectedMutantResult({ + factory.mutantResult({ fileName: 'qux.js', status: MutantStatus.Survived, }), - factory.timeoutMutantResult({ + factory.mutantResult({ fileName: '5.js', - status: MutantStatus.TimedOut, + status: MutantStatus.Timeout, }), - factory.invalidMutantResult({ + factory.mutantResult({ fileName: '6.js', status: MutantStatus.CompileError, }), @@ -137,38 +159,71 @@ describe(MutationTestReportHelper.name, () => { files.push(...inputMutants.map((m) => new File(m.fileName, ''))); // Act - const actualReport = actReportAll(inputMutants); + const [actualReport] = actReportAll(inputMutants); // Assert - expect(Object.keys(actualReport.files)).lengthOf(6); - expect(actualReport.files['foo.js'].mutants[0]).include({ + const expectedKilledMutant: Partial = { id: '1', mutatorName: 'Foo', replacement: 'foo replacement', - status: mutationTestReportSchema.MutantStatus.Killed, - }); - expect(actualReport.files['bar.js'].mutants[0]).include({ status: mutationTestReportSchema.MutantStatus.NoCoverage }); - expect(actualReport.files['baz.js'].mutants[0]).include({ status: mutationTestReportSchema.MutantStatus.RuntimeError }); - expect(actualReport.files['qux.js'].mutants[0]).include({ status: mutationTestReportSchema.MutantStatus.Survived }); - expect(actualReport.files['5.js'].mutants[0]).include({ status: mutationTestReportSchema.MutantStatus.Timeout }); - expect(actualReport.files['6.js'].mutants[0]).include({ status: mutationTestReportSchema.MutantStatus.CompileError }); + description: 'this is mutant foo', + duration: 42, + static: true, + statusReason: 'smacked on the head', + testsCompleted: 32, + status: MutantStatus.Killed, + }; + expect(Object.keys(actualReport.files)).lengthOf(6); + expect(actualReport.files['foo.js'].mutants[0]).include(expectedKilledMutant); + expect(actualReport.files['bar.js'].mutants[0]).include({ status: MutantStatus.NoCoverage }); + expect(actualReport.files['baz.js'].mutants[0]).include({ status: MutantStatus.RuntimeError }); + expect(actualReport.files['qux.js'].mutants[0]).include({ status: MutantStatus.Survived }); + expect(actualReport.files['5.js'].mutants[0]).include({ status: MutantStatus.Timeout }); + expect(actualReport.files['6.js'].mutants[0]).include({ status: MutantStatus.CompileError }); }); it('should offset location correctly', () => { - const inputMutants = [factory.killedMutantResult({ location: { end: { line: 3, column: 4 }, start: { line: 1, column: 2 } } })]; + const inputMutants = [factory.mutantResult({ location: { end: { line: 3, column: 4 }, start: { line: 1, column: 2 } } })]; files.push(...inputMutants.map((m) => new File(m.fileName, ''))); - const actualReport = actReportAll(inputMutants); + const [actualReport] = actReportAll(inputMutants); expect(actualReport.files['file.js'].mutants[0].location).deep.eq({ end: { line: 4, column: 5 }, start: { line: 2, column: 3 } }); }); + it('should remap test ids if possible (for brevity, since mocha, jest and karma use test titles as test ids)', () => { + // Arrange + dryRunResult.tests.push( + factory.testResult({ id: 'foo should bar', name: 'foo should bar' }), + factory.testResult({ id: 'baz should qux', name: 'baz should qux' }) + ); + const killedMutantResult = factory.mutantResult({ + fileName: 'foo.js', + killedBy: ['foo should bar'], + coveredBy: ['foo should bar', 'baz should qux', 'not found'], + }); + files.push(new File('foo.js', '')); + + // Act + const [actualReport] = actReportAll([killedMutantResult]); + + // Assert + const expectedTests: schema.TestDefinition[] = [ + { id: '0', name: 'foo should bar' }, + { id: '1', name: 'baz should qux' }, + ]; + const actualResultMutant = actualReport.files['foo.js'].mutants[0]; + expect(actualReport.testFiles?.[''].tests).deep.eq(expectedTests); + expect(actualResultMutant.coveredBy).deep.eq(['0', '1', 'not found']); + expect(actualResultMutant.killedBy).deep.eq(['0']); + }); + it('should group mutants by file name', () => { // Arrange const inputMutants = [ - factory.killedMutantResult({ + factory.mutantResult({ mutatorName: 'Foo', fileName: 'foo.js', }), - factory.undetectedMutantResult({ + factory.mutantResult({ mutatorName: 'Bar', fileName: 'foo.js', }), @@ -176,7 +231,7 @@ describe(MutationTestReportHelper.name, () => { files.push(new File('foo.js', '')); // Act - const actualReport = actReportAll(inputMutants); + const [actualReport] = actReportAll(inputMutants); // Assert expect(Object.keys(actualReport.files)).lengthOf(1); @@ -185,18 +240,41 @@ describe(MutationTestReportHelper.name, () => { it('should log a warning if source file could not be found', () => { const inputMutants = [factory.killedMutantResult({ fileName: 'not-found.js' })]; - const actualReport = actReportAll(inputMutants); + const [actualReport] = actReportAll(inputMutants); expect(Object.keys(actualReport.files)).lengthOf(0); expect(testInjector.logger.warn).calledWithMatch('File "not-found.js" not found'); }); + it('should provide the metrics as second argument', () => { + // Arrange + const inputMutants: MutantResult[] = [ + { + mutatorName: 'Foo', + fileName: 'foo.js', + status: MutantStatus.Killed, + range: [1, 2], + location: { start: { line: 1, column: 2 }, end: { line: 4, column: 5 } }, + replacement: '+', + id: '1', + }, + ]; + files.push(new File('foo.js', '')); + dryRunResult.tests.push(factory.testResult({ id: 'foo should bar', name: 'foo should bar' })); + + // Act + const [actualReport, metrics] = actReportAll(inputMutants); + + // Assert + expect(metrics).deep.eq(calculateMutationTestMetrics(actualReport)); + }); + describe('determineExitCode', () => { beforeEach(() => { files.push(new File('file.js', '')); }); it('should not set exit code = 1 if `threshold.break` is not configured', () => { - actReportAll([factory.undetectedMutantResult({ status: MutantStatus.Survived })]); + actReportAll([factory.mutantResult({ status: MutantStatus.Survived })]); expect(setExitCodeStub).not.called; expect(testInjector.logger.debug).calledWith( @@ -206,53 +284,23 @@ describe(MutationTestReportHelper.name, () => { it('should not set exit code = 1 if `threshold.break` === score', () => { testInjector.options.thresholds.break = 50; - actReportAll([ - factory.undetectedMutantResult({ status: MutantStatus.Survived }), - factory.killedMutantResult({ status: MutantStatus.Killed }), - ]); // 50 % + actReportAll([factory.mutantResult({ status: MutantStatus.Survived }), factory.mutantResult({ status: MutantStatus.Killed })]); // 50 % expect(setExitCodeStub).not.called; expect(testInjector.logger.info).calledWith('Final mutation score of 50.00 is greater than or equal to break threshold 50'); }); it('should set exit code = 1 if `threshold.break` > score', () => { testInjector.options.thresholds.break = 50.01; - actReportAll([ - factory.undetectedMutantResult({ status: MutantStatus.Survived }), - factory.killedMutantResult({ status: MutantStatus.Killed }), - ]); // 50 % + actReportAll([factory.mutantResult({ status: MutantStatus.Survived }), factory.mutantResult({ status: MutantStatus.Killed })]); // 50 % expect(setExitCodeStub).calledWith(1); expect(testInjector.logger.error).calledWith('Final mutation score 50.00 under breaking threshold 50.01, setting exit code to 1 (failure).'); expect(testInjector.logger.info).calledWith('(improve mutation score or set `thresholds.break = null` to prevent this error in the future)'); }); }); - describe('determine description', () => { - beforeEach(() => { - files.push(new File('file.js', '')); - }); - - it('should provide the error message as description', () => { - const mutantResult = factory.invalidMutantResult({ fileName: 'file.js', errorMessage: 'Cannot call "foo" of undefined' }); - const actualReport = actReportAll([mutantResult]); - expect(actualReport.files['file.js'].mutants[0].description).eq('Error message: Cannot call "foo" of undefined'); - }); - - it('should provide the "killedBy" as description', () => { - const mutantResult = factory.killedMutantResult({ fileName: 'file.js', killedBy: 'Foo should be bar' }); - const actualReport = actReportAll([mutantResult]); - expect(actualReport.files['file.js'].mutants[0].description).eq('Killed by: Foo should be bar'); - }); - - it('should provide the ignore reason as description', () => { - const mutantResult = factory.ignoredMutantResult({ fileName: 'file.js', ignoreReason: 'Ignored by "fooMutator" in excludedMutations' }); - const actualReport = actReportAll([mutantResult]); - expect(actualReport.files['file.js'].mutants[0].description).eq('Ignore reason: Ignored by "fooMutator" in excludedMutations'); - }); - }); - - function actReportAll(input: MutantResult[] = []): mutationTestReportSchema.MutationTestResult { + function actReportAll(input: MutantResult[] = []): Parameters['onMutationTestReportReady']> { sut.reportAll(input); - return reporterMock.onMutationTestReportReady.firstCall.args[0]; + return reporterMock.onMutationTestReportReady.firstCall.args; } }); @@ -261,177 +309,183 @@ describe(MutationTestReportHelper.name, () => { inputFiles = new InputFileCollection([new File('add.js', 'function add(a, b) {\n return a + b;\n}\n')], ['add.js']); }); - it('should map simple attributes to the mutant result', () => { - // Arrange - const sut = createSut(); - const location: Location = Object.freeze({ start: Object.freeze({ line: 1, column: 5 }), end: Object.freeze({ line: 3, column: 1 }) }); - const range: Range = [21, 35]; + describe(MutationTestReportHelper.prototype.reportCheckFailed.name, () => { + it('should map simple attributes to the mutant result', () => { + // Arrange + const sut = createSut(); + const location: Location = Object.freeze({ start: Object.freeze({ line: 1, column: 5 }), end: Object.freeze({ line: 3, column: 1 }) }); + const range: Range = [21, 35]; + + // Act + const actual = sut.reportCheckFailed( + factory.mutant({ + id: '32', + fileName: 'add.js', + location, + replacement: '{}', + mutatorName: 'fooMutator', + range, + }), + factory.failedCheckResult() + ); - // Act - const actual = sut.reportCheckFailed( - factory.mutant({ - id: 32, - fileName: 'add.js', + // Assert + const expected: Partial = { + id: '32', location, - replacement: '{}', mutatorName: 'fooMutator', range, - }), - factory.failedCheckResult() - ); - - // Assert - const expected: Partial = { - id: '32', - location, - mutatorName: 'fooMutator', - range, - fileName: 'add.js', - replacement: '{}', - }; - expect(actual).include(expected); - }); - - it('should report failed message on reportCheckFailed', () => { - // Arrange - const sut = createSut(); - - // Act - const actual = sut.reportCheckFailed( - factory.mutant({ fileName: 'add.js' }), - factory.failedCheckResult({ status: CheckStatus.CompileError, reason: 'cannot call foo of undefined' }) - ); - - // Assert - const expected: Partial = { - status: MutantStatus.CompileError, - errorMessage: 'cannot call foo of undefined', - }; - expect(actual).include(expected); - }); + fileName: 'add.js', + replacement: '{}', + }; + expect(actual).include(expected); + }); - it('should report an empty test filter on reportNoCoverage', () => { - // Arrange - const sut = createSut(); + it('should report statusReason', () => { + // Arrange + const sut = createSut(); - // Act - const actual = sut.reportNoCoverage(factory.mutant({ fileName: 'add.js' })); + // Act + const actual = sut.reportCheckFailed( + factory.mutant({ fileName: 'add.js' }), + factory.failedCheckResult({ status: CheckStatus.CompileError, reason: 'cannot call foo of undefined' }) + ); - // Assert - const expected: Partial = { - status: MutantStatus.NoCoverage, - testFilter: [], - }; - expect(actual).deep.include(expected); + // Assert + const expected: Partial = { + status: MutantStatus.CompileError, + statusReason: 'cannot call foo of undefined', + }; + expect(actual).include(expected); + }); }); - it('should report a killed mutant on reportMutantRunResult with a KilledMutantRunResult', () => { - // Arrange - dryRunResult.tests.push(factory.failedTestResult({ id: '1', name: 'foo should be bar' })); - const sut = createSut(); - - // Act - const actual = sut.reportMutantRunResult( - createMutantTestCoverage({ mutant: factory.mutant({ fileName: 'add.js' }) }), - factory.killedMutantRunResult({ killedBy: '1', nrOfTests: 42 }) - ); - - // Assert - const expected: Partial = { - status: MutantStatus.Killed, - killedBy: 'foo should be bar', - nrOfTestsRan: 42, - }; - expect(actual).deep.include(expected); + describe(MutationTestReportHelper.prototype.reportMutantStatus.name, () => { + it('should correctly map all properties', () => { + // Arrange + const input = factory.mutantTestCoverage({ + fileName: 'add.js', + id: '3', + location: factory.location(), + mutatorName: 'fooMutator', + range: [1, 3], + replacement: '"bar"', + coveredBy: ['1'], + static: false, + }); + const sut = createSut(); + + // Act + const actual = sut.reportMutantStatus(input, MutantStatus.NoCoverage); + + // Assert + const expected: MutantResult = { + status: MutantStatus.NoCoverage, + fileName: 'add.js', + id: '3', + location: factory.location(), + mutatorName: 'fooMutator', + range: [1, 3], + replacement: '"bar"', + coveredBy: ['1'], + static: false, + }; + expect(actual).deep.include(expected); + }); }); - it('should report a runtime error mutant on reportMutantRunResult with a ErrorMutantRunResult', () => { - // Arrange - const sut = createSut(); + describe(MutationTestReportHelper.prototype.reportMutantRunResult.name, () => { + it('should report a killed mutant when called with a KilledMutantRunResult', () => { + // Arrange + dryRunResult.tests.push(factory.failedTestResult({ id: '1', name: 'foo should be bar' })); + const sut = createSut(); - // Act - const actual = sut.reportMutantRunResult( - createMutantTestCoverage({ mutant: factory.mutant({ fileName: 'add.js' }) }), - factory.errorMutantRunResult({ errorMessage: 'Cannot call foo of null' }) - ); + // Act + const actual = sut.reportMutantRunResult( + factory.mutantTestCoverage({ fileName: 'add.js' }), + factory.killedMutantRunResult({ killedBy: '1', nrOfTests: 42, failureMessage: 'foo should have been bar at line 1' }) + ); - // Assert - const expected: Partial = { - status: MutantStatus.RuntimeError, - errorMessage: 'Cannot call foo of null', - }; - expect(actual).deep.include(expected); - }); + // Assert + const expected: Partial = { + status: MutantStatus.Killed, + killedBy: ['1'], + testsCompleted: 42, + statusReason: 'foo should have been bar at line 1', + }; + expect(actual).deep.include(expected); + }); - it('should report a timeout mutant on reportMutantRunResult with a TimeoutMutantRunResult', () => { - // Arrange - const sut = createSut(); + it('should report a runtime error when called with an ErrorMutantRunResult', () => { + // Arrange + const sut = createSut(); - // Act - const actual = sut.reportMutantRunResult( - createMutantTestCoverage({ mutant: factory.mutant({ fileName: 'add.js' }) }), - factory.timeoutMutantRunResult() - ); + // Act + const actual = sut.reportMutantRunResult( + factory.mutantTestCoverage({ fileName: 'add.js' }), + factory.errorMutantRunResult({ errorMessage: 'Cannot call foo of null' }) + ); - // Assert - const expected: Partial = { - status: MutantStatus.TimedOut, - }; - expect(actual).deep.include(expected); - }); + // Assert + const expected: Partial = { + status: MutantStatus.RuntimeError, + statusReason: 'Cannot call foo of null', + }; + expect(actual).deep.include(expected); + }); - it('should report an ignored mutant on reportMutantRunResult with a IgnoredMutantResult', () => { - // Arrange - const sut = createSut(); + it('should report a timeout mutant when called with a TimeoutMutantRunResult', () => { + // Arrange + const sut = createSut(); - // Act - const actual = sut.reportMutantIgnored(factory.mutant({ fileName: 'add.js', ignoreReason: 'foo is ignored' })); + // Act + const actual = sut.reportMutantRunResult(factory.mutantTestCoverage({ fileName: 'add.js' }), factory.timeoutMutantRunResult()); - // Assert - const expected: Partial = { - status: MutantStatus.Ignored, - ignoreReason: 'foo is ignored', - }; - expect(actual).deep.include(expected); - }); + // Assert + const expected: Partial = { + status: MutantStatus.Timeout, + }; + expect(actual).deep.include(expected); + }); - it('should report a survived mutant on reportMutantRunResult with a SurvivedMutantRunResult', () => { - // Arrange - dryRunResult.tests.push(factory.failedTestResult({ id: '1', name: 'foo should be bar' })); - const sut = createSut(); + it('should report a survived mutant when called with a SurvivedMutantRunResult', () => { + // Arrange + dryRunResult.tests.push(factory.failedTestResult({ id: '1', name: 'foo should be bar' })); + const sut = createSut(); - // Act - const actual = sut.reportMutantRunResult( - createMutantTestCoverage({ mutant: factory.mutant({ fileName: 'add.js' }), testFilter: ['1'] }), - factory.survivedMutantRunResult({ nrOfTests: 4 }) - ); + // Act + const actual = sut.reportMutantRunResult( + factory.mutantTestCoverage({ fileName: 'add.js', coveredBy: ['1'] }), + factory.survivedMutantRunResult({ nrOfTests: 4 }) + ); - // Assert - const expected: Partial = { - status: MutantStatus.Survived, - testFilter: ['foo should be bar'], - nrOfTestsRan: 4, - }; - expect(actual).deep.include(expected); - }); + // Assert + const expected: Partial = { + status: MutantStatus.Survived, + coveredBy: ['1'], + testsCompleted: 4, + }; + expect(actual).deep.include(expected); + }); - it('should be able to report testFilter as `undefined` for a survived mutant', () => { - // Arrange - dryRunResult.tests.push(factory.failedTestResult({ id: '1', name: 'foo should be bar' })); - const sut = createSut(); + it('should be able to report coveredBy as `undefined` for a survived mutant', () => { + // Arrange + dryRunResult.tests.push(factory.failedTestResult({ id: '1', name: 'foo should be bar' })); + const sut = createSut(); - // Act - const actual = sut.reportMutantRunResult( - createMutantTestCoverage({ mutant: factory.mutant({ fileName: 'add.js' }), testFilter: undefined }), - factory.survivedMutantRunResult() - ); + // Act + const actual = sut.reportMutantRunResult( + factory.mutantTestCoverage({ fileName: 'add.js', coveredBy: undefined }), + factory.survivedMutantRunResult() + ); - // Assert - const expected: Partial = { - status: MutantStatus.Survived, - testFilter: undefined, - }; - expect(actual).deep.include(expected); + // Assert + const expected: Partial = { + status: MutantStatus.Survived, + coveredBy: undefined, + }; + expect(actual).deep.include(expected); + }); }); }); }); diff --git a/packages/core/test/unit/reporters/progress-append-only-reporter.spec.ts b/packages/core/test/unit/reporters/progress-append-only-reporter.spec.ts index 20f61fd7cb..2d7682193e 100644 --- a/packages/core/test/unit/reporters/progress-append-only-reporter.spec.ts +++ b/packages/core/test/unit/reporters/progress-append-only-reporter.spec.ts @@ -24,9 +24,9 @@ describe(ProgressAppendOnlyReporter.name, () => { describe('onAllMutantsMatchedWithTests() with 3 mutants to test', () => { beforeEach(() => { sut.onAllMutantsMatchedWithTests([ - factory.matchedMutant({ runAllTests: true }), - factory.matchedMutant({ runAllTests: true }), - factory.matchedMutant({ runAllTests: true }), + factory.mutantTestCoverage({ static: true }), + factory.mutantTestCoverage({ coveredBy: ['1'] }), + factory.mutantTestCoverage({ static: true }), ]); }); diff --git a/packages/core/test/unit/reporters/progress-reporter.spec.ts b/packages/core/test/unit/reporters/progress-reporter.spec.ts index 8a0b9ddc30..bc85faaa8d 100644 --- a/packages/core/test/unit/reporters/progress-reporter.spec.ts +++ b/packages/core/test/unit/reporters/progress-reporter.spec.ts @@ -1,8 +1,8 @@ -import { MatchedMutant, MutantStatus } from '@stryker-mutator/api/report'; import { expect } from 'chai'; import sinon from 'sinon'; import ProgressBar from 'progress'; import { factory } from '@stryker-mutator/test-helpers'; +import { MutantStatus, MutantTestCoverage } from '@stryker-mutator/api/core'; import * as progressBarModule from '../../../src/reporters/progress-bar'; import { ProgressBarReporter } from '../../../src/reporters/progress-reporter'; @@ -16,7 +16,7 @@ const ONE_HOUR = SECOND * 3600; describe(ProgressBarReporter.name, () => { let sut: ProgressBarReporter; - let matchedMutants: MatchedMutant[]; + let mutants: MutantTestCoverage[]; let progressBar: Mock; const progressBarContent = 'Mutation testing [:bar] :percent (elapsed: :et, remaining: :etc) :tested/:total tested (:survived survived, :timedOut timed out)'; @@ -29,46 +29,38 @@ describe(ProgressBarReporter.name, () => { }); describe('onAllMutantsMatchedWithTests()', () => { - describe('when there are 3 MatchedMutants that all contain Tests', () => { - beforeEach(() => { - matchedMutants = [ - factory.matchedMutant({ runAllTests: true }), - factory.matchedMutant({ runAllTests: true }), - factory.matchedMutant({ runAllTests: true }), - ]; - - sut.onAllMutantsMatchedWithTests(matchedMutants); - }); - - it('the total of MatchedMutants in the progress bar should be 3', () => { - expect(progressBarModule.ProgressBar).to.have.been.calledWithMatch(progressBarContent, { total: 3 }); - }); + it('should show a progress bar for 3 mutants with 3 static mutants ', () => { + mutants = [ + factory.mutantTestCoverage({ static: true }), + factory.mutantTestCoverage({ static: true }), + factory.mutantTestCoverage({ static: true }), + ]; + + sut.onAllMutantsMatchedWithTests(mutants); + + expect(progressBarModule.ProgressBar).calledWithMatch(progressBarContent, { total: 3 }); }); - describe("when there are 2 MatchedMutants that all contain Tests and 1 MatchMutant that doesn't have tests", () => { - beforeEach(() => { - matchedMutants = [ - factory.matchedMutant({ testFilter: undefined }), - factory.matchedMutant({ testFilter: ['spec1'] }), - factory.matchedMutant({ testFilter: ['spec2'] }), - ]; - - sut.onAllMutantsMatchedWithTests(matchedMutants); - }); - - it('the total of MatchedMutants in the progress bar should be 2', () => { - expect(progressBarModule.ProgressBar).to.have.been.calledWithMatch(progressBarContent, { total: 2 }); - }); + + it('should show a progress bar for 2 mutants when 3 mutants are presented of which 2 have coverage', () => { + mutants = [ + factory.mutantTestCoverage({ coveredBy: undefined }), + factory.mutantTestCoverage({ coveredBy: ['spec1'] }), + factory.mutantTestCoverage({ coveredBy: ['spec2'] }), + ]; + + sut.onAllMutantsMatchedWithTests(mutants); + expect(progressBarModule.ProgressBar).calledWithMatch(progressBarContent, { total: 2 }); }); - describe('when mutants match to all tests', () => { - beforeEach(() => { - matchedMutants = [factory.matchedMutant({ runAllTests: true }), factory.matchedMutant({ runAllTests: true })]; - sut.onAllMutantsMatchedWithTests(matchedMutants); - }); + it('should show a progress bar of 2 mutants when 3 mutants are presented of which 1 is static and 1 has coverage', () => { + mutants = [ + factory.mutantTestCoverage({ static: true }), + factory.mutantTestCoverage({ coveredBy: ['spec1'] }), + factory.mutantTestCoverage({ static: false, coveredBy: undefined }), + ]; - it('the total of MatchedMutants in the progress bar should be 2', () => { - expect(progressBarModule.ProgressBar).to.have.been.calledWithMatch(progressBarContent, { total: 2 }); - }); + sut.onAllMutantsMatchedWithTests(mutants); + expect(progressBarModule.ProgressBar).calledWithMatch(progressBarContent, { total: 2 }); }); }); @@ -76,74 +68,73 @@ describe(ProgressBarReporter.name, () => { let progressBarTickTokens: any; beforeEach(() => { - matchedMutants = [ - factory.matchedMutant({ id: '0' }), // NoCoverage - factory.matchedMutant({ id: '1', testFilter: [''] }), - factory.matchedMutant({ id: '2', runAllTests: true }), - factory.matchedMutant({ id: '3', testFilter: [''] }), + mutants = [ + factory.mutantTestCoverage({ coveredBy: undefined, static: false }), // NoCoverage + factory.mutantTestCoverage({ coveredBy: [''] }), + factory.mutantTestCoverage({ static: true }), + factory.mutantTestCoverage({ coveredBy: [''] }), ]; - sut.onAllMutantsMatchedWithTests(matchedMutants); + sut.onAllMutantsMatchedWithTests(mutants); }); it('should tick the ProgressBar with 1 tested mutant, 0 survived when status is not "Survived"', () => { sut.onMutantTested(factory.killedMutantResult()); progressBarTickTokens = { total: 3, tested: 1, survived: 0 }; - expect(progressBar.tick).to.have.been.calledWithMatch(progressBarTickTokens); + expect(progressBar.tick).calledWithMatch(progressBarTickTokens); }); it("should not tick the ProgressBar if the result was for a mutant that wasn't matched to any tests", () => { - // mutant 0 isn't matched to any tests - sut.onMutantTested(factory.invalidMutantResult({ id: '0', status: MutantStatus.CompileError })); + sut.onMutantTested(factory.mutantResult({ coveredBy: undefined, static: false })); progressBarTickTokens = { total: 3, tested: 0, survived: 0 }; expect(progressBar.tick).to.not.have.been.called; }); it('should tick the ProgressBar with 1 survived mutant when status is "Survived"', () => { - sut.onMutantTested(factory.undetectedMutantResult({ status: MutantStatus.Survived })); + sut.onMutantTested(factory.mutantResult({ static: true, status: MutantStatus.Survived })); progressBarTickTokens = { total: 3, tested: 1, survived: 1 }; - expect(progressBar.tick).to.have.been.calledWithMatch(progressBarTickTokens); + expect(progressBar.tick).calledWithMatch(progressBarTickTokens); }); }); describe('ProgressBar estimated time for 3 mutants', () => { beforeEach(() => { sut.onAllMutantsMatchedWithTests([ - factory.matchedMutant({ id: '1', runAllTests: true }), - factory.matchedMutant({ id: '2', runAllTests: true }), - factory.matchedMutant({ id: '3', runAllTests: true }), + factory.mutantTestCoverage({ static: true }), + factory.mutantTestCoverage({ static: true }), + factory.mutantTestCoverage({ static: true }), ]); }); it('should show correct time info after ten seconds and 1 mutants tested', () => { sinon.clock.tick(TEN_SECONDS); - sut.onMutantTested(factory.killedMutantResult({ id: '1' })); + sut.onMutantTested(factory.mutantResult({ static: true })); - expect(progressBar.tick).to.have.been.calledWithMatch({ et: '<1m', etc: '<1m' }); + expect(progressBar.tick).calledWithMatch({ et: '<1m', etc: '<1m' }); }); it('should show correct time info after a hundred seconds and 1 mutants tested', () => { sinon.clock.tick(HUNDRED_SECONDS); - sut.onMutantTested(factory.killedMutantResult({ id: '1' })); + sut.onMutantTested(factory.mutantResult({ static: true })); - expect(progressBar.tick).to.have.been.calledWithMatch({ et: '~1m', etc: '~3m' }); + expect(progressBar.tick).calledWithMatch({ et: '~1m', etc: '~3m' }); }); it('should show correct time info after ten thousand seconds and 1 mutants tested', () => { sinon.clock.tick(TEN_THOUSAND_SECONDS); - sut.onMutantTested(factory.killedMutantResult({ id: '1' })); + sut.onMutantTested(factory.mutantResult({ static: true })); - expect(progressBar.tick).to.have.been.calledWithMatch({ et: '~2h 46m', etc: '~5h 33m' }); + expect(progressBar.tick).calledWithMatch({ et: '~2h 46m', etc: '~5h 33m' }); }); it('should show correct time info after an hour and 1 mutants tested', () => { sinon.clock.tick(ONE_HOUR); - sut.onMutantTested(factory.killedMutantResult({ id: '1', status: MutantStatus.Killed })); + sut.onMutantTested(factory.mutantResult({ status: MutantStatus.Killed })); - expect(progressBar.tick).to.have.been.calledWithMatch({ et: '~1h 0m', etc: '~2h 0m' }); + expect(progressBar.tick).calledWithMatch({ et: '~1h 0m', etc: '~2h 0m' }); }); }); }); diff --git a/packages/core/test/unit/stryker.spec.ts b/packages/core/test/unit/stryker.spec.ts index da6e3c2485..d8c09b3f07 100644 --- a/packages/core/test/unit/stryker.spec.ts +++ b/packages/core/test/unit/stryker.spec.ts @@ -2,8 +2,7 @@ import { factory } from '@stryker-mutator/test-helpers'; import { expect } from 'chai'; import sinon from 'sinon'; import * as typedInject from 'typed-inject'; -import { PartialStrykerOptions, LogLevel } from '@stryker-mutator/api/core'; -import { MutantResult } from '@stryker-mutator/api/report'; +import { PartialStrykerOptions, LogLevel, MutantResult } from '@stryker-mutator/api/core'; import { Logger } from '@stryker-mutator/api/logging'; import { commonTokens } from '@stryker-mutator/api/plugin'; diff --git a/packages/core/test/unit/test-runner/command-test-runner.spec.ts b/packages/core/test/unit/test-runner/command-test-runner.spec.ts index 7a723f85d0..cac29a0b8a 100644 --- a/packages/core/test/unit/test-runner/command-test-runner.spec.ts +++ b/packages/core/test/unit/test-runner/command-test-runner.spec.ts @@ -99,7 +99,7 @@ describe(CommandTestRunner.name, () => { describe(CommandTestRunner.prototype.mutantRun.name, () => { it('should run with __ACTIVE_MUTANT__ environment variable active', async () => { const sut = createSut(undefined, 'foobarDir'); - await actMutantRun(sut, { activeMutantId: 0 }); + await actMutantRun(sut, { activeMutantId: '0' }); expect(childProcess.exec).calledWith('npm test', { cwd: 'foobarDir', env: { ...process.env, __STRYKER_ACTIVE_MUTANT__: '0' } }); }); @@ -146,7 +146,7 @@ describe(CommandTestRunner.name, () => { return resultPromise; } - async function actMutantRun(sut: CommandTestRunner = createSut(), { exitCode = 0, activeMutantId = 0 }) { + async function actMutantRun(sut: CommandTestRunner = createSut(), { exitCode = 0, activeMutantId = '0' }) { const resultPromise = sut.mutantRun({ activeMutant: factory.mutant({ id: activeMutantId }) }); await actTestProcessEnds(exitCode); return resultPromise; diff --git a/packages/core/tsconfig.src.json b/packages/core/tsconfig.src.json index 348baab125..6d9cbfe26b 100644 --- a/packages/core/tsconfig.src.json +++ b/packages/core/tsconfig.src.json @@ -6,7 +6,9 @@ "noImplicitThis": true, "strictBindCallApply": true, "resolveJsonModule": true, - "types": [] // Exclude global mocha functions for the sources + "types": [ + "node" // Exclude global mocha functions for the sources + ] }, "include": [ "src" diff --git a/packages/instrumenter/src/mutant.ts b/packages/instrumenter/src/mutant.ts index 5a054b1d94..b021273fb0 100644 --- a/packages/instrumenter/src/mutant.ts +++ b/packages/instrumenter/src/mutant.ts @@ -1,6 +1,6 @@ import { types } from '@babel/core'; import generate from '@babel/generator'; -import { Mutant as ApiMutant, Location, Position } from '@stryker-mutator/api/core'; +import { Mutant as ApiMutant, Location, Position, MutantStatus } from '@stryker-mutator/api/core'; export interface NodeMutation { replacement: types.Node; @@ -19,7 +19,7 @@ export class Mutant { public readonly ignoreReason: string | undefined; constructor( - public readonly id: number, + public readonly id: string, public readonly fileName: string, specs: NamedNodeMutation, public readonly positionOffset: number = 0, @@ -40,7 +40,8 @@ export class Mutant { mutatorName: this.mutatorName, range: [this.original.start! + this.positionOffset, this.original.end! + this.positionOffset], replacement: this.replacementCode, - ignoreReason: this.ignoreReason, + statusReason: this.ignoreReason, + status: this.ignoreReason ? MutantStatus.Ignored : undefined, }; } } diff --git a/packages/instrumenter/src/transformers/mutant-collector.ts b/packages/instrumenter/src/transformers/mutant-collector.ts index d876f3d61c..2e90a22c16 100644 --- a/packages/instrumenter/src/transformers/mutant-collector.ts +++ b/packages/instrumenter/src/transformers/mutant-collector.ts @@ -22,7 +22,7 @@ export class MutantCollector { mutationSpecs.replacement.end = mutationSpecs.original.end; mutationSpecs.replacement.start = mutationSpecs.original.start; mutationSpecs.replacement.loc = mutationSpecs.original.loc; - const mutant = new Mutant(this._mutants.length, fileName, mutationSpecs, positionOffset, lineOffset); + const mutant = new Mutant(this._mutants.length.toString(), fileName, mutationSpecs, positionOffset, lineOffset); this._mutants.push(mutant); if (mutant.ignoreReason === undefined) { // Only place mutants that are not ignored diff --git a/packages/instrumenter/src/util/syntax-helpers.ts b/packages/instrumenter/src/util/syntax-helpers.ts index ec24517f9b..20d9e14d92 100644 --- a/packages/instrumenter/src/util/syntax-helpers.ts +++ b/packages/instrumenter/src/util/syntax-helpers.ts @@ -20,7 +20,7 @@ export const instrumentationBabelHeader = deepFreeze( var g = new Function("return this")(); var ns = g.${ID.NAMESPACE} || (g.${ID.NAMESPACE} = {}); if (ns.${ID.ACTIVE_MUTANT} === undefined && g.process && g.process.env && g.process.env.${ID.ACTIVE_MUTANT_ENV_VARIABLE}) { - ns.${ID.ACTIVE_MUTANT} = Number(g.process.env.${ID.ACTIVE_MUTANT_ENV_VARIABLE}); + ns.${ID.ACTIVE_MUTANT} = g.process.env.${ID.ACTIVE_MUTANT_ENV_VARIABLE}; } function retrieveNS(){ return ns; @@ -60,8 +60,8 @@ function ${IS_MUTANT_ACTIVE_HELPER}(id) { * returns syntax for `global.activeMutant === $mutantId` * @param mutantId The id of the mutant to switch */ -export function mutantTestExpression(mutantId: number): types.CallExpression { - return types.callExpression(types.identifier(IS_MUTANT_ACTIVE_HELPER), [types.numericLiteral(mutantId)]); +export function mutantTestExpression(mutantId: string): types.CallExpression { + return types.callExpression(types.identifier(IS_MUTANT_ACTIVE_HELPER), [types.stringLiteral(mutantId)]); } interface Position { @@ -143,7 +143,7 @@ export function mutationCoverageSequenceExpression(mutants: Mutant[], targetExpr const sequence: types.Expression[] = [ types.callExpression( types.identifier(COVER_MUTANT_HELPER), - mutants.map((mutant) => types.numericLiteral(mutant.id)) + mutants.map((mutant) => types.stringLiteral(mutant.id)) ), ]; if (targetExpression) { diff --git a/packages/instrumenter/test/helpers/factories.ts b/packages/instrumenter/test/helpers/factories.ts index 4e4f2c8ae7..7ad5441eda 100644 --- a/packages/instrumenter/test/helpers/factories.ts +++ b/packages/instrumenter/test/helpers/factories.ts @@ -66,7 +66,7 @@ export function createTSAst(overrides?: Partial): TSAst { } export function createMutant(overrides?: Partial): Mutant { - return new Mutant(overrides?.id ?? 1, overrides?.fileName ?? 'example.js', { + return new Mutant(overrides?.id ?? '1', overrides?.fileName ?? 'example.js', { mutatorName: overrides?.mutatorName ?? 'fooMutator', original: overrides?.original ?? types.identifier('foo'), replacement: overrides?.replacement ?? types.identifier('bar'), diff --git a/packages/instrumenter/test/integration/transformers.it.spec.ts.snap b/packages/instrumenter/test/integration/transformers.it.spec.ts.snap index 8280c06343..158b8cd39f 100644 --- a/packages/instrumenter/test/integration/transformers.it.spec.ts.snap +++ b/packages/instrumenter/test/integration/transformers.it.spec.ts.snap @@ -481,9 +481,9 @@ Object { "consequent": Object { "body": Array [ Object { - "end": 298, + "end": 290, "expression": Object { - "end": 297, + "end": 289, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -558,7 +558,7 @@ Object { }, "loc": Object { "end": Object { - "column": 69, + "column": 61, "line": 5, }, "filename": undefined, @@ -571,212 +571,165 @@ Object { "operator": "=", "range": undefined, "right": Object { - "arguments": Array [ - Object { + "computed": false, + "end": 289, + "extra": undefined, + "innerComments": undefined, + "leadingComments": undefined, + "loc": Object { + "end": Object { + "column": 61, + "line": 5, + }, + "filename": undefined, + "identifierName": undefined, + "start": Object { + "column": 22, + "line": 5, + }, + }, + "object": Object { + "computed": false, + "end": 263, + "extra": undefined, + "innerComments": undefined, + "leadingComments": undefined, + "loc": Object { + "end": Object { + "column": 35, + "line": 5, + }, + "filename": undefined, + "identifierName": undefined, + "start": Object { + "column": 22, + "line": 5, + }, + }, + "object": Object { "computed": false, - "end": 296, + "end": 259, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, "loc": Object { "end": Object { - "column": 68, + "column": 31, "line": 5, }, "filename": undefined, "identifierName": undefined, "start": Object { - "column": 29, + "column": 22, "line": 5, }, }, "object": Object { - "computed": false, - "end": 270, + "end": 251, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, "loc": Object { "end": Object { - "column": 42, + "column": 23, "line": 5, }, "filename": undefined, - "identifierName": undefined, + "identifierName": "g", "start": Object { - "column": 29, + "column": 22, "line": 5, }, }, - "object": Object { - "computed": false, - "end": 266, - "extra": undefined, - "innerComments": undefined, - "leadingComments": undefined, - "loc": Object { - "end": Object { - "column": 38, - "line": 5, - }, - "filename": undefined, - "identifierName": undefined, - "start": Object { - "column": 29, - "line": 5, - }, - }, - "object": Object { - "end": 258, - "extra": undefined, - "innerComments": undefined, - "leadingComments": undefined, - "loc": Object { - "end": Object { - "column": 30, - "line": 5, - }, - "filename": undefined, - "identifierName": "g", - "start": Object { - "column": 29, - "line": 5, - }, - }, - "name": "g", - "range": undefined, - "start": 257, - "trailingComments": undefined, - "type": "Identifier", - }, - "property": Object { - "end": 266, - "extra": undefined, - "innerComments": undefined, - "leadingComments": undefined, - "loc": Object { - "end": Object { - "column": 38, - "line": 5, - }, - "filename": undefined, - "identifierName": "process", - "start": Object { - "column": 31, - "line": 5, - }, - }, - "name": "process", - "range": undefined, - "start": 259, - "trailingComments": undefined, - "type": "Identifier", - }, - "range": undefined, - "start": 257, - "trailingComments": undefined, - "type": "MemberExpression", - }, - "property": Object { - "end": 270, - "extra": undefined, - "innerComments": undefined, - "leadingComments": undefined, - "loc": Object { - "end": Object { - "column": 42, - "line": 5, - }, - "filename": undefined, - "identifierName": "env", - "start": Object { - "column": 39, - "line": 5, - }, - }, - "name": "env", - "range": undefined, - "start": 267, - "trailingComments": undefined, - "type": "Identifier", - }, + "name": "g", "range": undefined, - "start": 257, + "start": 250, "trailingComments": undefined, - "type": "MemberExpression", + "type": "Identifier", }, "property": Object { - "end": 296, + "end": 259, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, "loc": Object { "end": Object { - "column": 68, + "column": 31, "line": 5, }, "filename": undefined, - "identifierName": "__STRYKER_ACTIVE_MUTANT__", + "identifierName": "process", "start": Object { - "column": 43, + "column": 24, "line": 5, }, }, - "name": "__STRYKER_ACTIVE_MUTANT__", + "name": "process", "range": undefined, - "start": 271, + "start": 252, "trailingComments": undefined, "type": "Identifier", }, "range": undefined, - "start": 257, + "start": 250, "trailingComments": undefined, "type": "MemberExpression", }, - ], - "callee": Object { - "end": 256, + "property": Object { + "end": 263, + "extra": undefined, + "innerComments": undefined, + "leadingComments": undefined, + "loc": Object { + "end": Object { + "column": 35, + "line": 5, + }, + "filename": undefined, + "identifierName": "env", + "start": Object { + "column": 32, + "line": 5, + }, + }, + "name": "env", + "range": undefined, + "start": 260, + "trailingComments": undefined, + "type": "Identifier", + }, + "range": undefined, + "start": 250, + "trailingComments": undefined, + "type": "MemberExpression", + }, + "property": Object { + "end": 289, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, "loc": Object { "end": Object { - "column": 28, + "column": 61, "line": 5, }, "filename": undefined, - "identifierName": "Number", + "identifierName": "__STRYKER_ACTIVE_MUTANT__", "start": Object { - "column": 22, + "column": 36, "line": 5, }, }, - "name": "Number", + "name": "__STRYKER_ACTIVE_MUTANT__", "range": undefined, - "start": 250, + "start": 264, "trailingComments": undefined, "type": "Identifier", }, - "end": 297, - "extra": undefined, - "innerComments": undefined, - "leadingComments": undefined, - "loc": Object { - "end": Object { - "column": 69, - "line": 5, - }, - "filename": undefined, - "identifierName": undefined, - "start": Object { - "column": 22, - "line": 5, - }, - }, "range": undefined, "start": 250, "trailingComments": undefined, - "type": "CallExpression", + "type": "MemberExpression", }, "start": 232, "trailingComments": undefined, @@ -787,7 +740,7 @@ Object { "leadingComments": undefined, "loc": Object { "end": Object { - "column": 70, + "column": 62, "line": 5, }, "filename": undefined, @@ -804,7 +757,7 @@ Object { }, ], "directives": Array [], - "end": 302, + "end": 294, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -825,7 +778,7 @@ Object { "trailingComments": undefined, "type": "BlockStatement", }, - "end": 302, + "end": 294, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -1381,7 +1334,7 @@ Object { "body": Array [ Object { "argument": Object { - "end": 341, + "end": 333, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -1399,11 +1352,11 @@ Object { }, "name": "ns", "range": undefined, - "start": 339, + "start": 331, "trailingComments": undefined, "type": "Identifier", }, - "end": 342, + "end": 334, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -1420,13 +1373,13 @@ Object { }, }, "range": undefined, - "start": 332, + "start": 324, "trailingComments": undefined, "type": "ReturnStatement", }, ], "directives": Array [], - "end": 346, + "end": 338, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -1443,15 +1396,15 @@ Object { }, }, "range": undefined, - "start": 326, + "start": 318, "trailingComments": undefined, "type": "BlockStatement", }, - "end": 346, + "end": 338, "extra": undefined, "generator": false, "id": Object { - "end": 324, + "end": 316, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -1469,7 +1422,7 @@ Object { }, "name": "retrieveNS", "range": undefined, - "start": 314, + "start": 306, "trailingComments": undefined, "type": "Identifier", }, @@ -1489,19 +1442,19 @@ Object { }, "params": Array [], "range": undefined, - "start": 305, + "start": 297, "trailingComments": undefined, "type": "FunctionDeclaration", }, Object { - "end": 375, + "end": 367, "expression": Object { - "end": 374, + "end": 366, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, "left": Object { - "end": 361, + "end": 353, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -1519,7 +1472,7 @@ Object { }, "name": "stryNS_9fa48", "range": undefined, - "start": 349, + "start": 341, "trailingComments": undefined, "type": "Identifier", }, @@ -1538,7 +1491,7 @@ Object { "operator": "=", "range": undefined, "right": Object { - "end": 374, + "end": 366, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -1556,11 +1509,11 @@ Object { }, "name": "retrieveNS", "range": undefined, - "start": 364, + "start": 356, "trailingComments": undefined, "type": "Identifier", }, - "start": 349, + "start": 341, "trailingComments": undefined, "type": "AssignmentExpression", }, @@ -1580,7 +1533,7 @@ Object { }, }, "range": undefined, - "start": 349, + "start": 341, "trailingComments": undefined, "type": "ExpressionStatement", }, @@ -1588,7 +1541,7 @@ Object { "argument": Object { "arguments": Array [], "callee": Object { - "end": 395, + "end": 387, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -1606,11 +1559,11 @@ Object { }, "name": "retrieveNS", "range": undefined, - "start": 385, + "start": 377, "trailingComments": undefined, "type": "Identifier", }, - "end": 397, + "end": 389, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -1627,11 +1580,11 @@ Object { }, }, "range": undefined, - "start": 385, + "start": 377, "trailingComments": undefined, "type": "CallExpression", }, - "end": 398, + "end": 390, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -1648,13 +1601,13 @@ Object { }, }, "range": undefined, - "start": 378, + "start": 370, "trailingComments": undefined, "type": "ReturnStatement", }, ], "directives": Array [], - "end": 400, + "end": 392, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -1675,7 +1628,7 @@ Object { "trailingComments": undefined, "type": "BlockStatement", }, - "end": 400, + "end": 392, "extra": undefined, "generator": false, "id": Object { @@ -1722,11 +1675,11 @@ Object { "type": "FunctionDeclaration", }, Object { - "end": 416, + "end": 408, "expression": Object { "arguments": Array [], "callee": Object { - "end": 413, + "end": 405, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -1744,11 +1697,11 @@ Object { }, "name": "stryNS_9fa48", "range": undefined, - "start": 401, + "start": 393, "trailingComments": undefined, "type": "Identifier", }, - "end": 415, + "end": 407, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -1765,7 +1718,7 @@ Object { }, }, "range": undefined, - "start": 401, + "start": 393, "trailingComments": undefined, "type": "CallExpression", }, @@ -1785,7 +1738,7 @@ Object { }, }, "range": undefined, - "start": 401, + "start": 393, "trailingComments": undefined, "type": "ExpressionStatement", }, @@ -1796,10 +1749,10 @@ Object { Object { "declarations": Array [ Object { - "end": 470, + "end": 462, "extra": undefined, "id": Object { - "end": 453, + "end": 445, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -1817,14 +1770,14 @@ Object { }, "name": "ns", "range": undefined, - "start": 451, + "start": 443, "trailingComments": undefined, "type": "Identifier", }, "init": Object { "arguments": Array [], "callee": Object { - "end": 468, + "end": 460, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -1842,11 +1795,11 @@ Object { }, "name": "stryNS_9fa48", "range": undefined, - "start": 456, + "start": 448, "trailingComments": undefined, "type": "Identifier", }, - "end": 470, + "end": 462, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -1863,7 +1816,7 @@ Object { }, }, "range": undefined, - "start": 456, + "start": 448, "trailingComments": undefined, "type": "CallExpression", }, @@ -1882,12 +1835,12 @@ Object { }, }, "range": undefined, - "start": 451, + "start": 443, "trailingComments": undefined, "type": "VariableDeclarator", }, ], - "end": 471, + "end": 463, "extra": undefined, "innerComments": undefined, "kind": "var", @@ -1905,17 +1858,17 @@ Object { }, }, "range": undefined, - "start": 447, + "start": 439, "trailingComments": undefined, "type": "VariableDeclaration", }, Object { "declarations": Array [ Object { - "end": 554, + "end": 546, "extra": undefined, "id": Object { - "end": 481, + "end": 473, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -1933,18 +1886,18 @@ Object { }, "name": "cov", "range": undefined, - "start": 478, + "start": 470, "trailingComments": undefined, "type": "Identifier", }, "init": Object { - "end": 554, + "end": 546, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, "left": Object { "computed": false, - "end": 501, + "end": 493, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -1961,7 +1914,7 @@ Object { }, }, "object": Object { - "end": 486, + "end": 478, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -1979,12 +1932,12 @@ Object { }, "name": "ns", "range": undefined, - "start": 484, + "start": 476, "trailingComments": undefined, "type": "Identifier", }, "property": Object { - "end": 501, + "end": 493, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -2002,12 +1955,12 @@ Object { }, "name": "mutantCoverage", "range": undefined, - "start": 487, + "start": 479, "trailingComments": undefined, "type": "Identifier", }, "range": undefined, - "start": 484, + "start": 476, "trailingComments": undefined, "type": "MemberExpression", }, @@ -2026,16 +1979,16 @@ Object { "operator": "||", "range": undefined, "right": Object { - "end": 553, + "end": 545, "extra": Object { - "parenStart": 505, + "parenStart": 497, "parenthesized": true, }, "innerComments": undefined, "leadingComments": undefined, "left": Object { "computed": false, - "end": 523, + "end": 515, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -2052,7 +2005,7 @@ Object { }, }, "object": Object { - "end": 508, + "end": 500, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -2070,12 +2023,12 @@ Object { }, "name": "ns", "range": undefined, - "start": 506, + "start": 498, "trailingComments": undefined, "type": "Identifier", }, "property": Object { - "end": 523, + "end": 515, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -2093,12 +2046,12 @@ Object { }, "name": "mutantCoverage", "range": undefined, - "start": 509, + "start": 501, "trailingComments": undefined, "type": "Identifier", }, "range": undefined, - "start": 506, + "start": 498, "trailingComments": undefined, "type": "MemberExpression", }, @@ -2117,7 +2070,7 @@ Object { "operator": "=", "range": undefined, "right": Object { - "end": 553, + "end": 545, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -2136,11 +2089,11 @@ Object { "properties": Array [ Object { "computed": false, - "end": 538, + "end": 530, "extra": undefined, "innerComments": undefined, "key": Object { - "end": 534, + "end": 526, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -2158,7 +2111,7 @@ Object { }, "name": "static", "range": undefined, - "start": 528, + "start": 520, "trailingComments": undefined, "type": "Identifier", }, @@ -2178,11 +2131,11 @@ Object { "method": false, "range": undefined, "shorthand": false, - "start": 528, + "start": 520, "trailingComments": undefined, "type": "ObjectProperty", "value": Object { - "end": 538, + "end": 530, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -2200,18 +2153,18 @@ Object { }, "properties": Array [], "range": undefined, - "start": 536, + "start": 528, "trailingComments": undefined, "type": "ObjectExpression", }, }, Object { "computed": false, - "end": 551, + "end": 543, "extra": undefined, "innerComments": undefined, "key": Object { - "end": 547, + "end": 539, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -2229,7 +2182,7 @@ Object { }, "name": "perTest", "range": undefined, - "start": 540, + "start": 532, "trailingComments": undefined, "type": "Identifier", }, @@ -2249,11 +2202,11 @@ Object { "method": false, "range": undefined, "shorthand": false, - "start": 540, + "start": 532, "trailingComments": undefined, "type": "ObjectProperty", "value": Object { - "end": 551, + "end": 543, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -2271,22 +2224,22 @@ Object { }, "properties": Array [], "range": undefined, - "start": 549, + "start": 541, "trailingComments": undefined, "type": "ObjectExpression", }, }, ], "range": undefined, - "start": 526, + "start": 518, "trailingComments": undefined, "type": "ObjectExpression", }, - "start": 506, + "start": 498, "trailingComments": undefined, "type": "AssignmentExpression", }, - "start": 484, + "start": 476, "trailingComments": undefined, "type": "LogicalExpression", }, @@ -2305,12 +2258,12 @@ Object { }, }, "range": undefined, - "start": 478, + "start": 470, "trailingComments": undefined, "type": "VariableDeclarator", }, ], - "end": 555, + "end": 547, "extra": undefined, "innerComments": undefined, "kind": "var", @@ -2328,7 +2281,7 @@ Object { }, }, "range": undefined, - "start": 474, + "start": 466, "trailingComments": undefined, "type": "VariableDeclaration", }, @@ -2339,10 +2292,10 @@ Object { Object { "declarations": Array [ Object { - "end": 599, + "end": 591, "extra": undefined, "id": Object { - "end": 586, + "end": 578, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -2360,13 +2313,13 @@ Object { }, "name": "c", "range": undefined, - "start": 585, + "start": 577, "trailingComments": undefined, "type": "Identifier", }, "init": Object { "computed": false, - "end": 599, + "end": 591, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -2383,7 +2336,7 @@ Object { }, }, "object": Object { - "end": 592, + "end": 584, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -2401,12 +2354,12 @@ Object { }, "name": "cov", "range": undefined, - "start": 589, + "start": 581, "trailingComments": undefined, "type": "Identifier", }, "property": Object { - "end": 599, + "end": 591, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -2424,12 +2377,12 @@ Object { }, "name": "static", "range": undefined, - "start": 593, + "start": 585, "trailingComments": undefined, "type": "Identifier", }, "range": undefined, - "start": 589, + "start": 581, "trailingComments": undefined, "type": "MemberExpression", }, @@ -2448,12 +2401,12 @@ Object { }, }, "range": undefined, - "start": 585, + "start": 577, "trailingComments": undefined, "type": "VariableDeclarator", }, ], - "end": 600, + "end": 592, "extra": undefined, "innerComments": undefined, "kind": "var", @@ -2471,7 +2424,7 @@ Object { }, }, "range": undefined, - "start": 581, + "start": 573, "trailingComments": undefined, "type": "VariableDeclaration", }, @@ -2480,14 +2433,14 @@ Object { "consequent": Object { "body": Array [ Object { - "end": 707, + "end": 699, "expression": Object { - "end": 706, + "end": 698, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, "left": Object { - "end": 636, + "end": 628, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -2505,7 +2458,7 @@ Object { }, "name": "c", "range": undefined, - "start": 635, + "start": 627, "trailingComments": undefined, "type": "Identifier", }, @@ -2524,13 +2477,13 @@ Object { "operator": "=", "range": undefined, "right": Object { - "end": 706, + "end": 698, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, "left": Object { "computed": true, - "end": 668, + "end": 660, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -2548,7 +2501,7 @@ Object { }, "object": Object { "computed": false, - "end": 650, + "end": 642, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -2565,7 +2518,7 @@ Object { }, }, "object": Object { - "end": 642, + "end": 634, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -2583,12 +2536,12 @@ Object { }, "name": "cov", "range": undefined, - "start": 639, + "start": 631, "trailingComments": undefined, "type": "Identifier", }, "property": Object { - "end": 650, + "end": 642, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -2606,18 +2559,18 @@ Object { }, "name": "perTest", "range": undefined, - "start": 643, + "start": 635, "trailingComments": undefined, "type": "Identifier", }, "range": undefined, - "start": 639, + "start": 631, "trailingComments": undefined, "type": "MemberExpression", }, "property": Object { "computed": false, - "end": 667, + "end": 659, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -2634,7 +2587,7 @@ Object { }, }, "object": Object { - "end": 653, + "end": 645, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -2652,12 +2605,12 @@ Object { }, "name": "ns", "range": undefined, - "start": 651, + "start": 643, "trailingComments": undefined, "type": "Identifier", }, "property": Object { - "end": 667, + "end": 659, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -2675,17 +2628,17 @@ Object { }, "name": "currentTestId", "range": undefined, - "start": 654, + "start": 646, "trailingComments": undefined, "type": "Identifier", }, "range": undefined, - "start": 651, + "start": 643, "trailingComments": undefined, "type": "MemberExpression", }, "range": undefined, - "start": 639, + "start": 631, "trailingComments": undefined, "type": "MemberExpression", }, @@ -2704,13 +2657,13 @@ Object { "operator": "=", "range": undefined, "right": Object { - "end": 706, + "end": 698, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, "left": Object { "computed": true, - "end": 700, + "end": 692, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -2728,7 +2681,7 @@ Object { }, "object": Object { "computed": false, - "end": 682, + "end": 674, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -2745,7 +2698,7 @@ Object { }, }, "object": Object { - "end": 674, + "end": 666, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -2763,12 +2716,12 @@ Object { }, "name": "cov", "range": undefined, - "start": 671, + "start": 663, "trailingComments": undefined, "type": "Identifier", }, "property": Object { - "end": 682, + "end": 674, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -2786,18 +2739,18 @@ Object { }, "name": "perTest", "range": undefined, - "start": 675, + "start": 667, "trailingComments": undefined, "type": "Identifier", }, "range": undefined, - "start": 671, + "start": 663, "trailingComments": undefined, "type": "MemberExpression", }, "property": Object { "computed": false, - "end": 699, + "end": 691, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -2814,7 +2767,7 @@ Object { }, }, "object": Object { - "end": 685, + "end": 677, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -2832,12 +2785,12 @@ Object { }, "name": "ns", "range": undefined, - "start": 683, + "start": 675, "trailingComments": undefined, "type": "Identifier", }, "property": Object { - "end": 699, + "end": 691, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -2855,17 +2808,17 @@ Object { }, "name": "currentTestId", "range": undefined, - "start": 686, + "start": 678, "trailingComments": undefined, "type": "Identifier", }, "range": undefined, - "start": 683, + "start": 675, "trailingComments": undefined, "type": "MemberExpression", }, "range": undefined, - "start": 671, + "start": 663, "trailingComments": undefined, "type": "MemberExpression", }, @@ -2884,7 +2837,7 @@ Object { "operator": "||", "range": undefined, "right": Object { - "end": 706, + "end": 698, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -2902,19 +2855,19 @@ Object { }, "properties": Array [], "range": undefined, - "start": 704, + "start": 696, "trailingComments": undefined, "type": "ObjectExpression", }, - "start": 671, + "start": 663, "trailingComments": undefined, "type": "LogicalExpression", }, - "start": 639, + "start": 631, "trailingComments": undefined, "type": "AssignmentExpression", }, - "start": 635, + "start": 627, "trailingComments": undefined, "type": "AssignmentExpression", }, @@ -2934,13 +2887,13 @@ Object { }, }, "range": undefined, - "start": 635, + "start": 627, "trailingComments": undefined, "type": "ExpressionStatement", }, ], "directives": Array [], - "end": 713, + "end": 705, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -2957,11 +2910,11 @@ Object { }, }, "range": undefined, - "start": 627, + "start": 619, "trailingComments": undefined, "type": "BlockStatement", }, - "end": 713, + "end": 705, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -2978,10 +2931,10 @@ Object { }, }, "range": undefined, - "start": 605, + "start": 597, "test": Object { "computed": false, - "end": 625, + "end": 617, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -2998,7 +2951,7 @@ Object { }, }, "object": Object { - "end": 611, + "end": 603, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -3016,12 +2969,12 @@ Object { }, "name": "ns", "range": undefined, - "start": 609, + "start": 601, "trailingComments": undefined, "type": "Identifier", }, "property": Object { - "end": 625, + "end": 617, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -3039,12 +2992,12 @@ Object { }, "name": "currentTestId", "range": undefined, - "start": 612, + "start": 604, "trailingComments": undefined, "type": "Identifier", }, "range": undefined, - "start": 609, + "start": 601, "trailingComments": undefined, "type": "MemberExpression", }, @@ -3054,10 +3007,10 @@ Object { Object { "declarations": Array [ Object { - "end": 735, + "end": 727, "extra": undefined, "id": Object { - "end": 723, + "end": 715, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -3075,12 +3028,12 @@ Object { }, "name": "a", "range": undefined, - "start": 722, + "start": 714, "trailingComments": undefined, "type": "Identifier", }, "init": Object { - "end": 735, + "end": 727, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -3098,7 +3051,7 @@ Object { }, "name": "arguments", "range": undefined, - "start": 726, + "start": 718, "trailingComments": undefined, "type": "Identifier", }, @@ -3117,12 +3070,12 @@ Object { }, }, "range": undefined, - "start": 722, + "start": 714, "trailingComments": undefined, "type": "VariableDeclarator", }, ], - "end": 736, + "end": 728, "extra": undefined, "innerComments": undefined, "kind": "var", @@ -3140,7 +3093,7 @@ Object { }, }, "range": undefined, - "start": 718, + "start": 710, "trailingComments": undefined, "type": "VariableDeclaration", }, @@ -3148,15 +3101,15 @@ Object { "body": Object { "body": Array [ Object { - "end": 809, + "end": 801, "expression": Object { - "end": 808, + "end": 800, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, "left": Object { "computed": true, - "end": 787, + "end": 779, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -3173,7 +3126,7 @@ Object { }, }, "object": Object { - "end": 781, + "end": 773, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -3191,13 +3144,13 @@ Object { }, "name": "c", "range": undefined, - "start": 780, + "start": 772, "trailingComments": undefined, "type": "Identifier", }, "property": Object { "computed": true, - "end": 786, + "end": 778, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -3214,7 +3167,7 @@ Object { }, }, "object": Object { - "end": 783, + "end": 775, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -3232,12 +3185,12 @@ Object { }, "name": "a", "range": undefined, - "start": 782, + "start": 774, "trailingComments": undefined, "type": "Identifier", }, "property": Object { - "end": 785, + "end": 777, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -3255,17 +3208,17 @@ Object { }, "name": "i", "range": undefined, - "start": 784, + "start": 776, "trailingComments": undefined, "type": "Identifier", }, "range": undefined, - "start": 782, + "start": 774, "trailingComments": undefined, "type": "MemberExpression", }, "range": undefined, - "start": 780, + "start": 772, "trailingComments": undefined, "type": "MemberExpression", }, @@ -3284,21 +3237,21 @@ Object { "operator": "=", "range": undefined, "right": Object { - "end": 808, + "end": 800, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, "left": Object { - "end": 803, + "end": 795, "extra": Object { - "parenStart": 790, + "parenStart": 782, "parenthesized": true, }, "innerComments": undefined, "leadingComments": undefined, "left": Object { "computed": true, - "end": 798, + "end": 790, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -3315,7 +3268,7 @@ Object { }, }, "object": Object { - "end": 792, + "end": 784, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -3333,13 +3286,13 @@ Object { }, "name": "c", "range": undefined, - "start": 791, + "start": 783, "trailingComments": undefined, "type": "Identifier", }, "property": Object { "computed": true, - "end": 797, + "end": 789, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -3356,7 +3309,7 @@ Object { }, }, "object": Object { - "end": 794, + "end": 786, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -3374,12 +3327,12 @@ Object { }, "name": "a", "range": undefined, - "start": 793, + "start": 785, "trailingComments": undefined, "type": "Identifier", }, "property": Object { - "end": 796, + "end": 788, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -3397,17 +3350,17 @@ Object { }, "name": "i", "range": undefined, - "start": 795, + "start": 787, "trailingComments": undefined, "type": "Identifier", }, "range": undefined, - "start": 793, + "start": 785, "trailingComments": undefined, "type": "MemberExpression", }, "range": undefined, - "start": 791, + "start": 783, "trailingComments": undefined, "type": "MemberExpression", }, @@ -3426,7 +3379,7 @@ Object { "operator": "||", "range": undefined, "right": Object { - "end": 803, + "end": 795, "extra": Object { "raw": "0", "rawValue": 0, @@ -3446,12 +3399,12 @@ Object { }, }, "range": undefined, - "start": 802, + "start": 794, "trailingComments": undefined, "type": "NumericLiteral", "value": 0, }, - "start": 791, + "start": 783, "trailingComments": undefined, "type": "LogicalExpression", }, @@ -3470,7 +3423,7 @@ Object { "operator": "+", "range": undefined, "right": Object { - "end": 808, + "end": 800, "extra": Object { "raw": "1", "rawValue": 1, @@ -3490,16 +3443,16 @@ Object { }, }, "range": undefined, - "start": 807, + "start": 799, "trailingComments": undefined, "type": "NumericLiteral", "value": 1, }, - "start": 790, + "start": 782, "trailingComments": undefined, "type": "BinaryExpression", }, - "start": 780, + "start": 772, "trailingComments": undefined, "type": "AssignmentExpression", }, @@ -3519,13 +3472,13 @@ Object { }, }, "range": undefined, - "start": 780, + "start": 772, "trailingComments": undefined, "type": "ExpressionStatement", }, ], "directives": Array [], - "end": 815, + "end": 807, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -3542,19 +3495,19 @@ Object { }, }, "range": undefined, - "start": 772, + "start": 764, "trailingComments": undefined, "type": "BlockStatement", }, - "end": 815, + "end": 807, "extra": undefined, "init": Object { "declarations": Array [ Object { - "end": 752, + "end": 744, "extra": undefined, "id": Object { - "end": 750, + "end": 742, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -3572,12 +3525,12 @@ Object { }, "name": "i", "range": undefined, - "start": 749, + "start": 741, "trailingComments": undefined, "type": "Identifier", }, "init": Object { - "end": 752, + "end": 744, "extra": Object { "raw": "0", "rawValue": 0, @@ -3597,7 +3550,7 @@ Object { }, }, "range": undefined, - "start": 751, + "start": 743, "trailingComments": undefined, "type": "NumericLiteral", "value": 0, @@ -3617,12 +3570,12 @@ Object { }, }, "range": undefined, - "start": 749, + "start": 741, "trailingComments": undefined, "type": "VariableDeclarator", }, ], - "end": 752, + "end": 744, "extra": undefined, "innerComments": undefined, "kind": "var", @@ -3640,7 +3593,7 @@ Object { }, }, "range": undefined, - "start": 745, + "start": 737, "trailingComments": undefined, "type": "VariableDeclaration", }, @@ -3659,14 +3612,14 @@ Object { }, }, "range": undefined, - "start": 741, + "start": 733, "test": Object { - "end": 766, + "end": 758, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, "left": Object { - "end": 755, + "end": 747, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -3684,7 +3637,7 @@ Object { }, "name": "i", "range": undefined, - "start": 754, + "start": 746, "trailingComments": undefined, "type": "Identifier", }, @@ -3704,7 +3657,7 @@ Object { "range": undefined, "right": Object { "computed": false, - "end": 766, + "end": 758, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -3721,7 +3674,7 @@ Object { }, }, "object": Object { - "end": 759, + "end": 751, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -3739,12 +3692,12 @@ Object { }, "name": "a", "range": undefined, - "start": 758, + "start": 750, "trailingComments": undefined, "type": "Identifier", }, "property": Object { - "end": 766, + "end": 758, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -3762,16 +3715,16 @@ Object { }, "name": "length", "range": undefined, - "start": 760, + "start": 752, "trailingComments": undefined, "type": "Identifier", }, "range": undefined, - "start": 758, + "start": 750, "trailingComments": undefined, "type": "MemberExpression", }, - "start": 754, + "start": 746, "trailingComments": undefined, "type": "BinaryExpression", }, @@ -3779,7 +3732,7 @@ Object { "type": "ForStatement", "update": Object { "argument": Object { - "end": 769, + "end": 761, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -3797,11 +3750,11 @@ Object { }, "name": "i", "range": undefined, - "start": 768, + "start": 760, "trailingComments": undefined, "type": "Identifier", }, - "end": 771, + "end": 763, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -3820,14 +3773,14 @@ Object { "operator": "++", "prefix": false, "range": undefined, - "start": 768, + "start": 760, "trailingComments": undefined, "type": "UpdateExpression", }, }, ], "directives": Array [], - "end": 819, + "end": 811, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -3844,15 +3797,15 @@ Object { }, }, "range": undefined, - "start": 575, + "start": 567, "trailingComments": undefined, "type": "BlockStatement", }, - "end": 819, + "end": 811, "extra": undefined, "generator": false, "id": Object { - "end": 572, + "end": 564, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -3870,7 +3823,7 @@ Object { }, "name": "cover", "range": undefined, - "start": 567, + "start": 559, "trailingComments": undefined, "type": "Identifier", }, @@ -3890,19 +3843,19 @@ Object { }, "params": Array [], "range": undefined, - "start": 558, + "start": 550, "trailingComments": undefined, "type": "FunctionDeclaration", }, Object { - "end": 844, + "end": 836, "expression": Object { - "end": 843, + "end": 835, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, "left": Object { - "end": 835, + "end": 827, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -3920,7 +3873,7 @@ Object { }, "name": "stryCov_9fa48", "range": undefined, - "start": 822, + "start": 814, "trailingComments": undefined, "type": "Identifier", }, @@ -3939,7 +3892,7 @@ Object { "operator": "=", "range": undefined, "right": Object { - "end": 843, + "end": 835, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -3957,11 +3910,11 @@ Object { }, "name": "cover", "range": undefined, - "start": 838, + "start": 830, "trailingComments": undefined, "type": "Identifier", }, - "start": 822, + "start": 814, "trailingComments": undefined, "type": "AssignmentExpression", }, @@ -3981,16 +3934,16 @@ Object { }, }, "range": undefined, - "start": 822, + "start": 814, "trailingComments": undefined, "type": "ExpressionStatement", }, Object { - "end": 876, + "end": 868, "expression": Object { "arguments": Array [ Object { - "end": 863, + "end": 855, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -4007,12 +3960,12 @@ Object { }, }, "range": undefined, - "start": 859, + "start": 851, "trailingComments": undefined, "type": "NullLiteral", }, Object { - "end": 874, + "end": 866, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -4030,14 +3983,14 @@ Object { }, "name": "arguments", "range": undefined, - "start": 865, + "start": 857, "trailingComments": undefined, "type": "Identifier", }, ], "callee": Object { "computed": false, - "end": 858, + "end": 850, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -4054,7 +4007,7 @@ Object { }, }, "object": Object { - "end": 852, + "end": 844, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -4072,12 +4025,12 @@ Object { }, "name": "cover", "range": undefined, - "start": 847, + "start": 839, "trailingComments": undefined, "type": "Identifier", }, "property": Object { - "end": 858, + "end": 850, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -4095,16 +4048,16 @@ Object { }, "name": "apply", "range": undefined, - "start": 853, + "start": 845, "trailingComments": undefined, "type": "Identifier", }, "range": undefined, - "start": 847, + "start": 839, "trailingComments": undefined, "type": "MemberExpression", }, - "end": 875, + "end": 867, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -4121,7 +4074,7 @@ Object { }, }, "range": undefined, - "start": 847, + "start": 839, "trailingComments": undefined, "type": "CallExpression", }, @@ -4141,13 +4094,13 @@ Object { }, }, "range": undefined, - "start": 847, + "start": 839, "trailingComments": undefined, "type": "ExpressionStatement", }, ], "directives": Array [], - "end": 878, + "end": 870, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -4164,15 +4117,15 @@ Object { }, }, "range": undefined, - "start": 443, + "start": 435, "trailingComments": undefined, "type": "BlockStatement", }, - "end": 878, + "end": 870, "extra": undefined, "generator": false, "id": Object { - "end": 440, + "end": 432, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -4190,7 +4143,7 @@ Object { }, "name": "stryCov_9fa48", "range": undefined, - "start": 427, + "start": 419, "trailingComments": undefined, "type": "Identifier", }, @@ -4210,7 +4163,7 @@ Object { }, "params": Array [], "range": undefined, - "start": 418, + "start": 410, "trailingComments": undefined, "type": "FunctionDeclaration", }, @@ -4221,10 +4174,10 @@ Object { Object { "declarations": Array [ Object { - "end": 936, + "end": 928, "extra": undefined, "id": Object { - "end": 919, + "end": 911, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -4242,14 +4195,14 @@ Object { }, "name": "ns", "range": undefined, - "start": 917, + "start": 909, "trailingComments": undefined, "type": "Identifier", }, "init": Object { "arguments": Array [], "callee": Object { - "end": 934, + "end": 926, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -4267,11 +4220,11 @@ Object { }, "name": "stryNS_9fa48", "range": undefined, - "start": 922, + "start": 914, "trailingComments": undefined, "type": "Identifier", }, - "end": 936, + "end": 928, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -4288,7 +4241,7 @@ Object { }, }, "range": undefined, - "start": 922, + "start": 914, "trailingComments": undefined, "type": "CallExpression", }, @@ -4307,12 +4260,12 @@ Object { }, }, "range": undefined, - "start": 917, + "start": 909, "trailingComments": undefined, "type": "VariableDeclarator", }, ], - "end": 937, + "end": 929, "extra": undefined, "innerComments": undefined, "kind": "var", @@ -4330,7 +4283,7 @@ Object { }, }, "range": undefined, - "start": 913, + "start": 905, "trailingComments": undefined, "type": "VariableDeclaration", }, @@ -4340,13 +4293,13 @@ Object { "body": Array [ Object { "argument": Object { - "end": 997, + "end": 989, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, "left": Object { "computed": false, - "end": 990, + "end": 982, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -4363,7 +4316,7 @@ Object { }, }, "object": Object { - "end": 977, + "end": 969, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -4381,12 +4334,12 @@ Object { }, "name": "ns", "range": undefined, - "start": 975, + "start": 967, "trailingComments": undefined, "type": "Identifier", }, "property": Object { - "end": 990, + "end": 982, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -4404,12 +4357,12 @@ Object { }, "name": "activeMutant", "range": undefined, - "start": 978, + "start": 970, "trailingComments": undefined, "type": "Identifier", }, "range": undefined, - "start": 975, + "start": 967, "trailingComments": undefined, "type": "MemberExpression", }, @@ -4428,7 +4381,7 @@ Object { "operator": "===", "range": undefined, "right": Object { - "end": 997, + "end": 989, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -4446,15 +4399,15 @@ Object { }, "name": "id", "range": undefined, - "start": 995, + "start": 987, "trailingComments": undefined, "type": "Identifier", }, - "start": 975, + "start": 967, "trailingComments": undefined, "type": "BinaryExpression", }, - "end": 998, + "end": 990, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -4471,13 +4424,13 @@ Object { }, }, "range": undefined, - "start": 968, + "start": 960, "trailingComments": undefined, "type": "ReturnStatement", }, ], "directives": Array [], - "end": 1002, + "end": 994, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -4494,15 +4447,15 @@ Object { }, }, "range": undefined, - "start": 962, + "start": 954, "trailingComments": undefined, "type": "BlockStatement", }, - "end": 1002, + "end": 994, "extra": undefined, "generator": false, "id": Object { - "end": 957, + "end": 949, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -4520,7 +4473,7 @@ Object { }, "name": "isActive", "range": undefined, - "start": 949, + "start": 941, "trailingComments": undefined, "type": "Identifier", }, @@ -4540,7 +4493,7 @@ Object { }, "params": Array [ Object { - "end": 960, + "end": 952, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -4558,25 +4511,25 @@ Object { }, "name": "id", "range": undefined, - "start": 958, + "start": 950, "trailingComments": undefined, "type": "Identifier", }, ], "range": undefined, - "start": 940, + "start": 932, "trailingComments": undefined, "type": "FunctionDeclaration", }, Object { - "end": 1033, + "end": 1025, "expression": Object { - "end": 1032, + "end": 1024, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, "left": Object { - "end": 1021, + "end": 1013, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -4594,7 +4547,7 @@ Object { }, "name": "stryMutAct_9fa48", "range": undefined, - "start": 1005, + "start": 997, "trailingComments": undefined, "type": "Identifier", }, @@ -4613,7 +4566,7 @@ Object { "operator": "=", "range": undefined, "right": Object { - "end": 1032, + "end": 1024, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -4631,11 +4584,11 @@ Object { }, "name": "isActive", "range": undefined, - "start": 1024, + "start": 1016, "trailingComments": undefined, "type": "Identifier", }, - "start": 1005, + "start": 997, "trailingComments": undefined, "type": "AssignmentExpression", }, @@ -4655,7 +4608,7 @@ Object { }, }, "range": undefined, - "start": 1005, + "start": 997, "trailingComments": undefined, "type": "ExpressionStatement", }, @@ -4663,7 +4616,7 @@ Object { "argument": Object { "arguments": Array [ Object { - "end": 1054, + "end": 1046, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -4681,13 +4634,13 @@ Object { }, "name": "id", "range": undefined, - "start": 1052, + "start": 1044, "trailingComments": undefined, "type": "Identifier", }, ], "callee": Object { - "end": 1051, + "end": 1043, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -4705,11 +4658,11 @@ Object { }, "name": "isActive", "range": undefined, - "start": 1043, + "start": 1035, "trailingComments": undefined, "type": "Identifier", }, - "end": 1055, + "end": 1047, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -4726,11 +4679,11 @@ Object { }, }, "range": undefined, - "start": 1043, + "start": 1035, "trailingComments": undefined, "type": "CallExpression", }, - "end": 1056, + "end": 1048, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -4747,13 +4700,13 @@ Object { }, }, "range": undefined, - "start": 1036, + "start": 1028, "trailingComments": undefined, "type": "ReturnStatement", }, ], "directives": Array [], - "end": 1058, + "end": 1050, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -4770,15 +4723,15 @@ Object { }, }, "range": undefined, - "start": 909, + "start": 901, "trailingComments": undefined, "type": "BlockStatement", }, - "end": 1058, + "end": 1050, "extra": undefined, "generator": false, "id": Object { - "end": 904, + "end": 896, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -4796,7 +4749,7 @@ Object { }, "name": "stryMutAct_9fa48", "range": undefined, - "start": 888, + "start": 880, "trailingComments": undefined, "type": "Identifier", }, @@ -4816,7 +4769,7 @@ Object { }, "params": Array [ Object { - "end": 907, + "end": 899, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -4834,13 +4787,13 @@ Object { }, "name": "id", "range": undefined, - "start": 905, + "start": 897, "trailingComments": undefined, "type": "Identifier", }, ], "range": undefined, - "start": 879, + "start": 871, "trailingComments": undefined, "type": "FunctionDeclaration", }, @@ -4878,8 +4831,8 @@ Object { Object { "arguments": Array [ Object { - "type": "NumericLiteral", - "value": 0, + "type": "StringLiteral", + "value": "0", }, ], "callee": Object { @@ -5048,8 +5001,8 @@ Object { "test": Object { "arguments": Array [ Object { - "type": "NumericLiteral", - "value": 0, + "type": "StringLiteral", + "value": "0", }, ], "callee": Object { @@ -5617,9 +5570,9 @@ Object { "consequent": Object { "body": Array [ Object { - "end": 298, + "end": 290, "expression": Object { - "end": 297, + "end": 289, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -5694,7 +5647,7 @@ Object { }, "loc": Object { "end": Object { - "column": 69, + "column": 61, "line": 5, }, "filename": undefined, @@ -5707,212 +5660,165 @@ Object { "operator": "=", "range": undefined, "right": Object { - "arguments": Array [ - Object { + "computed": false, + "end": 289, + "extra": undefined, + "innerComments": undefined, + "leadingComments": undefined, + "loc": Object { + "end": Object { + "column": 61, + "line": 5, + }, + "filename": undefined, + "identifierName": undefined, + "start": Object { + "column": 22, + "line": 5, + }, + }, + "object": Object { + "computed": false, + "end": 263, + "extra": undefined, + "innerComments": undefined, + "leadingComments": undefined, + "loc": Object { + "end": Object { + "column": 35, + "line": 5, + }, + "filename": undefined, + "identifierName": undefined, + "start": Object { + "column": 22, + "line": 5, + }, + }, + "object": Object { "computed": false, - "end": 296, + "end": 259, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, "loc": Object { "end": Object { - "column": 68, + "column": 31, "line": 5, }, "filename": undefined, "identifierName": undefined, "start": Object { - "column": 29, + "column": 22, "line": 5, }, }, "object": Object { - "computed": false, - "end": 270, + "end": 251, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, "loc": Object { "end": Object { - "column": 42, + "column": 23, "line": 5, }, "filename": undefined, - "identifierName": undefined, + "identifierName": "g", "start": Object { - "column": 29, + "column": 22, "line": 5, }, }, - "object": Object { - "computed": false, - "end": 266, - "extra": undefined, - "innerComments": undefined, - "leadingComments": undefined, - "loc": Object { - "end": Object { - "column": 38, - "line": 5, - }, - "filename": undefined, - "identifierName": undefined, - "start": Object { - "column": 29, - "line": 5, - }, - }, - "object": Object { - "end": 258, - "extra": undefined, - "innerComments": undefined, - "leadingComments": undefined, - "loc": Object { - "end": Object { - "column": 30, - "line": 5, - }, - "filename": undefined, - "identifierName": "g", - "start": Object { - "column": 29, - "line": 5, - }, - }, - "name": "g", - "range": undefined, - "start": 257, - "trailingComments": undefined, - "type": "Identifier", - }, - "property": Object { - "end": 266, - "extra": undefined, - "innerComments": undefined, - "leadingComments": undefined, - "loc": Object { - "end": Object { - "column": 38, - "line": 5, - }, - "filename": undefined, - "identifierName": "process", - "start": Object { - "column": 31, - "line": 5, - }, - }, - "name": "process", - "range": undefined, - "start": 259, - "trailingComments": undefined, - "type": "Identifier", - }, - "range": undefined, - "start": 257, - "trailingComments": undefined, - "type": "MemberExpression", - }, - "property": Object { - "end": 270, - "extra": undefined, - "innerComments": undefined, - "leadingComments": undefined, - "loc": Object { - "end": Object { - "column": 42, - "line": 5, - }, - "filename": undefined, - "identifierName": "env", - "start": Object { - "column": 39, - "line": 5, - }, - }, - "name": "env", - "range": undefined, - "start": 267, - "trailingComments": undefined, - "type": "Identifier", - }, + "name": "g", "range": undefined, - "start": 257, + "start": 250, "trailingComments": undefined, - "type": "MemberExpression", + "type": "Identifier", }, "property": Object { - "end": 296, + "end": 259, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, "loc": Object { "end": Object { - "column": 68, + "column": 31, "line": 5, }, "filename": undefined, - "identifierName": "__STRYKER_ACTIVE_MUTANT__", + "identifierName": "process", "start": Object { - "column": 43, + "column": 24, "line": 5, }, }, - "name": "__STRYKER_ACTIVE_MUTANT__", + "name": "process", "range": undefined, - "start": 271, + "start": 252, "trailingComments": undefined, "type": "Identifier", }, "range": undefined, - "start": 257, + "start": 250, "trailingComments": undefined, "type": "MemberExpression", }, - ], - "callee": Object { - "end": 256, + "property": Object { + "end": 263, + "extra": undefined, + "innerComments": undefined, + "leadingComments": undefined, + "loc": Object { + "end": Object { + "column": 35, + "line": 5, + }, + "filename": undefined, + "identifierName": "env", + "start": Object { + "column": 32, + "line": 5, + }, + }, + "name": "env", + "range": undefined, + "start": 260, + "trailingComments": undefined, + "type": "Identifier", + }, + "range": undefined, + "start": 250, + "trailingComments": undefined, + "type": "MemberExpression", + }, + "property": Object { + "end": 289, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, "loc": Object { "end": Object { - "column": 28, + "column": 61, "line": 5, }, "filename": undefined, - "identifierName": "Number", + "identifierName": "__STRYKER_ACTIVE_MUTANT__", "start": Object { - "column": 22, + "column": 36, "line": 5, }, }, - "name": "Number", + "name": "__STRYKER_ACTIVE_MUTANT__", "range": undefined, - "start": 250, + "start": 264, "trailingComments": undefined, "type": "Identifier", }, - "end": 297, - "extra": undefined, - "innerComments": undefined, - "leadingComments": undefined, - "loc": Object { - "end": Object { - "column": 69, - "line": 5, - }, - "filename": undefined, - "identifierName": undefined, - "start": Object { - "column": 22, - "line": 5, - }, - }, "range": undefined, "start": 250, "trailingComments": undefined, - "type": "CallExpression", + "type": "MemberExpression", }, "start": 232, "trailingComments": undefined, @@ -5923,7 +5829,7 @@ Object { "leadingComments": undefined, "loc": Object { "end": Object { - "column": 70, + "column": 62, "line": 5, }, "filename": undefined, @@ -5940,7 +5846,7 @@ Object { }, ], "directives": Array [], - "end": 302, + "end": 294, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -5961,7 +5867,7 @@ Object { "trailingComments": undefined, "type": "BlockStatement", }, - "end": 302, + "end": 294, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -6517,7 +6423,7 @@ Object { "body": Array [ Object { "argument": Object { - "end": 341, + "end": 333, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -6535,11 +6441,11 @@ Object { }, "name": "ns", "range": undefined, - "start": 339, + "start": 331, "trailingComments": undefined, "type": "Identifier", }, - "end": 342, + "end": 334, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -6556,13 +6462,13 @@ Object { }, }, "range": undefined, - "start": 332, + "start": 324, "trailingComments": undefined, "type": "ReturnStatement", }, ], "directives": Array [], - "end": 346, + "end": 338, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -6579,15 +6485,15 @@ Object { }, }, "range": undefined, - "start": 326, + "start": 318, "trailingComments": undefined, "type": "BlockStatement", }, - "end": 346, + "end": 338, "extra": undefined, "generator": false, "id": Object { - "end": 324, + "end": 316, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -6605,7 +6511,7 @@ Object { }, "name": "retrieveNS", "range": undefined, - "start": 314, + "start": 306, "trailingComments": undefined, "type": "Identifier", }, @@ -6625,19 +6531,19 @@ Object { }, "params": Array [], "range": undefined, - "start": 305, + "start": 297, "trailingComments": undefined, "type": "FunctionDeclaration", }, Object { - "end": 375, + "end": 367, "expression": Object { - "end": 374, + "end": 366, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, "left": Object { - "end": 361, + "end": 353, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -6655,7 +6561,7 @@ Object { }, "name": "stryNS_9fa48", "range": undefined, - "start": 349, + "start": 341, "trailingComments": undefined, "type": "Identifier", }, @@ -6674,7 +6580,7 @@ Object { "operator": "=", "range": undefined, "right": Object { - "end": 374, + "end": 366, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -6692,11 +6598,11 @@ Object { }, "name": "retrieveNS", "range": undefined, - "start": 364, + "start": 356, "trailingComments": undefined, "type": "Identifier", }, - "start": 349, + "start": 341, "trailingComments": undefined, "type": "AssignmentExpression", }, @@ -6716,7 +6622,7 @@ Object { }, }, "range": undefined, - "start": 349, + "start": 341, "trailingComments": undefined, "type": "ExpressionStatement", }, @@ -6724,7 +6630,7 @@ Object { "argument": Object { "arguments": Array [], "callee": Object { - "end": 395, + "end": 387, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -6742,11 +6648,11 @@ Object { }, "name": "retrieveNS", "range": undefined, - "start": 385, + "start": 377, "trailingComments": undefined, "type": "Identifier", }, - "end": 397, + "end": 389, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -6763,11 +6669,11 @@ Object { }, }, "range": undefined, - "start": 385, + "start": 377, "trailingComments": undefined, "type": "CallExpression", }, - "end": 398, + "end": 390, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -6784,13 +6690,13 @@ Object { }, }, "range": undefined, - "start": 378, + "start": 370, "trailingComments": undefined, "type": "ReturnStatement", }, ], "directives": Array [], - "end": 400, + "end": 392, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -6811,7 +6717,7 @@ Object { "trailingComments": undefined, "type": "BlockStatement", }, - "end": 400, + "end": 392, "extra": undefined, "generator": false, "id": Object { @@ -6858,11 +6764,11 @@ Object { "type": "FunctionDeclaration", }, Object { - "end": 416, + "end": 408, "expression": Object { "arguments": Array [], "callee": Object { - "end": 413, + "end": 405, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -6880,11 +6786,11 @@ Object { }, "name": "stryNS_9fa48", "range": undefined, - "start": 401, + "start": 393, "trailingComments": undefined, "type": "Identifier", }, - "end": 415, + "end": 407, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -6901,7 +6807,7 @@ Object { }, }, "range": undefined, - "start": 401, + "start": 393, "trailingComments": undefined, "type": "CallExpression", }, @@ -6921,7 +6827,7 @@ Object { }, }, "range": undefined, - "start": 401, + "start": 393, "trailingComments": undefined, "type": "ExpressionStatement", }, @@ -6932,10 +6838,10 @@ Object { Object { "declarations": Array [ Object { - "end": 470, + "end": 462, "extra": undefined, "id": Object { - "end": 453, + "end": 445, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -6953,14 +6859,14 @@ Object { }, "name": "ns", "range": undefined, - "start": 451, + "start": 443, "trailingComments": undefined, "type": "Identifier", }, "init": Object { "arguments": Array [], "callee": Object { - "end": 468, + "end": 460, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -6978,11 +6884,11 @@ Object { }, "name": "stryNS_9fa48", "range": undefined, - "start": 456, + "start": 448, "trailingComments": undefined, "type": "Identifier", }, - "end": 470, + "end": 462, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -6999,7 +6905,7 @@ Object { }, }, "range": undefined, - "start": 456, + "start": 448, "trailingComments": undefined, "type": "CallExpression", }, @@ -7018,12 +6924,12 @@ Object { }, }, "range": undefined, - "start": 451, + "start": 443, "trailingComments": undefined, "type": "VariableDeclarator", }, ], - "end": 471, + "end": 463, "extra": undefined, "innerComments": undefined, "kind": "var", @@ -7041,17 +6947,17 @@ Object { }, }, "range": undefined, - "start": 447, + "start": 439, "trailingComments": undefined, "type": "VariableDeclaration", }, Object { "declarations": Array [ Object { - "end": 554, + "end": 546, "extra": undefined, "id": Object { - "end": 481, + "end": 473, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -7069,18 +6975,18 @@ Object { }, "name": "cov", "range": undefined, - "start": 478, + "start": 470, "trailingComments": undefined, "type": "Identifier", }, "init": Object { - "end": 554, + "end": 546, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, "left": Object { "computed": false, - "end": 501, + "end": 493, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -7097,7 +7003,7 @@ Object { }, }, "object": Object { - "end": 486, + "end": 478, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -7115,12 +7021,12 @@ Object { }, "name": "ns", "range": undefined, - "start": 484, + "start": 476, "trailingComments": undefined, "type": "Identifier", }, "property": Object { - "end": 501, + "end": 493, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -7138,12 +7044,12 @@ Object { }, "name": "mutantCoverage", "range": undefined, - "start": 487, + "start": 479, "trailingComments": undefined, "type": "Identifier", }, "range": undefined, - "start": 484, + "start": 476, "trailingComments": undefined, "type": "MemberExpression", }, @@ -7162,16 +7068,16 @@ Object { "operator": "||", "range": undefined, "right": Object { - "end": 553, + "end": 545, "extra": Object { - "parenStart": 505, + "parenStart": 497, "parenthesized": true, }, "innerComments": undefined, "leadingComments": undefined, "left": Object { "computed": false, - "end": 523, + "end": 515, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -7188,7 +7094,7 @@ Object { }, }, "object": Object { - "end": 508, + "end": 500, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -7206,12 +7112,12 @@ Object { }, "name": "ns", "range": undefined, - "start": 506, + "start": 498, "trailingComments": undefined, "type": "Identifier", }, "property": Object { - "end": 523, + "end": 515, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -7229,12 +7135,12 @@ Object { }, "name": "mutantCoverage", "range": undefined, - "start": 509, + "start": 501, "trailingComments": undefined, "type": "Identifier", }, "range": undefined, - "start": 506, + "start": 498, "trailingComments": undefined, "type": "MemberExpression", }, @@ -7253,7 +7159,7 @@ Object { "operator": "=", "range": undefined, "right": Object { - "end": 553, + "end": 545, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -7272,11 +7178,11 @@ Object { "properties": Array [ Object { "computed": false, - "end": 538, + "end": 530, "extra": undefined, "innerComments": undefined, "key": Object { - "end": 534, + "end": 526, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -7294,7 +7200,7 @@ Object { }, "name": "static", "range": undefined, - "start": 528, + "start": 520, "trailingComments": undefined, "type": "Identifier", }, @@ -7314,11 +7220,11 @@ Object { "method": false, "range": undefined, "shorthand": false, - "start": 528, + "start": 520, "trailingComments": undefined, "type": "ObjectProperty", "value": Object { - "end": 538, + "end": 530, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -7336,18 +7242,18 @@ Object { }, "properties": Array [], "range": undefined, - "start": 536, + "start": 528, "trailingComments": undefined, "type": "ObjectExpression", }, }, Object { "computed": false, - "end": 551, + "end": 543, "extra": undefined, "innerComments": undefined, "key": Object { - "end": 547, + "end": 539, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -7365,7 +7271,7 @@ Object { }, "name": "perTest", "range": undefined, - "start": 540, + "start": 532, "trailingComments": undefined, "type": "Identifier", }, @@ -7385,11 +7291,11 @@ Object { "method": false, "range": undefined, "shorthand": false, - "start": 540, + "start": 532, "trailingComments": undefined, "type": "ObjectProperty", "value": Object { - "end": 551, + "end": 543, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -7407,22 +7313,22 @@ Object { }, "properties": Array [], "range": undefined, - "start": 549, + "start": 541, "trailingComments": undefined, "type": "ObjectExpression", }, }, ], "range": undefined, - "start": 526, + "start": 518, "trailingComments": undefined, "type": "ObjectExpression", }, - "start": 506, + "start": 498, "trailingComments": undefined, "type": "AssignmentExpression", }, - "start": 484, + "start": 476, "trailingComments": undefined, "type": "LogicalExpression", }, @@ -7441,12 +7347,12 @@ Object { }, }, "range": undefined, - "start": 478, + "start": 470, "trailingComments": undefined, "type": "VariableDeclarator", }, ], - "end": 555, + "end": 547, "extra": undefined, "innerComments": undefined, "kind": "var", @@ -7464,7 +7370,7 @@ Object { }, }, "range": undefined, - "start": 474, + "start": 466, "trailingComments": undefined, "type": "VariableDeclaration", }, @@ -7475,10 +7381,10 @@ Object { Object { "declarations": Array [ Object { - "end": 599, + "end": 591, "extra": undefined, "id": Object { - "end": 586, + "end": 578, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -7496,13 +7402,13 @@ Object { }, "name": "c", "range": undefined, - "start": 585, + "start": 577, "trailingComments": undefined, "type": "Identifier", }, "init": Object { "computed": false, - "end": 599, + "end": 591, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -7519,7 +7425,7 @@ Object { }, }, "object": Object { - "end": 592, + "end": 584, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -7537,12 +7443,12 @@ Object { }, "name": "cov", "range": undefined, - "start": 589, + "start": 581, "trailingComments": undefined, "type": "Identifier", }, "property": Object { - "end": 599, + "end": 591, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -7560,12 +7466,12 @@ Object { }, "name": "static", "range": undefined, - "start": 593, + "start": 585, "trailingComments": undefined, "type": "Identifier", }, "range": undefined, - "start": 589, + "start": 581, "trailingComments": undefined, "type": "MemberExpression", }, @@ -7584,12 +7490,12 @@ Object { }, }, "range": undefined, - "start": 585, + "start": 577, "trailingComments": undefined, "type": "VariableDeclarator", }, ], - "end": 600, + "end": 592, "extra": undefined, "innerComments": undefined, "kind": "var", @@ -7607,7 +7513,7 @@ Object { }, }, "range": undefined, - "start": 581, + "start": 573, "trailingComments": undefined, "type": "VariableDeclaration", }, @@ -7616,14 +7522,14 @@ Object { "consequent": Object { "body": Array [ Object { - "end": 707, + "end": 699, "expression": Object { - "end": 706, + "end": 698, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, "left": Object { - "end": 636, + "end": 628, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -7641,7 +7547,7 @@ Object { }, "name": "c", "range": undefined, - "start": 635, + "start": 627, "trailingComments": undefined, "type": "Identifier", }, @@ -7660,13 +7566,13 @@ Object { "operator": "=", "range": undefined, "right": Object { - "end": 706, + "end": 698, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, "left": Object { "computed": true, - "end": 668, + "end": 660, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -7684,7 +7590,7 @@ Object { }, "object": Object { "computed": false, - "end": 650, + "end": 642, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -7701,7 +7607,7 @@ Object { }, }, "object": Object { - "end": 642, + "end": 634, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -7719,12 +7625,12 @@ Object { }, "name": "cov", "range": undefined, - "start": 639, + "start": 631, "trailingComments": undefined, "type": "Identifier", }, "property": Object { - "end": 650, + "end": 642, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -7742,18 +7648,18 @@ Object { }, "name": "perTest", "range": undefined, - "start": 643, + "start": 635, "trailingComments": undefined, "type": "Identifier", }, "range": undefined, - "start": 639, + "start": 631, "trailingComments": undefined, "type": "MemberExpression", }, "property": Object { "computed": false, - "end": 667, + "end": 659, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -7770,7 +7676,7 @@ Object { }, }, "object": Object { - "end": 653, + "end": 645, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -7788,12 +7694,12 @@ Object { }, "name": "ns", "range": undefined, - "start": 651, + "start": 643, "trailingComments": undefined, "type": "Identifier", }, "property": Object { - "end": 667, + "end": 659, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -7811,17 +7717,17 @@ Object { }, "name": "currentTestId", "range": undefined, - "start": 654, + "start": 646, "trailingComments": undefined, "type": "Identifier", }, "range": undefined, - "start": 651, + "start": 643, "trailingComments": undefined, "type": "MemberExpression", }, "range": undefined, - "start": 639, + "start": 631, "trailingComments": undefined, "type": "MemberExpression", }, @@ -7840,13 +7746,13 @@ Object { "operator": "=", "range": undefined, "right": Object { - "end": 706, + "end": 698, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, "left": Object { "computed": true, - "end": 700, + "end": 692, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -7864,7 +7770,7 @@ Object { }, "object": Object { "computed": false, - "end": 682, + "end": 674, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -7881,7 +7787,7 @@ Object { }, }, "object": Object { - "end": 674, + "end": 666, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -7899,12 +7805,12 @@ Object { }, "name": "cov", "range": undefined, - "start": 671, + "start": 663, "trailingComments": undefined, "type": "Identifier", }, "property": Object { - "end": 682, + "end": 674, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -7922,18 +7828,18 @@ Object { }, "name": "perTest", "range": undefined, - "start": 675, + "start": 667, "trailingComments": undefined, "type": "Identifier", }, "range": undefined, - "start": 671, + "start": 663, "trailingComments": undefined, "type": "MemberExpression", }, "property": Object { "computed": false, - "end": 699, + "end": 691, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -7950,7 +7856,7 @@ Object { }, }, "object": Object { - "end": 685, + "end": 677, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -7968,12 +7874,12 @@ Object { }, "name": "ns", "range": undefined, - "start": 683, + "start": 675, "trailingComments": undefined, "type": "Identifier", }, "property": Object { - "end": 699, + "end": 691, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -7991,17 +7897,17 @@ Object { }, "name": "currentTestId", "range": undefined, - "start": 686, + "start": 678, "trailingComments": undefined, "type": "Identifier", }, "range": undefined, - "start": 683, + "start": 675, "trailingComments": undefined, "type": "MemberExpression", }, "range": undefined, - "start": 671, + "start": 663, "trailingComments": undefined, "type": "MemberExpression", }, @@ -8020,7 +7926,7 @@ Object { "operator": "||", "range": undefined, "right": Object { - "end": 706, + "end": 698, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -8038,19 +7944,19 @@ Object { }, "properties": Array [], "range": undefined, - "start": 704, + "start": 696, "trailingComments": undefined, "type": "ObjectExpression", }, - "start": 671, + "start": 663, "trailingComments": undefined, "type": "LogicalExpression", }, - "start": 639, + "start": 631, "trailingComments": undefined, "type": "AssignmentExpression", }, - "start": 635, + "start": 627, "trailingComments": undefined, "type": "AssignmentExpression", }, @@ -8070,13 +7976,13 @@ Object { }, }, "range": undefined, - "start": 635, + "start": 627, "trailingComments": undefined, "type": "ExpressionStatement", }, ], "directives": Array [], - "end": 713, + "end": 705, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -8093,11 +7999,11 @@ Object { }, }, "range": undefined, - "start": 627, + "start": 619, "trailingComments": undefined, "type": "BlockStatement", }, - "end": 713, + "end": 705, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -8114,10 +8020,10 @@ Object { }, }, "range": undefined, - "start": 605, + "start": 597, "test": Object { "computed": false, - "end": 625, + "end": 617, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -8134,7 +8040,7 @@ Object { }, }, "object": Object { - "end": 611, + "end": 603, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -8152,12 +8058,12 @@ Object { }, "name": "ns", "range": undefined, - "start": 609, + "start": 601, "trailingComments": undefined, "type": "Identifier", }, "property": Object { - "end": 625, + "end": 617, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -8175,12 +8081,12 @@ Object { }, "name": "currentTestId", "range": undefined, - "start": 612, + "start": 604, "trailingComments": undefined, "type": "Identifier", }, "range": undefined, - "start": 609, + "start": 601, "trailingComments": undefined, "type": "MemberExpression", }, @@ -8190,10 +8096,10 @@ Object { Object { "declarations": Array [ Object { - "end": 735, + "end": 727, "extra": undefined, "id": Object { - "end": 723, + "end": 715, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -8211,12 +8117,12 @@ Object { }, "name": "a", "range": undefined, - "start": 722, + "start": 714, "trailingComments": undefined, "type": "Identifier", }, "init": Object { - "end": 735, + "end": 727, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -8234,7 +8140,7 @@ Object { }, "name": "arguments", "range": undefined, - "start": 726, + "start": 718, "trailingComments": undefined, "type": "Identifier", }, @@ -8253,12 +8159,12 @@ Object { }, }, "range": undefined, - "start": 722, + "start": 714, "trailingComments": undefined, "type": "VariableDeclarator", }, ], - "end": 736, + "end": 728, "extra": undefined, "innerComments": undefined, "kind": "var", @@ -8276,7 +8182,7 @@ Object { }, }, "range": undefined, - "start": 718, + "start": 710, "trailingComments": undefined, "type": "VariableDeclaration", }, @@ -8284,15 +8190,15 @@ Object { "body": Object { "body": Array [ Object { - "end": 809, + "end": 801, "expression": Object { - "end": 808, + "end": 800, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, "left": Object { "computed": true, - "end": 787, + "end": 779, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -8309,7 +8215,7 @@ Object { }, }, "object": Object { - "end": 781, + "end": 773, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -8327,13 +8233,13 @@ Object { }, "name": "c", "range": undefined, - "start": 780, + "start": 772, "trailingComments": undefined, "type": "Identifier", }, "property": Object { "computed": true, - "end": 786, + "end": 778, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -8350,7 +8256,7 @@ Object { }, }, "object": Object { - "end": 783, + "end": 775, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -8368,12 +8274,12 @@ Object { }, "name": "a", "range": undefined, - "start": 782, + "start": 774, "trailingComments": undefined, "type": "Identifier", }, "property": Object { - "end": 785, + "end": 777, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -8391,17 +8297,17 @@ Object { }, "name": "i", "range": undefined, - "start": 784, + "start": 776, "trailingComments": undefined, "type": "Identifier", }, "range": undefined, - "start": 782, + "start": 774, "trailingComments": undefined, "type": "MemberExpression", }, "range": undefined, - "start": 780, + "start": 772, "trailingComments": undefined, "type": "MemberExpression", }, @@ -8420,21 +8326,21 @@ Object { "operator": "=", "range": undefined, "right": Object { - "end": 808, + "end": 800, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, "left": Object { - "end": 803, + "end": 795, "extra": Object { - "parenStart": 790, + "parenStart": 782, "parenthesized": true, }, "innerComments": undefined, "leadingComments": undefined, "left": Object { "computed": true, - "end": 798, + "end": 790, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -8451,7 +8357,7 @@ Object { }, }, "object": Object { - "end": 792, + "end": 784, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -8469,13 +8375,13 @@ Object { }, "name": "c", "range": undefined, - "start": 791, + "start": 783, "trailingComments": undefined, "type": "Identifier", }, "property": Object { "computed": true, - "end": 797, + "end": 789, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -8492,7 +8398,7 @@ Object { }, }, "object": Object { - "end": 794, + "end": 786, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -8510,12 +8416,12 @@ Object { }, "name": "a", "range": undefined, - "start": 793, + "start": 785, "trailingComments": undefined, "type": "Identifier", }, "property": Object { - "end": 796, + "end": 788, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -8533,17 +8439,17 @@ Object { }, "name": "i", "range": undefined, - "start": 795, + "start": 787, "trailingComments": undefined, "type": "Identifier", }, "range": undefined, - "start": 793, + "start": 785, "trailingComments": undefined, "type": "MemberExpression", }, "range": undefined, - "start": 791, + "start": 783, "trailingComments": undefined, "type": "MemberExpression", }, @@ -8562,7 +8468,7 @@ Object { "operator": "||", "range": undefined, "right": Object { - "end": 803, + "end": 795, "extra": Object { "raw": "0", "rawValue": 0, @@ -8582,12 +8488,12 @@ Object { }, }, "range": undefined, - "start": 802, + "start": 794, "trailingComments": undefined, "type": "NumericLiteral", "value": 0, }, - "start": 791, + "start": 783, "trailingComments": undefined, "type": "LogicalExpression", }, @@ -8606,7 +8512,7 @@ Object { "operator": "+", "range": undefined, "right": Object { - "end": 808, + "end": 800, "extra": Object { "raw": "1", "rawValue": 1, @@ -8626,16 +8532,16 @@ Object { }, }, "range": undefined, - "start": 807, + "start": 799, "trailingComments": undefined, "type": "NumericLiteral", "value": 1, }, - "start": 790, + "start": 782, "trailingComments": undefined, "type": "BinaryExpression", }, - "start": 780, + "start": 772, "trailingComments": undefined, "type": "AssignmentExpression", }, @@ -8655,13 +8561,13 @@ Object { }, }, "range": undefined, - "start": 780, + "start": 772, "trailingComments": undefined, "type": "ExpressionStatement", }, ], "directives": Array [], - "end": 815, + "end": 807, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -8678,19 +8584,19 @@ Object { }, }, "range": undefined, - "start": 772, + "start": 764, "trailingComments": undefined, "type": "BlockStatement", }, - "end": 815, + "end": 807, "extra": undefined, "init": Object { "declarations": Array [ Object { - "end": 752, + "end": 744, "extra": undefined, "id": Object { - "end": 750, + "end": 742, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -8708,12 +8614,12 @@ Object { }, "name": "i", "range": undefined, - "start": 749, + "start": 741, "trailingComments": undefined, "type": "Identifier", }, "init": Object { - "end": 752, + "end": 744, "extra": Object { "raw": "0", "rawValue": 0, @@ -8733,7 +8639,7 @@ Object { }, }, "range": undefined, - "start": 751, + "start": 743, "trailingComments": undefined, "type": "NumericLiteral", "value": 0, @@ -8753,12 +8659,12 @@ Object { }, }, "range": undefined, - "start": 749, + "start": 741, "trailingComments": undefined, "type": "VariableDeclarator", }, ], - "end": 752, + "end": 744, "extra": undefined, "innerComments": undefined, "kind": "var", @@ -8776,7 +8682,7 @@ Object { }, }, "range": undefined, - "start": 745, + "start": 737, "trailingComments": undefined, "type": "VariableDeclaration", }, @@ -8795,14 +8701,14 @@ Object { }, }, "range": undefined, - "start": 741, + "start": 733, "test": Object { - "end": 766, + "end": 758, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, "left": Object { - "end": 755, + "end": 747, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -8820,7 +8726,7 @@ Object { }, "name": "i", "range": undefined, - "start": 754, + "start": 746, "trailingComments": undefined, "type": "Identifier", }, @@ -8840,7 +8746,7 @@ Object { "range": undefined, "right": Object { "computed": false, - "end": 766, + "end": 758, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -8857,7 +8763,7 @@ Object { }, }, "object": Object { - "end": 759, + "end": 751, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -8875,12 +8781,12 @@ Object { }, "name": "a", "range": undefined, - "start": 758, + "start": 750, "trailingComments": undefined, "type": "Identifier", }, "property": Object { - "end": 766, + "end": 758, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -8898,16 +8804,16 @@ Object { }, "name": "length", "range": undefined, - "start": 760, + "start": 752, "trailingComments": undefined, "type": "Identifier", }, "range": undefined, - "start": 758, + "start": 750, "trailingComments": undefined, "type": "MemberExpression", }, - "start": 754, + "start": 746, "trailingComments": undefined, "type": "BinaryExpression", }, @@ -8915,7 +8821,7 @@ Object { "type": "ForStatement", "update": Object { "argument": Object { - "end": 769, + "end": 761, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -8933,11 +8839,11 @@ Object { }, "name": "i", "range": undefined, - "start": 768, + "start": 760, "trailingComments": undefined, "type": "Identifier", }, - "end": 771, + "end": 763, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -8956,14 +8862,14 @@ Object { "operator": "++", "prefix": false, "range": undefined, - "start": 768, + "start": 760, "trailingComments": undefined, "type": "UpdateExpression", }, }, ], "directives": Array [], - "end": 819, + "end": 811, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -8980,15 +8886,15 @@ Object { }, }, "range": undefined, - "start": 575, + "start": 567, "trailingComments": undefined, "type": "BlockStatement", }, - "end": 819, + "end": 811, "extra": undefined, "generator": false, "id": Object { - "end": 572, + "end": 564, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -9006,7 +8912,7 @@ Object { }, "name": "cover", "range": undefined, - "start": 567, + "start": 559, "trailingComments": undefined, "type": "Identifier", }, @@ -9026,19 +8932,19 @@ Object { }, "params": Array [], "range": undefined, - "start": 558, + "start": 550, "trailingComments": undefined, "type": "FunctionDeclaration", }, Object { - "end": 844, + "end": 836, "expression": Object { - "end": 843, + "end": 835, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, "left": Object { - "end": 835, + "end": 827, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -9056,7 +8962,7 @@ Object { }, "name": "stryCov_9fa48", "range": undefined, - "start": 822, + "start": 814, "trailingComments": undefined, "type": "Identifier", }, @@ -9075,7 +8981,7 @@ Object { "operator": "=", "range": undefined, "right": Object { - "end": 843, + "end": 835, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -9093,11 +8999,11 @@ Object { }, "name": "cover", "range": undefined, - "start": 838, + "start": 830, "trailingComments": undefined, "type": "Identifier", }, - "start": 822, + "start": 814, "trailingComments": undefined, "type": "AssignmentExpression", }, @@ -9117,16 +9023,16 @@ Object { }, }, "range": undefined, - "start": 822, + "start": 814, "trailingComments": undefined, "type": "ExpressionStatement", }, Object { - "end": 876, + "end": 868, "expression": Object { "arguments": Array [ Object { - "end": 863, + "end": 855, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -9143,12 +9049,12 @@ Object { }, }, "range": undefined, - "start": 859, + "start": 851, "trailingComments": undefined, "type": "NullLiteral", }, Object { - "end": 874, + "end": 866, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -9166,14 +9072,14 @@ Object { }, "name": "arguments", "range": undefined, - "start": 865, + "start": 857, "trailingComments": undefined, "type": "Identifier", }, ], "callee": Object { "computed": false, - "end": 858, + "end": 850, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -9190,7 +9096,7 @@ Object { }, }, "object": Object { - "end": 852, + "end": 844, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -9208,12 +9114,12 @@ Object { }, "name": "cover", "range": undefined, - "start": 847, + "start": 839, "trailingComments": undefined, "type": "Identifier", }, "property": Object { - "end": 858, + "end": 850, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -9231,16 +9137,16 @@ Object { }, "name": "apply", "range": undefined, - "start": 853, + "start": 845, "trailingComments": undefined, "type": "Identifier", }, "range": undefined, - "start": 847, + "start": 839, "trailingComments": undefined, "type": "MemberExpression", }, - "end": 875, + "end": 867, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -9257,7 +9163,7 @@ Object { }, }, "range": undefined, - "start": 847, + "start": 839, "trailingComments": undefined, "type": "CallExpression", }, @@ -9277,13 +9183,13 @@ Object { }, }, "range": undefined, - "start": 847, + "start": 839, "trailingComments": undefined, "type": "ExpressionStatement", }, ], "directives": Array [], - "end": 878, + "end": 870, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -9300,15 +9206,15 @@ Object { }, }, "range": undefined, - "start": 443, + "start": 435, "trailingComments": undefined, "type": "BlockStatement", }, - "end": 878, + "end": 870, "extra": undefined, "generator": false, "id": Object { - "end": 440, + "end": 432, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -9326,7 +9232,7 @@ Object { }, "name": "stryCov_9fa48", "range": undefined, - "start": 427, + "start": 419, "trailingComments": undefined, "type": "Identifier", }, @@ -9346,7 +9252,7 @@ Object { }, "params": Array [], "range": undefined, - "start": 418, + "start": 410, "trailingComments": undefined, "type": "FunctionDeclaration", }, @@ -9357,10 +9263,10 @@ Object { Object { "declarations": Array [ Object { - "end": 936, + "end": 928, "extra": undefined, "id": Object { - "end": 919, + "end": 911, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -9378,14 +9284,14 @@ Object { }, "name": "ns", "range": undefined, - "start": 917, + "start": 909, "trailingComments": undefined, "type": "Identifier", }, "init": Object { "arguments": Array [], "callee": Object { - "end": 934, + "end": 926, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -9403,11 +9309,11 @@ Object { }, "name": "stryNS_9fa48", "range": undefined, - "start": 922, + "start": 914, "trailingComments": undefined, "type": "Identifier", }, - "end": 936, + "end": 928, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -9424,7 +9330,7 @@ Object { }, }, "range": undefined, - "start": 922, + "start": 914, "trailingComments": undefined, "type": "CallExpression", }, @@ -9443,12 +9349,12 @@ Object { }, }, "range": undefined, - "start": 917, + "start": 909, "trailingComments": undefined, "type": "VariableDeclarator", }, ], - "end": 937, + "end": 929, "extra": undefined, "innerComments": undefined, "kind": "var", @@ -9466,7 +9372,7 @@ Object { }, }, "range": undefined, - "start": 913, + "start": 905, "trailingComments": undefined, "type": "VariableDeclaration", }, @@ -9476,13 +9382,13 @@ Object { "body": Array [ Object { "argument": Object { - "end": 997, + "end": 989, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, "left": Object { "computed": false, - "end": 990, + "end": 982, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -9499,7 +9405,7 @@ Object { }, }, "object": Object { - "end": 977, + "end": 969, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -9517,12 +9423,12 @@ Object { }, "name": "ns", "range": undefined, - "start": 975, + "start": 967, "trailingComments": undefined, "type": "Identifier", }, "property": Object { - "end": 990, + "end": 982, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -9540,12 +9446,12 @@ Object { }, "name": "activeMutant", "range": undefined, - "start": 978, + "start": 970, "trailingComments": undefined, "type": "Identifier", }, "range": undefined, - "start": 975, + "start": 967, "trailingComments": undefined, "type": "MemberExpression", }, @@ -9564,7 +9470,7 @@ Object { "operator": "===", "range": undefined, "right": Object { - "end": 997, + "end": 989, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -9582,15 +9488,15 @@ Object { }, "name": "id", "range": undefined, - "start": 995, + "start": 987, "trailingComments": undefined, "type": "Identifier", }, - "start": 975, + "start": 967, "trailingComments": undefined, "type": "BinaryExpression", }, - "end": 998, + "end": 990, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -9607,13 +9513,13 @@ Object { }, }, "range": undefined, - "start": 968, + "start": 960, "trailingComments": undefined, "type": "ReturnStatement", }, ], "directives": Array [], - "end": 1002, + "end": 994, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -9630,15 +9536,15 @@ Object { }, }, "range": undefined, - "start": 962, + "start": 954, "trailingComments": undefined, "type": "BlockStatement", }, - "end": 1002, + "end": 994, "extra": undefined, "generator": false, "id": Object { - "end": 957, + "end": 949, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -9656,7 +9562,7 @@ Object { }, "name": "isActive", "range": undefined, - "start": 949, + "start": 941, "trailingComments": undefined, "type": "Identifier", }, @@ -9676,7 +9582,7 @@ Object { }, "params": Array [ Object { - "end": 960, + "end": 952, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -9694,25 +9600,25 @@ Object { }, "name": "id", "range": undefined, - "start": 958, + "start": 950, "trailingComments": undefined, "type": "Identifier", }, ], "range": undefined, - "start": 940, + "start": 932, "trailingComments": undefined, "type": "FunctionDeclaration", }, Object { - "end": 1033, + "end": 1025, "expression": Object { - "end": 1032, + "end": 1024, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, "left": Object { - "end": 1021, + "end": 1013, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -9730,7 +9636,7 @@ Object { }, "name": "stryMutAct_9fa48", "range": undefined, - "start": 1005, + "start": 997, "trailingComments": undefined, "type": "Identifier", }, @@ -9749,7 +9655,7 @@ Object { "operator": "=", "range": undefined, "right": Object { - "end": 1032, + "end": 1024, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -9767,11 +9673,11 @@ Object { }, "name": "isActive", "range": undefined, - "start": 1024, + "start": 1016, "trailingComments": undefined, "type": "Identifier", }, - "start": 1005, + "start": 997, "trailingComments": undefined, "type": "AssignmentExpression", }, @@ -9791,7 +9697,7 @@ Object { }, }, "range": undefined, - "start": 1005, + "start": 997, "trailingComments": undefined, "type": "ExpressionStatement", }, @@ -9799,7 +9705,7 @@ Object { "argument": Object { "arguments": Array [ Object { - "end": 1054, + "end": 1046, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -9817,13 +9723,13 @@ Object { }, "name": "id", "range": undefined, - "start": 1052, + "start": 1044, "trailingComments": undefined, "type": "Identifier", }, ], "callee": Object { - "end": 1051, + "end": 1043, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -9841,11 +9747,11 @@ Object { }, "name": "isActive", "range": undefined, - "start": 1043, + "start": 1035, "trailingComments": undefined, "type": "Identifier", }, - "end": 1055, + "end": 1047, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -9862,11 +9768,11 @@ Object { }, }, "range": undefined, - "start": 1043, + "start": 1035, "trailingComments": undefined, "type": "CallExpression", }, - "end": 1056, + "end": 1048, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -9883,13 +9789,13 @@ Object { }, }, "range": undefined, - "start": 1036, + "start": 1028, "trailingComments": undefined, "type": "ReturnStatement", }, ], "directives": Array [], - "end": 1058, + "end": 1050, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -9906,15 +9812,15 @@ Object { }, }, "range": undefined, - "start": 909, + "start": 901, "trailingComments": undefined, "type": "BlockStatement", }, - "end": 1058, + "end": 1050, "extra": undefined, "generator": false, "id": Object { - "end": 904, + "end": 896, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -9932,7 +9838,7 @@ Object { }, "name": "stryMutAct_9fa48", "range": undefined, - "start": 888, + "start": 880, "trailingComments": undefined, "type": "Identifier", }, @@ -9952,7 +9858,7 @@ Object { }, "params": Array [ Object { - "end": 907, + "end": 899, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -9970,13 +9876,13 @@ Object { }, "name": "id", "range": undefined, - "start": 905, + "start": 897, "trailingComments": undefined, "type": "Identifier", }, ], "range": undefined, - "start": 879, + "start": 871, "trailingComments": undefined, "type": "FunctionDeclaration", }, @@ -10058,8 +9964,8 @@ Object { Object { "arguments": Array [ Object { - "type": "NumericLiteral", - "value": 0, + "type": "StringLiteral", + "value": "0", }, ], "callee": Object { @@ -10228,8 +10134,8 @@ Object { "test": Object { "arguments": Array [ Object { - "type": "NumericLiteral", - "value": 0, + "type": "StringLiteral", + "value": "0", }, ], "callee": Object { @@ -10803,9 +10709,9 @@ Object { "consequent": Object { "body": Array [ Object { - "end": 298, + "end": 290, "expression": Object { - "end": 297, + "end": 289, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -10880,7 +10786,7 @@ Object { }, "loc": Object { "end": Object { - "column": 69, + "column": 61, "line": 5, }, "filename": undefined, @@ -10893,212 +10799,165 @@ Object { "operator": "=", "range": undefined, "right": Object { - "arguments": Array [ - Object { + "computed": false, + "end": 289, + "extra": undefined, + "innerComments": undefined, + "leadingComments": undefined, + "loc": Object { + "end": Object { + "column": 61, + "line": 5, + }, + "filename": undefined, + "identifierName": undefined, + "start": Object { + "column": 22, + "line": 5, + }, + }, + "object": Object { + "computed": false, + "end": 263, + "extra": undefined, + "innerComments": undefined, + "leadingComments": undefined, + "loc": Object { + "end": Object { + "column": 35, + "line": 5, + }, + "filename": undefined, + "identifierName": undefined, + "start": Object { + "column": 22, + "line": 5, + }, + }, + "object": Object { "computed": false, - "end": 296, + "end": 259, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, "loc": Object { "end": Object { - "column": 68, + "column": 31, "line": 5, }, "filename": undefined, "identifierName": undefined, "start": Object { - "column": 29, + "column": 22, "line": 5, }, }, "object": Object { - "computed": false, - "end": 270, + "end": 251, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, "loc": Object { "end": Object { - "column": 42, + "column": 23, "line": 5, }, "filename": undefined, - "identifierName": undefined, + "identifierName": "g", "start": Object { - "column": 29, + "column": 22, "line": 5, }, }, - "object": Object { - "computed": false, - "end": 266, - "extra": undefined, - "innerComments": undefined, - "leadingComments": undefined, - "loc": Object { - "end": Object { - "column": 38, - "line": 5, - }, - "filename": undefined, - "identifierName": undefined, - "start": Object { - "column": 29, - "line": 5, - }, - }, - "object": Object { - "end": 258, - "extra": undefined, - "innerComments": undefined, - "leadingComments": undefined, - "loc": Object { - "end": Object { - "column": 30, - "line": 5, - }, - "filename": undefined, - "identifierName": "g", - "start": Object { - "column": 29, - "line": 5, - }, - }, - "name": "g", - "range": undefined, - "start": 257, - "trailingComments": undefined, - "type": "Identifier", - }, - "property": Object { - "end": 266, - "extra": undefined, - "innerComments": undefined, - "leadingComments": undefined, - "loc": Object { - "end": Object { - "column": 38, - "line": 5, - }, - "filename": undefined, - "identifierName": "process", - "start": Object { - "column": 31, - "line": 5, - }, - }, - "name": "process", - "range": undefined, - "start": 259, - "trailingComments": undefined, - "type": "Identifier", - }, - "range": undefined, - "start": 257, - "trailingComments": undefined, - "type": "MemberExpression", - }, - "property": Object { - "end": 270, - "extra": undefined, - "innerComments": undefined, - "leadingComments": undefined, - "loc": Object { - "end": Object { - "column": 42, - "line": 5, - }, - "filename": undefined, - "identifierName": "env", - "start": Object { - "column": 39, - "line": 5, - }, - }, - "name": "env", - "range": undefined, - "start": 267, - "trailingComments": undefined, - "type": "Identifier", - }, + "name": "g", "range": undefined, - "start": 257, + "start": 250, "trailingComments": undefined, - "type": "MemberExpression", + "type": "Identifier", }, "property": Object { - "end": 296, + "end": 259, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, "loc": Object { "end": Object { - "column": 68, + "column": 31, "line": 5, }, "filename": undefined, - "identifierName": "__STRYKER_ACTIVE_MUTANT__", + "identifierName": "process", "start": Object { - "column": 43, + "column": 24, "line": 5, }, }, - "name": "__STRYKER_ACTIVE_MUTANT__", + "name": "process", "range": undefined, - "start": 271, + "start": 252, "trailingComments": undefined, "type": "Identifier", }, "range": undefined, - "start": 257, + "start": 250, "trailingComments": undefined, "type": "MemberExpression", }, - ], - "callee": Object { - "end": 256, + "property": Object { + "end": 263, + "extra": undefined, + "innerComments": undefined, + "leadingComments": undefined, + "loc": Object { + "end": Object { + "column": 35, + "line": 5, + }, + "filename": undefined, + "identifierName": "env", + "start": Object { + "column": 32, + "line": 5, + }, + }, + "name": "env", + "range": undefined, + "start": 260, + "trailingComments": undefined, + "type": "Identifier", + }, + "range": undefined, + "start": 250, + "trailingComments": undefined, + "type": "MemberExpression", + }, + "property": Object { + "end": 289, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, "loc": Object { "end": Object { - "column": 28, + "column": 61, "line": 5, }, "filename": undefined, - "identifierName": "Number", + "identifierName": "__STRYKER_ACTIVE_MUTANT__", "start": Object { - "column": 22, + "column": 36, "line": 5, }, }, - "name": "Number", + "name": "__STRYKER_ACTIVE_MUTANT__", "range": undefined, - "start": 250, + "start": 264, "trailingComments": undefined, "type": "Identifier", }, - "end": 297, - "extra": undefined, - "innerComments": undefined, - "leadingComments": undefined, - "loc": Object { - "end": Object { - "column": 69, - "line": 5, - }, - "filename": undefined, - "identifierName": undefined, - "start": Object { - "column": 22, - "line": 5, - }, - }, "range": undefined, "start": 250, "trailingComments": undefined, - "type": "CallExpression", + "type": "MemberExpression", }, "start": 232, "trailingComments": undefined, @@ -11109,7 +10968,7 @@ Object { "leadingComments": undefined, "loc": Object { "end": Object { - "column": 70, + "column": 62, "line": 5, }, "filename": undefined, @@ -11126,7 +10985,7 @@ Object { }, ], "directives": Array [], - "end": 302, + "end": 294, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -11147,7 +11006,7 @@ Object { "trailingComments": undefined, "type": "BlockStatement", }, - "end": 302, + "end": 294, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -11703,7 +11562,7 @@ Object { "body": Array [ Object { "argument": Object { - "end": 341, + "end": 333, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -11721,11 +11580,11 @@ Object { }, "name": "ns", "range": undefined, - "start": 339, + "start": 331, "trailingComments": undefined, "type": "Identifier", }, - "end": 342, + "end": 334, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -11742,13 +11601,13 @@ Object { }, }, "range": undefined, - "start": 332, + "start": 324, "trailingComments": undefined, "type": "ReturnStatement", }, ], "directives": Array [], - "end": 346, + "end": 338, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -11765,15 +11624,15 @@ Object { }, }, "range": undefined, - "start": 326, + "start": 318, "trailingComments": undefined, "type": "BlockStatement", }, - "end": 346, + "end": 338, "extra": undefined, "generator": false, "id": Object { - "end": 324, + "end": 316, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -11791,7 +11650,7 @@ Object { }, "name": "retrieveNS", "range": undefined, - "start": 314, + "start": 306, "trailingComments": undefined, "type": "Identifier", }, @@ -11811,19 +11670,19 @@ Object { }, "params": Array [], "range": undefined, - "start": 305, + "start": 297, "trailingComments": undefined, "type": "FunctionDeclaration", }, Object { - "end": 375, + "end": 367, "expression": Object { - "end": 374, + "end": 366, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, "left": Object { - "end": 361, + "end": 353, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -11841,7 +11700,7 @@ Object { }, "name": "stryNS_9fa48", "range": undefined, - "start": 349, + "start": 341, "trailingComments": undefined, "type": "Identifier", }, @@ -11860,7 +11719,7 @@ Object { "operator": "=", "range": undefined, "right": Object { - "end": 374, + "end": 366, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -11878,11 +11737,11 @@ Object { }, "name": "retrieveNS", "range": undefined, - "start": 364, + "start": 356, "trailingComments": undefined, "type": "Identifier", }, - "start": 349, + "start": 341, "trailingComments": undefined, "type": "AssignmentExpression", }, @@ -11902,7 +11761,7 @@ Object { }, }, "range": undefined, - "start": 349, + "start": 341, "trailingComments": undefined, "type": "ExpressionStatement", }, @@ -11910,7 +11769,7 @@ Object { "argument": Object { "arguments": Array [], "callee": Object { - "end": 395, + "end": 387, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -11928,11 +11787,11 @@ Object { }, "name": "retrieveNS", "range": undefined, - "start": 385, + "start": 377, "trailingComments": undefined, "type": "Identifier", }, - "end": 397, + "end": 389, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -11949,11 +11808,11 @@ Object { }, }, "range": undefined, - "start": 385, + "start": 377, "trailingComments": undefined, "type": "CallExpression", }, - "end": 398, + "end": 390, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -11970,13 +11829,13 @@ Object { }, }, "range": undefined, - "start": 378, + "start": 370, "trailingComments": undefined, "type": "ReturnStatement", }, ], "directives": Array [], - "end": 400, + "end": 392, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -11997,7 +11856,7 @@ Object { "trailingComments": undefined, "type": "BlockStatement", }, - "end": 400, + "end": 392, "extra": undefined, "generator": false, "id": Object { @@ -12044,11 +11903,11 @@ Object { "type": "FunctionDeclaration", }, Object { - "end": 416, + "end": 408, "expression": Object { "arguments": Array [], "callee": Object { - "end": 413, + "end": 405, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -12066,11 +11925,11 @@ Object { }, "name": "stryNS_9fa48", "range": undefined, - "start": 401, + "start": 393, "trailingComments": undefined, "type": "Identifier", }, - "end": 415, + "end": 407, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -12087,7 +11946,7 @@ Object { }, }, "range": undefined, - "start": 401, + "start": 393, "trailingComments": undefined, "type": "CallExpression", }, @@ -12107,7 +11966,7 @@ Object { }, }, "range": undefined, - "start": 401, + "start": 393, "trailingComments": undefined, "type": "ExpressionStatement", }, @@ -12118,10 +11977,10 @@ Object { Object { "declarations": Array [ Object { - "end": 470, + "end": 462, "extra": undefined, "id": Object { - "end": 453, + "end": 445, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -12139,14 +11998,14 @@ Object { }, "name": "ns", "range": undefined, - "start": 451, + "start": 443, "trailingComments": undefined, "type": "Identifier", }, "init": Object { "arguments": Array [], "callee": Object { - "end": 468, + "end": 460, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -12164,11 +12023,11 @@ Object { }, "name": "stryNS_9fa48", "range": undefined, - "start": 456, + "start": 448, "trailingComments": undefined, "type": "Identifier", }, - "end": 470, + "end": 462, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -12185,7 +12044,7 @@ Object { }, }, "range": undefined, - "start": 456, + "start": 448, "trailingComments": undefined, "type": "CallExpression", }, @@ -12204,12 +12063,12 @@ Object { }, }, "range": undefined, - "start": 451, + "start": 443, "trailingComments": undefined, "type": "VariableDeclarator", }, ], - "end": 471, + "end": 463, "extra": undefined, "innerComments": undefined, "kind": "var", @@ -12227,17 +12086,17 @@ Object { }, }, "range": undefined, - "start": 447, + "start": 439, "trailingComments": undefined, "type": "VariableDeclaration", }, Object { "declarations": Array [ Object { - "end": 554, + "end": 546, "extra": undefined, "id": Object { - "end": 481, + "end": 473, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -12255,18 +12114,18 @@ Object { }, "name": "cov", "range": undefined, - "start": 478, + "start": 470, "trailingComments": undefined, "type": "Identifier", }, "init": Object { - "end": 554, + "end": 546, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, "left": Object { "computed": false, - "end": 501, + "end": 493, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -12283,7 +12142,7 @@ Object { }, }, "object": Object { - "end": 486, + "end": 478, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -12301,12 +12160,12 @@ Object { }, "name": "ns", "range": undefined, - "start": 484, + "start": 476, "trailingComments": undefined, "type": "Identifier", }, "property": Object { - "end": 501, + "end": 493, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -12324,12 +12183,12 @@ Object { }, "name": "mutantCoverage", "range": undefined, - "start": 487, + "start": 479, "trailingComments": undefined, "type": "Identifier", }, "range": undefined, - "start": 484, + "start": 476, "trailingComments": undefined, "type": "MemberExpression", }, @@ -12348,16 +12207,16 @@ Object { "operator": "||", "range": undefined, "right": Object { - "end": 553, + "end": 545, "extra": Object { - "parenStart": 505, + "parenStart": 497, "parenthesized": true, }, "innerComments": undefined, "leadingComments": undefined, "left": Object { "computed": false, - "end": 523, + "end": 515, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -12374,7 +12233,7 @@ Object { }, }, "object": Object { - "end": 508, + "end": 500, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -12392,12 +12251,12 @@ Object { }, "name": "ns", "range": undefined, - "start": 506, + "start": 498, "trailingComments": undefined, "type": "Identifier", }, "property": Object { - "end": 523, + "end": 515, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -12415,12 +12274,12 @@ Object { }, "name": "mutantCoverage", "range": undefined, - "start": 509, + "start": 501, "trailingComments": undefined, "type": "Identifier", }, "range": undefined, - "start": 506, + "start": 498, "trailingComments": undefined, "type": "MemberExpression", }, @@ -12439,7 +12298,7 @@ Object { "operator": "=", "range": undefined, "right": Object { - "end": 553, + "end": 545, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -12458,11 +12317,11 @@ Object { "properties": Array [ Object { "computed": false, - "end": 538, + "end": 530, "extra": undefined, "innerComments": undefined, "key": Object { - "end": 534, + "end": 526, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -12480,7 +12339,7 @@ Object { }, "name": "static", "range": undefined, - "start": 528, + "start": 520, "trailingComments": undefined, "type": "Identifier", }, @@ -12500,11 +12359,11 @@ Object { "method": false, "range": undefined, "shorthand": false, - "start": 528, + "start": 520, "trailingComments": undefined, "type": "ObjectProperty", "value": Object { - "end": 538, + "end": 530, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -12522,18 +12381,18 @@ Object { }, "properties": Array [], "range": undefined, - "start": 536, + "start": 528, "trailingComments": undefined, "type": "ObjectExpression", }, }, Object { "computed": false, - "end": 551, + "end": 543, "extra": undefined, "innerComments": undefined, "key": Object { - "end": 547, + "end": 539, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -12551,7 +12410,7 @@ Object { }, "name": "perTest", "range": undefined, - "start": 540, + "start": 532, "trailingComments": undefined, "type": "Identifier", }, @@ -12571,11 +12430,11 @@ Object { "method": false, "range": undefined, "shorthand": false, - "start": 540, + "start": 532, "trailingComments": undefined, "type": "ObjectProperty", "value": Object { - "end": 551, + "end": 543, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -12593,22 +12452,22 @@ Object { }, "properties": Array [], "range": undefined, - "start": 549, + "start": 541, "trailingComments": undefined, "type": "ObjectExpression", }, }, ], "range": undefined, - "start": 526, + "start": 518, "trailingComments": undefined, "type": "ObjectExpression", }, - "start": 506, + "start": 498, "trailingComments": undefined, "type": "AssignmentExpression", }, - "start": 484, + "start": 476, "trailingComments": undefined, "type": "LogicalExpression", }, @@ -12627,12 +12486,12 @@ Object { }, }, "range": undefined, - "start": 478, + "start": 470, "trailingComments": undefined, "type": "VariableDeclarator", }, ], - "end": 555, + "end": 547, "extra": undefined, "innerComments": undefined, "kind": "var", @@ -12650,7 +12509,7 @@ Object { }, }, "range": undefined, - "start": 474, + "start": 466, "trailingComments": undefined, "type": "VariableDeclaration", }, @@ -12661,10 +12520,10 @@ Object { Object { "declarations": Array [ Object { - "end": 599, + "end": 591, "extra": undefined, "id": Object { - "end": 586, + "end": 578, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -12682,13 +12541,13 @@ Object { }, "name": "c", "range": undefined, - "start": 585, + "start": 577, "trailingComments": undefined, "type": "Identifier", }, "init": Object { "computed": false, - "end": 599, + "end": 591, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -12705,7 +12564,7 @@ Object { }, }, "object": Object { - "end": 592, + "end": 584, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -12723,12 +12582,12 @@ Object { }, "name": "cov", "range": undefined, - "start": 589, + "start": 581, "trailingComments": undefined, "type": "Identifier", }, "property": Object { - "end": 599, + "end": 591, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -12746,12 +12605,12 @@ Object { }, "name": "static", "range": undefined, - "start": 593, + "start": 585, "trailingComments": undefined, "type": "Identifier", }, "range": undefined, - "start": 589, + "start": 581, "trailingComments": undefined, "type": "MemberExpression", }, @@ -12770,12 +12629,12 @@ Object { }, }, "range": undefined, - "start": 585, + "start": 577, "trailingComments": undefined, "type": "VariableDeclarator", }, ], - "end": 600, + "end": 592, "extra": undefined, "innerComments": undefined, "kind": "var", @@ -12793,7 +12652,7 @@ Object { }, }, "range": undefined, - "start": 581, + "start": 573, "trailingComments": undefined, "type": "VariableDeclaration", }, @@ -12802,14 +12661,14 @@ Object { "consequent": Object { "body": Array [ Object { - "end": 707, + "end": 699, "expression": Object { - "end": 706, + "end": 698, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, "left": Object { - "end": 636, + "end": 628, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -12827,7 +12686,7 @@ Object { }, "name": "c", "range": undefined, - "start": 635, + "start": 627, "trailingComments": undefined, "type": "Identifier", }, @@ -12846,13 +12705,13 @@ Object { "operator": "=", "range": undefined, "right": Object { - "end": 706, + "end": 698, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, "left": Object { "computed": true, - "end": 668, + "end": 660, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -12870,7 +12729,7 @@ Object { }, "object": Object { "computed": false, - "end": 650, + "end": 642, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -12887,7 +12746,7 @@ Object { }, }, "object": Object { - "end": 642, + "end": 634, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -12905,12 +12764,12 @@ Object { }, "name": "cov", "range": undefined, - "start": 639, + "start": 631, "trailingComments": undefined, "type": "Identifier", }, "property": Object { - "end": 650, + "end": 642, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -12928,18 +12787,18 @@ Object { }, "name": "perTest", "range": undefined, - "start": 643, + "start": 635, "trailingComments": undefined, "type": "Identifier", }, "range": undefined, - "start": 639, + "start": 631, "trailingComments": undefined, "type": "MemberExpression", }, "property": Object { "computed": false, - "end": 667, + "end": 659, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -12956,7 +12815,7 @@ Object { }, }, "object": Object { - "end": 653, + "end": 645, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -12974,12 +12833,12 @@ Object { }, "name": "ns", "range": undefined, - "start": 651, + "start": 643, "trailingComments": undefined, "type": "Identifier", }, "property": Object { - "end": 667, + "end": 659, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -12997,17 +12856,17 @@ Object { }, "name": "currentTestId", "range": undefined, - "start": 654, + "start": 646, "trailingComments": undefined, "type": "Identifier", }, "range": undefined, - "start": 651, + "start": 643, "trailingComments": undefined, "type": "MemberExpression", }, "range": undefined, - "start": 639, + "start": 631, "trailingComments": undefined, "type": "MemberExpression", }, @@ -13026,13 +12885,13 @@ Object { "operator": "=", "range": undefined, "right": Object { - "end": 706, + "end": 698, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, "left": Object { "computed": true, - "end": 700, + "end": 692, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -13050,7 +12909,7 @@ Object { }, "object": Object { "computed": false, - "end": 682, + "end": 674, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -13067,7 +12926,7 @@ Object { }, }, "object": Object { - "end": 674, + "end": 666, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -13085,12 +12944,12 @@ Object { }, "name": "cov", "range": undefined, - "start": 671, + "start": 663, "trailingComments": undefined, "type": "Identifier", }, "property": Object { - "end": 682, + "end": 674, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -13108,18 +12967,18 @@ Object { }, "name": "perTest", "range": undefined, - "start": 675, + "start": 667, "trailingComments": undefined, "type": "Identifier", }, "range": undefined, - "start": 671, + "start": 663, "trailingComments": undefined, "type": "MemberExpression", }, "property": Object { "computed": false, - "end": 699, + "end": 691, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -13136,7 +12995,7 @@ Object { }, }, "object": Object { - "end": 685, + "end": 677, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -13154,12 +13013,12 @@ Object { }, "name": "ns", "range": undefined, - "start": 683, + "start": 675, "trailingComments": undefined, "type": "Identifier", }, "property": Object { - "end": 699, + "end": 691, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -13177,17 +13036,17 @@ Object { }, "name": "currentTestId", "range": undefined, - "start": 686, + "start": 678, "trailingComments": undefined, "type": "Identifier", }, "range": undefined, - "start": 683, + "start": 675, "trailingComments": undefined, "type": "MemberExpression", }, "range": undefined, - "start": 671, + "start": 663, "trailingComments": undefined, "type": "MemberExpression", }, @@ -13206,7 +13065,7 @@ Object { "operator": "||", "range": undefined, "right": Object { - "end": 706, + "end": 698, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -13224,19 +13083,19 @@ Object { }, "properties": Array [], "range": undefined, - "start": 704, + "start": 696, "trailingComments": undefined, "type": "ObjectExpression", }, - "start": 671, + "start": 663, "trailingComments": undefined, "type": "LogicalExpression", }, - "start": 639, + "start": 631, "trailingComments": undefined, "type": "AssignmentExpression", }, - "start": 635, + "start": 627, "trailingComments": undefined, "type": "AssignmentExpression", }, @@ -13256,13 +13115,13 @@ Object { }, }, "range": undefined, - "start": 635, + "start": 627, "trailingComments": undefined, "type": "ExpressionStatement", }, ], "directives": Array [], - "end": 713, + "end": 705, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -13279,11 +13138,11 @@ Object { }, }, "range": undefined, - "start": 627, + "start": 619, "trailingComments": undefined, "type": "BlockStatement", }, - "end": 713, + "end": 705, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -13300,10 +13159,10 @@ Object { }, }, "range": undefined, - "start": 605, + "start": 597, "test": Object { "computed": false, - "end": 625, + "end": 617, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -13320,7 +13179,7 @@ Object { }, }, "object": Object { - "end": 611, + "end": 603, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -13338,12 +13197,12 @@ Object { }, "name": "ns", "range": undefined, - "start": 609, + "start": 601, "trailingComments": undefined, "type": "Identifier", }, "property": Object { - "end": 625, + "end": 617, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -13361,12 +13220,12 @@ Object { }, "name": "currentTestId", "range": undefined, - "start": 612, + "start": 604, "trailingComments": undefined, "type": "Identifier", }, "range": undefined, - "start": 609, + "start": 601, "trailingComments": undefined, "type": "MemberExpression", }, @@ -13376,10 +13235,10 @@ Object { Object { "declarations": Array [ Object { - "end": 735, + "end": 727, "extra": undefined, "id": Object { - "end": 723, + "end": 715, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -13397,12 +13256,12 @@ Object { }, "name": "a", "range": undefined, - "start": 722, + "start": 714, "trailingComments": undefined, "type": "Identifier", }, "init": Object { - "end": 735, + "end": 727, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -13420,7 +13279,7 @@ Object { }, "name": "arguments", "range": undefined, - "start": 726, + "start": 718, "trailingComments": undefined, "type": "Identifier", }, @@ -13439,12 +13298,12 @@ Object { }, }, "range": undefined, - "start": 722, + "start": 714, "trailingComments": undefined, "type": "VariableDeclarator", }, ], - "end": 736, + "end": 728, "extra": undefined, "innerComments": undefined, "kind": "var", @@ -13462,7 +13321,7 @@ Object { }, }, "range": undefined, - "start": 718, + "start": 710, "trailingComments": undefined, "type": "VariableDeclaration", }, @@ -13470,15 +13329,15 @@ Object { "body": Object { "body": Array [ Object { - "end": 809, + "end": 801, "expression": Object { - "end": 808, + "end": 800, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, "left": Object { "computed": true, - "end": 787, + "end": 779, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -13495,7 +13354,7 @@ Object { }, }, "object": Object { - "end": 781, + "end": 773, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -13513,13 +13372,13 @@ Object { }, "name": "c", "range": undefined, - "start": 780, + "start": 772, "trailingComments": undefined, "type": "Identifier", }, "property": Object { "computed": true, - "end": 786, + "end": 778, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -13536,7 +13395,7 @@ Object { }, }, "object": Object { - "end": 783, + "end": 775, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -13554,12 +13413,12 @@ Object { }, "name": "a", "range": undefined, - "start": 782, + "start": 774, "trailingComments": undefined, "type": "Identifier", }, "property": Object { - "end": 785, + "end": 777, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -13577,17 +13436,17 @@ Object { }, "name": "i", "range": undefined, - "start": 784, + "start": 776, "trailingComments": undefined, "type": "Identifier", }, "range": undefined, - "start": 782, + "start": 774, "trailingComments": undefined, "type": "MemberExpression", }, "range": undefined, - "start": 780, + "start": 772, "trailingComments": undefined, "type": "MemberExpression", }, @@ -13606,21 +13465,21 @@ Object { "operator": "=", "range": undefined, "right": Object { - "end": 808, + "end": 800, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, "left": Object { - "end": 803, + "end": 795, "extra": Object { - "parenStart": 790, + "parenStart": 782, "parenthesized": true, }, "innerComments": undefined, "leadingComments": undefined, "left": Object { "computed": true, - "end": 798, + "end": 790, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -13637,7 +13496,7 @@ Object { }, }, "object": Object { - "end": 792, + "end": 784, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -13655,13 +13514,13 @@ Object { }, "name": "c", "range": undefined, - "start": 791, + "start": 783, "trailingComments": undefined, "type": "Identifier", }, "property": Object { "computed": true, - "end": 797, + "end": 789, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -13678,7 +13537,7 @@ Object { }, }, "object": Object { - "end": 794, + "end": 786, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -13696,12 +13555,12 @@ Object { }, "name": "a", "range": undefined, - "start": 793, + "start": 785, "trailingComments": undefined, "type": "Identifier", }, "property": Object { - "end": 796, + "end": 788, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -13719,17 +13578,17 @@ Object { }, "name": "i", "range": undefined, - "start": 795, + "start": 787, "trailingComments": undefined, "type": "Identifier", }, "range": undefined, - "start": 793, + "start": 785, "trailingComments": undefined, "type": "MemberExpression", }, "range": undefined, - "start": 791, + "start": 783, "trailingComments": undefined, "type": "MemberExpression", }, @@ -13748,7 +13607,7 @@ Object { "operator": "||", "range": undefined, "right": Object { - "end": 803, + "end": 795, "extra": Object { "raw": "0", "rawValue": 0, @@ -13768,12 +13627,12 @@ Object { }, }, "range": undefined, - "start": 802, + "start": 794, "trailingComments": undefined, "type": "NumericLiteral", "value": 0, }, - "start": 791, + "start": 783, "trailingComments": undefined, "type": "LogicalExpression", }, @@ -13792,7 +13651,7 @@ Object { "operator": "+", "range": undefined, "right": Object { - "end": 808, + "end": 800, "extra": Object { "raw": "1", "rawValue": 1, @@ -13812,16 +13671,16 @@ Object { }, }, "range": undefined, - "start": 807, + "start": 799, "trailingComments": undefined, "type": "NumericLiteral", "value": 1, }, - "start": 790, + "start": 782, "trailingComments": undefined, "type": "BinaryExpression", }, - "start": 780, + "start": 772, "trailingComments": undefined, "type": "AssignmentExpression", }, @@ -13841,13 +13700,13 @@ Object { }, }, "range": undefined, - "start": 780, + "start": 772, "trailingComments": undefined, "type": "ExpressionStatement", }, ], "directives": Array [], - "end": 815, + "end": 807, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -13864,19 +13723,19 @@ Object { }, }, "range": undefined, - "start": 772, + "start": 764, "trailingComments": undefined, "type": "BlockStatement", }, - "end": 815, + "end": 807, "extra": undefined, "init": Object { "declarations": Array [ Object { - "end": 752, + "end": 744, "extra": undefined, "id": Object { - "end": 750, + "end": 742, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -13894,12 +13753,12 @@ Object { }, "name": "i", "range": undefined, - "start": 749, + "start": 741, "trailingComments": undefined, "type": "Identifier", }, "init": Object { - "end": 752, + "end": 744, "extra": Object { "raw": "0", "rawValue": 0, @@ -13919,7 +13778,7 @@ Object { }, }, "range": undefined, - "start": 751, + "start": 743, "trailingComments": undefined, "type": "NumericLiteral", "value": 0, @@ -13939,12 +13798,12 @@ Object { }, }, "range": undefined, - "start": 749, + "start": 741, "trailingComments": undefined, "type": "VariableDeclarator", }, ], - "end": 752, + "end": 744, "extra": undefined, "innerComments": undefined, "kind": "var", @@ -13962,7 +13821,7 @@ Object { }, }, "range": undefined, - "start": 745, + "start": 737, "trailingComments": undefined, "type": "VariableDeclaration", }, @@ -13981,14 +13840,14 @@ Object { }, }, "range": undefined, - "start": 741, + "start": 733, "test": Object { - "end": 766, + "end": 758, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, "left": Object { - "end": 755, + "end": 747, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -14006,7 +13865,7 @@ Object { }, "name": "i", "range": undefined, - "start": 754, + "start": 746, "trailingComments": undefined, "type": "Identifier", }, @@ -14026,7 +13885,7 @@ Object { "range": undefined, "right": Object { "computed": false, - "end": 766, + "end": 758, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -14043,7 +13902,7 @@ Object { }, }, "object": Object { - "end": 759, + "end": 751, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -14061,12 +13920,12 @@ Object { }, "name": "a", "range": undefined, - "start": 758, + "start": 750, "trailingComments": undefined, "type": "Identifier", }, "property": Object { - "end": 766, + "end": 758, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -14084,16 +13943,16 @@ Object { }, "name": "length", "range": undefined, - "start": 760, + "start": 752, "trailingComments": undefined, "type": "Identifier", }, "range": undefined, - "start": 758, + "start": 750, "trailingComments": undefined, "type": "MemberExpression", }, - "start": 754, + "start": 746, "trailingComments": undefined, "type": "BinaryExpression", }, @@ -14101,7 +13960,7 @@ Object { "type": "ForStatement", "update": Object { "argument": Object { - "end": 769, + "end": 761, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -14119,11 +13978,11 @@ Object { }, "name": "i", "range": undefined, - "start": 768, + "start": 760, "trailingComments": undefined, "type": "Identifier", }, - "end": 771, + "end": 763, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -14142,14 +14001,14 @@ Object { "operator": "++", "prefix": false, "range": undefined, - "start": 768, + "start": 760, "trailingComments": undefined, "type": "UpdateExpression", }, }, ], "directives": Array [], - "end": 819, + "end": 811, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -14166,15 +14025,15 @@ Object { }, }, "range": undefined, - "start": 575, + "start": 567, "trailingComments": undefined, "type": "BlockStatement", }, - "end": 819, + "end": 811, "extra": undefined, "generator": false, "id": Object { - "end": 572, + "end": 564, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -14192,7 +14051,7 @@ Object { }, "name": "cover", "range": undefined, - "start": 567, + "start": 559, "trailingComments": undefined, "type": "Identifier", }, @@ -14212,19 +14071,19 @@ Object { }, "params": Array [], "range": undefined, - "start": 558, + "start": 550, "trailingComments": undefined, "type": "FunctionDeclaration", }, Object { - "end": 844, + "end": 836, "expression": Object { - "end": 843, + "end": 835, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, "left": Object { - "end": 835, + "end": 827, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -14242,7 +14101,7 @@ Object { }, "name": "stryCov_9fa48", "range": undefined, - "start": 822, + "start": 814, "trailingComments": undefined, "type": "Identifier", }, @@ -14261,7 +14120,7 @@ Object { "operator": "=", "range": undefined, "right": Object { - "end": 843, + "end": 835, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -14279,11 +14138,11 @@ Object { }, "name": "cover", "range": undefined, - "start": 838, + "start": 830, "trailingComments": undefined, "type": "Identifier", }, - "start": 822, + "start": 814, "trailingComments": undefined, "type": "AssignmentExpression", }, @@ -14303,16 +14162,16 @@ Object { }, }, "range": undefined, - "start": 822, + "start": 814, "trailingComments": undefined, "type": "ExpressionStatement", }, Object { - "end": 876, + "end": 868, "expression": Object { "arguments": Array [ Object { - "end": 863, + "end": 855, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -14329,12 +14188,12 @@ Object { }, }, "range": undefined, - "start": 859, + "start": 851, "trailingComments": undefined, "type": "NullLiteral", }, Object { - "end": 874, + "end": 866, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -14352,14 +14211,14 @@ Object { }, "name": "arguments", "range": undefined, - "start": 865, + "start": 857, "trailingComments": undefined, "type": "Identifier", }, ], "callee": Object { "computed": false, - "end": 858, + "end": 850, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -14376,7 +14235,7 @@ Object { }, }, "object": Object { - "end": 852, + "end": 844, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -14394,12 +14253,12 @@ Object { }, "name": "cover", "range": undefined, - "start": 847, + "start": 839, "trailingComments": undefined, "type": "Identifier", }, "property": Object { - "end": 858, + "end": 850, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -14417,16 +14276,16 @@ Object { }, "name": "apply", "range": undefined, - "start": 853, + "start": 845, "trailingComments": undefined, "type": "Identifier", }, "range": undefined, - "start": 847, + "start": 839, "trailingComments": undefined, "type": "MemberExpression", }, - "end": 875, + "end": 867, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -14443,7 +14302,7 @@ Object { }, }, "range": undefined, - "start": 847, + "start": 839, "trailingComments": undefined, "type": "CallExpression", }, @@ -14463,13 +14322,13 @@ Object { }, }, "range": undefined, - "start": 847, + "start": 839, "trailingComments": undefined, "type": "ExpressionStatement", }, ], "directives": Array [], - "end": 878, + "end": 870, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -14486,15 +14345,15 @@ Object { }, }, "range": undefined, - "start": 443, + "start": 435, "trailingComments": undefined, "type": "BlockStatement", }, - "end": 878, + "end": 870, "extra": undefined, "generator": false, "id": Object { - "end": 440, + "end": 432, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -14512,7 +14371,7 @@ Object { }, "name": "stryCov_9fa48", "range": undefined, - "start": 427, + "start": 419, "trailingComments": undefined, "type": "Identifier", }, @@ -14532,7 +14391,7 @@ Object { }, "params": Array [], "range": undefined, - "start": 418, + "start": 410, "trailingComments": undefined, "type": "FunctionDeclaration", }, @@ -14543,10 +14402,10 @@ Object { Object { "declarations": Array [ Object { - "end": 936, + "end": 928, "extra": undefined, "id": Object { - "end": 919, + "end": 911, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -14564,14 +14423,14 @@ Object { }, "name": "ns", "range": undefined, - "start": 917, + "start": 909, "trailingComments": undefined, "type": "Identifier", }, "init": Object { "arguments": Array [], "callee": Object { - "end": 934, + "end": 926, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -14589,11 +14448,11 @@ Object { }, "name": "stryNS_9fa48", "range": undefined, - "start": 922, + "start": 914, "trailingComments": undefined, "type": "Identifier", }, - "end": 936, + "end": 928, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -14610,7 +14469,7 @@ Object { }, }, "range": undefined, - "start": 922, + "start": 914, "trailingComments": undefined, "type": "CallExpression", }, @@ -14629,12 +14488,12 @@ Object { }, }, "range": undefined, - "start": 917, + "start": 909, "trailingComments": undefined, "type": "VariableDeclarator", }, ], - "end": 937, + "end": 929, "extra": undefined, "innerComments": undefined, "kind": "var", @@ -14652,7 +14511,7 @@ Object { }, }, "range": undefined, - "start": 913, + "start": 905, "trailingComments": undefined, "type": "VariableDeclaration", }, @@ -14662,13 +14521,13 @@ Object { "body": Array [ Object { "argument": Object { - "end": 997, + "end": 989, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, "left": Object { "computed": false, - "end": 990, + "end": 982, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -14685,7 +14544,7 @@ Object { }, }, "object": Object { - "end": 977, + "end": 969, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -14703,12 +14562,12 @@ Object { }, "name": "ns", "range": undefined, - "start": 975, + "start": 967, "trailingComments": undefined, "type": "Identifier", }, "property": Object { - "end": 990, + "end": 982, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -14726,12 +14585,12 @@ Object { }, "name": "activeMutant", "range": undefined, - "start": 978, + "start": 970, "trailingComments": undefined, "type": "Identifier", }, "range": undefined, - "start": 975, + "start": 967, "trailingComments": undefined, "type": "MemberExpression", }, @@ -14750,7 +14609,7 @@ Object { "operator": "===", "range": undefined, "right": Object { - "end": 997, + "end": 989, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -14768,15 +14627,15 @@ Object { }, "name": "id", "range": undefined, - "start": 995, + "start": 987, "trailingComments": undefined, "type": "Identifier", }, - "start": 975, + "start": 967, "trailingComments": undefined, "type": "BinaryExpression", }, - "end": 998, + "end": 990, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -14793,13 +14652,13 @@ Object { }, }, "range": undefined, - "start": 968, + "start": 960, "trailingComments": undefined, "type": "ReturnStatement", }, ], "directives": Array [], - "end": 1002, + "end": 994, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -14816,15 +14675,15 @@ Object { }, }, "range": undefined, - "start": 962, + "start": 954, "trailingComments": undefined, "type": "BlockStatement", }, - "end": 1002, + "end": 994, "extra": undefined, "generator": false, "id": Object { - "end": 957, + "end": 949, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -14842,7 +14701,7 @@ Object { }, "name": "isActive", "range": undefined, - "start": 949, + "start": 941, "trailingComments": undefined, "type": "Identifier", }, @@ -14862,7 +14721,7 @@ Object { }, "params": Array [ Object { - "end": 960, + "end": 952, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -14880,25 +14739,25 @@ Object { }, "name": "id", "range": undefined, - "start": 958, + "start": 950, "trailingComments": undefined, "type": "Identifier", }, ], "range": undefined, - "start": 940, + "start": 932, "trailingComments": undefined, "type": "FunctionDeclaration", }, Object { - "end": 1033, + "end": 1025, "expression": Object { - "end": 1032, + "end": 1024, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, "left": Object { - "end": 1021, + "end": 1013, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -14916,7 +14775,7 @@ Object { }, "name": "stryMutAct_9fa48", "range": undefined, - "start": 1005, + "start": 997, "trailingComments": undefined, "type": "Identifier", }, @@ -14935,7 +14794,7 @@ Object { "operator": "=", "range": undefined, "right": Object { - "end": 1032, + "end": 1024, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -14953,11 +14812,11 @@ Object { }, "name": "isActive", "range": undefined, - "start": 1024, + "start": 1016, "trailingComments": undefined, "type": "Identifier", }, - "start": 1005, + "start": 997, "trailingComments": undefined, "type": "AssignmentExpression", }, @@ -14977,7 +14836,7 @@ Object { }, }, "range": undefined, - "start": 1005, + "start": 997, "trailingComments": undefined, "type": "ExpressionStatement", }, @@ -14985,7 +14844,7 @@ Object { "argument": Object { "arguments": Array [ Object { - "end": 1054, + "end": 1046, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -15003,13 +14862,13 @@ Object { }, "name": "id", "range": undefined, - "start": 1052, + "start": 1044, "trailingComments": undefined, "type": "Identifier", }, ], "callee": Object { - "end": 1051, + "end": 1043, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -15027,11 +14886,11 @@ Object { }, "name": "isActive", "range": undefined, - "start": 1043, + "start": 1035, "trailingComments": undefined, "type": "Identifier", }, - "end": 1055, + "end": 1047, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -15048,11 +14907,11 @@ Object { }, }, "range": undefined, - "start": 1043, + "start": 1035, "trailingComments": undefined, "type": "CallExpression", }, - "end": 1056, + "end": 1048, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -15069,13 +14928,13 @@ Object { }, }, "range": undefined, - "start": 1036, + "start": 1028, "trailingComments": undefined, "type": "ReturnStatement", }, ], "directives": Array [], - "end": 1058, + "end": 1050, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -15092,15 +14951,15 @@ Object { }, }, "range": undefined, - "start": 909, + "start": 901, "trailingComments": undefined, "type": "BlockStatement", }, - "end": 1058, + "end": 1050, "extra": undefined, "generator": false, "id": Object { - "end": 904, + "end": 896, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -15118,7 +14977,7 @@ Object { }, "name": "stryMutAct_9fa48", "range": undefined, - "start": 888, + "start": 880, "trailingComments": undefined, "type": "Identifier", }, @@ -15138,7 +14997,7 @@ Object { }, "params": Array [ Object { - "end": 907, + "end": 899, "extra": undefined, "innerComments": undefined, "leadingComments": undefined, @@ -15156,13 +15015,13 @@ Object { }, "name": "id", "range": undefined, - "start": 905, + "start": 897, "trailingComments": undefined, "type": "Identifier", }, ], "range": undefined, - "start": 879, + "start": 871, "trailingComments": undefined, "type": "FunctionDeclaration", }, @@ -15200,8 +15059,8 @@ Object { Object { "arguments": Array [ Object { - "type": "NumericLiteral", - "value": 0, + "type": "StringLiteral", + "value": "0", }, ], "callee": Object { @@ -15370,8 +15229,8 @@ Object { "test": Object { "arguments": Array [ Object { - "type": "NumericLiteral", - "value": 0, + "type": "StringLiteral", + "value": "0", }, ], "callee": Object { diff --git a/packages/instrumenter/test/unit/mutant-placers/expression-mutant-placer.spec.ts b/packages/instrumenter/test/unit/mutant-placers/expression-mutant-placer.spec.ts index 3322f445f3..57e08c9b67 100644 --- a/packages/instrumenter/test/unit/mutant-placers/expression-mutant-placer.spec.ts +++ b/packages/instrumenter/test/unit/mutant-placers/expression-mutant-placer.spec.ts @@ -22,7 +22,7 @@ describe(expressionMutantPlacer.name, () => { function arrangeSingleMutant() { const ast = parseJS('const foo = a + b'); const binaryExpression = findNodePath(ast, (p) => p.isBinaryExpression()); - const mutant = new Mutant(1, 'file.js', { + const mutant = new Mutant('1', 'file.js', { original: binaryExpression.node, replacement: types.binaryExpression('>>>', types.identifier('bar'), types.identifier('baz')), mutatorName: 'fooMutator', @@ -40,7 +40,7 @@ describe(expressionMutantPlacer.name, () => { // Assert expect(actual).true; - expect(actualCode).contains('const foo = stryMutAct_9fa48(1) ? bar >>> baz'); + expect(actualCode).contains('const foo = stryMutAct_9fa48("1") ? bar >>> baz'); }); it('should place the original code as the alternative', () => { @@ -56,7 +56,7 @@ describe(expressionMutantPlacer.name, () => { expressionMutantPlacer(binaryExpression, [mutant]); const actualAlternative = findNodePath(ast, (p) => p.isConditionalExpression()).node.alternate; const actualAlternativeCode = generate(actualAlternative).code; - const expected = 'stryCov_9fa48(1), a + b'; + const expected = 'stryCov_9fa48("1"), a + b'; expect(actualAlternativeCode.startsWith(expected), `${actualAlternativeCode} did not start with "${expected}"`).true; }); @@ -66,12 +66,12 @@ describe(expressionMutantPlacer.name, () => { const binaryExpression = findNodePath(ast, (p) => p.isBinaryExpression()); const mutants = [ createMutant({ - id: 52, + id: '52', original: binaryExpression.node, replacement: types.binaryExpression('-', types.identifier('bar'), types.identifier('baz')), }), createMutant({ - id: 659, + id: '659', original: binaryExpression.node, replacement: types.identifier('bar'), }), @@ -82,7 +82,7 @@ describe(expressionMutantPlacer.name, () => { const actualCode = normalizeWhitespaces(generate(ast).code); // Assert - expect(actualCode).contains('const foo = stryMutAct_9fa48(659) ? bar : stryMutAct_9fa48(52) ? bar - baz'); + expect(actualCode).contains('const foo = stryMutAct_9fa48("659") ? bar : stryMutAct_9fa48("52") ? bar - baz'); }); describe('object literals', () => { @@ -107,7 +107,7 @@ describe(expressionMutantPlacer.name, () => { function arrangeActAssert(ast: types.File, expression: NodePath, expectedMatch: RegExp) { const mutants = [ createMutant({ - id: 4, + id: '4', original: expression.node, replacement: types.identifier('bar'), }), diff --git a/packages/instrumenter/test/unit/mutant-placers/statement-mutant-placer.spec.ts b/packages/instrumenter/test/unit/mutant-placers/statement-mutant-placer.spec.ts index af90c1b02c..b434abc9e6 100644 --- a/packages/instrumenter/test/unit/mutant-placers/statement-mutant-placer.spec.ts +++ b/packages/instrumenter/test/unit/mutant-placers/statement-mutant-placer.spec.ts @@ -27,7 +27,7 @@ describe(statementMutantPlacer.name, () => { const ast = parseJS('const foo = a + b'); const statement = findNodePath(ast, (p) => p.isVariableDeclaration()); const nodeToMutate = findNodePath(ast, (p) => p.isBinaryExpression()); - const mutant = new Mutant(1, 'file.js', { + const mutant = new Mutant('1', 'file.js', { original: nodeToMutate.node, replacement: types.binaryExpression('>>>', types.identifier('bar'), types.identifier('baz')), mutatorName: 'fooMutator', @@ -45,7 +45,7 @@ describe(statementMutantPlacer.name, () => { // Assert expect(actual).true; - expect(actualCode).contains(normalizeWhitespaces('if (stryMutAct_9fa48(1)) { const foo = bar >>> baz; } else ')); + expect(actualCode).contains(normalizeWhitespaces('if (stryMutAct_9fa48("1")) { const foo = bar >>> baz; } else ')); }); it('should keep block statements in tact', () => { @@ -78,7 +78,7 @@ describe(statementMutantPlacer.name, () => { const { ast, mutant, statement } = arrangeSingleMutant(); statementMutantPlacer(statement, [mutant]); const actualCode = normalizeWhitespaces(generate(ast).code); - expect(actualCode).matches(/else\s*{\s*stryCov_9fa48\(1\)/); + expect(actualCode).matches(/else\s*{\s*stryCov_9fa48\("1"\)/); }); it('should be able to place multiple mutants', () => { @@ -88,12 +88,12 @@ describe(statementMutantPlacer.name, () => { const binaryExpression = findNodePath(ast, (p) => p.isBinaryExpression()); const fooIdentifier = findNodePath(ast, (p) => p.isIdentifier()); const mutants = [ - new Mutant(52, 'file.js', { + new Mutant('52', 'file.js', { original: binaryExpression.node, replacement: types.binaryExpression('>>>', types.identifier('bar'), types.identifier('baz')), mutatorName: 'fooMutator', }), - new Mutant(659, 'file.js', { + new Mutant('659', 'file.js', { original: fooIdentifier.node, replacement: types.identifier('bar'), mutatorName: 'fooMutator', @@ -106,12 +106,12 @@ describe(statementMutantPlacer.name, () => { // Assert expect(actualCode).contains( - normalizeWhitespaces(`if (stryMutAct_9fa48(659)) { + normalizeWhitespaces(`if (stryMutAct_9fa48("659")) { const bar = a + b; - } else if (stryMutAct_9fa48(52)) { + } else if (stryMutAct_9fa48("52")) { const foo = bar >>> baz; } else { - stryCov_9fa48(52, 659)`) + stryCov_9fa48("52", "659")`) ); }); }); diff --git a/packages/instrumenter/test/unit/mutant-placers/switch-case-mutant-placer.spec.ts b/packages/instrumenter/test/unit/mutant-placers/switch-case-mutant-placer.spec.ts index 013d88ef60..0407c5e852 100644 --- a/packages/instrumenter/test/unit/mutant-placers/switch-case-mutant-placer.spec.ts +++ b/packages/instrumenter/test/unit/mutant-placers/switch-case-mutant-placer.spec.ts @@ -38,7 +38,7 @@ describe(sut.name, () => { it('should place a mutant in the "consequent" part of a switch-case', () => { // Arrange - const mutant = createMutant({ id: 42, original: switchCase.node, replacement: types.switchCase(types.stringLiteral('bar'), []) }); + const mutant = createMutant({ id: '42', original: switchCase.node, replacement: types.switchCase(types.stringLiteral('bar'), []) }); // Act const actual = sut(switchCase, [mutant]); @@ -46,12 +46,12 @@ describe(sut.name, () => { // Assert expect(actual).true; - expect(actualCode).contains(normalizeWhitespaces('switch (foo) { case "bar": if (stryMutAct_9fa48(42))')); + expect(actualCode).contains(normalizeWhitespaces('switch (foo) { case "bar": if (stryMutAct_9fa48("42"))')); }); it('should place the original code as alternative (inside `else`)', () => { // Arrange - const mutant = createMutant({ id: 42, original: switchCase.node, replacement: types.switchCase(types.stringLiteral('bar'), []) }); + const mutant = createMutant({ id: '42', original: switchCase.node, replacement: types.switchCase(types.stringLiteral('bar'), []) }); // Act const actual = sut(switchCase, [mutant]); @@ -64,7 +64,7 @@ describe(sut.name, () => { it('should add mutant coverage syntax', () => { // Arrange - const mutant = createMutant({ id: 42, original: switchCase.node, replacement: types.switchCase(types.stringLiteral('bar'), []) }); + const mutant = createMutant({ id: '42', original: switchCase.node, replacement: types.switchCase(types.stringLiteral('bar'), []) }); // Act const actual = sut(switchCase, [mutant]); @@ -72,15 +72,15 @@ describe(sut.name, () => { // Assert expect(actual).true; - expect(actualCode).matches(/else\s*{\s*stryCov_9fa48\(42\)/); + expect(actualCode).matches(/else\s*{\s*stryCov_9fa48\("42"\)/); }); it('should be able to place multiple mutants', () => { // Arrange const mutants = [ - createMutant({ id: 42, original: switchCase.node, replacement: types.switchCase(types.stringLiteral('bar'), []) }), + createMutant({ id: '42', original: switchCase.node, replacement: types.switchCase(types.stringLiteral('bar'), []) }), createMutant({ - id: 156, + id: '156', original: switchCase.node, replacement: types.switchCase(types.stringLiteral('bar'), [types.expressionStatement(types.callExpression(types.identifier('foo'), []))]), }), @@ -92,11 +92,11 @@ describe(sut.name, () => { // Assert expect(actualCode).contains( - normalizeWhitespaces(`if (stryMutAct_9fa48(156)) { + normalizeWhitespaces(`if (stryMutAct_9fa48("156")) { foo(); - } else if (stryMutAct_9fa48(42)) {} + } else if (stryMutAct_9fa48("42")) {} else { - stryCov_9fa48(42, 156)`) + stryCov_9fa48("42", "156")`) ); }); }); diff --git a/packages/instrumenter/test/unit/mutant.spec.ts b/packages/instrumenter/test/unit/mutant.spec.ts index 0d48d7da27..f60bf26862 100644 --- a/packages/instrumenter/test/unit/mutant.spec.ts +++ b/packages/instrumenter/test/unit/mutant.spec.ts @@ -1,6 +1,6 @@ import { types } from '@babel/core'; -import { Mutant as MutantApi } from '@stryker-mutator/api/core'; +import { Mutant as MutantApi, MutantStatus } from '@stryker-mutator/api/core'; import { expect } from 'chai'; @@ -15,7 +15,7 @@ describe(Mutant.name, () => { // Arrange const original = types.binaryExpression('+', types.numericLiteral(40), types.numericLiteral(2)); const replacement = types.binaryExpression('-', types.numericLiteral(40), types.numericLiteral(2)); - const mutant = new Mutant(2, 'file.js', { original, replacement, mutatorName: 'fooMutator' }); + const mutant = new Mutant('2', 'file.js', { original, replacement, mutatorName: 'fooMutator' }); // Act replacement.operator = '%'; @@ -26,8 +26,8 @@ describe(Mutant.name, () => { }); describe(Mutant.prototype.toApiMutant.name, () => { - it('should map all properties as expected', () => { - const mutant = new Mutant(2, 'file.js', { + it('should map all properties as expected for an ignored mutant', () => { + const mutant = new Mutant('2', 'file.js', { original: types.stringLiteral(''), replacement: types.stringLiteral('Stryker was here!'), mutatorName: 'fooMutator', @@ -36,10 +36,29 @@ describe(Mutant.name, () => { mutant.original.loc = { start: { column: 0, line: 0 }, end: { column: 0, line: 0 } }; const expected: Partial = { fileName: 'file.js', - id: 2, + id: '2', mutatorName: 'fooMutator', replacement: '"Stryker was here!"', - ignoreReason: 'ignore', + statusReason: 'ignore', + status: MutantStatus.Ignored, + }; + expect(mutant.toApiMutant()).deep.include(expected); + }); + + it('should map all properties as expected for a placed mutant', () => { + const mutant = new Mutant('2', 'file.js', { + original: types.stringLiteral(''), + replacement: types.stringLiteral('Stryker was here!'), + mutatorName: 'fooMutator', + }); + mutant.original.loc = { start: { column: 0, line: 0 }, end: { column: 0, line: 0 } }; + const expected: Partial = { + fileName: 'file.js', + id: '2', + mutatorName: 'fooMutator', + replacement: '"Stryker was here!"', + statusReason: undefined, + status: undefined, }; expect(mutant.toApiMutant()).deep.include(expected); }); @@ -48,7 +67,7 @@ describe(Mutant.name, () => { // Arrange const lt = findNodePath(parseJS('if(a < b) { console.log("hello world"); }'), (p) => p.isBinaryExpression()).node; const lte = types.binaryExpression('<=', lt.left, lt.right); - const mutant = new Mutant(1, 'bar.js', { original: lt, replacement: lte, mutatorName: 'barMutator' }, 42, 4); + const mutant = new Mutant('1', 'bar.js', { original: lt, replacement: lte, mutatorName: 'barMutator' }, 42, 4); // Act const actual = mutant.toApiMutant(); diff --git a/packages/instrumenter/test/unit/transformers/mutant-collector.spec.ts b/packages/instrumenter/test/unit/transformers/mutant-collector.spec.ts index cfa7a293b0..52c211a1e8 100644 --- a/packages/instrumenter/test/unit/transformers/mutant-collector.spec.ts +++ b/packages/instrumenter/test/unit/transformers/mutant-collector.spec.ts @@ -24,7 +24,7 @@ describe(MutantCollector.name, () => { expect(sut.mutants).deep.eq([ createMutant({ fileName, - id: 0, + id: '0', original, replacement, }), @@ -41,7 +41,7 @@ describe(MutantCollector.name, () => { expect(sut.mutants[1]).deep.eq( createMutant({ fileName, - id: 1, + id: '1', original, replacement, }) diff --git a/packages/instrumenter/testResources/instrumenter/app.component.ts.out.snap b/packages/instrumenter/testResources/instrumenter/app.component.ts.out.snap index dd3e7e79b5..a8a716b134 100644 --- a/packages/instrumenter/testResources/instrumenter/app.component.ts.out.snap +++ b/packages/instrumenter/testResources/instrumenter/app.component.ts.out.snap @@ -6,7 +6,7 @@ exports[`instrumenter integration should be able to instrument an angular compon var ns = g.__stryker__ || (g.__stryker__ = {}); if (ns.activeMutant === undefined && g.process && g.process.env && g.process.env.__STRYKER_ACTIVE_MUTANT__) { - ns.activeMutant = Number(g.process.env.__STRYKER_ACTIVE_MUTANT__); + ns.activeMutant = g.process.env.__STRYKER_ACTIVE_MUTANT__; } function retrieveNS() { @@ -62,6 +62,6 @@ import { Component } from '@angular/core'; styleUrls: ['./app.component.scss'] }) export class AppComponent { - title = stryMutAct_9fa48(0) ? \\"\\" : (stryCov_9fa48(0), 'angular-app'); + title = stryMutAct_9fa48(\\"0\\") ? \\"\\" : (stryCov_9fa48(\\"0\\"), 'angular-app'); }" `; diff --git a/packages/instrumenter/testResources/instrumenter/html-sample.html.out.snap b/packages/instrumenter/testResources/instrumenter/html-sample.html.out.snap index 6b663eb18b..8cbb80f078 100644 --- a/packages/instrumenter/testResources/instrumenter/html-sample.html.out.snap +++ b/packages/instrumenter/testResources/instrumenter/html-sample.html.out.snap @@ -17,7 +17,7 @@ function stryNS_9fa48() { var ns = g.__stryker__ || (g.__stryker__ = {}); if (ns.activeMutant === undefined && g.process && g.process.env && g.process.env.__STRYKER_ACTIVE_MUTANT__) { - ns.activeMutant = Number(g.process.env.__STRYKER_ACTIVE_MUTANT__); + ns.activeMutant = g.process.env.__STRYKER_ACTIVE_MUTANT__; } function retrieveNS() { @@ -67,11 +67,11 @@ function stryMutAct_9fa48(id) { } function add(a, b) { - if (stryMutAct_9fa48(0)) { + if (stryMutAct_9fa48(\\"0\\")) { {} } else { - stryCov_9fa48(0); - return stryMutAct_9fa48(1) ? a - b : (stryCov_9fa48(1), a + b); + stryCov_9fa48(\\"0\\"); + return stryMutAct_9fa48(\\"1\\") ? a - b : (stryCov_9fa48(\\"1\\"), a + b); } } diff --git a/packages/instrumenter/testResources/instrumenter/ignore.js.out.snap b/packages/instrumenter/testResources/instrumenter/ignore.js.out.snap index b060f79dfe..3f72e94779 100644 --- a/packages/instrumenter/testResources/instrumenter/ignore.js.out.snap +++ b/packages/instrumenter/testResources/instrumenter/ignore.js.out.snap @@ -6,7 +6,7 @@ exports[`instrumenter integration should not place ignored mutants 1`] = ` var ns = g.__stryker__ || (g.__stryker__ = {}); if (ns.activeMutant === undefined && g.process && g.process.env && g.process.env.__STRYKER_ACTIVE_MUTANT__) { - ns.activeMutant = Number(g.process.env.__STRYKER_ACTIVE_MUTANT__); + ns.activeMutant = g.process.env.__STRYKER_ACTIVE_MUTANT__; } function retrieveNS() { @@ -56,10 +56,10 @@ function stryMutAct_9fa48(id) { } function add(a, b) { - if (stryMutAct_9fa48(0)) { + if (stryMutAct_9fa48(\\"0\\")) { {} } else { - stryCov_9fa48(0); + stryCov_9fa48(\\"0\\"); return a + b; } }" diff --git a/packages/instrumenter/testResources/instrumenter/js-sample.js.out.snap b/packages/instrumenter/testResources/instrumenter/js-sample.js.out.snap index 3e464ff6ac..92c0a0f4af 100644 --- a/packages/instrumenter/testResources/instrumenter/js-sample.js.out.snap +++ b/packages/instrumenter/testResources/instrumenter/js-sample.js.out.snap @@ -6,7 +6,7 @@ exports[`instrumenter integration should be able to instrument a simple js file var ns = g.__stryker__ || (g.__stryker__ = {}); if (ns.activeMutant === undefined && g.process && g.process.env && g.process.env.__STRYKER_ACTIVE_MUTANT__) { - ns.activeMutant = Number(g.process.env.__STRYKER_ACTIVE_MUTANT__); + ns.activeMutant = g.process.env.__STRYKER_ACTIVE_MUTANT__; } function retrieveNS() { @@ -56,11 +56,11 @@ function stryMutAct_9fa48(id) { } function add(a, b) { - if (stryMutAct_9fa48(0)) { + if (stryMutAct_9fa48(\\"0\\")) { {} } else { - stryCov_9fa48(0); - return stryMutAct_9fa48(1) ? a - b : (stryCov_9fa48(1), a + b); + stryCov_9fa48(\\"0\\"); + return stryMutAct_9fa48(\\"1\\") ? a - b : (stryCov_9fa48(\\"1\\"), a + b); } } diff --git a/packages/instrumenter/testResources/instrumenter/lit-html-sample.ts.out.snap b/packages/instrumenter/testResources/instrumenter/lit-html-sample.ts.out.snap index cee223251a..e64a1310e3 100644 --- a/packages/instrumenter/testResources/instrumenter/lit-html-sample.ts.out.snap +++ b/packages/instrumenter/testResources/instrumenter/lit-html-sample.ts.out.snap @@ -6,7 +6,7 @@ exports[`instrumenter integration should be able to instrument a lit-html file 1 var ns = g.__stryker__ || (g.__stryker__ = {}); if (ns.activeMutant === undefined && g.process && g.process.env && g.process.env.__STRYKER_ACTIVE_MUTANT__) { - ns.activeMutant = Number(g.process.env.__STRYKER_ACTIVE_MUTANT__); + ns.activeMutant = g.process.env.__STRYKER_ACTIVE_MUTANT__; } function retrieveNS() { @@ -67,32 +67,32 @@ export class MutationTestReportTotalsComponent extends LitElement { @property() public thresholds: Thresholds | undefined; @property() - public currentPath: string[] = stryMutAct_9fa48(0) ? [\\"Stryker was here\\"] : (stryCov_9fa48(0), []); - private readonly fileIcon = stryMutAct_9fa48(1) ? svg\`\` : (stryCov_9fa48(1), svg\`\`); - private readonly directoryIcon = stryMutAct_9fa48(2) ? svg\`\` : (stryCov_9fa48(2), svg\`\`); + public currentPath: string[] = stryMutAct_9fa48(\\"0\\") ? [\\"Stryker was here\\"] : (stryCov_9fa48(\\"0\\"), []); + private readonly fileIcon = stryMutAct_9fa48(\\"1\\") ? svg\`\` : (stryCov_9fa48(\\"1\\"), svg\`\`); + private readonly directoryIcon = stryMutAct_9fa48(\\"2\\") ? svg\`\` : (stryCov_9fa48(\\"2\\"), svg\`\`); public render() { - if (stryMutAct_9fa48(3)) { + if (stryMutAct_9fa48(\\"3\\")) { {} } else { - stryCov_9fa48(3); + stryCov_9fa48(\\"3\\"); - if (stryMutAct_9fa48(5) ? false : stryMutAct_9fa48(4) ? true : (stryCov_9fa48(4, 5), this.model)) { - if (stryMutAct_9fa48(6)) { + if (stryMutAct_9fa48(\\"5\\") ? false : stryMutAct_9fa48(\\"4\\") ? true : (stryCov_9fa48(\\"4\\", \\"5\\"), this.model)) { + if (stryMutAct_9fa48(\\"6\\")) { {} } else { - stryCov_9fa48(6); - return stryMutAct_9fa48(7) ? html\`\` : (stryCov_9fa48(7), html\` + stryCov_9fa48(\\"6\\"); + return stryMutAct_9fa48(\\"7\\") ? html\`\` : (stryCov_9fa48(\\"7\\"), html\` \${this.renderHead()} \${this.renderTableBody(this.model)}
\`); } } else { - if (stryMutAct_9fa48(8)) { + if (stryMutAct_9fa48(\\"8\\")) { {} } else { - stryCov_9fa48(8); + stryCov_9fa48(\\"8\\"); return undefined; } } @@ -100,11 +100,11 @@ export class MutationTestReportTotalsComponent extends LitElement { } private renderHead() { - if (stryMutAct_9fa48(9)) { + if (stryMutAct_9fa48(\\"9\\")) { {} } else { - stryCov_9fa48(9); - return stryMutAct_9fa48(10) ? html\`\` : (stryCov_9fa48(10), html\` + stryCov_9fa48(\\"9\\"); + return stryMutAct_9fa48(\\"10\\") ? html\`\` : (stryCov_9fa48(\\"10\\"), html\`
File / Directory
@@ -148,41 +148,41 @@ export class MutationTestReportTotalsComponent extends LitElement { } private renderTableBody(model: MetricsResult) { - if (stryMutAct_9fa48(11)) { + if (stryMutAct_9fa48(\\"11\\")) { {} } else { - stryCov_9fa48(11); + stryCov_9fa48(\\"11\\"); const renderChildren = () => { - if (stryMutAct_9fa48(12)) { + if (stryMutAct_9fa48(\\"12\\")) { {} } else { - stryCov_9fa48(12); + stryCov_9fa48(\\"12\\"); - if (stryMutAct_9fa48(14) ? false : stryMutAct_9fa48(13) ? true : (stryCov_9fa48(13, 14), model.file)) { - if (stryMutAct_9fa48(15)) { + if (stryMutAct_9fa48(\\"14\\") ? false : stryMutAct_9fa48(\\"13\\") ? true : (stryCov_9fa48(\\"13\\", \\"14\\"), model.file)) { + if (stryMutAct_9fa48(\\"15\\")) { {} } else { - stryCov_9fa48(15); + stryCov_9fa48(\\"15\\"); return undefined; } } else { - if (stryMutAct_9fa48(16)) { + if (stryMutAct_9fa48(\\"16\\")) { {} } else { - stryCov_9fa48(16); + stryCov_9fa48(\\"16\\"); return model.childResults.map(childResult => { - if (stryMutAct_9fa48(17)) { + if (stryMutAct_9fa48(\\"17\\")) { {} } else { - stryCov_9fa48(17); + stryCov_9fa48(\\"17\\"); let fullName: string = childResult.name; - while (stryMutAct_9fa48(19) ? !childResult.file || childResult.childResults.length === 1 : stryMutAct_9fa48(18) ? false : (stryCov_9fa48(18, 19), (stryMutAct_9fa48(20) ? childResult.file : (stryCov_9fa48(20), !childResult.file)) && (stryMutAct_9fa48(23) ? childResult.childResults.length !== 1 : stryMutAct_9fa48(22) ? false : stryMutAct_9fa48(21) ? true : (stryCov_9fa48(21, 22, 23), childResult.childResults.length === 1)))) { - if (stryMutAct_9fa48(24)) { + while (stryMutAct_9fa48(\\"19\\") ? !childResult.file || childResult.childResults.length === 1 : stryMutAct_9fa48(\\"18\\") ? false : (stryCov_9fa48(\\"18\\", \\"19\\"), (stryMutAct_9fa48(\\"20\\") ? childResult.file : (stryCov_9fa48(\\"20\\"), !childResult.file)) && (stryMutAct_9fa48(\\"23\\") ? childResult.childResults.length !== 1 : stryMutAct_9fa48(\\"22\\") ? false : stryMutAct_9fa48(\\"21\\") ? true : (stryCov_9fa48(\\"21\\", \\"22\\", \\"23\\"), childResult.childResults.length === 1)))) { + if (stryMutAct_9fa48(\\"24\\")) { {} } else { - stryCov_9fa48(24); + stryCov_9fa48(\\"24\\"); childResult = childResult.childResults[0]; fullName = pathJoin(fullName, childResult.name); } @@ -196,7 +196,7 @@ export class MutationTestReportTotalsComponent extends LitElement { } }; - return stryMutAct_9fa48(25) ? html\`\` : (stryCov_9fa48(25), html\` + return stryMutAct_9fa48(\\"25\\") ? html\`\` : (stryCov_9fa48(\\"25\\"), html\` \${this.renderRow(model.name, model, undefined)} \${renderChildren()} @@ -205,26 +205,26 @@ export class MutationTestReportTotalsComponent extends LitElement { } private renderRow(name: string, row: MetricsResult, path: string | undefined) { - if (stryMutAct_9fa48(26)) { + if (stryMutAct_9fa48(\\"26\\")) { {} } else { - stryCov_9fa48(26); + stryCov_9fa48(\\"26\\"); const { mutationScore } = row.metrics; - const scoreIsPresent = stryMutAct_9fa48(27) ? isNaN(mutationScore) : (stryCov_9fa48(27), !isNaN(mutationScore)); + const scoreIsPresent = stryMutAct_9fa48(\\"27\\") ? isNaN(mutationScore) : (stryCov_9fa48(\\"27\\"), !isNaN(mutationScore)); const coloringClass = this.determineColoringClass(mutationScore); const mutationScoreRounded = mutationScore.toFixed(2); - const progressBarStyle = stryMutAct_9fa48(28) ? \`\` : (stryCov_9fa48(28), \`width: \${mutationScore}%\`); - return stryMutAct_9fa48(29) ? html\`\` : (stryCov_9fa48(29), html\` + const progressBarStyle = stryMutAct_9fa48(\\"28\\") ? \`\` : (stryCov_9fa48(\\"28\\"), \`width: \${mutationScore}%\`); + return stryMutAct_9fa48(\\"29\\") ? html\`\` : (stryCov_9fa48(\\"29\\"), html\` \${row.file ? this.fileIcon : this.directoryIcon} \${(stryMutAct_9fa48(32) ? typeof path !== 'string' : stryMutAct_9fa48(31) ? false : stryMutAct_9fa48(30) ? true : (stryCov_9fa48(30, 31, 32), typeof path === (stryMutAct_9fa48(33) ? \\"\\" : (stryCov_9fa48(33), 'string')))) ? stryMutAct_9fa48(34) ? html\`\` : (stryCov_9fa48(34), html\`\${name}\`) : stryMutAct_9fa48(35) ? html\`\` : (stryCov_9fa48(35), html\`\${row.name}\`)}\${(stryMutAct_9fa48(\\"32\\") ? typeof path !== 'string' : stryMutAct_9fa48(\\"31\\") ? false : stryMutAct_9fa48(\\"30\\") ? true : (stryCov_9fa48(\\"30\\", \\"31\\", \\"32\\"), typeof path === (stryMutAct_9fa48(\\"33\\") ? \\"\\" : (stryCov_9fa48(\\"33\\"), 'string')))) ? stryMutAct_9fa48(\\"34\\") ? html\`\` : (stryCov_9fa48(\\"34\\"), html\`\${name}\`) : stryMutAct_9fa48(\\"35\\") ? html\`\` : (stryCov_9fa48(\\"35\\"), html\`\${row.name}\`)} - \${scoreIsPresent ? stryMutAct_9fa48(36) ? html\`\` : (stryCov_9fa48(36), html\`
+ \${scoreIsPresent ? stryMutAct_9fa48(\\"36\\") ? html\`\` : (stryCov_9fa48(\\"36\\"), html\`
\${mutationScoreRounded}%
-
\`) : stryMutAct_9fa48(37) ? html\`\` : (stryCov_9fa48(37), html\` N/A \`)} +
\`) : stryMutAct_9fa48(\\"37\\") ? html\`\` : (stryCov_9fa48(\\"37\\"), html\` N/A \`)} \${scoreIsPresent ? mutationScoreRounded : undefined} @@ -255,46 +255,46 @@ export class MutationTestReportTotalsComponent extends LitElement { } private determineColoringClass(mutationScore: number) { - if (stryMutAct_9fa48(38)) { + if (stryMutAct_9fa48(\\"38\\")) { {} } else { - stryCov_9fa48(38); + stryCov_9fa48(\\"38\\"); - if (stryMutAct_9fa48(41) ? !isNaN(mutationScore) || this.thresholds : stryMutAct_9fa48(40) ? false : stryMutAct_9fa48(39) ? true : (stryCov_9fa48(39, 40, 41), (stryMutAct_9fa48(42) ? isNaN(mutationScore) : (stryCov_9fa48(42), !isNaN(mutationScore))) && this.thresholds)) { - if (stryMutAct_9fa48(43)) { + if (stryMutAct_9fa48(\\"41\\") ? !isNaN(mutationScore) || this.thresholds : stryMutAct_9fa48(\\"40\\") ? false : stryMutAct_9fa48(\\"39\\") ? true : (stryCov_9fa48(\\"39\\", \\"40\\", \\"41\\"), (stryMutAct_9fa48(\\"42\\") ? isNaN(mutationScore) : (stryCov_9fa48(\\"42\\"), !isNaN(mutationScore))) && this.thresholds)) { + if (stryMutAct_9fa48(\\"43\\")) { {} } else { - stryCov_9fa48(43); + stryCov_9fa48(\\"43\\"); - if (stryMutAct_9fa48(47) ? mutationScore >= this.thresholds.low : stryMutAct_9fa48(46) ? mutationScore <= this.thresholds.low : stryMutAct_9fa48(45) ? false : stryMutAct_9fa48(44) ? true : (stryCov_9fa48(44, 45, 46, 47), mutationScore < this.thresholds.low)) { - if (stryMutAct_9fa48(48)) { + if (stryMutAct_9fa48(\\"47\\") ? mutationScore >= this.thresholds.low : stryMutAct_9fa48(\\"46\\") ? mutationScore <= this.thresholds.low : stryMutAct_9fa48(\\"45\\") ? false : stryMutAct_9fa48(\\"44\\") ? true : (stryCov_9fa48(\\"44\\", \\"45\\", \\"46\\", \\"47\\"), mutationScore < this.thresholds.low)) { + if (stryMutAct_9fa48(\\"48\\")) { {} } else { - stryCov_9fa48(48); - return stryMutAct_9fa48(49) ? \\"\\" : (stryCov_9fa48(49), 'danger'); + stryCov_9fa48(\\"48\\"); + return stryMutAct_9fa48(\\"49\\") ? \\"\\" : (stryCov_9fa48(\\"49\\"), 'danger'); } - } else if (stryMutAct_9fa48(53) ? mutationScore >= this.thresholds.high : stryMutAct_9fa48(52) ? mutationScore <= this.thresholds.high : stryMutAct_9fa48(51) ? false : stryMutAct_9fa48(50) ? true : (stryCov_9fa48(50, 51, 52, 53), mutationScore < this.thresholds.high)) { - if (stryMutAct_9fa48(54)) { + } else if (stryMutAct_9fa48(\\"53\\") ? mutationScore >= this.thresholds.high : stryMutAct_9fa48(\\"52\\") ? mutationScore <= this.thresholds.high : stryMutAct_9fa48(\\"51\\") ? false : stryMutAct_9fa48(\\"50\\") ? true : (stryCov_9fa48(\\"50\\", \\"51\\", \\"52\\", \\"53\\"), mutationScore < this.thresholds.high)) { + if (stryMutAct_9fa48(\\"54\\")) { {} } else { - stryCov_9fa48(54); - return stryMutAct_9fa48(55) ? \\"\\" : (stryCov_9fa48(55), 'warning'); + stryCov_9fa48(\\"54\\"); + return stryMutAct_9fa48(\\"55\\") ? \\"\\" : (stryCov_9fa48(\\"55\\"), 'warning'); } } else { - if (stryMutAct_9fa48(56)) { + if (stryMutAct_9fa48(\\"56\\")) { {} } else { - stryCov_9fa48(56); - return stryMutAct_9fa48(57) ? \\"\\" : (stryCov_9fa48(57), 'success'); + stryCov_9fa48(\\"56\\"); + return stryMutAct_9fa48(\\"57\\") ? \\"\\" : (stryCov_9fa48(\\"57\\"), 'success'); } } } } else { - if (stryMutAct_9fa48(58)) { + if (stryMutAct_9fa48(\\"58\\")) { {} } else { - stryCov_9fa48(58); - return stryMutAct_9fa48(59) ? \\"\\" : (stryCov_9fa48(59), 'default'); + stryCov_9fa48(\\"58\\"); + return stryMutAct_9fa48(\\"59\\") ? \\"\\" : (stryCov_9fa48(\\"59\\"), 'default'); } } } diff --git a/packages/instrumenter/testResources/instrumenter/shebang.js.out.snap b/packages/instrumenter/testResources/instrumenter/shebang.js.out.snap index 239391de3d..164d9a1264 100644 --- a/packages/instrumenter/testResources/instrumenter/shebang.js.out.snap +++ b/packages/instrumenter/testResources/instrumenter/shebang.js.out.snap @@ -8,7 +8,7 @@ function stryNS_9fa48() { var ns = g.__stryker__ || (g.__stryker__ = {}); if (ns.activeMutant === undefined && g.process && g.process.env && g.process.env.__STRYKER_ACTIVE_MUTANT__) { - ns.activeMutant = Number(g.process.env.__STRYKER_ACTIVE_MUTANT__); + ns.activeMutant = g.process.env.__STRYKER_ACTIVE_MUTANT__; } function retrieveNS() { @@ -57,5 +57,5 @@ function stryMutAct_9fa48(id) { return isActive(id); } -console.log(stryMutAct_9fa48(0) ? \\"\\" : (stryCov_9fa48(0), 'test'));" +console.log(stryMutAct_9fa48(\\"0\\") ? \\"\\" : (stryCov_9fa48(\\"0\\"), 'test'));" `; diff --git a/packages/instrumenter/testResources/instrumenter/super-call.ts.out.snap b/packages/instrumenter/testResources/instrumenter/super-call.ts.out.snap index 70d4976668..da4ba9e87e 100644 --- a/packages/instrumenter/testResources/instrumenter/super-call.ts.out.snap +++ b/packages/instrumenter/testResources/instrumenter/super-call.ts.out.snap @@ -6,7 +6,7 @@ exports[`instrumenter integration should be able to instrument super calls 1`] = var ns = g.__stryker__ || (g.__stryker__ = {}); if (ns.activeMutant === undefined && g.process && g.process.env && g.process.env.__STRYKER_ACTIVE_MUTANT__) { - ns.activeMutant = Number(g.process.env.__STRYKER_ACTIVE_MUTANT__); + ns.activeMutant = g.process.env.__STRYKER_ACTIVE_MUTANT__; } function retrieveNS() { @@ -57,7 +57,7 @@ function stryMutAct_9fa48(id) { export class InjectionError extends TypedInjectError { constructor(public readonly path: InjectionTarget[], public readonly cause: Error) { - super(stryMutAct_9fa48(0) ? \`\` : (stryCov_9fa48(0), \`Could not \${describeInjectAction(path[0])} \${path.map(name).join(stryMutAct_9fa48(1) ? \\"\\" : (stryCov_9fa48(1), ' -> '))}. Cause: \${cause.message}\`)); + super(stryMutAct_9fa48(\\"0\\") ? \`\` : (stryCov_9fa48(\\"0\\"), \`Could not \${describeInjectAction(path[0])} \${path.map(name).join(stryMutAct_9fa48(\\"1\\") ? \\"\\" : (stryCov_9fa48(\\"1\\"), ' -> '))}. Cause: \${cause.message}\`)); } }" diff --git a/packages/instrumenter/testResources/instrumenter/switch-case.js.out.snap b/packages/instrumenter/testResources/instrumenter/switch-case.js.out.snap index 4fa31ea6dc..bb10c3627e 100644 --- a/packages/instrumenter/testResources/instrumenter/switch-case.js.out.snap +++ b/packages/instrumenter/testResources/instrumenter/switch-case.js.out.snap @@ -6,7 +6,7 @@ exports[`instrumenter integration should be able to instrument switch case state var ns = g.__stryker__ || (g.__stryker__ = {}); if (ns.activeMutant === undefined && g.process && g.process.env && g.process.env.__STRYKER_ACTIVE_MUTANT__) { - ns.activeMutant = Number(g.process.env.__STRYKER_ACTIVE_MUTANT__); + ns.activeMutant = g.process.env.__STRYKER_ACTIVE_MUTANT__; } function retrieveNS() { @@ -56,17 +56,17 @@ function stryMutAct_9fa48(id) { } switch (foo) { - case stryMutAct_9fa48(1) ? \\"\\" : (stryCov_9fa48(1), 'bar'): - if (stryMutAct_9fa48(0)) {} else { - stryCov_9fa48(0); - console.log(stryMutAct_9fa48(2) ? \\"\\" : (stryCov_9fa48(2), 'bar')); + case stryMutAct_9fa48(\\"1\\") ? \\"\\" : (stryCov_9fa48(\\"1\\"), 'bar'): + if (stryMutAct_9fa48(\\"0\\")) {} else { + stryCov_9fa48(\\"0\\"); + console.log(stryMutAct_9fa48(\\"2\\") ? \\"\\" : (stryCov_9fa48(\\"2\\"), 'bar')); break; } - case stryMutAct_9fa48(4) ? \\"\\" : (stryCov_9fa48(4), 'baz'): - if (stryMutAct_9fa48(3)) {} else { - stryCov_9fa48(3); - console.log(stryMutAct_9fa48(5) ? \\"\\" : (stryCov_9fa48(5), 'baz')); + case stryMutAct_9fa48(\\"4\\") ? \\"\\" : (stryCov_9fa48(\\"4\\"), 'baz'): + if (stryMutAct_9fa48(\\"3\\")) {} else { + stryCov_9fa48(\\"3\\"); + console.log(stryMutAct_9fa48(\\"5\\") ? \\"\\" : (stryCov_9fa48(\\"5\\"), 'baz')); break; } diff --git a/packages/instrumenter/testResources/instrumenter/ts-sample.ts.out.snap b/packages/instrumenter/testResources/instrumenter/ts-sample.ts.out.snap index 5319f0f1d3..8a3ad3631d 100644 --- a/packages/instrumenter/testResources/instrumenter/ts-sample.ts.out.snap +++ b/packages/instrumenter/testResources/instrumenter/ts-sample.ts.out.snap @@ -6,7 +6,7 @@ exports[`instrumenter integration should be able to instrument a simple ts file var ns = g.__stryker__ || (g.__stryker__ = {}); if (ns.activeMutant === undefined && g.process && g.process.env && g.process.env.__STRYKER_ACTIVE_MUTANT__) { - ns.activeMutant = Number(g.process.env.__STRYKER_ACTIVE_MUTANT__); + ns.activeMutant = g.process.env.__STRYKER_ACTIVE_MUTANT__; } function retrieveNS() { @@ -55,32 +55,32 @@ function stryMutAct_9fa48(id) { return isActive(id); } -const bar: number = stryMutAct_9fa48(0) ? 40 - 2 : (stryCov_9fa48(0), 40 + 2); +const bar: number = stryMutAct_9fa48(\\"0\\") ? 40 - 2 : (stryCov_9fa48(\\"0\\"), 40 + 2); class Person { - #name = stryMutAct_9fa48(1) ? \\"\\" : (stryCov_9fa48(1), 'unknown'); + #name = stryMutAct_9fa48(\\"1\\") ? \\"\\" : (stryCov_9fa48(\\"1\\"), 'unknown'); get name(): string { - if (stryMutAct_9fa48(2)) { + if (stryMutAct_9fa48(\\"2\\")) { {} } else { - stryCov_9fa48(2); + stryCov_9fa48(\\"2\\"); return this.#name; } } set name(value: string) { - if (stryMutAct_9fa48(3)) { + if (stryMutAct_9fa48(\\"3\\")) { {} } else { - stryCov_9fa48(3); + stryCov_9fa48(\\"3\\"); - if (stryMutAct_9fa48(7) ? value.length >= 2 : stryMutAct_9fa48(6) ? value.length <= 2 : stryMutAct_9fa48(5) ? false : stryMutAct_9fa48(4) ? true : (stryCov_9fa48(4, 5, 6, 7), value.length < 2)) { - if (stryMutAct_9fa48(8)) { + if (stryMutAct_9fa48(\\"7\\") ? value.length >= 2 : stryMutAct_9fa48(\\"6\\") ? value.length <= 2 : stryMutAct_9fa48(\\"5\\") ? false : stryMutAct_9fa48(\\"4\\") ? true : (stryCov_9fa48(\\"4\\", \\"5\\", \\"6\\", \\"7\\"), value.length < 2)) { + if (stryMutAct_9fa48(\\"8\\")) { {} } else { - stryCov_9fa48(8); - throw new Error(stryMutAct_9fa48(9) ? \\"\\" : (stryCov_9fa48(9), 'Name should be at least 2 characters long')); + stryCov_9fa48(\\"8\\"); + throw new Error(stryMutAct_9fa48(\\"9\\") ? \\"\\" : (stryCov_9fa48(\\"9\\"), 'Name should be at least 2 characters long')); } } diff --git a/packages/instrumenter/testResources/instrumenter/vue-sample.vue.out.snap b/packages/instrumenter/testResources/instrumenter/vue-sample.vue.out.snap index 7d66b34bc1..fe812a52ce 100644 --- a/packages/instrumenter/testResources/instrumenter/vue-sample.vue.out.snap +++ b/packages/instrumenter/testResources/instrumenter/vue-sample.vue.out.snap @@ -47,7 +47,7 @@ function stryNS_9fa48() { var ns = g.__stryker__ || (g.__stryker__ = {}); if (ns.activeMutant === undefined && g.process && g.process.env && g.process.env.__STRYKER_ACTIVE_MUTANT__) { - ns.activeMutant = Number(g.process.env.__STRYKER_ACTIVE_MUTANT__); + ns.activeMutant = g.process.env.__STRYKER_ACTIVE_MUTANT__; } function retrieveNS() { @@ -96,32 +96,32 @@ function stryMutAct_9fa48(id) { return isActive(id); } -export default stryMutAct_9fa48(0) ? {} : (stryCov_9fa48(0), { - name: stryMutAct_9fa48(1) ? \\"\\" : (stryCov_9fa48(1), 'HelloWorld'), +export default stryMutAct_9fa48(\\"0\\") ? {} : (stryCov_9fa48(\\"0\\"), { + name: stryMutAct_9fa48(\\"1\\") ? \\"\\" : (stryCov_9fa48(\\"1\\"), 'HelloWorld'), data() { - if (stryMutAct_9fa48(2)) { + if (stryMutAct_9fa48(\\"2\\")) { {} } else { - stryCov_9fa48(2); - return stryMutAct_9fa48(3) ? {} : (stryCov_9fa48(3), { - msg: stryMutAct_9fa48(4) ? \\"\\" : (stryCov_9fa48(4), 'Welcome to Your Vue.js App') + stryCov_9fa48(\\"2\\"); + return stryMutAct_9fa48(\\"3\\") ? {} : (stryCov_9fa48(\\"3\\"), { + msg: stryMutAct_9fa48(\\"4\\") ? \\"\\" : (stryCov_9fa48(\\"4\\"), 'Welcome to Your Vue.js App') }); } }, - watch: stryMutAct_9fa48(5) ? {} : (stryCov_9fa48(5), { + watch: stryMutAct_9fa48(\\"5\\") ? {} : (stryCov_9fa48(\\"5\\"), { 'category.type'(categoryType) { - if (stryMutAct_9fa48(6)) { + if (stryMutAct_9fa48(\\"6\\")) { {} } else { - stryCov_9fa48(6); + stryCov_9fa48(\\"6\\"); - if (stryMutAct_9fa48(9) ? this.isNew || this.category : stryMutAct_9fa48(8) ? false : stryMutAct_9fa48(7) ? true : (stryCov_9fa48(7, 8, 9), this.isNew && this.category)) { - if (stryMutAct_9fa48(10)) { + if (stryMutAct_9fa48(\\"9\\") ? this.isNew || this.category : stryMutAct_9fa48(\\"8\\") ? false : stryMutAct_9fa48(\\"7\\") ? true : (stryCov_9fa48(\\"7\\", \\"8\\", \\"9\\"), this.isNew && this.category)) { + if (stryMutAct_9fa48(\\"10\\")) { {} } else { - stryCov_9fa48(10); + stryCov_9fa48(\\"10\\"); this.category.permissions = getDefaultDocumentCategoryPermissions(categoryType); } } @@ -137,7 +137,7 @@ function stryNS_9fa48() { var ns = g.__stryker__ || (g.__stryker__ = {}); if (ns.activeMutant === undefined && g.process && g.process.env && g.process.env.__STRYKER_ACTIVE_MUTANT__) { - ns.activeMutant = Number(g.process.env.__STRYKER_ACTIVE_MUTANT__); + ns.activeMutant = g.process.env.__STRYKER_ACTIVE_MUTANT__; } function retrieveNS() { @@ -186,7 +186,7 @@ function stryMutAct_9fa48(id) { return isActive(id); } -const b = stryMutAct_9fa48(11) ? a - c : (stryCov_9fa48(11), a + c); +const b = stryMutAct_9fa48(\\"11\\") ? a - c : (stryCov_9fa48(\\"11\\"), a + c); diff --git a/packages/jasmine-runner/test/integration/jasmine-init-instrumented.it.spec.ts b/packages/jasmine-runner/test/integration/jasmine-init-instrumented.it.spec.ts index d5cfc5568f..8a84ded5be 100644 --- a/packages/jasmine-runner/test/integration/jasmine-init-instrumented.it.spec.ts +++ b/packages/jasmine-runner/test/integration/jasmine-init-instrumented.it.spec.ts @@ -43,20 +43,20 @@ describe('JasmineRunner integration with code instrumentation', () => { describe('mutantRun', () => { it('should be able to kill a mutant', async () => { - const result = await sut.mutantRun(factory.mutantRunOptions({ activeMutant: factory.mutant({ id: 1 }) })); + const result = await sut.mutantRun(factory.mutantRunOptions({ activeMutant: factory.mutant({ id: '1' }) })); assertions.expectKilled(result); expect(result.killedBy).eq('spec0'); expect(result.failureMessage).eq('Expected Player({ currentlyPlayingSong: Song({ }), isPlaying: false }) to be playing Song({ }).'); }); it('should be able report "survive" when a mutant is invincible', async () => { - const result = await sut.mutantRun(factory.mutantRunOptions({ activeMutant: factory.mutant({ id: 12 }) })); + const result = await sut.mutantRun(factory.mutantRunOptions({ activeMutant: factory.mutant({ id: '12' }) })); assertions.expectSurvived(result); }); it('should be able to kill again after a mutant survived', async () => { - await sut.mutantRun(factory.mutantRunOptions({ activeMutant: factory.mutant({ id: 12 }) })); - const result = await sut.mutantRun(factory.mutantRunOptions({ activeMutant: factory.mutant({ id: 2 }) })); + await sut.mutantRun(factory.mutantRunOptions({ activeMutant: factory.mutant({ id: '12' }) })); + const result = await sut.mutantRun(factory.mutantRunOptions({ activeMutant: factory.mutant({ id: '2' }) })); const expected = factory.killedMutantRunResult({ killedBy: 'spec1', status: MutantRunStatus.Killed, diff --git a/packages/jasmine-runner/test/unit/jasmine-test-runner.spec.ts b/packages/jasmine-runner/test/unit/jasmine-test-runner.spec.ts index 47290b500a..99221c604a 100644 --- a/packages/jasmine-runner/test/unit/jasmine-test-runner.spec.ts +++ b/packages/jasmine-runner/test/unit/jasmine-test-runner.spec.ts @@ -5,6 +5,8 @@ import { TestStatus, CompleteDryRunResult, DryRunStatus } from '@stryker-mutator import Jasmine from 'jasmine'; import { DirectoryRequireCache } from '@stryker-mutator/util'; +import { MutantCoverage } from '@stryker-mutator/api/core'; + import * as helpers from '../../src/helpers'; import * as pluginTokens from '../../src/plugin-tokens'; import { JasmineTestRunner } from '../../src'; @@ -69,8 +71,8 @@ describe(JasmineTestRunner.name, () => { }); it('should set the activeMutant on global scope', async () => { - actEmptyMutantRun(undefined, factory.mutant({ id: 23 })); - expect(global.__stryker2__?.activeMutant).eq(23); + actEmptyMutantRun(undefined, factory.mutant({ id: '23' })); + expect(global.__stryker2__?.activeMutant).eq('23'); }); function actEmptyMutantRun(testFilter?: string[], activeMutant = factory.mutant(), sandboxFileName = 'sandbox/file') { @@ -108,9 +110,9 @@ describe(JasmineTestRunner.name, () => { (['perTest', 'all'] as const).forEach((coverageAnalysis) => it(`should report mutation coverage when coverage analysis is ${coverageAnalysis}`, async () => { // Arrange - const expectedMutationCoverage = { + const expectedMutationCoverage: MutantCoverage = { perTest: { - [1]: [2, 3], + '1': { '0': 2, '1': 3 }, }, static: {}, }; diff --git a/packages/jasmine-runner/testResources/jasmine-init-instrumented/lib/jasmine_examples/Player.js b/packages/jasmine-runner/testResources/jasmine-init-instrumented/lib/jasmine_examples/Player.js index 0e2e05da89..b0fbd5e638 100644 --- a/packages/jasmine-runner/testResources/jasmine-init-instrumented/lib/jasmine_examples/Player.js +++ b/packages/jasmine-runner/testResources/jasmine-init-instrumented/lib/jasmine_examples/Player.js @@ -4,7 +4,7 @@ var ns = g.__stryker2__ || (g.__stryker2__ = {}); if (ns.activeMutant === undefined && g.process && g.process.env && g.process.env.__STRYKER_ACTIVE_MUTANT__) { - ns.activeMutant = Number(g.process.env.__STRYKER_ACTIVE_MUTANT__); + ns.activeMutant = g.process.env.__STRYKER_ACTIVE_MUTANT__; } function retrieveNS() { @@ -56,52 +56,52 @@ function stryMutAct_9fa48(id) { function Player() {} Player.prototype.play = function (song) { - if (stryMutAct_9fa48(0)) { + if (stryMutAct_9fa48("0")) { {} } else { - stryCov_9fa48(0); + stryCov_9fa48("0"); this.currentlyPlayingSong = song; - this.isPlaying = stryMutAct_9fa48(1) ? false : (stryCov_9fa48(1), true); + this.isPlaying = stryMutAct_9fa48("1") ? false : (stryCov_9fa48("1"), true); } }; Player.prototype.pause = function () { - if (stryMutAct_9fa48(2)) { + if (stryMutAct_9fa48("2")) { {} } else { - stryCov_9fa48(2); - this.isPlaying = stryMutAct_9fa48(3) ? true : (stryCov_9fa48(3), false); + stryCov_9fa48("2"); + this.isPlaying = stryMutAct_9fa48("3") ? true : (stryCov_9fa48("3"), false); } }; Player.prototype.resume = function () { - if (stryMutAct_9fa48(4)) { + if (stryMutAct_9fa48("4")) { {} } else { - stryCov_9fa48(4); + stryCov_9fa48("4"); - if (stryMutAct_9fa48(6) ? false : stryMutAct_9fa48(5) ? true : (stryCov_9fa48(5, 6), this.isPlaying)) { - if (stryMutAct_9fa48(7)) { + if (stryMutAct_9fa48("6") ? false : stryMutAct_9fa48("5") ? true : (stryCov_9fa48("5", "6"), this.isPlaying)) { + if (stryMutAct_9fa48("7")) { {} } else { - stryCov_9fa48(7); - throw new Error(stryMutAct_9fa48(8) ? "" : (stryCov_9fa48(8), "song is already playing")); + stryCov_9fa48("7"); + throw new Error(stryMutAct_9fa48("8") ? "" : (stryCov_9fa48("8"), "song is already playing")); } } - this.isPlaying = stryMutAct_9fa48(9) ? false : (stryCov_9fa48(9), true); + this.isPlaying = stryMutAct_9fa48("9") ? false : (stryCov_9fa48("9"), true); } }; Player.prototype.makeFavorite = function () { - if (stryMutAct_9fa48(10)) { + if (stryMutAct_9fa48("10")) { {} } else { - stryCov_9fa48(10); - this.currentlyPlayingSong.persistFavoriteStatus(stryMutAct_9fa48(11) ? false : (stryCov_9fa48(11), true)); + stryCov_9fa48("10"); + this.currentlyPlayingSong.persistFavoriteStatus(stryMutAct_9fa48("11") ? false : (stryCov_9fa48("11"), true)); } }; // Add random string, resulting in a static mutant in the instrumented code. -module.exports.foo = stryMutAct_9fa48(12) ? "" : (stryCov_9fa48(12), 'bar'); +module.exports.foo = stryMutAct_9fa48("12") ? "" : (stryCov_9fa48("12"), 'bar'); module.exports = Player; \ No newline at end of file diff --git a/packages/jasmine-runner/testResources/jasmine-init-instrumented/lib/jasmine_examples/Song.js b/packages/jasmine-runner/testResources/jasmine-init-instrumented/lib/jasmine_examples/Song.js index aa0cea72b2..41efe8c2ec 100644 --- a/packages/jasmine-runner/testResources/jasmine-init-instrumented/lib/jasmine_examples/Song.js +++ b/packages/jasmine-runner/testResources/jasmine-init-instrumented/lib/jasmine_examples/Song.js @@ -4,7 +4,7 @@ var ns = g.__stryker2__ || (g.__stryker2__ = {}); if (ns.activeMutant === undefined && g.process && g.process.env && g.process.env.__STRYKER_ACTIVE_MUTANT__) { - ns.activeMutant = Number(g.process.env.__STRYKER_ACTIVE_MUTANT__); + ns.activeMutant = g.process.env.__STRYKER_ACTIVE_MUTANT__; } function retrieveNS() { @@ -56,12 +56,12 @@ function stryMutAct_9fa48(id) { function Song() {} Song.prototype.persistFavoriteStatus = function (value) { - if (stryMutAct_9fa48(13)) { + if (stryMutAct_9fa48("13")) { {} } else { - stryCov_9fa48(13); + stryCov_9fa48("13"); // something complicated - throw new Error(stryMutAct_9fa48(14) ? "" : (stryCov_9fa48(14), "not yet implemented")); + throw new Error(stryMutAct_9fa48("14") ? "" : (stryCov_9fa48("14"), "not yet implemented")); } }; diff --git a/packages/jest-runner/src/config-loaders/react-scripts-ts-jest-config-loader.ts b/packages/jest-runner/src/config-loaders/react-scripts-ts-jest-config-loader.ts new file mode 100644 index 0000000000..86b573a2fb --- /dev/null +++ b/packages/jest-runner/src/config-loaders/react-scripts-ts-jest-config-loader.ts @@ -0,0 +1,45 @@ +import path from 'path'; + +import { Logger } from '@stryker-mutator/api/logging'; +import { tokens, commonTokens } from '@stryker-mutator/api/plugin'; + +import { Config } from '@jest/types'; + +import { createReactTsJestConfig } from '../utils'; +import * as pluginTokens from '../plugin-tokens'; + +import { JestConfigLoader } from './jest-config-loader'; + +export class ReactScriptsTSJestConfigLoader implements JestConfigLoader { + public static inject = tokens(commonTokens.logger, pluginTokens.resolve, pluginTokens.projectRoot); + + constructor(private readonly log: Logger, private readonly resolve: RequireResolve, private readonly projectRoot: string) {} + + public loadConfig(): Config.InitialOptions { + try { + // Get the location of react-ts script, this is later used to generate the Jest configuration used for React projects. + const reactScriptsTsLocation = path.join(this.resolve('react-scripts-ts/package.json'), '..'); + + // Create the React configuration for Jest + const jestConfiguration = this.createJestConfig(reactScriptsTsLocation); + jestConfiguration.testEnvironment = 'jsdom'; + this.log.warn( + 'DEPRECATED: The support for create-react-app-ts projects is deprecated and will be removed in the future. Please migrate your project to create-react-app and update your Stryker config setting to "create-react-app" (see https://create-react-app.dev/docs/adding-typescript/)' + ); + return jestConfiguration; + } catch (e) { + if (this.isNodeErrnoException(e) && e.code === 'MODULE_NOT_FOUND') { + throw Error('Unable to locate package react-scripts-ts. ' + 'This package is required when projectType is set to "create-react-app-ts".'); + } + throw e; + } + } + + private isNodeErrnoException(arg: any): arg is NodeJS.ErrnoException { + return arg.code !== undefined; + } + + private createJestConfig(reactScriptsTsLocation: string): Config.InitialOptions { + return createReactTsJestConfig((relativePath: string): string => path.join(reactScriptsTsLocation, relativePath), this.projectRoot, false); + } +} diff --git a/packages/jest-runner/test/integration/coverage-analysis.it.spec.ts b/packages/jest-runner/test/integration/coverage-analysis.it.spec.ts index a69c7a3e0f..c034b92743 100644 --- a/packages/jest-runner/test/integration/coverage-analysis.it.spec.ts +++ b/packages/jest-runner/test/integration/coverage-analysis.it.spec.ts @@ -98,7 +98,7 @@ describe('JestTestRunner coverage analysis integration', () => { const result = await sut.mutantRun( factory.mutantRunOptions({ testFilter: ['Add should be able to recognize a negative number'], - activeMutant: factory.mutant({ id: 6 }), + activeMutant: factory.mutant({ id: '6' }), sandboxFileName: resolveTestCase('src', 'Add.js'), }) ); @@ -111,7 +111,7 @@ describe('JestTestRunner coverage analysis integration', () => { const result = await sut.mutantRun( factory.mutantRunOptions({ testFilter: ['Add should be able to add two numbers', 'Circle should have a circumference of 2PI when the radius is 1'], - activeMutant: factory.mutant({ id: 6 }), // mutant inside the "isNegativeNumber" function + activeMutant: factory.mutant({ id: '6' }), // mutant inside the "isNegativeNumber" function sandboxFileName: resolveTestCase('src', 'Add.js'), }) ); @@ -237,7 +237,7 @@ describe('JestTestRunner coverage analysis integration', () => { const result = await sut.mutantRun( factory.mutantRunOptions({ testFilter: ['Add should be able to recognize a negative number'], - activeMutant: factory.mutant({ id: 21 }), + activeMutant: factory.mutant({ id: '21' }), sandboxFileName: resolveTestCase('src', 'Add.js'), }) ); @@ -250,7 +250,7 @@ describe('JestTestRunner coverage analysis integration', () => { const result = await sut.mutantRun( factory.mutantRunOptions({ testFilter: ['Add should be able to add two numbers', 'Circle should have a circumference of 2PI when the radius is 1'], - activeMutant: factory.mutant({ id: 11 }), // mutant inside the "negate" function + activeMutant: factory.mutant({ id: '11' }), // mutant inside the "negate" function sandboxFileName: resolveTestCase('src', 'Add.js'), }) ); diff --git a/packages/jest-runner/test/integration/jest-test-runner.it.spec.ts b/packages/jest-runner/test/integration/jest-test-runner.it.spec.ts index 317c2989db..3df78b0b70 100644 --- a/packages/jest-runner/test/integration/jest-test-runner.it.spec.ts +++ b/packages/jest-runner/test/integration/jest-test-runner.it.spec.ts @@ -75,12 +75,10 @@ describe(`${JestTestRunner.name} integration test`, () => { process.chdir(exampleProjectRoot); const jestTestRunner = createSut(); const mutantRunOptions = factory.mutantRunOptions({ - activeMutant: factory.mutant({ - id: 1, - }), + activeMutant: factory.mutant({ id: '1' }), sandboxFileName: require.resolve(path.resolve(exampleProjectRoot, 'src', 'Add.js')), }); - mutantRunOptions.activeMutant.id = 1; + mutantRunOptions.activeMutant.id = '1'; const runResult = await jestTestRunner.mutantRun(mutantRunOptions); @@ -96,7 +94,7 @@ describe(`${JestTestRunner.name} integration test`, () => { const mutantRunOptions = factory.mutantRunOptions({ sandboxFileName: require.resolve(path.resolve(exampleProjectRoot, 'src', 'Circle.js')), }); - mutantRunOptions.activeMutant.id = 11; + mutantRunOptions.activeMutant.id = '11'; const runResult = await jestTestRunner.mutantRun(mutantRunOptions); @@ -111,11 +109,11 @@ describe(`${JestTestRunner.name} integration test`, () => { const mutantRunOptions = factory.mutantRunOptions({ sandboxFileName: require.resolve(path.resolve(exampleProjectRoot, 'src', 'Add.js')), }); - mutantRunOptions.activeMutant.id = 1; + mutantRunOptions.activeMutant.id = '1'; // Act const firstResult = await jestTestRunner.mutantRun(mutantRunOptions); - mutantRunOptions.activeMutant.id = 10; + mutantRunOptions.activeMutant.id = '10'; const secondResult = await jestTestRunner.mutantRun(mutantRunOptions); // Assert diff --git a/packages/jest-runner/test/unit/config-loaders/react-scripts-ts-jest-config-loader.spec.ts b/packages/jest-runner/test/unit/config-loaders/react-scripts-ts-jest-config-loader.spec.ts new file mode 100644 index 0000000000..9ec75f5f0b --- /dev/null +++ b/packages/jest-runner/test/unit/config-loaders/react-scripts-ts-jest-config-loader.spec.ts @@ -0,0 +1,75 @@ +import path from 'path'; + +import { Logger } from '@stryker-mutator/api/logging'; +import { factory } from '@stryker-mutator/test-helpers'; + +import { assert, expect } from 'chai'; +import sinon from 'sinon'; + +import { ReactScriptsTSJestConfigLoader } from '../../../src/config-loaders/react-scripts-ts-jest-config-loader'; +import * as helper from '../../../src/utils/create-react-jest-config'; + +describe(ReactScriptsTSJestConfigLoader.name, () => { + let sut: ReactScriptsTSJestConfigLoader; + let requireResolveStub: sinon.SinonStub; + let createReactJestConfigStub: sinon.SinonStub; + let loggerStub: sinon.SinonStubbedInstance; + + const projectRoot = '/path/to/project'; + const reactScriptsTsPackagePath = './node_modules/react-scripts-ts/package.json'; + + beforeEach(() => { + createReactJestConfigStub = sinon.stub(helper, 'createReactTsJestConfig'); + createReactJestConfigStub.callsFake((resolve: any, root: string, eject: boolean) => ({ + eject, + projectRoot: root, + relativePath: resolve('test'), + })); + + requireResolveStub = sinon.stub(); + requireResolveStub.returns(reactScriptsTsPackagePath); + + loggerStub = factory.logger(); + + sut = new ReactScriptsTSJestConfigLoader(loggerStub, (requireResolveStub as unknown) as RequireResolve, projectRoot); + }); + + it('should load the configuration via the createJestConfig method provided by react-scripts-ts', () => { + sut.loadConfig(); + + assert(requireResolveStub.calledWith('react-scripts-ts/package.json')); + }); + + it('should log a deprecation warning', () => { + sut.loadConfig(); + + assert( + loggerStub.warn.calledWith( + 'DEPRECATED: The support for create-react-app-ts projects is deprecated and will be removed in the future. Please migrate your project to create-react-app and update your Stryker config setting to "create-react-app" (see https://create-react-app.dev/docs/adding-typescript/)' + ) + ); + }); + + it('should generate a configuration', () => { + const config = sut.loadConfig(); + + expect(config).to.deep.equal({ + eject: false, + projectRoot: '/path/to/project', + relativePath: path.join('node_modules', 'react-scripts-ts', 'test'), + testEnvironment: 'jsdom', + }); + }); + + it('should throw an error when react-scripts could not be found', () => { + // Arrange + const error: NodeJS.ErrnoException = new Error(''); + error.code = 'MODULE_NOT_FOUND'; + requireResolveStub.throws(error); + + // Act & Assert + expect(() => sut.loadConfig()).throws( + 'Unable to locate package react-scripts-ts. This package is required when projectType is set to "create-react-app-ts".' + ); + }); +}); diff --git a/packages/jest-runner/test/unit/jest-test-runner.spec.ts b/packages/jest-runner/test/unit/jest-test-runner.spec.ts index 2f4c6f31ea..fe7f5f7a51 100644 --- a/packages/jest-runner/test/unit/jest-test-runner.spec.ts +++ b/packages/jest-runner/test/unit/jest-test-runner.spec.ts @@ -438,20 +438,20 @@ describe(JestTestRunner.name, () => { it('should set the active mutant in environment variable', async () => { const sut = createSut(); - const onGoingWork = sut.mutantRun(factory.mutantRunOptions({ activeMutant: factory.mutant({ id: 25 }) })); + const onGoingWork = sut.mutantRun(factory.mutantRunOptions({ activeMutant: factory.mutant({ id: '25' }) })); expect(process.env[INSTRUMENTER_CONSTANTS.ACTIVE_MUTANT_ENV_VARIABLE]).to.equal('25'); await onGoingWork; }); it('should reset the active mutant in environment variable', async () => { const sut = createSut(); - await sut.mutantRun(factory.mutantRunOptions({ activeMutant: factory.mutant({ id: 25 }) })); + await sut.mutantRun(factory.mutantRunOptions({ activeMutant: factory.mutant({ id: '25' }) })); expect(process.env[INSTRUMENTER_CONSTANTS.ACTIVE_MUTANT_ENV_VARIABLE]).to.equal(undefined); }); it('should set the __strykerGlobalNamespace__ in globals', async () => { const sut = createSut(); - await sut.mutantRun(factory.mutantRunOptions({ activeMutant: factory.mutant({ id: 25 }) })); + await sut.mutantRun(factory.mutantRunOptions({ activeMutant: factory.mutant({ id: '25' }) })); expect(jestTestAdapterMock.run).calledWithMatch( sinon.match({ jestConfig: { @@ -469,7 +469,7 @@ describe(JestTestRunner.name, () => { }; options.jest.config = customConfig; const sut = createSut(); - await sut.mutantRun(factory.mutantRunOptions({ activeMutant: factory.mutant({ id: 25 }) })); + await sut.mutantRun(factory.mutantRunOptions({ activeMutant: factory.mutant({ id: '25' }) })); expect(jestTestAdapterMock.run).calledWithMatch( sinon.match({ jestConfig: { diff --git a/packages/jest-runner/testResources/jasmine2-dom-sixteen-instrumented/src/Add.js b/packages/jest-runner/testResources/jasmine2-dom-sixteen-instrumented/src/Add.js index d630d67020..392724aa5d 100644 --- a/packages/jest-runner/testResources/jasmine2-dom-sixteen-instrumented/src/Add.js +++ b/packages/jest-runner/testResources/jasmine2-dom-sixteen-instrumented/src/Add.js @@ -4,7 +4,7 @@ var ns = g.__stryker2__ || (g.__stryker2__ = {}); if (ns.activeMutant === undefined && g.process && g.process.env && g.process.env.__STRYKER_ACTIVE_MUTANT__) { - ns.activeMutant = Number(g.process.env.__STRYKER_ACTIVE_MUTANT__); + ns.activeMutant = g.process.env.__STRYKER_ACTIVE_MUTANT__; } function retrieveNS() { @@ -55,38 +55,38 @@ function stryMutAct_9fa48(id) { class CalculatorElement extends HTMLElement { connectedCallback() { - if (stryMutAct_9fa48(0)) { + if (stryMutAct_9fa48("0")) { {} } else { - stryCov_9fa48(0); + stryCov_9fa48("0"); - switch (this.getAttribute(stryMutAct_9fa48(1) ? "" : (stryCov_9fa48(1), 'operator'))) { - case stryMutAct_9fa48(3) ? "" : (stryCov_9fa48(3), 'add'): - if (stryMutAct_9fa48(2)) {} else { - stryCov_9fa48(2); - this.innerHTML = stryMutAct_9fa48(4) ? Number(this.getAttribute(stryMutAct_9fa48(5) ? "" : (stryCov_9fa48(5), 'a'))) - Number(this.getAttribute(stryMutAct_9fa48(6) ? "" : (stryCov_9fa48(6), 'b'))) : (stryCov_9fa48(4), Number(this.getAttribute(stryMutAct_9fa48(5) ? "" : (stryCov_9fa48(5), 'a'))) + Number(this.getAttribute(stryMutAct_9fa48(6) ? "" : (stryCov_9fa48(6), 'b')))); + switch (this.getAttribute(stryMutAct_9fa48("1") ? "" : (stryCov_9fa48("1"), 'operator'))) { + case stryMutAct_9fa48("3") ? "" : (stryCov_9fa48("3"), 'add'): + if (stryMutAct_9fa48("2")) {} else { + stryCov_9fa48("2"); + this.innerHTML = stryMutAct_9fa48("4") ? Number(this.getAttribute(stryMutAct_9fa48("5") ? "" : (stryCov_9fa48("5"), 'a'))) - Number(this.getAttribute(stryMutAct_9fa48("6") ? "" : (stryCov_9fa48("6"), 'b'))) : (stryCov_9fa48("4"), Number(this.getAttribute(stryMutAct_9fa48("5") ? "" : (stryCov_9fa48("5"), 'a'))) + Number(this.getAttribute(stryMutAct_9fa48("6") ? "" : (stryCov_9fa48("6"), 'b')))); break; } - case stryMutAct_9fa48(8) ? "" : (stryCov_9fa48(8), 'addOne'): - if (stryMutAct_9fa48(7)) {} else { - stryCov_9fa48(7); - this.innerHTML = stryMutAct_9fa48(9) ? Number(this.getAttribute(stryMutAct_9fa48(10) ? "" : (stryCov_9fa48(10), 'a'))) - 1 : (stryCov_9fa48(9), Number(this.getAttribute(stryMutAct_9fa48(10) ? "" : (stryCov_9fa48(10), 'a'))) + 1); + case stryMutAct_9fa48("8") ? "" : (stryCov_9fa48("8"), 'addOne'): + if (stryMutAct_9fa48("7")) {} else { + stryCov_9fa48("7"); + this.innerHTML = stryMutAct_9fa48("9") ? Number(this.getAttribute(stryMutAct_9fa48("10") ? "" : (stryCov_9fa48("10"), 'a'))) - 1 : (stryCov_9fa48("9"), Number(this.getAttribute(stryMutAct_9fa48("10") ? "" : (stryCov_9fa48("10"), 'a'))) + 1); break; } - case stryMutAct_9fa48(12) ? "" : (stryCov_9fa48(12), 'negate'): - if (stryMutAct_9fa48(11)) {} else { - stryCov_9fa48(11); - this.innerHTML = stryMutAct_9fa48(13) ? +Number(this.getAttribute(stryMutAct_9fa48(14) ? "" : (stryCov_9fa48(14), 'a'))) : (stryCov_9fa48(13), -Number(this.getAttribute(stryMutAct_9fa48(14) ? "" : (stryCov_9fa48(14), 'a')))); + case stryMutAct_9fa48("12") ? "" : (stryCov_9fa48("12"), 'negate'): + if (stryMutAct_9fa48("11")) {} else { + stryCov_9fa48("11"); + this.innerHTML = stryMutAct_9fa48("13") ? +Number(this.getAttribute(stryMutAct_9fa48("14") ? "" : (stryCov_9fa48("14"), 'a'))) : (stryCov_9fa48("13"), -Number(this.getAttribute(stryMutAct_9fa48("14") ? "" : (stryCov_9fa48("14"), 'a')))); break; } - case stryMutAct_9fa48(16) ? "" : (stryCov_9fa48(16), 'isNegative'): - if (stryMutAct_9fa48(15)) {} else { - stryCov_9fa48(15); - const a = Number(this.getAttribute(stryMutAct_9fa48(17) ? "" : (stryCov_9fa48(17), 'a'))); - this.innerHTML = stryMutAct_9fa48(21) ? a >= 0 : stryMutAct_9fa48(20) ? a <= 0 : stryMutAct_9fa48(19) ? false : stryMutAct_9fa48(18) ? true : (stryCov_9fa48(18, 19, 20, 21), a < 0); + case stryMutAct_9fa48("16") ? "" : (stryCov_9fa48("16"), 'isNegative'): + if (stryMutAct_9fa48("15")) {} else { + stryCov_9fa48("15"); + const a = Number(this.getAttribute(stryMutAct_9fa48("17") ? "" : (stryCov_9fa48("17"), 'a'))); + this.innerHTML = stryMutAct_9fa48("21") ? a >= 0 : stryMutAct_9fa48("20") ? a <= 0 : stryMutAct_9fa48("19") ? false : stryMutAct_9fa48("18") ? true : (stryCov_9fa48("18", "19", "20", "21"), a < 0); break; } @@ -96,4 +96,4 @@ class CalculatorElement extends HTMLElement { } -customElements.define(stryMutAct_9fa48(22) ? "" : (stryCov_9fa48(22), 'my-calculator'), CalculatorElement); \ No newline at end of file +customElements.define(stryMutAct_9fa48("22") ? "" : (stryCov_9fa48("22"), 'my-calculator'), CalculatorElement); \ No newline at end of file diff --git a/packages/jest-runner/testResources/jasmine2-dom-sixteen-instrumented/src/Circle.js b/packages/jest-runner/testResources/jasmine2-dom-sixteen-instrumented/src/Circle.js index 0dbd1abb73..0e0a9eac96 100644 --- a/packages/jest-runner/testResources/jasmine2-dom-sixteen-instrumented/src/Circle.js +++ b/packages/jest-runner/testResources/jasmine2-dom-sixteen-instrumented/src/Circle.js @@ -4,7 +4,7 @@ var ns = g.__stryker2__ || (g.__stryker2__ = {}); if (ns.activeMutant === undefined && g.process && g.process.env && g.process.env.__STRYKER_ACTIVE_MUTANT__) { - ns.activeMutant = Number(g.process.env.__STRYKER_ACTIVE_MUTANT__); + ns.activeMutant = g.process.env.__STRYKER_ACTIVE_MUTANT__; } function retrieveNS() { @@ -55,23 +55,23 @@ function stryMutAct_9fa48(id) { class CircleElement extends HTMLElement { get circumference() { - if (stryMutAct_9fa48(23)) { + if (stryMutAct_9fa48("23")) { {} } else { - stryCov_9fa48(23); - return stryMutAct_9fa48(24) ? 2 * Math.PI / Number(this.getAttribute(stryMutAct_9fa48(26) ? "" : (stryCov_9fa48(26), 'radius'))) : (stryCov_9fa48(24), (stryMutAct_9fa48(25) ? 2 / Math.PI : (stryCov_9fa48(25), 2 * Math.PI)) * Number(this.getAttribute(stryMutAct_9fa48(26) ? "" : (stryCov_9fa48(26), 'radius')))); + stryCov_9fa48("23"); + return stryMutAct_9fa48("24") ? 2 * Math.PI / Number(this.getAttribute(stryMutAct_9fa48("26") ? "" : (stryCov_9fa48("26"), 'radius'))) : (stryCov_9fa48("24"), (stryMutAct_9fa48("25") ? 2 / Math.PI : (stryCov_9fa48("25"), 2 * Math.PI)) * Number(this.getAttribute(stryMutAct_9fa48("26") ? "" : (stryCov_9fa48("26"), 'radius')))); } } untestedFunction() { - if (stryMutAct_9fa48(27)) { + if (stryMutAct_9fa48("27")) { {} } else { - stryCov_9fa48(27); - return stryMutAct_9fa48(28) ? 5 / 2 / 3 : (stryCov_9fa48(28), (stryMutAct_9fa48(29) ? 5 * 2 : (stryCov_9fa48(29), 5 / 2)) * 3); + stryCov_9fa48("27"); + return stryMutAct_9fa48("28") ? 5 / 2 / 3 : (stryCov_9fa48("28"), (stryMutAct_9fa48("29") ? 5 * 2 : (stryCov_9fa48("29"), 5 / 2)) * 3); } } } -customElements.define(stryMutAct_9fa48(30) ? "" : (stryCov_9fa48(30), 'my-circle'), CircleElement); \ No newline at end of file +customElements.define(stryMutAct_9fa48("30") ? "" : (stryCov_9fa48("30"), 'my-circle'), CircleElement); \ No newline at end of file diff --git a/packages/jest-runner/testResources/jasmine2-node-instrumented/src/Add.js b/packages/jest-runner/testResources/jasmine2-node-instrumented/src/Add.js index 147bc36216..953461dfbc 100644 --- a/packages/jest-runner/testResources/jasmine2-node-instrumented/src/Add.js +++ b/packages/jest-runner/testResources/jasmine2-node-instrumented/src/Add.js @@ -4,7 +4,7 @@ var ns = g.__stryker2__ || (g.__stryker2__ = {}); if (ns.activeMutant === undefined && g.process && g.process.env && g.process.env.__STRYKER_ACTIVE_MUTANT__) { - ns.activeMutant = Number(g.process.env.__STRYKER_ACTIVE_MUTANT__); + ns.activeMutant = g.process.env.__STRYKER_ACTIVE_MUTANT__; } function retrieveNS() { @@ -54,46 +54,46 @@ function stryMutAct_9fa48(id) { } exports.add = function (num1, num2) { - if (stryMutAct_9fa48(0)) { + if (stryMutAct_9fa48("0")) { {} } else { - stryCov_9fa48(0); - return stryMutAct_9fa48(1) ? num1 - num2 : (stryCov_9fa48(1), num1 + num2); + stryCov_9fa48("0"); + return stryMutAct_9fa48("1") ? num1 - num2 : (stryCov_9fa48("1"), num1 + num2); } }; exports.addOne = function (number) { - if (stryMutAct_9fa48(2)) { + if (stryMutAct_9fa48("2")) { {} } else { - stryCov_9fa48(2); - stryMutAct_9fa48(3) ? number-- : (stryCov_9fa48(3), number++); + stryCov_9fa48("2"); + stryMutAct_9fa48("3") ? number-- : (stryCov_9fa48("3"), number++); return number; } }; exports.negate = function (number) { - if (stryMutAct_9fa48(4)) { + if (stryMutAct_9fa48("4")) { {} } else { - stryCov_9fa48(4); - return stryMutAct_9fa48(5) ? +number : (stryCov_9fa48(5), -number); + stryCov_9fa48("4"); + return stryMutAct_9fa48("5") ? +number : (stryCov_9fa48("5"), -number); } }; exports.isNegativeNumber = function (number) { - if (stryMutAct_9fa48(6)) { + if (stryMutAct_9fa48("6")) { {} } else { - stryCov_9fa48(6); - var isNegative = stryMutAct_9fa48(7) ? true : (stryCov_9fa48(7), false); + stryCov_9fa48("6"); + var isNegative = stryMutAct_9fa48("7") ? true : (stryCov_9fa48("7"), false); - if (stryMutAct_9fa48(11) ? number >= 0 : stryMutAct_9fa48(10) ? number <= 0 : stryMutAct_9fa48(9) ? false : stryMutAct_9fa48(8) ? true : (stryCov_9fa48(8, 9, 10, 11), number < 0)) { - if (stryMutAct_9fa48(12)) { + if (stryMutAct_9fa48("11") ? number >= 0 : stryMutAct_9fa48("10") ? number <= 0 : stryMutAct_9fa48("9") ? false : stryMutAct_9fa48("8") ? true : (stryCov_9fa48("8", "9", "10", "11"), number < 0)) { + if (stryMutAct_9fa48("12")) { {} } else { - stryCov_9fa48(12); - isNegative = stryMutAct_9fa48(13) ? false : (stryCov_9fa48(13), true); + stryCov_9fa48("12"); + isNegative = stryMutAct_9fa48("13") ? false : (stryCov_9fa48("13"), true); } } diff --git a/packages/jest-runner/testResources/jasmine2-node-instrumented/src/Circle.js b/packages/jest-runner/testResources/jasmine2-node-instrumented/src/Circle.js index de935dfabe..915b9ee9f8 100644 --- a/packages/jest-runner/testResources/jasmine2-node-instrumented/src/Circle.js +++ b/packages/jest-runner/testResources/jasmine2-node-instrumented/src/Circle.js @@ -4,7 +4,7 @@ var ns = g.__stryker2__ || (g.__stryker2__ = {}); if (ns.activeMutant === undefined && g.process && g.process.env && g.process.env.__STRYKER_ACTIVE_MUTANT__) { - ns.activeMutant = Number(g.process.env.__STRYKER_ACTIVE_MUTANT__); + ns.activeMutant = g.process.env.__STRYKER_ACTIVE_MUTANT__; } function retrieveNS() { @@ -54,20 +54,20 @@ function stryMutAct_9fa48(id) { } exports.getCircumference = function (radius) { - if (stryMutAct_9fa48(14)) { + if (stryMutAct_9fa48("14")) { {} } else { - stryCov_9fa48(14); + stryCov_9fa48("14"); //Function to test multiple math mutations in a single function. - return stryMutAct_9fa48(15) ? 2 * Math.PI / radius : (stryCov_9fa48(15), (stryMutAct_9fa48(16) ? 2 / Math.PI : (stryCov_9fa48(16), 2 * Math.PI)) * radius); + return stryMutAct_9fa48("15") ? 2 * Math.PI / radius : (stryCov_9fa48("15"), (stryMutAct_9fa48("16") ? 2 / Math.PI : (stryCov_9fa48("16"), 2 * Math.PI)) * radius); } }; exports.untestedFunction = function () { - if (stryMutAct_9fa48(17)) { + if (stryMutAct_9fa48("17")) { {} } else { - stryCov_9fa48(17); - var i = stryMutAct_9fa48(18) ? 5 / 2 / 3 : (stryCov_9fa48(18), (stryMutAct_9fa48(19) ? 5 * 2 : (stryCov_9fa48(19), 5 / 2)) * 3); + stryCov_9fa48("17"); + var i = stryMutAct_9fa48("18") ? 5 / 2 / 3 : (stryCov_9fa48("18"), (stryMutAct_9fa48("19") ? 5 * 2 : (stryCov_9fa48("19"), 5 / 2)) * 3); } }; \ No newline at end of file diff --git a/packages/karma-runner/src/karma-plugins/test-hooks-middleware.ts b/packages/karma-runner/src/karma-plugins/test-hooks-middleware.ts index 7c79fcc169..8a08a7dab3 100644 --- a/packages/karma-runner/src/karma-plugins/test-hooks-middleware.ts +++ b/packages/karma-runner/src/karma-plugins/test-hooks-middleware.ts @@ -57,7 +57,7 @@ export class TestHooksMiddleware { public configureActiveMutant({ activeMutant, testFilter }: MutantRunOptions): void { this.configureCoverageAnalysis('off'); this.currentTestHooks += `window.${NAMESPACE} = window.${NAMESPACE} || {}; - window.${NAMESPACE}.${ACTIVE_MUTANT} = ${activeMutant.id};`; + window.${NAMESPACE}.${ACTIVE_MUTANT} = "${activeMutant.id}";`; if (testFilter) { switch (this.testFramework) { case 'jasmine': diff --git a/packages/karma-runner/test/integration/instrumented.it.spec.ts b/packages/karma-runner/test/integration/instrumented.it.spec.ts index 11f588a9eb..e8b9b8f163 100644 --- a/packages/karma-runner/test/integration/instrumented.it.spec.ts +++ b/packages/karma-runner/test/integration/instrumented.it.spec.ts @@ -108,7 +108,7 @@ describe(`${KarmaTestRunner.name} running on instrumented code`, () => { describe('mutantRun', () => { it('should be able to kill a mutant', async () => { - const result = await sut.mutantRun(factory.mutantRunOptions({ activeMutant: factory.mutant({ id: 0 }) })); + const result = await sut.mutantRun(factory.mutantRunOptions({ activeMutant: factory.mutant({ id: '0' }) })); assertions.expectKilled(result); expect(result.killedBy).eq('spec0'); expect(result.failureMessage.split('\n')[0]).eq('Error: Expected undefined to be 7.'); @@ -117,7 +117,7 @@ describe(`${KarmaTestRunner.name} running on instrumented code`, () => { it('should survive if the filtered tests do not kill the mutant', async () => { const result = await sut.mutantRun( factory.mutantRunOptions({ - activeMutant: factory.mutant({ id: 2 }), + activeMutant: factory.mutant({ id: '2' }), testFilter: [ 'spec0', //'spec1' => would kill the mutant @@ -129,8 +129,8 @@ describe(`${KarmaTestRunner.name} running on instrumented code`, () => { }); it('should be able to kill again after a mutant survived', async () => { - await sut.mutantRun(factory.mutantRunOptions({ activeMutant: factory.mutant({ id: 11 }) })); - const result = await sut.mutantRun(factory.mutantRunOptions({ activeMutant: factory.mutant({ id: 2 }), testFilter: ['spec1'] })); + await sut.mutantRun(factory.mutantRunOptions({ activeMutant: factory.mutant({ id: '11' }) })); + const result = await sut.mutantRun(factory.mutantRunOptions({ activeMutant: factory.mutant({ id: '2' }), testFilter: ['spec1'] })); assertions.expectKilled(result); result.failureMessage = result.failureMessage.split('\n')[0]; const expected = factory.killedMutantRunResult({ @@ -143,8 +143,8 @@ describe(`${KarmaTestRunner.name} running on instrumented code`, () => { }); it('should be able to clear the test filter', async () => { - await sut.mutantRun(factory.mutantRunOptions({ activeMutant: factory.mutant({ id: 2 }), testFilter: ['spec1'] })); - const result = await sut.mutantRun(factory.mutantRunOptions({ activeMutant: factory.mutant({ id: 1 }), testFilter: undefined })); + await sut.mutantRun(factory.mutantRunOptions({ activeMutant: factory.mutant({ id: '2' }), testFilter: ['spec1'] })); + const result = await sut.mutantRun(factory.mutantRunOptions({ activeMutant: factory.mutant({ id: '1' }), testFilter: undefined })); assertions.expectKilled(result); }); }); @@ -236,14 +236,14 @@ describe(`${KarmaTestRunner.name} running on instrumented code`, () => { describe('mutantRun', () => { it('should be able to kill a mutant', async () => { - const result = await sut.mutantRun(factory.mutantRunOptions({ activeMutant: factory.mutant({ id: 0 }) })); + const result = await sut.mutantRun(factory.mutantRunOptions({ activeMutant: factory.mutant({ id: '0' }) })); assertions.expectKilled(result); expect(result.killedBy).eq('Add should be able to add two numbers'); expect(result.failureMessage.split('\n')[0]).eq('AssertionError: expected undefined to equal 7'); }); it('should bail after first failing test', async () => { - const result = await sut.mutantRun(factory.mutantRunOptions({ activeMutant: factory.mutant({ id: 0 }) })); + const result = await sut.mutantRun(factory.mutantRunOptions({ activeMutant: factory.mutant({ id: '0' }) })); assertions.expectKilled(result); expect(result.nrOfTests).eq(1); }); @@ -251,7 +251,7 @@ describe(`${KarmaTestRunner.name} running on instrumented code`, () => { it('should survive if the filtered tests do not kill the mutant', async () => { const result = await sut.mutantRun( factory.mutantRunOptions({ - activeMutant: factory.mutant({ id: 2 }), + activeMutant: factory.mutant({ id: '2' }), testFilter: [ 'Add should be able to add two numbers', //'Add should be able 1 to a number' => would kill the mutant @@ -264,9 +264,9 @@ describe(`${KarmaTestRunner.name} running on instrumented code`, () => { }); it('should be able to kill again after a mutant survived', async () => { - await sut.mutantRun(factory.mutantRunOptions({ activeMutant: factory.mutant({ id: 11 }) })); + await sut.mutantRun(factory.mutantRunOptions({ activeMutant: factory.mutant({ id: '11' }) })); const result = await sut.mutantRun( - factory.mutantRunOptions({ activeMutant: factory.mutant({ id: 2 }), testFilter: ['Add should be able 1 to a number'] }) + factory.mutantRunOptions({ activeMutant: factory.mutant({ id: '2' }), testFilter: ['Add should be able 1 to a number'] }) ); assertions.expectKilled(result); result.failureMessage = result.failureMessage.split('\n')[0]; @@ -280,8 +280,10 @@ describe(`${KarmaTestRunner.name} running on instrumented code`, () => { }); it('should be able to clear the test filter', async () => { - await sut.mutantRun(factory.mutantRunOptions({ activeMutant: factory.mutant({ id: 2 }), testFilter: ['Add should be able 1 to a number'] })); - const result = await sut.mutantRun(factory.mutantRunOptions({ activeMutant: factory.mutant({ id: 1 }), testFilter: undefined })); + await sut.mutantRun( + factory.mutantRunOptions({ activeMutant: factory.mutant({ id: '2' }), testFilter: ['Add should be able 1 to a number'] }) + ); + const result = await sut.mutantRun(factory.mutantRunOptions({ activeMutant: factory.mutant({ id: '1' }), testFilter: undefined })); assertions.expectKilled(result); }); }); diff --git a/packages/karma-runner/test/unit/karma-plugins/test-hooks-middleware.spec.ts b/packages/karma-runner/test/unit/karma-plugins/test-hooks-middleware.spec.ts index ef376796c3..391f0e5475 100644 --- a/packages/karma-runner/test/unit/karma-plugins/test-hooks-middleware.spec.ts +++ b/packages/karma-runner/test/unit/karma-plugins/test-hooks-middleware.spec.ts @@ -61,13 +61,13 @@ describe(TestHooksMiddleware.name, () => { }); it('should declare the __stryker__ namespace', () => { - sut.configureActiveMutant(factory.mutantRunOptions({ activeMutant: factory.mutant({ id: 42 }) })); + sut.configureActiveMutant(factory.mutantRunOptions({ activeMutant: factory.mutant({ id: '42' }) })); expect(sut.currentTestHooks).contains('window.__stryker__ = window.__stryker__ || {}'); }); it('should set the "activeMutant" id', () => { - sut.configureActiveMutant(factory.mutantRunOptions({ activeMutant: factory.mutant({ id: 42 }) })); - expect(sut.currentTestHooks).contains('window.__stryker__.activeMutant = 42'); + sut.configureActiveMutant(factory.mutantRunOptions({ activeMutant: factory.mutant({ id: '42' }) })); + expect(sut.currentTestHooks).contains('window.__stryker__.activeMutant = "42"'); }); it("should ignore the test filter if the current test framework doesn't support it", () => { diff --git a/packages/karma-runner/testResources/instrumented/src/Add.js b/packages/karma-runner/testResources/instrumented/src/Add.js index d9d9f1b450..3f7617e030 100644 --- a/packages/karma-runner/testResources/instrumented/src/Add.js +++ b/packages/karma-runner/testResources/instrumented/src/Add.js @@ -4,7 +4,7 @@ var ns = g.__stryker__ || (g.__stryker__ = {}); if (ns.activeMutant === undefined && g.process && g.process.env && g.process.env.__STRYKER_ACTIVE_MUTANT__) { - ns.activeMutant = Number(g.process.env.__STRYKER_ACTIVE_MUTANT__); + ns.activeMutant = g.process.env.__STRYKER_ACTIVE_MUTANT__; } function retrieveNS() { @@ -54,46 +54,46 @@ function stryMutAct_9fa48(id) { } var add = function (num1, num2) { - if (stryMutAct_9fa48(0)) { + if (stryMutAct_9fa48("0")) { {} } else { - stryCov_9fa48(0); - return stryMutAct_9fa48(1) ? num1 - num2 : (stryCov_9fa48(1), num1 + num2); + stryCov_9fa48("0"); + return stryMutAct_9fa48("1") ? num1 - num2 : (stryCov_9fa48("1"), num1 + num2); } }; var addOne = function (number) { - if (stryMutAct_9fa48(2)) { + if (stryMutAct_9fa48("2")) { {} } else { - stryCov_9fa48(2); - stryMutAct_9fa48(3) ? number-- : (stryCov_9fa48(3), number++); + stryCov_9fa48("2"); + stryMutAct_9fa48("3") ? number-- : (stryCov_9fa48("3"), number++); return number; } }; var negate = function (number) { - if (stryMutAct_9fa48(4)) { + if (stryMutAct_9fa48("4")) { {} } else { - stryCov_9fa48(4); - return stryMutAct_9fa48(5) ? +number : (stryCov_9fa48(5), -number); + stryCov_9fa48("4"); + return stryMutAct_9fa48("5") ? +number : (stryCov_9fa48("5"), -number); } }; var isNegativeNumber = function (number) { - if (stryMutAct_9fa48(6)) { + if (stryMutAct_9fa48("6")) { {} } else { - stryCov_9fa48(6); - var isNegative = stryMutAct_9fa48(7) ? true : (stryCov_9fa48(7), false); + stryCov_9fa48("6"); + var isNegative = stryMutAct_9fa48("7") ? true : (stryCov_9fa48("7"), false); - if (stryMutAct_9fa48(11) ? number >= 0 : stryMutAct_9fa48(10) ? number <= 0 : stryMutAct_9fa48(9) ? false : stryMutAct_9fa48(8) ? true : (stryCov_9fa48(8, 9, 10, 11), number < 0)) { - if (stryMutAct_9fa48(12)) { + if (stryMutAct_9fa48("11") ? number >= 0 : stryMutAct_9fa48("10") ? number <= 0 : stryMutAct_9fa48("9") ? false : stryMutAct_9fa48("8") ? true : (stryCov_9fa48("8", "9", "10", "11"), number < 0)) { + if (stryMutAct_9fa48("12")) { {} } else { - stryCov_9fa48(12); - isNegative = stryMutAct_9fa48(13) ? false : (stryCov_9fa48(13), true); + stryCov_9fa48("12"); + isNegative = stryMutAct_9fa48("13") ? false : (stryCov_9fa48("13"), true); } } diff --git a/packages/karma-runner/testResources/instrumented/src/Circle.js b/packages/karma-runner/testResources/instrumented/src/Circle.js index 5f5f5b0490..8b995abfae 100644 --- a/packages/karma-runner/testResources/instrumented/src/Circle.js +++ b/packages/karma-runner/testResources/instrumented/src/Circle.js @@ -4,7 +4,7 @@ var ns = g.__stryker__ || (g.__stryker__ = {}); if (ns.activeMutant === undefined && g.process && g.process.env && g.process.env.__STRYKER_ACTIVE_MUTANT__) { - ns.activeMutant = Number(g.process.env.__STRYKER_ACTIVE_MUTANT__); + ns.activeMutant = g.process.env.__STRYKER_ACTIVE_MUTANT__; } function retrieveNS() { @@ -54,20 +54,20 @@ function stryMutAct_9fa48(id) { } var getCircumference = function (radius) { - if (stryMutAct_9fa48(14)) { + if (stryMutAct_9fa48("14")) { {} } else { - stryCov_9fa48(14); + stryCov_9fa48("14"); //Function to test multiple math mutations in a single function. - return stryMutAct_9fa48(15) ? 2 * Math.PI / radius : (stryCov_9fa48(15), (stryMutAct_9fa48(16) ? 2 / Math.PI : (stryCov_9fa48(16), 2 * Math.PI)) * radius); + return stryMutAct_9fa48("15") ? 2 * Math.PI / radius : (stryCov_9fa48("15"), (stryMutAct_9fa48("16") ? 2 / Math.PI : (stryCov_9fa48("16"), 2 * Math.PI)) * radius); } }; var untestedFunction = function () { - if (stryMutAct_9fa48(17)) { + if (stryMutAct_9fa48("17")) { {} } else { - stryCov_9fa48(17); - var i = stryMutAct_9fa48(18) ? 5 / 2 / 3 : (stryCov_9fa48(18), (stryMutAct_9fa48(19) ? 5 * 2 : (stryCov_9fa48(19), 5 / 2)) * 3); + stryCov_9fa48("17"); + var i = stryMutAct_9fa48("18") ? 5 / 2 / 3 : (stryCov_9fa48("18"), (stryMutAct_9fa48("19") ? 5 * 2 : (stryCov_9fa48("19"), 5 / 2)) * 3); } }; \ No newline at end of file diff --git a/packages/mocha-runner/test/integration/sample-project-instrumented.it.spec.ts b/packages/mocha-runner/test/integration/sample-project-instrumented.it.spec.ts index 394bc7b114..228c5934bd 100644 --- a/packages/mocha-runner/test/integration/sample-project-instrumented.it.spec.ts +++ b/packages/mocha-runner/test/integration/sample-project-instrumented.it.spec.ts @@ -104,26 +104,26 @@ describe('Running an instrumented project', () => { describe('mutantRun', () => { it('should be able to survive a mutant', async () => { - const result = await sut.mutantRun(factory.mutantRunOptions({ activeMutant: factory.mutant({ id: 0 }) })); + const result = await sut.mutantRun(factory.mutantRunOptions({ activeMutant: factory.mutant({ id: '0' }) })); assertions.expectSurvived(result); }); it('should be able to kill a mutant', async () => { - const result = await sut.mutantRun(factory.mutantRunOptions({ activeMutant: factory.mutant({ id: 3 }) })); + const result = await sut.mutantRun(factory.mutantRunOptions({ activeMutant: factory.mutant({ id: '3' }) })); assertions.expectKilled(result); expect(result.killedBy).eq('MyMath should be able to add two numbers'); expect(result.failureMessage).eq('expected -3 to equal 7'); }); it('should bail after the first failed test', async () => { - const result = await sut.mutantRun(factory.mutantRunOptions({ activeMutant: factory.mutant({ id: 3 }) })); + const result = await sut.mutantRun(factory.mutantRunOptions({ activeMutant: factory.mutant({ id: '3' }) })); assertions.expectKilled(result); expect(result.nrOfTests).eq(1); }); it('should be able to kill a mutant with filtered test', async () => { const result = await sut.mutantRun( - factory.mutantRunOptions({ activeMutant: factory.mutant({ id: 3 }), testFilter: ['MyMath should be able to add two numbers'] }) + factory.mutantRunOptions({ activeMutant: factory.mutant({ id: '3' }), testFilter: ['MyMath should be able to add two numbers'] }) ); assertions.expectKilled(result); expect(result.killedBy).eq('MyMath should be able to add two numbers'); @@ -133,7 +133,7 @@ describe('Running an instrumented project', () => { it('should be able to survive if killer test is not filtered', async () => { const result = await sut.mutantRun( factory.mutantRunOptions({ - activeMutant: factory.mutant({ id: 3 }), + activeMutant: factory.mutant({ id: '3' }), testFilter: ['MyMath should be able negate a number', 'MyMath should be able to recognize a negative number'], }) ); diff --git a/packages/mocha-runner/test/unit/mocha-test-runner.spec.ts b/packages/mocha-runner/test/unit/mocha-test-runner.spec.ts index 3d51bc10ad..1c71035207 100644 --- a/packages/mocha-runner/test/unit/mocha-test-runner.spec.ts +++ b/packages/mocha-runner/test/unit/mocha-test-runner.spec.ts @@ -240,8 +240,8 @@ describe(MochaTestRunner.name, () => { }); it('should active the given mutant', async () => { - await actMutantRun(factory.mutantRunOptions({ activeMutant: factory.mutant({ id: 42 }) })); - expect(global.__stryker2__?.activeMutant).eq(42); + await actMutantRun(factory.mutantRunOptions({ activeMutant: factory.mutant({ id: '42' }) })); + expect(global.__stryker2__?.activeMutant).eq('42'); }); it('should use `grep` to when the test filter is specified', async () => { diff --git a/packages/mocha-runner/testResources/sample-project-instrumented/MyMath.js b/packages/mocha-runner/testResources/sample-project-instrumented/MyMath.js index b3a16ffba3..9fb68947d6 100644 --- a/packages/mocha-runner/testResources/sample-project-instrumented/MyMath.js +++ b/packages/mocha-runner/testResources/sample-project-instrumented/MyMath.js @@ -6,7 +6,7 @@ function stryNS_9fa48() { var ns = g.__stryker2__ || (g.__stryker2__ = {}); if (ns.activeMutant === undefined && g.process && g.process.env && g.process.env.__STRYKER_ACTIVE_MUTANT__) { - ns.activeMutant = Number(g.process.env.__STRYKER_ACTIVE_MUTANT__); + ns.activeMutant = g.process.env.__STRYKER_ACTIVE_MUTANT__; } function retrieveNS() { @@ -55,58 +55,58 @@ function stryMutAct_9fa48(id) { return isActive(id); } -const pi = stryMutAct_9fa48(0) ? 3 - .14 : (stryCov_9fa48(0), 3 + .14); +const pi = stryMutAct_9fa48("0") ? 3 - .14 : (stryCov_9fa48("0"), 3 + .14); function MyMath() { - if (stryMutAct_9fa48(1)) { + if (stryMutAct_9fa48("1")) { {} } else { - stryCov_9fa48(1); + stryCov_9fa48("1"); this.pi = pi; } } MyMath.prototype.add = function (num1, num2) { - if (stryMutAct_9fa48(2)) { + if (stryMutAct_9fa48("2")) { {} } else { - stryCov_9fa48(2); - return stryMutAct_9fa48(3) ? num1 - num2 : (stryCov_9fa48(3), num1 + num2); + stryCov_9fa48("2"); + return stryMutAct_9fa48("3") ? num1 - num2 : (stryCov_9fa48("3"), num1 + num2); } }; MyMath.prototype.addOne = function (number) { - if (stryMutAct_9fa48(4)) { + if (stryMutAct_9fa48("4")) { {} } else { - stryCov_9fa48(4); - stryMutAct_9fa48(5) ? number-- : (stryCov_9fa48(5), number++); + stryCov_9fa48("4"); + stryMutAct_9fa48("5") ? number-- : (stryCov_9fa48("5"), number++); return number; } }; MyMath.prototype.negate = function (number) { - if (stryMutAct_9fa48(6)) { + if (stryMutAct_9fa48("6")) { {} } else { - stryCov_9fa48(6); - return stryMutAct_9fa48(7) ? +number : (stryCov_9fa48(7), -number); + stryCov_9fa48("6"); + return stryMutAct_9fa48("7") ? +number : (stryCov_9fa48("7"), -number); } }; MyMath.prototype.isNegativeNumber = function (number) { - if (stryMutAct_9fa48(8)) { + if (stryMutAct_9fa48("8")) { {} } else { - stryCov_9fa48(8); - var isNegative = stryMutAct_9fa48(9) ? true : (stryCov_9fa48(9), false); + stryCov_9fa48("8"); + var isNegative = stryMutAct_9fa48("9") ? true : (stryCov_9fa48("9"), false); - if (stryMutAct_9fa48(13) ? number >= 0 : stryMutAct_9fa48(12) ? number <= 0 : stryMutAct_9fa48(11) ? false : stryMutAct_9fa48(10) ? true : (stryCov_9fa48(10, 11, 12, 13), number < 0)) { - if (stryMutAct_9fa48(14)) { + if (stryMutAct_9fa48("13") ? number >= 0 : stryMutAct_9fa48("12") ? number <= 0 : stryMutAct_9fa48("11") ? false : stryMutAct_9fa48("10") ? true : (stryCov_9fa48("10", "11", "12", "13"), number < 0)) { + if (stryMutAct_9fa48("14")) { {} } else { - stryCov_9fa48(14); - isNegative = stryMutAct_9fa48(15) ? false : (stryCov_9fa48(15), true); + stryCov_9fa48("14"); + isNegative = stryMutAct_9fa48("15") ? false : (stryCov_9fa48("15"), true); } } diff --git a/packages/test-helpers/package.json b/packages/test-helpers/package.json index 71bf3ff87b..f51eb932fd 100644 --- a/packages/test-helpers/package.json +++ b/packages/test-helpers/package.json @@ -18,7 +18,7 @@ "license": "ISC", "dependencies": { "ajv": "~7.1.0", - "mutation-testing-metrics": "~1.5.2" + "mutation-testing-metrics": "~1.6.2" }, "devDependencies": { "@stryker-mutator/api": "4.5.1", diff --git a/packages/test-helpers/src/factory.ts b/packages/test-helpers/src/factory.ts index d9ea219cef..28aa4a8c71 100644 --- a/packages/test-helpers/src/factory.ts +++ b/packages/test-helpers/src/factory.ts @@ -7,21 +7,15 @@ import { strykerCoreSchema, WarningOptions, Mutant, + MutantTestCoverage, + MutantResult, MutantCoverage, + schema, + MutantStatus, } from '@stryker-mutator/api/core'; import { Logger } from '@stryker-mutator/api/logging'; -import { - MatchedMutant, - MutantStatus, - mutationTestReportSchema, - Reporter, - KilledMutantResult, - InvalidMutantResult, - UndetectedMutantResult, - TimeoutMutantResult, - IgnoredMutantResult, -} from '@stryker-mutator/api/report'; -import { Metrics, MetricsResult } from 'mutation-testing-metrics'; +import { Reporter, SourceFile } from '@stryker-mutator/api/report'; +import { calculateMutationTestMetrics, Metrics, MetricsResult, MutationTestMetricsResult } from 'mutation-testing-metrics'; import sinon from 'sinon'; import { Injector } from 'typed-inject'; import { PluginResolver } from '@stryker-mutator/api/plugin'; @@ -87,75 +81,31 @@ export const warningOptions = factoryMethod(() => ({ preprocessorErrors: true, })); -export const killedMutantResult = factoryMethod(() => ({ - id: '256', - location: location(), - mutatedLines: '', - mutatorName: '', - originalLines: '', - range: [0, 0], - replacement: '', - fileName: 'file.js', - status: MutantStatus.Killed, - killedBy: '', - nrOfTestsRan: 2, -})); -export const timeoutMutantResult = factoryMethod(() => ({ - id: '256', - location: location(), - mutatedLines: '', - mutatorName: '', - originalLines: '', - range: [0, 0], - replacement: '', - fileName: 'file.js', - status: MutantStatus.TimedOut, - nrOfTestsRan: 0, -})); - -export const invalidMutantResult = factoryMethod(() => ({ - id: '256', - location: location(), - mutatedLines: '', - mutatorName: '', - originalLines: '', - range: [0, 0], - replacement: '', - fileName: 'file.js', - status: MutantStatus.RuntimeError, - errorMessage: 'expected error', - nrOfTestsRan: 2, -})); - -export const ignoredMutantResult = factoryMethod(() => ({ - id: '256', - location: location(), - mutatedLines: '', - mutatorName: '', - originalLines: '', - range: [0, 0], - replacement: '', - fileName: 'file.js', - status: MutantStatus.Ignored, - ignoreReason: 'Ignored by "fooMutator" in excludedMutations', - nrOfTestsRan: 2, -})); - -export const undetectedMutantResult = factoryMethod(() => ({ +export const killedMutantResult = (overrides?: Partial>): MutantResult => + mutantResult({ ...overrides, status: MutantStatus.Killed, killedBy: ['45'], testsCompleted: 2 }); +export const timeoutMutantResult = (overrides?: Partial>): MutantResult => + mutantResult({ ...overrides, status: MutantStatus.Timeout, statusReason: 'expected error' }); +export const runtimeErrorMutantResult = (overrides?: Partial>): MutantResult => + mutantResult({ ...overrides, status: MutantStatus.RuntimeError, statusReason: 'expected error' }); +export const ignoredMutantResult = (overrides?: Partial>): MutantResult => + mutantResult({ ...overrides, status: MutantStatus.Ignored, statusReason: 'Ignored by "fooMutator" in excludedMutations' }); +export const noCoverageMutantResult = (overrides?: Partial>): MutantResult => + mutantResult({ ...overrides, status: MutantStatus.NoCoverage }); + +export const mutantResult = factoryMethod(() => ({ id: '256', location: location(), - mutatedLines: '', mutatorName: '', - originalLines: '', range: [0, 0], replacement: '', fileName: 'file.js', - status: MutantStatus.NoCoverage, - testFilter: undefined, - nrOfTestsRan: 2, + status: MutantStatus.Survived, + coveredBy: ['1', '2'], + testsCompleted: 2, + static: false, })); -export const mutationTestReportSchemaMutantResult = factoryMethod(() => ({ +export const mutationTestReportSchemaMutantResult = factoryMethod(() => ({ id: '256', location: location(), mutatedLines: '', @@ -164,17 +114,27 @@ export const mutationTestReportSchemaMutantResult = factoryMethod(() => ({ +export const mutationTestReportSchemaFileResult = factoryMethod(() => ({ language: 'javascript', mutants: [mutationTestReportSchemaMutantResult()], source: 'export function add (a, b) { return a + b; }', })); -export const mutationTestReportSchemaMutationTestResult = factoryMethod(() => ({ +export const mutationTestReportSchemaTestFile = factoryMethod(() => ({ + tests: [], + source: '', +})); + +export const mutationTestReportSchemaTestDefinition = factoryMethod(() => ({ + id: '4', + name: 'foo should be bar', +})); + +export const mutationTestReportSchemaMutationTestResult = factoryMethod(() => ({ files: { 'fileA.js': mutationTestReportSchemaFileResult(), }, @@ -185,8 +145,12 @@ export const mutationTestReportSchemaMutationTestResult = factoryMethod(() => + calculateMutationTestMetrics(mutationTestReportSchemaMutationTestResult()) +); + export const mutant = factoryMethod(() => ({ - id: 42, + id: '42', fileName: 'file', mutatorName: 'foobarMutator', range: [0, 0], @@ -369,14 +333,16 @@ export function reporter(name = 'fooReporter'): sinon.SinonStubbedInstance(() => ({ - testFilter: undefined, +export const mutantTestCoverage = factoryMethod(() => ({ + coveredBy: undefined, fileName: '', id: '1', mutatorName: '', - runAllTests: false, + static: false, replacement: '', - timeSpentScopedTests: 0, + location: location(), + estimatedNetTime: 42, + range: [0, 1], })); export function injector(): sinon.SinonStubbedInstance { @@ -399,6 +365,11 @@ export function file(): File { return new File('', ''); } +export const sourceFile = factoryMethod(() => ({ + content: 'foo.bar()', + path: 'foo.js', +})); + export function fileNotFoundError(): NodeJS.ErrnoException { return createErrnoException('ENOENT'); }