Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added Typescript group checking 🚀 #3900

Merged
merged 101 commits into from
Feb 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
101 commits
Select commit Hold shift + click to select a range
c64665c
Added Graph
ThierryRietveld Oct 28, 2022
67af494
GetAllParentReferences signature
odinvanderlinden Oct 28, 2022
b2b99b4
Begin groups
ThierryRietveld Oct 28, 2022
b63fa01
a
ThierryRietveld Oct 28, 2022
e87e930
getAllParentReferences implementation
odinvanderlinden Oct 28, 2022
804f182
Merge branch 'master' of https://github.com/danny12321/stryker-js-typ…
ThierryRietveld Oct 28, 2022
12048fa
rename of getAllParentReferences + unit tests
odinvanderlinden Oct 28, 2022
bfca8b4
method rename
odinvanderlinden Oct 28, 2022
d2f0c64
Create helpers
ThierryRietveld Oct 28, 2022
45b6200
Merge branch 'master' of https://github.com/danny12321/stryker-js-typ…
ThierryRietveld Oct 28, 2022
21cdb7e
replaced null with empty array
odinvanderlinden Oct 28, 2022
d43dd95
temp mutants
odinvanderlinden Oct 28, 2022
ed962fa
Hier joh
ThierryRietveld Oct 28, 2022
f73714a
Merge branch 'master' of https://github.com/danny12321/stryker-js-typ…
ThierryRietveld Oct 28, 2022
19290fd
Update selectNode to findNode
danny12321 Oct 28, 2022
1a13b31
Merge branch 'master' of https://github.com/danny12321/stryker-js-typ…
danny12321 Oct 28, 2022
a9384ae
halve
ThierryRietveld Oct 28, 2022
c65a41c
Merge branch 'master' of https://github.com/danny12321/stryker-js-typ…
ThierryRietveld Oct 28, 2022
f141542
resolved circular recursion
odinvanderlinden Oct 28, 2022
8821094
Merge branch 'master' of https://github.com/danny12321/stryker-js-typ…
odinvanderlinden Oct 28, 2022
7bebab3
removed not used code
odinvanderlinden Oct 28, 2022
d7eec39
Created createGroups
ThierryRietveld Oct 28, 2022
678c749
Merge branch 'master' of https://github.com/danny12321/stryker-js-typ…
ThierryRietveld Oct 28, 2022
a53120c
Fixed selectNewMutant
ThierryRietveld Oct 28, 2022
c2f801e
Changed ts compiler
danny12321 Oct 28, 2022
13b841b
Merge branch 'master' of https://github.com/danny12321/stryker-js-typ…
danny12321 Oct 28, 2022
1fb2652
WORKING ALGORITHM 🧙‍♂️
odinvanderlinden Oct 28, 2022
9c9fc82
Merge branch 'master' of https://github.com/danny12321/stryker-js-typ…
odinvanderlinden Oct 28, 2022
ffd5c33
Update node
danny12321 Oct 28, 2022
8da5721
Merge branch 'master' of https://github.com/danny12321/stryker-js-typ…
danny12321 Oct 28, 2022
0a60518
implemented check function
odinvanderlinden Oct 28, 2022
e066733
Merge branch 'master' of https://github.com/danny12321/stryker-js-typ…
odinvanderlinden Oct 28, 2022
300e3ec
getFileRelationsAsNodes rename
odinvanderlinden Oct 28, 2022
6b025fb
refacoted ts compiler
danny12321 Oct 29, 2022
dfad8cb
Commands and code style
ThierryRietveld Oct 29, 2022
60a8971
Add command
ThierryRietveld Oct 29, 2022
c2becbc
Merge branch 'master' of https://github.com/danny12321/stryker-js-typ…
danny12321 Oct 29, 2022
40c8723
Refactored group mutants
ThierryRietveld Oct 29, 2022
8279015
Changes
danny12321 Oct 29, 2022
a82638a
Merge branch 'master' of https://github.com/danny12321/stryker-js-typ…
danny12321 Oct 29, 2022
c1763e9
ding
ThierryRietveld Oct 29, 2022
f09a3f9
Added debug
danny12321 Oct 29, 2022
d5365cb
Merge branch 'master' of https://github.com/danny12321/stryker-js-typ…
danny12321 Oct 29, 2022
0389531
Using maps instead of arrays 🚀
danny12321 Nov 11, 2022
f05bb94
Changed ts retry
danny12321 Nov 11, 2022
2a5d5bf
Merge remote-tracking branch 'upstream/master'
danny12321 Nov 11, 2022
01fa25e
create-group tests now use maps
odinvanderlinden Dec 4, 2022
457e913
Changes
Dec 9, 2022
58ecb08
Changes
Dec 9, 2022
b882213
Merge branch 'master' of https://github.com/danny12321/stryker-js-typ…
Dec 9, 2022
5834a4a
comments to clarify
odinvanderlinden Dec 9, 2022
93cf60f
extra node.ts tests
odinvanderlinden Dec 9, 2022
b09326e
Fixed typo in comment
Dec 9, 2022
a5481d5
more node.ts tests
odinvanderlinden Dec 9, 2022
d103d88
Fixed typescript-helpers tests
Dec 9, 2022
f76c473
Merge branch 'master' of https://github.com/danny12321/stryker-js-typ…
odinvanderlinden Dec 9, 2022
245dd16
removed test.only
Dec 9, 2022
1b25634
Simplify grouping alorithm
nicojs Dec 13, 2022
8019a49
Fixed some tests
Dec 23, 2022
b6b5dae
Merge branch 'master' of https://github.com/danny12321/stryker-js-typ…
Dec 23, 2022
cba4567
Merge pull request #1 from stryker-mutator/feat/simpler-grouping-algo…
danny12321 Dec 23, 2022
ba38fc3
change addAll to addRangeOfNodesToSet
Dec 23, 2022
730ad3d
fixed tests
Dec 23, 2022
35feb9d
Changed grouping mutants outside of the project
Dec 23, 2022
9fd6e48
Changed back to posixFileName
Dec 23, 2022
7f551b0
pr suggestions + ts checker strategy option
odinvanderlinden Dec 23, 2022
8f98a03
Merge branch 'master' of https://github.com/danny12321/stryker-js-typ…
odinvanderlinden Dec 23, 2022
fe3875d
multiple tests
odinvanderlinden Dec 23, 2022
1fcc250
typo
odinvanderlinden Dec 23, 2022
47fe4ee
Merge branch 'master' of https://github.com/danny12321/stryker-js-typ…
odinvanderlinden Jan 3, 2023
f1caccb
Clarification with comments + some refactoring
odinvanderlinden Jan 3, 2023
62ce278
fix test
odinvanderlinden Jan 3, 2023
2da1fc6
revert options setup removal
odinvanderlinden Jan 3, 2023
98d44ed
Merge branch 'master' of https://github.com/danny12321/stryker-js-typ…
odinvanderlinden Jan 3, 2023
3522d45
Update packages/typescript-checker/src/fs/script-file.ts
danny12321 Jan 5, 2023
75386e4
Update packages/typescript-checker/schema/typescript-checker-options.…
danny12321 Jan 5, 2023
bf6dda7
Update packages/typescript-checker/src/typescript-checker.ts
danny12321 Jan 6, 2023
5b209c5
Update packages/typescript-checker/test/unit/grouping/create-groups.s…
danny12321 Jan 6, 2023
f1c10d2
Fixed typo's
danny12321 Jan 6, 2023
9ae598c
Merge branch 'master' of https://github.com/danny12321/stryker-js-typ…
danny12321 Jan 6, 2023
9b33db4
Fix typo
danny12321 Jan 6, 2023
f9f0c3d
Fixed some comments
danny12321 Jan 6, 2023
73f049c
Fixed typo in comment
danny12321 Jan 6, 2023
605a583
Updated declaration test
danny12321 Jan 6, 2023
2d8ce3c
Fixed PR comments
danny12321 Jan 20, 2023
0a26a2d
Fix conflicts
danny12321 Jan 20, 2023
14e430c
Change info log to debug log
danny12321 Jan 20, 2023
afa479e
Fixed default options
danny12321 Jan 20, 2023
236b310
Added prioritizePerformanceOverAccuracy option to read me
danny12321 Jan 20, 2023
3ead12a
Removed structuredClone from tests
danny12321 Jan 20, 2023
eaaf158
Changed [Tt]ypeScript to [Tt]ypescript
danny12321 Jan 20, 2023
68fcdbf
Removed unnecessary init in test
danny12321 Jan 20, 2023
2f04be8
refactor(split): mutant array by iterating once
nicojs Jan 23, 2023
4029df7
feat(log): correctly log the groupsize
nicojs Jan 23, 2023
51e08f4
Add unit tests for the typescript checker
nicojs Jan 25, 2023
c550517
fix: don't create empty groups
nicojs Jan 25, 2023
8642187
Fixed findSourceMapRegex and added project reference test
danny12321 Feb 2, 2023
8b82423
Fix broken test
danny12321 Feb 2, 2023
0a38a7e
Changed testResource
danny12321 Feb 3, 2023
4a1316a
Added ts-project-references e2e tests
danny12321 Feb 10, 2023
7bccbd6
Added .snap for typescript-project-references
danny12321 Feb 10, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion docs/typescript-checker.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,10 @@ You can configure the typescript checker in the `stryker.conf.js` (or `stryker.c
```json
{
"checkers": ["typescript"],
"tsconfigFile": "tsconfig.json"
"tsconfigFile": "tsconfig.json",
"typeScriptChecker": {
"prioritizePerformanceOverAccuracy": true
}
}
```

Expand All @@ -52,6 +55,12 @@ _Note: the following compiler options are always overridden by @stryker-mutator/
}
```

### `typeScriptChecker.prioritizePerformanceOverAccuracy` [`boolean`]

Default: `true`

Sets the performance strategy for the typescript-checker. Defaults to `true` which the fastest strategy with the consequence of losing some accuracy. The accuracy that is lost comes down to having mutants with a status other than `CompileError` while they should have this status. This result in a report that may not be 100% accurate. Setting this option to `false` results in an accurate report but may take (way) longer.

## Peer dependencies

The `@stryker-mutator/typescript-checker` package for `stryker` to enable `typescript` support. As such, you should make sure you have the correct versions of its dependencies installed:
Expand Down
24 changes: 24 additions & 0 deletions e2e/test/typescript-project-references/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"name": "typescript-project-references",
"version": "0.0.0",
"private": true,
"description": "A module to perform an integration test",
"main": "index.js",
"scripts": {
"clean": "rimraf dist",
"prebuild": "npm run clean",
"build": "tsc -b tsconfig.json",
"pretest:unit": "npm run build",
"test:unit": "mocha",
"pretest": "rimraf \"reports\" \"dist\" \"stryker.log\"",
"test": "stryker run",
"posttest": "mocha --no-config --no-package --timeout 0 verify/verify.js"
},
"mocha": {
"spec": [
"test/**/*.js"
]
},
"author": "",
"license": "ISC"
}
5 changes: 5 additions & 0 deletions e2e/test/typescript-project-references/src/core/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { count } from '../utils/math.js';

export function countArrayLength(todo: any[]): number {
return count(todo);
}
7 changes: 7 additions & 0 deletions e2e/test/typescript-project-references/src/core/job.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { toUpperCase } from '../utils/text.js';

export function start(): string {
const logText = "Starting job";
console.log(toUpperCase(logText));
return logText;
}
9 changes: 9 additions & 0 deletions e2e/test/typescript-project-references/src/core/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"extends": "../../tsconfig.settings",
"compilerOptions": {
"outDir": "../dist/src"
},
"references": [
{ "path": "../utils" }
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"program":{"fileNames":["../../../../node_modules/typescript/lib/lib.d.ts","../../../../node_modules/typescript/lib/lib.es5.d.ts","../../../../node_modules/typescript/lib/lib.dom.d.ts","../../../../node_modules/typescript/lib/lib.webworker.importscripts.d.ts","../../../../node_modules/typescript/lib/lib.scripthost.d.ts","./index.ts","./job.ts"],"fileInfos":["2dc8c927c9c162a773c6bb3cdc4f3286c23f10eedc67414028f9cb5951610f60",{"version":"f20c05dbfe50a208301d2a1da37b9931bce0466eb5a1f4fe240971b4ecc82b67","affectsGlobalScope":true},{"version":"9b087de7268e4efc5f215347a62656663933d63c0b1d7b624913240367b999ea","affectsGlobalScope":true},{"version":"7fac8cb5fc820bc2a59ae11ef1c5b38d3832c6d0dfaec5acdb5569137d09a481","affectsGlobalScope":true},{"version":"097a57355ded99c68e6df1b738990448e0bf170e606707df5a7c0481ff2427cd","affectsGlobalScope":true},{"version":"c9b6bdd48b8bdb8d8e7690c7cc18897a494b6ab17dc58083dacfaf14b846ab4f","signature":"40b6409b8d0dced1f6c3964012b7a7c1cd50e24c3242095d1c8cfc6cabe8bd31"},{"version":"e4c28c497fe6cc6364b113c181c32ba58e70f02d824295e72b15d9570b403104","signature":"9be66c79f48b4876970daed5167e069d7f12f1a1ca616ecaa0ca8280946344ca"}],"options":{"composite":true,"declaration":true,"declarationMap":true,"module":1,"noUnusedLocals":true,"noUnusedParameters":true,"strict":true,"target":1},"referencedMap":[],"exportedModulesMap":[],"semanticDiagnosticsPerFile":[1,3,2,5,4],"changeFileSet":[6,7],"latestChangedDtsFile":"./job.d.ts"},"version":"4.8.4"}
3 changes: 3 additions & 0 deletions e2e/test/typescript-project-references/src/utils/math.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export function count(array: any[]) {
return array.length;
}
3 changes: 3 additions & 0 deletions e2e/test/typescript-project-references/src/utils/text.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export function toUpperCase(text: string) {
return text.toUpperCase();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"extends": "../../tsconfig.settings",
"compilerOptions": {
"outDir": "../dist/utils",
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"program":{"fileNames":["../../../../node_modules/typescript/lib/lib.d.ts","../../../../node_modules/typescript/lib/lib.es5.d.ts","../../../../node_modules/typescript/lib/lib.dom.d.ts","../../../../node_modules/typescript/lib/lib.webworker.importscripts.d.ts","../../../../node_modules/typescript/lib/lib.scripthost.d.ts","./math.ts","./text.ts"],"fileInfos":["2dc8c927c9c162a773c6bb3cdc4f3286c23f10eedc67414028f9cb5951610f60",{"version":"f20c05dbfe50a208301d2a1da37b9931bce0466eb5a1f4fe240971b4ecc82b67","affectsGlobalScope":true},{"version":"9b087de7268e4efc5f215347a62656663933d63c0b1d7b624913240367b999ea","affectsGlobalScope":true},{"version":"7fac8cb5fc820bc2a59ae11ef1c5b38d3832c6d0dfaec5acdb5569137d09a481","affectsGlobalScope":true},{"version":"097a57355ded99c68e6df1b738990448e0bf170e606707df5a7c0481ff2427cd","affectsGlobalScope":true},{"version":"6198e7d4a43aabb174a72ec9f0e8d2962912ad59ad90010aac3930868a8f62a4","signature":"0400cb85cef49e897c47df13e38b5cd199e0c900253f2d2ddf2e3491c27bc0a8"},{"version":"becd081df112726ab94c1ca1c05d6a59268fe0dabf7ad076d16ea851bf99e8fb","signature":"6039d94241358544e8d62a3a0ba90752a9973b3b2b422c187e2bcf7256fcda2e"}],"options":{"composite":true,"declaration":true,"declarationMap":true,"module":1,"noUnusedLocals":true,"noUnusedParameters":true,"strict":true,"target":1},"referencedMap":[],"exportedModulesMap":[],"semanticDiagnosticsPerFile":[6,7,1,3,2,5,4],"latestChangedDtsFile":"./text.d.ts"},"version":"4.8.4"}
17 changes: 17 additions & 0 deletions e2e/test/typescript-project-references/stryker.conf.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"$schema": "../../node_modules/@stryker-mutator/core/schema/stryker-schema.json",
"packageManager": "npm",
"disableTypeChecks": true,
"testRunner": "mocha",
"concurrency": 1,
"coverageAnalysis": "perTest",
"reporters": ["json", "html", "progress", "clear-text"],
"checkers": ["typescript"],
"tsconfigFile": "src/core/tsconfig.json",
"fileLogLevel": "warn",
"buildCommand": "npm run build",
"plugins": [
"@stryker-mutator/mocha-runner",
"@stryker-mutator/typescript-checker"
]
}
12 changes: 12 additions & 0 deletions e2e/test/typescript-project-references/test/job.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { expect } from 'chai';
import {start} from '../src/core/job';

describe(start.name, () => {
it('should format a correct message', () => {
// Act
const result = start();

// Assert
expect(result).eq("Starting job");
});
});
3 changes: 3 additions & 0 deletions e2e/test/typescript-project-references/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"include": ["src/core", "src/utils", "test"]
}
17 changes: 17 additions & 0 deletions e2e/test/typescript-project-references/tsconfig.settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"compilerOptions": {
"strict": true,
"target": "es5",
"moduleResolution": "node",
"module": "commonjs",
"composite": true,
"declaration": true,
"declarationMap": true,

// These settings should be overridden by the typescript checker
"noUnusedLocals": true,
"noUnusedParameters": true,

"types": []
}
}
3 changes: 3 additions & 0 deletions e2e/test/typescript-project-references/verify/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"type": "module"
}
7 changes: 7 additions & 0 deletions e2e/test/typescript-project-references/verify/verify.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { expectMetricsJsonToMatchSnapshot } from '../../../helpers.js';

describe('Verify stryker has ran correctly', () => {
it('should report correct score', async () => {
await expectMetricsJsonToMatchSnapshot();
});
});
21 changes: 21 additions & 0 deletions e2e/test/typescript-project-references/verify/verify.js.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`Verify stryker has ran correctly should report correct score 1`] = `
Object {
"compileErrors": 3,
"ignored": 0,
"killed": 1,
"mutationScore": 33.33333333333333,
"mutationScoreBasedOnCoveredCode": 33.33333333333333,
"noCoverage": 0,
"runtimeErrors": 0,
"survived": 2,
"timeout": 0,
"totalCovered": 3,
"totalDetected": 1,
"totalInvalid": 3,
"totalMutants": 6,
"totalUndetected": 2,
"totalValid": 3,
}
`;
20 changes: 18 additions & 2 deletions packages/typescript-checker/.vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,24 @@
{
"type": "node",
"request": "launch",
"name": "💙 Unit / Integration tests",
"name": "💙 Unit tests",
"program": "${workspaceRoot}/../../node_modules/mocha/bin/_mocha",
"internalConsoleOptions": "openOnSessionStart",
"outFiles": [
"${workspaceRoot}/dist/**/*.js"
],
"skipFiles": [
"<node_internals>/**"
],
"args": [
"--no-timeout",
"dist/test/unit/**/*.js",
]
},
{
"type": "node",
"request": "launch",
"name": "💙 Integration tests",
"program": "${workspaceRoot}/../../node_modules/mocha/bin/_mocha",
"internalConsoleOptions": "openOnSessionStart",
"outFiles": [
Expand All @@ -15,7 +32,6 @@
],
"args": [
"--no-timeout",
"dist/test/unit/**/*.js",
"dist/test/integration/**/*.js"
]
}
Expand Down
22 changes: 22 additions & 0 deletions packages/typescript-checker/schema/typescript-checker-options.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"$schema": "http://json-schema.org/draft-07/schema",
"title": "TypescriptCheckerPluginOptions",
"type": "object",
"additionalProperties": false,
"properties": {
"typescriptChecker": {
"description": "Configuration for @stryker-mutator/typescript-checker",
"title": "TypescriptCheckerOptions",
"additionalProperties": false,
"type": "object",
"default": {},
"properties": {
"prioritizePerformanceOverAccuracy": {
"description": "Configures the performance of the TypescriptChecker. Setting this to false results in a slower, but more accurate result.",
"type": "boolean",
"default": true
}
}
}
}
}
15 changes: 0 additions & 15 deletions packages/typescript-checker/src/fs/hybrid-file-system.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import ts from 'typescript';
import { Mutant } from '@stryker-mutator/api/core';
import { Logger } from '@stryker-mutator/api/logging';
import { tokens, commonTokens } from '@stryker-mutator/api/plugin';

Expand All @@ -16,7 +15,6 @@ import { ScriptFile } from './script-file.js';
*/
export class HybridFileSystem {
private readonly files = new Map<string, ScriptFile | undefined>();
private mutatedFile: ScriptFile | undefined;

public static inject = tokens(commonTokens.logger);
constructor(private readonly log: Logger) {}
Expand All @@ -32,19 +30,6 @@ export class HybridFileSystem {
}
}

public mutate(mutant: Pick<Mutant, 'fileName' | 'location' | 'replacement'>): void {
const fileName = toPosixFileName(mutant.fileName);
const file = this.files.get(fileName);
if (!file) {
throw new Error(`File "${mutant.fileName}" cannot be found.`);
}
if (this.mutatedFile && this.mutatedFile !== file) {
this.mutatedFile.resetMutant();
}
file.mutate(mutant);
this.mutatedFile = file;
}

public watchFile(fileName: string, watcher: ts.FileWatcherCallback): void {
const file = this.getFile(fileName);
if (file) {
Expand Down
2 changes: 1 addition & 1 deletion packages/typescript-checker/src/fs/script-file.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export class ScriptFile {
}
}

private touch() {
private touch(): void {
this.modifiedTime = new Date();
this.watcher?.(this.fileName, ts.FileWatcherEventKind.Changed);
}
Expand Down
89 changes: 89 additions & 0 deletions packages/typescript-checker/src/grouping/create-groups.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import { Mutant } from '@stryker-mutator/api/src/core/index.js';

import { toPosixFileName } from '../tsconfig-helpers.js';

import { TSFileNode } from './ts-file-node.js';

/**
* To speed up the type-checking we want to check multiple mutants at once.
* When multiple mutants in different files don't have overlap in affected files (or have small overlap), we can type-check them simultaneously.
* These mutants who can be tested at the same time are called a group.
* Therefore, the return type is an array of arrays, in other words: an array of groups.
*
* @param mutants All the mutants of the test project.
* @param nodes A graph representation of the test project.
*
* @example
* Let's assume we got the following dependencies in files of a project, and in every file is one mutant.
*
* ========
* = A.ts =
* ========
* / \
* ======== ========
* = B.ts = = C.ts =
* ======== ========
* \
* ========
* = D.ts =
* ========
*
* A imports B and C
* C imports D
*
* In this example, we can type-check B and D simultaneously.
* This is because these files can't throw errors in each other.
* If we type check them, let's say B reports an error.
* We know that the mutant in B created the type error.
* If we type check B and D at the same time, it is possible that an error shows up in A.
* When this happens, we go down the dependency graph and individually test the mutants in that group.
*
* In this function, we create groups of mutants who can be tested at the same time.
*/
export function createGroups(mutants: Mutant[], nodes: Map<string, TSFileNode>): string[][] {
const groups: string[][] = [];
const mutantsToGroup = new Set(mutants);

while (mutantsToGroup.size) {
const group: string[] = [];
const groupNodes = new Set<TSFileNode>();
const nodesToIgnore = new Set<TSFileNode>();

for (const currentMutant of mutantsToGroup) {
const currentNode = findNode(currentMutant.fileName, nodes);
if (!nodesToIgnore.has(currentNode) && !parentsHaveOverlapWith(currentNode, groupNodes)) {
group.push(currentMutant.id);
groupNodes.add(currentNode);
mutantsToGroup.delete(currentMutant);
addRangeOfNodesToSet(nodesToIgnore, currentNode.getAllParentReferencesIncludingSelf());
}
}
groups.push(group);
}

return groups;
}

function addRangeOfNodesToSet(nodes: Set<TSFileNode>, nodesToAdd: Iterable<TSFileNode>) {
for (const parent of nodesToAdd) {
nodes.add(parent);
}
}

function findNode(fileName: string, nodes: Map<string, TSFileNode>) {
const node = nodes.get(toPosixFileName(fileName));
if (node == null) {
throw new Error(`Node not in graph: ${fileName}`);
}
return node;
}

function parentsHaveOverlapWith(currentNode: TSFileNode, groupNodes: Set<TSFileNode>) {
for (const parentNode of currentNode.getAllParentReferencesIncludingSelf()) {
if (groupNodes.has(parentNode)) {
return true;
}
}

return false;
}
Loading