From 2ac7e13fe689f913169bf7b199da1bf01daf6218 Mon Sep 17 00:00:00 2001 From: maks-rafalko Date: Mon, 13 Dec 2021 10:30:53 +0300 Subject: [PATCH 1/8] Introduce HTML report (by using Stryker Elements) --- infection.json | 3 +- report.json | 3330 ++++++++++++++++ resources/mutation-testing-report-schema.json | 353 ++ resources/schema.json | 6 +- src/Configuration/Entry/Logs.php | 9 + .../Schema/SchemaConfigurationFactory.php | 1 + src/Container.php | 12 +- src/Logger/FileLoggerFactory.php | 16 +- src/Logger/Html/HtmlFileLogger.php | 79 + src/Logger/Html/StrykerHtmlReportBuilder.php | 324 ++ .../TargetDetectionStatusesProvider.php | 7 + src/Mutant/MutantExecutionResult.php | 73 +- src/Mutant/MutantExecutionResultFactory.php | 7 +- src/Mutation/Mutation.php | 17 + stryker-report.html | 3353 +++++++++++++++++ tests/e2e/Example_Test/infection.json | 3 +- tests/e2e/Example_Test/src/SourceClass.php | 4 + .../Example_Test/tests/SourceClassTest.php | 8 + .../Configuration/ConfigurationAssertions.php | 1 + .../ConfigurationFactoryTest.php | 2 + .../Configuration/ConfigurationTest.php | 1 + .../Configuration/Entry/LogsAssertions.php | 2 + .../phpunit/Configuration/Entry/LogsTest.php | 6 + .../Schema/SchemaConfigurationFactoryTest.php | 40 + .../Schema/SchemaConfigurationTest.php | 1 + tests/phpunit/Fixtures/EmptyClass.php | 12 + .../phpunit/Logger/BadgeLoggerFactoryTest.php | 4 + .../Logger/CreateMetricsCalculator.php | 7 +- .../phpunit/Logger/FileLoggerFactoryTest.php | 30 +- .../Html/StrykerHtmlReportBuilderTest.php | 191 + .../Metrics/CreateMutantExecutionResult.php | 7 +- .../SortableMutantExecutionResultsTest.php | 7 +- .../Mutant/MutantExecutionResultTest.php | 11 +- 33 files changed, 7912 insertions(+), 15 deletions(-) create mode 100644 report.json create mode 100644 resources/mutation-testing-report-schema.json create mode 100644 src/Logger/Html/HtmlFileLogger.php create mode 100644 src/Logger/Html/StrykerHtmlReportBuilder.php create mode 100644 stryker-report.html create mode 100644 tests/phpunit/Fixtures/EmptyClass.php create mode 100644 tests/phpunit/Logger/Html/StrykerHtmlReportBuilderTest.php diff --git a/infection.json b/infection.json index 789682b19..b2fc6725c 100644 --- a/infection.json +++ b/infection.json @@ -9,7 +9,8 @@ "logs": { "badge": { "branch": "master" - } + }, + "html": "infection.html" }, "mutators": { "global-ignoreSourceCodeByRegex": [ diff --git a/report.json b/report.json new file mode 100644 index 000000000..2719cab5f --- /dev/null +++ b/report.json @@ -0,0 +1,3330 @@ +{ + "files": { + "/home/nicojs/github/stryker-js/packages/util/src/deep-merge.ts": { + "language": "typescript", + "mutants": [ + { + "id": "3", + "mutatorName": "ConditionalExpression", + "replacement": "true", + "statusReason": "expected { foo: undefined } to deeply equal { foo: '1' }", + "status": "Killed", + "estimatedNetTime": 3, + "hitCount": 5, + "static": false, + "testsCompleted": 4, + "killedBy": ["4"], + "coveredBy": ["1", "2", "3", "4"], + "location": { "end": { "column": 36, "line": 14 }, "start": { "column": 9, "line": 14 } } + }, + { + "id": "2", + "mutatorName": "BlockStatement", + "replacement": "{}", + "statusReason": "expected { foo: 'bar' } to deeply equal { foo: 'bar', baz: 42 }", + "status": "Killed", + "estimatedNetTime": 3, + "hitCount": 5, + "static": false, + "testsCompleted": 1, + "killedBy": ["1"], + "coveredBy": ["1", "2", "3", "4"], + "location": { "end": { "column": 4, "line": 21 }, "start": { "column": 43, "line": 11 } } + }, + { + "id": "1", + "mutatorName": "BlockStatement", + "replacement": "{}", + "statusReason": "expected { foo: 'bar' } to deeply equal { foo: 'bar', baz: 42 }", + "status": "Killed", + "estimatedNetTime": 3, + "hitCount": 5, + "static": false, + "testsCompleted": 1, + "killedBy": ["1"], + "coveredBy": ["1", "2", "3", "4"], + "location": { "end": { "column": 2, "line": 22 }, "start": { "column": 76, "line": 10 } } + }, + { + "id": "4", + "mutatorName": "ConditionalExpression", + "replacement": "false", + "statusReason": "expected { foo: 'bar' } to deeply equal { foo: 'bar', baz: 42 }", + "status": "Killed", + "estimatedNetTime": 3, + "hitCount": 5, + "static": false, + "testsCompleted": 1, + "killedBy": ["1"], + "coveredBy": ["1", "2", "3", "4"], + "location": { "end": { "column": 36, "line": 14 }, "start": { "column": 9, "line": 14 } } + }, + { + "id": "6", + "mutatorName": "BlockStatement", + "replacement": "{}", + "statusReason": "expected { foo: 'bar' } to deeply equal { foo: 'bar', baz: 42 }", + "status": "Killed", + "estimatedNetTime": 2, + "hitCount": 4, + "static": false, + "testsCompleted": 1, + "killedBy": ["1"], + "coveredBy": ["1", "2", "3"], + "location": { "end": { "column": 6, "line": 20 }, "start": { "column": 38, "line": 14 } } + }, + { + "id": "7", + "mutatorName": "ConditionalExpression", + "replacement": "true", + "statusReason": "expected { child: { baz: 42 } } to deeply equal { child: { foo: 'child', baz: 42 } }", + "status": "Killed", + "estimatedNetTime": 2, + "hitCount": 4, + "static": false, + "testsCompleted": 2, + "killedBy": ["2"], + "coveredBy": ["1", "2", "3"], + "location": { "end": { "column": 141, "line": 15 }, "start": { "column": 11, "line": 15 } } + }, + { + "id": "8", + "mutatorName": "ConditionalExpression", + "replacement": "false", + "statusReason": "expected { foo: 'bar' } to deeply equal { foo: 'bar', baz: 42 }", + "status": "Killed", + "estimatedNetTime": 2, + "hitCount": 4, + "static": false, + "testsCompleted": 1, + "killedBy": ["1"], + "coveredBy": ["1", "2", "3"], + "location": { "end": { "column": 141, "line": 15 }, "start": { "column": 11, "line": 15 } } + }, + { + "id": "9", + "mutatorName": "LogicalOperator", + "replacement": "(defaultValue === undefined || typeof defaultValue !== 'object' || typeof overrideValue !== 'object') && Array.isArray(defaultValue)", + "statusReason": "expected { foo: 'bar' } to deeply equal { foo: 'bar', baz: 42 }", + "status": "Killed", + "estimatedNetTime": 2, + "hitCount": 4, + "static": false, + "testsCompleted": 1, + "killedBy": ["1"], + "coveredBy": ["1", "2", "3"], + "location": { "end": { "column": 141, "line": 15 }, "start": { "column": 11, "line": 15 } } + }, + { + "id": "10", + "mutatorName": "ConditionalExpression", + "replacement": "true", + "statusReason": "expected { child: { baz: 42 } } to deeply equal { child: { foo: 'child', baz: 42 } }", + "status": "Killed", + "estimatedNetTime": 2, + "hitCount": 4, + "static": false, + "testsCompleted": 2, + "killedBy": ["2"], + "coveredBy": ["1", "2", "3"], + "location": { "end": { "column": 110, "line": 15 }, "start": { "column": 11, "line": 15 } } + }, + { + "id": "5", + "mutatorName": "EqualityOperator", + "replacement": "overrideValue === undefined", + "statusReason": "expected { foo: 'bar' } to deeply equal { foo: 'bar', baz: 42 }", + "status": "Killed", + "estimatedNetTime": 3, + "hitCount": 5, + "static": false, + "testsCompleted": 1, + "killedBy": ["1"], + "coveredBy": ["1", "2", "3", "4"], + "location": { "end": { "column": 36, "line": 14 }, "start": { "column": 9, "line": 14 } } + }, + { + "id": "11", + "mutatorName": "ConditionalExpression", + "replacement": "false", + "statusReason": "expected { foo: 'bar' } to deeply equal { foo: 'bar', baz: 42 }", + "status": "Killed", + "estimatedNetTime": 2, + "hitCount": 4, + "static": false, + "testsCompleted": 1, + "killedBy": ["1"], + "coveredBy": ["1", "2", "3"], + "location": { "end": { "column": 110, "line": 15 }, "start": { "column": 11, "line": 15 } } + }, + { + "id": "12", + "mutatorName": "LogicalOperator", + "replacement": "(defaultValue === undefined || typeof defaultValue !== 'object') && typeof overrideValue !== 'object'", + "status": "Survived", + "estimatedNetTime": 2, + "hitCount": 4, + "static": false, + "testsCompleted": 3, + "coveredBy": ["1", "2", "3"], + "location": { "end": { "column": 110, "line": 15 }, "start": { "column": 11, "line": 15 } } + }, + { + "id": "13", + "mutatorName": "ConditionalExpression", + "replacement": "true", + "statusReason": "expected { child: { baz: 42 } } to deeply equal { child: { foo: 'child', baz: 42 } }", + "status": "Killed", + "estimatedNetTime": 2, + "hitCount": 4, + "static": false, + "testsCompleted": 2, + "killedBy": ["2"], + "coveredBy": ["1", "2", "3"], + "location": { "end": { "column": 73, "line": 15 }, "start": { "column": 11, "line": 15 } } + }, + { + "id": "14", + "mutatorName": "ConditionalExpression", + "replacement": "false", + "status": "Survived", + "estimatedNetTime": 2, + "hitCount": 4, + "static": false, + "testsCompleted": 3, + "coveredBy": ["1", "2", "3"], + "location": { "end": { "column": 73, "line": 15 }, "start": { "column": 11, "line": 15 } } + }, + { + "id": "15", + "mutatorName": "LogicalOperator", + "replacement": "defaultValue === undefined && typeof defaultValue !== 'object'", + "status": "Survived", + "estimatedNetTime": 2, + "hitCount": 4, + "static": false, + "testsCompleted": 3, + "coveredBy": ["1", "2", "3"], + "location": { "end": { "column": 73, "line": 15 }, "start": { "column": 11, "line": 15 } } + }, + { + "id": "16", + "mutatorName": "ConditionalExpression", + "replacement": "true", + "statusReason": "expected { child: { baz: 42 } } to deeply equal { child: { foo: 'child', baz: 42 } }", + "status": "Killed", + "estimatedNetTime": 2, + "hitCount": 4, + "static": false, + "testsCompleted": 2, + "killedBy": ["2"], + "coveredBy": ["1", "2", "3"], + "location": { "end": { "column": 37, "line": 15 }, "start": { "column": 11, "line": 15 } } + }, + { + "id": "17", + "mutatorName": "ConditionalExpression", + "replacement": "false", + "status": "Survived", + "estimatedNetTime": 2, + "hitCount": 4, + "static": false, + "testsCompleted": 3, + "coveredBy": ["1", "2", "3"], + "location": { "end": { "column": 37, "line": 15 }, "start": { "column": 11, "line": 15 } } + }, + { + "id": "18", + "mutatorName": "EqualityOperator", + "replacement": "defaultValue !== undefined", + "statusReason": "expected { child: { baz: 42 } } to deeply equal { child: { foo: 'child', baz: 42 } }", + "status": "Killed", + "estimatedNetTime": 2, + "hitCount": 4, + "static": false, + "testsCompleted": 2, + "killedBy": ["2"], + "coveredBy": ["1", "2", "3"], + "location": { "end": { "column": 37, "line": 15 }, "start": { "column": 11, "line": 15 } } + }, + { + "id": "19", + "mutatorName": "ConditionalExpression", + "replacement": "true", + "statusReason": "expected { child: { baz: 42 } } to deeply equal { child: { foo: 'child', baz: 42 } }", + "status": "Killed", + "estimatedNetTime": 0, + "hitCount": 2, + "static": false, + "testsCompleted": 1, + "killedBy": ["2"], + "coveredBy": ["2", "3"], + "location": { "end": { "column": 73, "line": 15 }, "start": { "column": 41, "line": 15 } } + }, + { + "id": "22", + "mutatorName": "StringLiteral", + "replacement": "\"\"", + "statusReason": "src/deep-merge.ts(15,41): error TS2367: This condition will always return 'true' since the types '\"string\" | \"number\" | \"bigint\" | \"boolean\" | \"symbol\" | \"undefined\" | \"object\" | \"function\"' and '\"\"' have no overlap.\n", + "status": "CompileError", + "estimatedNetTime": 0, + "hitCount": 2, + "static": false, + "coveredBy": ["2", "3"], + "location": { "end": { "column": 73, "line": 15 }, "start": { "column": 65, "line": 15 } } + }, + { + "id": "20", + "mutatorName": "ConditionalExpression", + "replacement": "false", + "status": "Survived", + "estimatedNetTime": 0, + "hitCount": 2, + "static": false, + "testsCompleted": 2, + "coveredBy": ["2", "3"], + "location": { "end": { "column": 73, "line": 15 }, "start": { "column": 41, "line": 15 } } + }, + { + "id": "21", + "mutatorName": "EqualityOperator", + "replacement": "typeof defaultValue === 'object'", + "statusReason": "expected { child: { baz: 42 } } to deeply equal { child: { foo: 'child', baz: 42 } }", + "status": "Killed", + "estimatedNetTime": 0, + "hitCount": 2, + "static": false, + "testsCompleted": 1, + "killedBy": ["2"], + "coveredBy": ["2", "3"], + "location": { "end": { "column": 73, "line": 15 }, "start": { "column": 41, "line": 15 } } + }, + { + "id": "23", + "mutatorName": "ConditionalExpression", + "replacement": "true", + "statusReason": "expected { child: { baz: 42 } } to deeply equal { child: { foo: 'child', baz: 42 } }", + "status": "Killed", + "estimatedNetTime": 0, + "hitCount": 2, + "static": false, + "testsCompleted": 1, + "killedBy": ["2"], + "coveredBy": ["2", "3"], + "location": { "end": { "column": 110, "line": 15 }, "start": { "column": 77, "line": 15 } } + }, + { + "id": "26", + "mutatorName": "StringLiteral", + "replacement": "\"\"", + "statusReason": "src/deep-merge.ts(15,77): error TS2367: This condition will always return 'true' since the types '\"string\" | \"number\" | \"bigint\" | \"boolean\" | \"symbol\" | \"undefined\" | \"object\" | \"function\"' and '\"\"' have no overlap.\n", + "status": "CompileError", + "estimatedNetTime": 0, + "hitCount": 2, + "static": false, + "coveredBy": ["2", "3"], + "location": { "end": { "column": 110, "line": 15 }, "start": { "column": 102, "line": 15 } } + }, + { + "id": "25", + "mutatorName": "EqualityOperator", + "replacement": "typeof overrideValue === 'object'", + "statusReason": "expected { child: { baz: 42 } } to deeply equal { child: { foo: 'child', baz: 42 } }", + "status": "Killed", + "estimatedNetTime": 0, + "hitCount": 2, + "static": false, + "testsCompleted": 1, + "killedBy": ["2"], + "coveredBy": ["2", "3"], + "location": { "end": { "column": 110, "line": 15 }, "start": { "column": 77, "line": 15 } } + }, + { + "id": "24", + "mutatorName": "ConditionalExpression", + "replacement": "false", + "status": "Survived", + "estimatedNetTime": 0, + "hitCount": 2, + "static": false, + "testsCompleted": 2, + "coveredBy": ["2", "3"], + "location": { "end": { "column": 110, "line": 15 }, "start": { "column": 77, "line": 15 } } + }, + { + "id": "27", + "mutatorName": "BlockStatement", + "replacement": "{}", + "statusReason": "expected { foo: 'bar' } to deeply equal { foo: 'bar', baz: 42 }", + "status": "Killed", + "estimatedNetTime": 2, + "hitCount": 3, + "static": false, + "testsCompleted": 1, + "killedBy": ["1"], + "coveredBy": ["1", "2", "3"], + "location": { "end": { "column": 8, "line": 17 }, "start": { "column": 143, "line": 15 } } + }, + { + "id": "28", + "mutatorName": "BlockStatement", + "replacement": "{}", + "statusReason": "expected { child: { foo: 'child' } } to deeply equal { child: { foo: 'child', baz: 42 } }", + "status": "Killed", + "estimatedNetTime": 0, + "hitCount": 1, + "static": false, + "testsCompleted": 1, + "killedBy": ["2"], + "coveredBy": ["2"], + "location": { "end": { "column": 8, "line": 19 }, "start": { "column": 14, "line": 17 } } + } + ], + "source": "export type DeepPartial = {\n [P in keyof T]?: T[P] extends Record ? DeepPartial : T[P];\n};\n\n/**\n *\n * @param defaults\n * @param overrides\n */\nexport function deepMerge(defaults: T, overrides: DeepPartial): void {\n Object.keys(overrides).forEach((key) => {\n const defaultValue = (defaults as any)[key];\n const overrideValue = (overrides as any)[key];\n if (overrideValue !== undefined) {\n if (defaultValue === undefined || typeof defaultValue !== 'object' || typeof overrideValue !== 'object' || Array.isArray(defaultValue)) {\n (defaults as any)[key] = overrideValue;\n } else {\n deepMerge(defaultValue, overrideValue as DeepPartial);\n }\n }\n });\n}\n" + }, + "/home/nicojs/github/stryker-js/packages/util/src/child-process-as-promised.ts": { + "language": "typescript", + "mutants": [ + { + "id": "0", + "mutatorName": "ObjectLiteral", + "replacement": "{}", + "statusReason": "test/unit/child-process-as-promised.spec.ts(11,35): error TS2339: Property 'exec' does not exist on type '{}'.\n", + "status": "CompileError", + "estimatedNetTime": 73, + "hitCount": 1, + "static": true, + "location": { "end": { "column": 2, "line": 6 }, "start": { "column": 39, "line": 4 } } + } + ], + "source": "import * as childProcess from 'child_process';\nimport { promisify } from 'util';\n\nexport const childProcessAsPromised = {\n exec: promisify(childProcess.exec),\n};\n" + }, + "/home/nicojs/github/stryker-js/packages/util/src/directory-require-cache.ts": { + "language": "typescript", + "mutants": [ + { + "id": "29", + "mutatorName": "BlockStatement", + "replacement": "{}", + "statusReason": "expected { Object (exports, children, ...) } to be undefined", + "status": "Killed", + "estimatedNetTime": 23, + "hitCount": 12, + "static": false, + "testsCompleted": 1, + "killedBy": ["5"], + "coveredBy": ["5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15"], + "location": { "end": { "column": 4, "line": 43 }, "start": { "column": 25, "line": 22 } } + }, + { + "id": "30", + "mutatorName": "BooleanLiteral", + "replacement": "this.cache", + "statusReason": "expected { Object (exports, children, ...) } to be undefined", + "status": "Killed", + "estimatedNetTime": 23, + "hitCount": 12, + "static": false, + "testsCompleted": 1, + "killedBy": ["5"], + "coveredBy": ["5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15"], + "location": { "end": { "column": 20, "line": 23 }, "start": { "column": 9, "line": 23 } } + }, + { + "id": "31", + "mutatorName": "ConditionalExpression", + "replacement": "true", + "statusReason": "expected undefined not to be undefined", + "status": "Killed", + "estimatedNetTime": 23, + "hitCount": 12, + "static": false, + "testsCompleted": 2, + "killedBy": ["6"], + "coveredBy": ["5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15"], + "location": { "end": { "column": 20, "line": 23 }, "start": { "column": 9, "line": 23 } } + }, + { + "id": "32", + "mutatorName": "ConditionalExpression", + "replacement": "false", + "statusReason": "expected { Object (exports, children, ...) } to be undefined", + "status": "Killed", + "estimatedNetTime": 23, + "hitCount": 12, + "static": false, + "testsCompleted": 1, + "killedBy": ["5"], + "coveredBy": ["5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15"], + "location": { "end": { "column": 20, "line": 23 }, "start": { "column": 9, "line": 23 } } + }, + { + "id": "33", + "mutatorName": "BlockStatement", + "replacement": "{}", + "statusReason": "expected { Object (exports, children, ...) } to be undefined", + "status": "Killed", + "estimatedNetTime": 23, + "hitCount": 11, + "static": false, + "testsCompleted": 1, + "killedBy": ["5"], + "coveredBy": ["5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15"], + "location": { "end": { "column": 6, "line": 42 }, "start": { "column": 22, "line": 23 } } + }, + { + "id": "34", + "mutatorName": "ArrowFunction", + "replacement": "() => undefined", + "statusReason": "expected { Object (exports, children, ...) } to be undefined", + "status": "Killed", + "estimatedNetTime": 23, + "hitCount": 11, + "static": false, + "testsCompleted": 10, + "killedBy": ["14"], + "coveredBy": ["5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15"], + "location": { "end": { "column": 134, "line": 26 }, "start": { "column": 41, "line": 26 } } + }, + { + "id": "35", + "mutatorName": "ArrowFunction", + "replacement": "() => undefined", + "statusReason": "expected { Object (exports, children, ...) } to be undefined", + "status": "Killed", + "estimatedNetTime": 23, + "hitCount": 11, + "static": false, + "testsCompleted": 1, + "killedBy": ["5"], + "coveredBy": ["5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15"], + "location": { "end": { "column": 104, "line": 27 }, "start": { "column": 39, "line": 27 } } + }, + { + "id": "36", + "mutatorName": "ArrowFunction", + "replacement": "() => undefined", + "statusReason": "expected { Object (exports, children, ...) } to be undefined", + "status": "Killed", + "estimatedNetTime": 23, + "hitCount": 11, + "static": false, + "testsCompleted": 1, + "killedBy": ["5"], + "coveredBy": ["5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15"], + "location": { "end": { "column": 129, "line": 30 }, "start": { "column": 17, "line": 30 } } + }, + { + "id": "37", + "mutatorName": "ConditionalExpression", + "replacement": "true", + "statusReason": "expected undefined to equal 'baz'", + "status": "Killed", + "estimatedNetTime": 23, + "hitCount": 14611, + "static": false, + "testsCompleted": 1, + "killedBy": ["5"], + "coveredBy": ["5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15"], + "location": { "end": { "column": 129, "line": 30 }, "start": { "column": 31, "line": 30 } } + }, + { + "id": "38", + "mutatorName": "ConditionalExpression", + "replacement": "false", + "statusReason": "expected { Object (exports, children, ...) } to be undefined", + "status": "Killed", + "estimatedNetTime": 23, + "hitCount": 14611, + "static": false, + "testsCompleted": 1, + "killedBy": ["5"], + "coveredBy": ["5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15"], + "location": { "end": { "column": 129, "line": 30 }, "start": { "column": 31, "line": 30 } } + }, + { + "id": "39", + "mutatorName": "LogicalOperator", + "replacement": "startsWith(fileName, `${cwd}${path.sep}`) || !startsWith(fileName, path.join(cwd, 'node_modules'))", + "statusReason": "expected undefined to equal 'baz'", + "status": "Killed", + "estimatedNetTime": 23, + "hitCount": 14611, + "static": false, + "testsCompleted": 1, + "killedBy": ["5"], + "coveredBy": ["5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15"], + "location": { "end": { "column": 129, "line": 30 }, "start": { "column": 31, "line": 30 } } + }, + { + "id": "40", + "mutatorName": "StringLiteral", + "replacement": "``", + "statusReason": "expected undefined to equal 'baz'", + "status": "Killed", + "estimatedNetTime": 23, + "hitCount": 14611, + "static": false, + "testsCompleted": 1, + "killedBy": ["5"], + "coveredBy": ["5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15"], + "location": { "end": { "column": 71, "line": 30 }, "start": { "column": 52, "line": 30 } } + }, + { + "id": "41", + "mutatorName": "BooleanLiteral", + "replacement": "startsWith(fileName, path.join(cwd, 'node_modules'))", + "statusReason": "expected { Object (exports, children, ...) } to be undefined", + "status": "Killed", + "estimatedNetTime": 23, + "hitCount": 19, + "static": false, + "testsCompleted": 1, + "killedBy": ["5"], + "coveredBy": ["5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15"], + "location": { "end": { "column": 129, "line": 30 }, "start": { "column": 76, "line": 30 } } + }, + { + "id": "44", + "mutatorName": "ArrowFunction", + "replacement": "() => undefined", + "statusReason": "src/directory-require-cache.ts(33,7): error TS2322: Type 'Set' is not assignable to type 'Set'.\n Type 'undefined' is not assignable to type 'string'.\nsrc/directory-require-cache.ts(40,50): error TS2345: Argument of type 'undefined' is not assignable to parameter of type 'string'.\n", + "status": "CompileError", + "estimatedNetTime": 23, + "hitCount": 11, + "static": false, + "coveredBy": ["5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15"], + "location": { "end": { "column": 71, "line": 37 }, "start": { "column": 16, "line": 37 } } + }, + { + "id": "42", + "mutatorName": "StringLiteral", + "replacement": "\"\"", + "statusReason": "expected { Object (exports, children, ...) } to be undefined", + "status": "Killed", + "estimatedNetTime": 23, + "hitCount": 19, + "static": false, + "testsCompleted": 1, + "killedBy": ["5"], + "coveredBy": ["5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15"], + "location": { "end": { "column": 127, "line": 30 }, "start": { "column": 113, "line": 30 } } + }, + { + "id": "45", + "mutatorName": "OptionalChaining", + "replacement": "require.cache[fileName]?.parent.filename", + "statusReason": "src/directory-require-cache.ts(37,30): error TS2533: Object is possibly 'null' or 'undefined'.\n", + "status": "CompileError", + "estimatedNetTime": 23, + "hitCount": 18, + "static": false, + "coveredBy": ["5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15"], + "location": { "end": { "column": 71, "line": 37 }, "start": { "column": 30, "line": 37 } } + }, + { + "id": "46", + "mutatorName": "OptionalChaining", + "replacement": "require.cache[fileName].parent", + "statusReason": "src/directory-require-cache.ts(37,30): error TS2532: Object is possibly 'undefined'.\n", + "status": "CompileError", + "estimatedNetTime": 23, + "hitCount": 18, + "static": false, + "coveredBy": ["5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15"], + "location": { "end": { "column": 61, "line": 37 }, "start": { "column": 30, "line": 37 } } + }, + { + "id": "43", + "mutatorName": "ArrowFunction", + "replacement": "() => undefined", + "statusReason": "Attempted to wrap cwd which is already wrapped", + "status": "Killed", + "estimatedNetTime": 23, + "hitCount": 11, + "static": false, + "testsCompleted": 1, + "killedBy": ["5"], + "coveredBy": ["5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15"], + "location": { "end": { "column": 43, "line": 31 }, "start": { "column": 18, "line": 31 } } + }, + { + "id": "47", + "mutatorName": "ArrowFunction", + "replacement": "() => undefined", + "statusReason": "expected [ Array(2) ] to have a length of 1 but got 2", + "status": "Killed", + "estimatedNetTime": 23, + "hitCount": 11, + "static": false, + "testsCompleted": 2, + "killedBy": ["6"], + "coveredBy": ["5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15"], + "location": { "end": { "column": 65, "line": 40 }, "start": { "column": 19, "line": 40 } } + }, + { + "id": "50", + "mutatorName": "ConditionalExpression", + "replacement": "true", + "statusReason": "src/directory-require-cache.ts(48,7): error TS2532: Object is possibly 'undefined'.\nsrc/directory-require-cache.ts(51,82): error TS2532: Object is possibly 'undefined'.\nsrc/directory-require-cache.ts(54,7): error TS2532: Object is possibly 'undefined'.\n", + "status": "CompileError", + "estimatedNetTime": 23, + "hitCount": 11, + "static": false, + "coveredBy": ["5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15"], + "location": { "end": { "column": 35, "line": 46 }, "start": { "column": 9, "line": 46 } } + }, + { + "id": "48", + "mutatorName": "BooleanLiteral", + "replacement": "cache.has(parentFileName)", + "statusReason": "Attempted to wrap cwd which is already wrapped", + "status": "Killed", + "estimatedNetTime": 19, + "hitCount": 14, + "static": false, + "testsCompleted": 1, + "killedBy": ["5"], + "coveredBy": ["5", "6", "7", "8", "9", "10", "11", "12"], + "location": { "end": { "column": 65, "line": 40 }, "start": { "column": 39, "line": 40 } } + }, + { + "id": "49", + "mutatorName": "BlockStatement", + "replacement": "{}", + "statusReason": "Attempted to wrap cwd which is already wrapped", + "status": "Killed", + "estimatedNetTime": 23, + "hitCount": 11, + "static": false, + "testsCompleted": 1, + "killedBy": ["5"], + "coveredBy": ["5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15"], + "location": { "end": { "column": 4, "line": 56 }, "start": { "column": 24, "line": 45 } } + }, + { + "id": "51", + "mutatorName": "ConditionalExpression", + "replacement": "false", + "statusReason": "src/directory-require-cache.ts(48,7): error TS2532: Object is possibly 'undefined'.\nsrc/directory-require-cache.ts(51,82): error TS2532: Object is possibly 'undefined'.\nsrc/directory-require-cache.ts(54,7): error TS2532: Object is possibly 'undefined'.\n", + "status": "CompileError", + "estimatedNetTime": 23, + "hitCount": 11, + "static": false, + "coveredBy": ["5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15"], + "location": { "end": { "column": 35, "line": 46 }, "start": { "column": 9, "line": 46 } } + }, + { + "id": "52", + "mutatorName": "LogicalOperator", + "replacement": "this.cache || this.parents", + "statusReason": "src/directory-require-cache.ts(48,7): error TS2532: Object is possibly 'undefined'.\nsrc/directory-require-cache.ts(51,82): error TS2532: Object is possibly 'undefined'.\nsrc/directory-require-cache.ts(54,7): error TS2532: Object is possibly 'undefined'.\n", + "status": "CompileError", + "estimatedNetTime": 23, + "hitCount": 11, + "static": false, + "coveredBy": ["5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15"], + "location": { "end": { "column": 35, "line": 46 }, "start": { "column": 9, "line": 46 } } + }, + { + "id": "55", + "mutatorName": "ConditionalExpression", + "replacement": "true", + "statusReason": "src/directory-require-cache.ts(51,11): error TS2532: Object is possibly 'undefined'.\nsrc/directory-require-cache.ts(51,35): error TS2532: Object is possibly 'undefined'.\n", + "status": "CompileError", + "estimatedNetTime": 19, + "hitCount": 9, + "static": false, + "coveredBy": ["5", "6", "7", "8", "9", "10", "11", "12"], + "location": { "end": { "column": 25, "line": 50 }, "start": { "column": 13, "line": 50 } } + }, + { + "id": "56", + "mutatorName": "ConditionalExpression", + "replacement": "false", + "statusReason": "src/directory-require-cache.ts(51,11): error TS2532: Object is possibly 'undefined'.\nsrc/directory-require-cache.ts(51,35): error TS2532: Object is possibly 'undefined'.\n", + "status": "CompileError", + "estimatedNetTime": 19, + "hitCount": 9, + "static": false, + "coveredBy": ["5", "6", "7", "8", "9", "10", "11", "12"], + "location": { "end": { "column": 25, "line": 50 }, "start": { "column": 13, "line": 50 } } + }, + { + "id": "54", + "mutatorName": "BlockStatement", + "replacement": "{}", + "statusReason": "Attempted to wrap cwd which is already wrapped", + "status": "Killed", + "estimatedNetTime": 19, + "hitCount": 9, + "static": false, + "testsCompleted": 1, + "killedBy": ["5"], + "coveredBy": ["5", "6", "7", "8", "9", "10", "11", "12"], + "location": { "end": { "column": 8, "line": 53 }, "start": { "column": 40, "line": 48 } } + }, + { + "id": "53", + "mutatorName": "BlockStatement", + "replacement": "{}", + "statusReason": "expected { Object (exports, children, ...) } to be undefined", + "status": "Killed", + "estimatedNetTime": 23, + "hitCount": 11, + "static": false, + "testsCompleted": 1, + "killedBy": ["5"], + "coveredBy": ["5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15"], + "location": { "end": { "column": 6, "line": 55 }, "start": { "column": 37, "line": 46 } } + }, + { + "id": "57", + "mutatorName": "BlockStatement", + "replacement": "{}", + "statusReason": "Attempted to wrap cwd which is already wrapped", + "status": "Killed", + "estimatedNetTime": 18, + "hitCount": 8, + "static": false, + "testsCompleted": 1, + "killedBy": ["5"], + "coveredBy": ["5", "6", "7", "8", "9", "11", "12"], + "location": { "end": { "column": 10, "line": 52 }, "start": { "column": 27, "line": 50 } } + }, + { + "id": "58", + "mutatorName": "ArrowFunction", + "replacement": "() => undefined", + "statusReason": "Attempted to wrap cwd which is already wrapped", + "status": "Killed", + "estimatedNetTime": 18, + "hitCount": 8, + "static": false, + "testsCompleted": 1, + "killedBy": ["5"], + "coveredBy": ["5", "6", "7", "8", "9", "11", "12"], + "location": { "end": { "column": 107, "line": 51 }, "start": { "column": 64, "line": 51 } } + }, + { + "id": "59", + "mutatorName": "BooleanLiteral", + "replacement": "cache.has(childModule.id)", + "statusReason": "expected [ Array(2) ] to have a length of 1 but got 2", + "status": "Killed", + "estimatedNetTime": 18, + "hitCount": 14, + "static": false, + "testsCompleted": 3, + "killedBy": ["7"], + "coveredBy": ["5", "6", "7", "8", "9", "11", "12"], + "location": { "end": { "column": 107, "line": 51 }, "start": { "column": 81, "line": 51 } } + }, + { + "id": "60", + "mutatorName": "ArrowFunction", + "replacement": "() => undefined", + "statusReason": "Attempted to wrap cwd which is already wrapped", + "status": "Killed", + "estimatedNetTime": 23, + "hitCount": 11, + "static": false, + "testsCompleted": 1, + "killedBy": ["5"], + "coveredBy": ["5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15"], + "location": { "end": { "column": 65, "line": 54 }, "start": { "column": 21, "line": 54 } } + } + ], + "source": "import path from 'path';\n\nimport { notEmpty } from './not-empty';\nimport { caseSensitiveFs } from './platform';\n\n/**\n * A helper class that can be used by test runners.\n * The first time you call `record`, it will fill the internal registry with the files required in the current working directory (excluding node_modules)\n * Then each time you call `clear` it will clear those files from the require cache\n *\n * It will also delete the `module.children` property of the root module.\n * @see https://github.com/stryker-mutator/stryker-js/issues/2461\n */\nexport class DirectoryRequireCache {\n private cache: Set | undefined;\n private parents: Set | undefined;\n\n /**\n * Records the files required in the current working directory (excluding node_modules)\n * Only does so the first time, any subsequent calls will be ignored\n */\n public record(): void {\n if (!this.cache) {\n const cache = (this.cache = new Set());\n const cwd = process.cwd();\n const startsWithCaseInsensitive = (filename: string, prefix: string) => filename.toLowerCase().startsWith(prefix.toLowerCase());\n const startsWithCaseSensitive = (filename: string, prefix: string) => filename.startsWith(prefix);\n const startsWith = caseSensitiveFs() ? startsWithCaseSensitive : startsWithCaseInsensitive;\n Object.keys(require.cache)\n .filter((fileName) => startsWith(fileName, `${cwd}${path.sep}`) && !startsWith(fileName, path.join(cwd, 'node_modules')))\n .forEach((file) => cache.add(file));\n\n this.parents = new Set(\n Array.from(cache)\n // `module.parent` is deprecated, but seems to work fine, might never be removed.\n // See https://nodejs.org/api/modules.html#modules_module_parent\n .map((fileName) => require.cache[fileName]?.parent?.filename)\n .filter(notEmpty)\n // Filter out any parents that are in the current cache, since they will be removed anyway\n .filter((parentFileName) => !cache.has(parentFileName))\n );\n }\n }\n\n public clear(): void {\n if (this.cache && this.parents) {\n const cache = this.cache;\n this.parents.forEach((parent) => {\n const parentModule = require.cache[parent];\n if (parentModule) {\n parentModule.children = parentModule.children.filter((childModule) => !cache.has(childModule.id));\n }\n });\n cache.forEach((fileName) => delete require.cache[fileName]);\n }\n }\n}\n" + }, + "/home/nicojs/github/stryker-js/packages/util/src/errors.ts": { + "language": "typescript", + "mutants": [ + { + "id": "61", + "mutatorName": "BlockStatement", + "replacement": "{}", + "statusReason": "src/errors.ts(1,51): error TS2355: A function whose declared type is neither 'void' nor 'any' must return a value.\n", + "status": "CompileError", + "estimatedNetTime": 10, + "hitCount": 6, + "static": false, + "coveredBy": ["17", "18", "19", "101", "102"], + "location": { "end": { "column": 2, "line": 3 }, "start": { "column": 82, "line": 1 } } + }, + { + "id": "62", + "mutatorName": "ConditionalExpression", + "replacement": "true", + "statusReason": "expected 'Error: undefined (undefined) Error: expected error\\n at Context. (/home/nicojs/github/stryker-js/packages/util/.stryker-tmp/sandbox8696228/test/unit/errors.spec.ts:24:21)\\n at callFn (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runnable.js:366:21)\\n at Test.Runnable.run (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runnable.js:354:5)\\n at Runner.runTest (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:681:10)\\n at /home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:804:12\\n at next (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:596:14)\\n at /home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:606:7\\n at next (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:489:14)\\n at Immediate._onImmediate (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:574:5)\\n at processImmediate (internal/timers.js:464:21)' to equal 'Error: expected error\\nError: expected error\\n at Context. (/home/nicojs/github/stryker-js/packages/util/.stryker-tmp/sandbox8696228/test/unit/errors.spec.ts:24:21)\\n at callFn (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runnable.js:366:21)\\n at Test.Runnable.run (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runnable.js:354:5)\\n at Runner.runTest (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:681:10)\\n at /home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:804:12\\n at next (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:596:14)\\n at /home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:606:7\\n at next (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:489:14)\\n at Immediate._onImmediate (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:574:5)\\n at processImmediate (internal/timers.js:464:21)'", + "status": "Killed", + "estimatedNetTime": 10, + "hitCount": 6, + "static": false, + "testsCompleted": 2, + "killedBy": ["18"], + "coveredBy": ["17", "18", "19", "101", "102"], + "location": { "end": { "column": 93, "line": 2 }, "start": { "column": 10, "line": 2 } } + }, + { + "id": "63", + "mutatorName": "ConditionalExpression", + "replacement": "false", + "statusReason": "expected 'name: message\\nqux' to equal 'name: foo (baz) qux'", + "status": "Killed", + "estimatedNetTime": 10, + "hitCount": 6, + "static": false, + "testsCompleted": 1, + "killedBy": ["17"], + "coveredBy": ["17", "18", "19", "101", "102"], + "location": { "end": { "column": 93, "line": 2 }, "start": { "column": 10, "line": 2 } } + }, + { + "id": "64", + "mutatorName": "LogicalOperator", + "replacement": "error instanceof Error || typeof (error as NodeJS.ErrnoException).code === 'string'", + "statusReason": "expected 'Error: undefined (undefined) Error: expected error\\n at Context. (/home/nicojs/github/stryker-js/packages/util/.stryker-tmp/sandbox8696228/test/unit/errors.spec.ts:24:21)\\n at callFn (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runnable.js:366:21)\\n at Test.Runnable.run (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runnable.js:354:5)\\n at Runner.runTest (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:681:10)\\n at /home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:804:12\\n at next (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:596:14)\\n at /home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:606:7\\n at next (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:489:14)\\n at Immediate._onImmediate (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:574:5)\\n at processImmediate (internal/timers.js:464:21)' to equal 'Error: expected error\\nError: expected error\\n at Context. (/home/nicojs/github/stryker-js/packages/util/.stryker-tmp/sandbox8696228/test/unit/errors.spec.ts:24:21)\\n at callFn (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runnable.js:366:21)\\n at Test.Runnable.run (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runnable.js:354:5)\\n at Runner.runTest (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:681:10)\\n at /home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:804:12\\n at next (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:596:14)\\n at /home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:606:7\\n at next (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:489:14)\\n at Immediate._onImmediate (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:574:5)\\n at processImmediate (internal/timers.js:464:21)'", + "status": "Killed", + "estimatedNetTime": 10, + "hitCount": 6, + "static": false, + "testsCompleted": 2, + "killedBy": ["18"], + "coveredBy": ["17", "18", "19", "101", "102"], + "location": { "end": { "column": 93, "line": 2 }, "start": { "column": 10, "line": 2 } } + }, + { + "id": "65", + "mutatorName": "ConditionalExpression", + "replacement": "true", + "statusReason": "expected 'Error: undefined (undefined) Error: expected error\\n at Context. (/home/nicojs/github/stryker-js/packages/util/.stryker-tmp/sandbox8696228/test/unit/errors.spec.ts:24:21)\\n at callFn (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runnable.js:366:21)\\n at Test.Runnable.run (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runnable.js:354:5)\\n at Runner.runTest (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:681:10)\\n at /home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:804:12\\n at next (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:596:14)\\n at /home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:606:7\\n at next (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:489:14)\\n at Immediate._onImmediate (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:574:5)\\n at processImmediate (internal/timers.js:464:21)' to equal 'Error: expected error\\nError: expected error\\n at Context. (/home/nicojs/github/stryker-js/packages/util/.stryker-tmp/sandbox8696228/test/unit/errors.spec.ts:24:21)\\n at callFn (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runnable.js:366:21)\\n at Test.Runnable.run (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runnable.js:354:5)\\n at Runner.runTest (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:681:10)\\n at /home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:804:12\\n at next (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:596:14)\\n at /home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:606:7\\n at next (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:489:14)\\n at Immediate._onImmediate (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:574:5)\\n at processImmediate (internal/timers.js:464:21)'", + "status": "Killed", + "estimatedNetTime": 10, + "hitCount": 6, + "static": false, + "testsCompleted": 2, + "killedBy": ["18"], + "coveredBy": ["17", "18", "19", "101", "102"], + "location": { "end": { "column": 93, "line": 2 }, "start": { "column": 36, "line": 2 } } + }, + { + "id": "68", + "mutatorName": "StringLiteral", + "replacement": "\"\"", + "statusReason": "src/errors.ts(2,36): error TS2367: This condition will always return 'false' since the types '\"string\" | \"number\" | \"bigint\" | \"boolean\" | \"symbol\" | \"undefined\" | \"object\" | \"function\"' and '\"\"' have no overlap.\n", + "status": "CompileError", + "estimatedNetTime": 10, + "hitCount": 6, + "static": false, + "coveredBy": ["17", "18", "19", "101", "102"], + "location": { "end": { "column": 93, "line": 2 }, "start": { "column": 85, "line": 2 } } + }, + { + "id": "66", + "mutatorName": "ConditionalExpression", + "replacement": "false", + "statusReason": "expected 'name: message\\nqux' to equal 'name: foo (baz) qux'", + "status": "Killed", + "estimatedNetTime": 10, + "hitCount": 6, + "static": false, + "testsCompleted": 1, + "killedBy": ["17"], + "coveredBy": ["17", "18", "19", "101", "102"], + "location": { "end": { "column": 93, "line": 2 }, "start": { "column": 36, "line": 2 } } + }, + { + "id": "69", + "mutatorName": "BlockStatement", + "replacement": "{}", + "statusReason": "src/errors.ts(6,44): error TS2355: A function whose declared type is neither 'void' nor 'any' must return a value.\n", + "status": "CompileError", + "estimatedNetTime": 10, + "hitCount": 7, + "static": false, + "coveredBy": ["16", "17", "18", "19", "101", "102"], + "location": { "end": { "column": 2, "line": 22 }, "start": { "column": 51, "line": 6 } } + }, + { + "id": "67", + "mutatorName": "EqualityOperator", + "replacement": "typeof (error as NodeJS.ErrnoException).code !== 'string'", + "statusReason": "expected 'name: message\\nqux' to equal 'name: foo (baz) qux'", + "status": "Killed", + "estimatedNetTime": 10, + "hitCount": 6, + "static": false, + "testsCompleted": 1, + "killedBy": ["17"], + "coveredBy": ["17", "18", "19", "101", "102"], + "location": { "end": { "column": 93, "line": 2 }, "start": { "column": 36, "line": 2 } } + }, + { + "id": "70", + "mutatorName": "BooleanLiteral", + "replacement": "error", + "statusReason": "Cannot read property 'toString' of undefined", + "status": "Killed", + "estimatedNetTime": 10, + "hitCount": 7, + "static": false, + "testsCompleted": 1, + "killedBy": ["16"], + "coveredBy": ["16", "17", "18", "19", "101", "102"], + "location": { "end": { "column": 13, "line": 7 }, "start": { "column": 7, "line": 7 } } + }, + { + "id": "71", + "mutatorName": "ConditionalExpression", + "replacement": "true", + "statusReason": "expected '' to equal 'name: foo (baz) qux'", + "status": "Killed", + "estimatedNetTime": 10, + "hitCount": 7, + "static": false, + "testsCompleted": 2, + "killedBy": ["17"], + "coveredBy": ["16", "17", "18", "19", "101", "102"], + "location": { "end": { "column": 13, "line": 7 }, "start": { "column": 7, "line": 7 } } + }, + { + "id": "73", + "mutatorName": "BlockStatement", + "replacement": "{}", + "statusReason": "Cannot read property 'toString' of undefined", + "status": "Killed", + "estimatedNetTime": 0, + "hitCount": 1, + "static": false, + "testsCompleted": 1, + "killedBy": ["16"], + "coveredBy": ["16"], + "location": { "end": { "column": 4, "line": 9 }, "start": { "column": 15, "line": 7 } } + }, + { + "id": "72", + "mutatorName": "ConditionalExpression", + "replacement": "false", + "statusReason": "Cannot read property 'toString' of undefined", + "status": "Killed", + "estimatedNetTime": 10, + "hitCount": 7, + "static": false, + "testsCompleted": 1, + "killedBy": ["16"], + "coveredBy": ["16", "17", "18", "19", "101", "102"], + "location": { "end": { "column": 13, "line": 7 }, "start": { "column": 7, "line": 7 } } + }, + { + "id": "74", + "mutatorName": "StringLiteral", + "replacement": "\"Stryker was here!\"", + "statusReason": "expected 'Stryker was here!' to equal ''", + "status": "Killed", + "estimatedNetTime": 0, + "hitCount": 1, + "static": false, + "testsCompleted": 1, + "killedBy": ["16"], + "coveredBy": ["16"], + "location": { "end": { "column": 14, "line": 8 }, "start": { "column": 12, "line": 8 } } + }, + { + "id": "75", + "mutatorName": "ConditionalExpression", + "replacement": "true", + "status": "Survived", + "estimatedNetTime": 10, + "hitCount": 6, + "static": false, + "testsCompleted": 5, + "coveredBy": ["17", "18", "19", "101", "102"], + "location": { "end": { "column": 29, "line": 10 }, "start": { "column": 7, "line": 10 } } + }, + { + "id": "76", + "mutatorName": "ConditionalExpression", + "replacement": "false", + "statusReason": "expected 'name: message' to equal 'name: foo (baz) qux'", + "status": "Killed", + "estimatedNetTime": 10, + "hitCount": 6, + "static": false, + "testsCompleted": 1, + "killedBy": ["17"], + "coveredBy": ["17", "18", "19", "101", "102"], + "location": { "end": { "column": 29, "line": 10 }, "start": { "column": 7, "line": 10 } } + }, + { + "id": "77", + "mutatorName": "BlockStatement", + "replacement": "{}", + "statusReason": "expected 'name: message' to equal 'name: foo (baz) qux'", + "status": "Killed", + "estimatedNetTime": 10, + "hitCount": 6, + "static": false, + "testsCompleted": 1, + "killedBy": ["17"], + "coveredBy": ["17", "18", "19", "101", "102"], + "location": { "end": { "column": 4, "line": 20 }, "start": { "column": 31, "line": 10 } } + }, + { + "id": "78", + "mutatorName": "ConditionalExpression", + "replacement": "true", + "statusReason": "src/errors.ts(12,38): error TS2339: Property 'code' does not exist on type 'Error'.\nsrc/errors.ts(12,53): error TS2339: Property 'syscall' does not exist on type 'Error'.\n", + "status": "CompileError", + "estimatedNetTime": 10, + "hitCount": 6, + "static": false, + "coveredBy": ["17", "18", "19", "101", "102"], + "location": { "end": { "column": 32, "line": 11 }, "start": { "column": 9, "line": 11 } } + }, + { + "id": "79", + "mutatorName": "ConditionalExpression", + "replacement": "false", + "statusReason": "expected 'name: message\\nqux' to equal 'name: foo (baz) qux'", + "status": "Killed", + "estimatedNetTime": 10, + "hitCount": 6, + "static": false, + "testsCompleted": 1, + "killedBy": ["17"], + "coveredBy": ["17", "18", "19", "101", "102"], + "location": { "end": { "column": 32, "line": 11 }, "start": { "column": 9, "line": 11 } } + }, + { + "id": "80", + "mutatorName": "BlockStatement", + "replacement": "{}", + "statusReason": "expected 'name: message\\nqux' to equal 'name: foo (baz) qux'", + "status": "Killed", + "estimatedNetTime": 1, + "hitCount": 1, + "static": false, + "testsCompleted": 1, + "killedBy": ["17"], + "coveredBy": ["17"], + "location": { "end": { "column": 6, "line": 13 }, "start": { "column": 34, "line": 11 } } + }, + { + "id": "81", + "mutatorName": "StringLiteral", + "replacement": "``", + "statusReason": "expected '' to equal 'name: foo (baz) qux'", + "status": "Killed", + "estimatedNetTime": 1, + "hitCount": 1, + "static": false, + "testsCompleted": 1, + "killedBy": ["17"], + "coveredBy": ["17"], + "location": { "end": { "column": 78, "line": 12 }, "start": { "column": 14, "line": 12 } } + }, + { + "id": "82", + "mutatorName": "StringLiteral", + "replacement": "``", + "statusReason": "expected '\\nError: expected error\\n at Context. (/home/nicojs/github/stryker-js/packages/util/.stryker-tmp/sandbox8696228/test/unit/errors.spec.ts:24:21)\\n at callFn (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runnable.js:366:21)\\n at Test.Runnable.run (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runnable.js:354:5)\\n at Runner.runTest (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:681:10)\\n at /home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:804:12\\n at next (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:596:14)\\n at /home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:606:7\\n at next (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:489:14)\\n at Immediate._onImmediate (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:574:5)\\n at processImmediate (internal/timers.js:464:21)' to equal 'Error: expected error\\nError: expected error\\n at Context. (/home/nicojs/github/stryker-js/packages/util/.stryker-tmp/sandbox8696228/test/unit/errors.spec.ts:24:21)\\n at callFn (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runnable.js:366:21)\\n at Test.Runnable.run (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runnable.js:354:5)\\n at Runner.runTest (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:681:10)\\n at /home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:804:12\\n at next (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:596:14)\\n at /home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:606:7\\n at next (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:489:14)\\n at Immediate._onImmediate (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:574:5)\\n at processImmediate (internal/timers.js:464:21)'", + "status": "Killed", + "estimatedNetTime": 9, + "hitCount": 5, + "static": false, + "testsCompleted": 1, + "killedBy": ["18"], + "coveredBy": ["18", "19", "101", "102"], + "location": { "end": { "column": 54, "line": 14 }, "start": { "column": 21, "line": 14 } } + }, + { + "id": "83", + "mutatorName": "ConditionalExpression", + "replacement": "true", + "statusReason": "src/errors.ts(16,29): error TS2532: Object is possibly 'undefined'.\n", + "status": "CompileError", + "estimatedNetTime": 9, + "hitCount": 5, + "static": false, + "coveredBy": ["18", "19", "101", "102"], + "location": { "end": { "column": 20, "line": 15 }, "start": { "column": 9, "line": 15 } } + }, + { + "id": "84", + "mutatorName": "ConditionalExpression", + "replacement": "false", + "statusReason": "expected 'Error: expected error' to equal 'Error: expected error\\nError: expected error\\n at Context. (/home/nicojs/github/stryker-js/packages/util/.stryker-tmp/sandbox8696228/test/unit/errors.spec.ts:24:21)\\n at callFn (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runnable.js:366:21)\\n at Test.Runnable.run (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runnable.js:354:5)\\n at Runner.runTest (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:681:10)\\n at /home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:804:12\\n at next (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:596:14)\\n at /home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:606:7\\n at next (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:489:14)\\n at Immediate._onImmediate (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:574:5)\\n at processImmediate (internal/timers.js:464:21)'", + "status": "Killed", + "estimatedNetTime": 9, + "hitCount": 5, + "static": false, + "testsCompleted": 1, + "killedBy": ["18"], + "coveredBy": ["18", "19", "101", "102"], + "location": { "end": { "column": 20, "line": 15 }, "start": { "column": 9, "line": 15 } } + }, + { + "id": "85", + "mutatorName": "BlockStatement", + "replacement": "{}", + "statusReason": "expected 'Error: expected error' to equal 'Error: expected error\\nError: expected error\\n at Context. (/home/nicojs/github/stryker-js/packages/util/.stryker-tmp/sandbox8696228/test/unit/errors.spec.ts:24:21)\\n at callFn (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runnable.js:366:21)\\n at Test.Runnable.run (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runnable.js:354:5)\\n at Runner.runTest (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:681:10)\\n at /home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:804:12\\n at next (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:596:14)\\n at /home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:606:7\\n at next (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:489:14)\\n at Immediate._onImmediate (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:574:5)\\n at processImmediate (internal/timers.js:464:21)'", + "status": "Killed", + "estimatedNetTime": 9, + "hitCount": 4, + "static": false, + "testsCompleted": 1, + "killedBy": ["18"], + "coveredBy": ["18", "101", "102"], + "location": { "end": { "column": 6, "line": 17 }, "start": { "column": 22, "line": 15 } } + }, + { + "id": "86", + "mutatorName": "StringLiteral", + "replacement": "``", + "statusReason": "expected '' to equal 'Error: expected error\\nError: expected error\\n at Context. (/home/nicojs/github/stryker-js/packages/util/.stryker-tmp/sandbox8696228/test/unit/errors.spec.ts:24:21)\\n at callFn (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runnable.js:366:21)\\n at Test.Runnable.run (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runnable.js:354:5)\\n at Runner.runTest (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:681:10)\\n at /home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:804:12\\n at next (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:596:14)\\n at /home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:606:7\\n at next (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:489:14)\\n at Immediate._onImmediate (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:574:5)\\n at processImmediate (internal/timers.js:464:21)'", + "status": "Killed", + "estimatedNetTime": 9, + "hitCount": 4, + "static": false, + "testsCompleted": 1, + "killedBy": ["18"], + "coveredBy": ["18", "101", "102"], + "location": { "end": { "column": 53, "line": 16 }, "start": { "column": 14, "line": 16 } } + }, + { + "id": "87", + "mutatorName": "BlockStatement", + "replacement": "{}", + "status": "Survived", + "estimatedNetTime": 0, + "hitCount": 1, + "static": false, + "testsCompleted": 1, + "coveredBy": ["19"], + "location": { "end": { "column": 6, "line": 19 }, "start": { "column": 12, "line": 17 } } + } + ], + "source": "export function isErrnoException(error: unknown): error is NodeJS.ErrnoException {\n return error instanceof Error && typeof (error as NodeJS.ErrnoException).code === 'string';\n}\n\n// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types\nexport function errorToString(error: any): string {\n if (!error) {\n return '';\n }\n if (error instanceof Error) {\n if (isErrnoException(error)) {\n return `${error.name}: ${error.code} (${error.syscall}) ${error.stack}`;\n }\n const message = `${error.name}: ${error.message}`;\n if (error.stack) {\n return `${message}\\n${error.stack.toString()}`;\n } else {\n return message;\n }\n }\n return error.toString();\n}\n" + }, + "/home/nicojs/github/stryker-js/packages/util/src/find-unserializables.ts": { + "language": "typescript", + "mutants": [ + { + "id": "88", + "mutatorName": "BlockStatement", + "replacement": "{}", + "statusReason": "src/find-unserializables.ts(8,54): error TS2355: A function whose declared type is neither 'void' nor 'any' must return a value.\n", + "status": "CompileError", + "estimatedNetTime": 8, + "hitCount": 85, + "static": false, + "coveredBy": [ + "20", + "21", + "22", + "23", + "24", + "25", + "26", + "27", + "28", + "29", + "30", + "31", + "32", + "33", + "34", + "35", + "36", + "37", + "38", + "39", + "40", + "41", + "42", + "43", + "44", + "45" + ], + "location": { "end": { "column": 2, "line": 61 }, "start": { "column": 94, "line": 8 } } + }, + { + "id": "90", + "mutatorName": "StringLiteral", + "replacement": "\"\"", + "statusReason": "src/find-unserializables.ts(8,54): error TS7030: Not all code paths return a value.\nsrc/find-unserializables.ts(10,10): error TS2678: Type '\"\"' is not comparable to type '\"string\" | \"number\" | \"bigint\" | \"boolean\" | \"symbol\" | \"undefined\" | \"object\" | \"function\"'.\nsrc/find-unserializables.ts(11,24): error TS2345: Argument of type 'unknown' is not assignable to parameter of type 'number'.\n", + "status": "CompileError", + "estimatedNetTime": 8, + "hitCount": 85, + "static": false, + "coveredBy": [ + "20", + "21", + "22", + "23", + "24", + "25", + "26", + "27", + "28", + "29", + "30", + "31", + "32", + "33", + "34", + "35", + "36", + "37", + "38", + "39", + "40", + "41", + "42", + "43", + "44", + "45" + ], + "location": { "end": { "column": 18, "line": 10 }, "start": { "column": 10, "line": 10 } } + }, + { + "id": "89", + "mutatorName": "ConditionalExpression", + "replacement": "case 'number':", + "statusReason": "expected undefined to be truthy", + "status": "Killed", + "estimatedNetTime": 3, + "hitCount": 13, + "static": false, + "testsCompleted": 2, + "killedBy": ["31"], + "coveredBy": ["20", "31", "32", "33", "35", "45"], + "location": { "end": { "column": 124, "line": 11 }, "start": { "column": 5, "line": 10 } } + }, + { + "id": "91", + "mutatorName": "BooleanLiteral", + "replacement": "isFinite(thing)", + "statusReason": "expected [ Array(1) ] to be undefined", + "status": "Killed", + "estimatedNetTime": 3, + "hitCount": 13, + "static": false, + "testsCompleted": 1, + "killedBy": ["20"], + "coveredBy": ["20", "31", "32", "33", "35", "45"], + "location": { "end": { "column": 30, "line": 11 }, "start": { "column": 14, "line": 11 } } + }, + { + "id": "93", + "mutatorName": "ObjectLiteral", + "replacement": "{}", + "statusReason": "src/find-unserializables.ts(11,7): error TS2322: Type '{}[] | undefined' is not assignable to type 'UnserializableDescription[] | undefined'.\n Type '{}[]' is not assignable to type 'UnserializableDescription[]'.\n Type '{}' is missing the following properties from type 'UnserializableDescription': path, reason\n", + "status": "CompileError", + "estimatedNetTime": 1, + "hitCount": 4, + "static": false, + "coveredBy": ["31", "32", "33", "45"], + "location": { "end": { "column": 110, "line": 11 }, "start": { "column": 34, "line": 11 } } + }, + { + "id": "92", + "mutatorName": "ArrayDeclaration", + "replacement": "[]", + "statusReason": "Cannot read property 'reason' of undefined", + "status": "Killed", + "estimatedNetTime": 1, + "hitCount": 4, + "static": false, + "testsCompleted": 4, + "killedBy": ["45"], + "coveredBy": ["31", "32", "33", "45"], + "location": { "end": { "column": 111, "line": 11 }, "start": { "column": 33, "line": 11 } } + }, + { + "id": "96", + "mutatorName": "StringLiteral", + "replacement": "\"\"", + "statusReason": "src/find-unserializables.ts(8,54): error TS7030: Not all code paths return a value.\nsrc/find-unserializables.ts(12,10): error TS2678: Type '\"\"' is not comparable to type '\"string\" | \"number\" | \"bigint\" | \"boolean\" | \"symbol\" | \"undefined\" | \"object\" | \"function\"'.\n", + "status": "CompileError", + "estimatedNetTime": 6, + "hitCount": 72, + "static": false, + "coveredBy": ["21", "22", "23", "24", "25", "26", "27", "28", "29", "30", "34", "35", "36", "37", "38", "39", "40", "41", "42", "43", "44"], + "location": { "end": { "column": 18, "line": 12 }, "start": { "column": 10, "line": 12 } } + }, + { + "id": "94", + "mutatorName": "StringLiteral", + "replacement": "``", + "statusReason": "expected '' to equal 'Number value `NaN` has no JSON representation'", + "status": "Killed", + "estimatedNetTime": 1, + "hitCount": 4, + "static": false, + "testsCompleted": 4, + "killedBy": ["45"], + "coveredBy": ["31", "32", "33", "45"], + "location": { "end": { "column": 98, "line": 11 }, "start": { "column": 44, "line": 11 } } + }, + { + "id": "97", + "mutatorName": "StringLiteral", + "replacement": "\"\"", + "statusReason": "src/find-unserializables.ts(8,54): error TS7030: Not all code paths return a value.\nsrc/find-unserializables.ts(13,10): error TS2678: Type '\"\"' is not comparable to type '\"string\" | \"number\" | \"bigint\" | \"boolean\" | \"symbol\" | \"undefined\" | \"object\" | \"function\"'.\n", + "status": "CompileError", + "estimatedNetTime": 5, + "hitCount": 52, + "static": false, + "coveredBy": ["21", "22", "23", "25", "26", "27", "28", "29", "30", "34", "35", "36", "37", "38", "39", "40", "41", "42", "43", "44"], + "location": { "end": { "column": 19, "line": 13 }, "start": { "column": 10, "line": 13 } } + }, + { + "id": "95", + "mutatorName": "ArrayDeclaration", + "replacement": "[\"Stryker was here\"]", + "status": "Survived", + "estimatedNetTime": 1, + "hitCount": 4, + "static": false, + "testsCompleted": 4, + "coveredBy": ["31", "32", "33", "45"], + "location": { "end": { "column": 108, "line": 11 }, "start": { "column": 106, "line": 11 } } + }, + { + "id": "99", + "mutatorName": "StringLiteral", + "replacement": "\"\"", + "statusReason": "src/find-unserializables.ts(8,54): error TS7030: Not all code paths return a value.\nsrc/find-unserializables.ts(14,10): error TS2678: Type '\"\"' is not comparable to type '\"string\" | \"number\" | \"bigint\" | \"boolean\" | \"symbol\" | \"undefined\" | \"object\" | \"function\"'.\n", + "status": "CompileError", + "estimatedNetTime": 5, + "hitCount": 43, + "static": false, + "coveredBy": ["22", "23", "25", "26", "27", "28", "29", "30", "34", "35", "36", "37", "38", "39", "40", "41", "42", "43", "44"], + "location": { "end": { "column": 21, "line": 14 }, "start": { "column": 10, "line": 14 } } + }, + { + "id": "100", + "mutatorName": "StringLiteral", + "replacement": "\"\"", + "statusReason": "src/find-unserializables.ts(8,54): error TS7030: Not all code paths return a value.\nsrc/find-unserializables.ts(16,10): error TS2678: Type '\"\"' is not comparable to type '\"string\" | \"number\" | \"bigint\" | \"boolean\" | \"symbol\" | \"undefined\" | \"object\" | \"function\"'.\n", + "status": "CompileError", + "estimatedNetTime": 5, + "hitCount": 42, + "static": false, + "coveredBy": ["23", "25", "26", "27", "28", "29", "30", "34", "35", "36", "37", "38", "39", "40", "41", "42", "43", "44"], + "location": { "end": { "column": 18, "line": 16 }, "start": { "column": 10, "line": 16 } } + }, + { + "id": "101", + "mutatorName": "StringLiteral", + "replacement": "\"\"", + "statusReason": "src/find-unserializables.ts(8,54): error TS7030: Not all code paths return a value.\nsrc/find-unserializables.ts(17,10): error TS2678: Type '\"\"' is not comparable to type '\"string\" | \"number\" | \"bigint\" | \"boolean\" | \"symbol\" | \"undefined\" | \"object\" | \"function\"'.\n", + "status": "CompileError", + "estimatedNetTime": 4, + "hitCount": 40, + "static": false, + "coveredBy": ["23", "25", "26", "27", "28", "30", "34", "35", "36", "37", "38", "39", "41", "42", "43", "44"], + "location": { "end": { "column": 20, "line": 17 }, "start": { "column": 10, "line": 17 } } + }, + { + "id": "98", + "mutatorName": "ConditionalExpression", + "replacement": "case 'undefined':", + "statusReason": "expected [ Array(1) ] to be undefined", + "status": "Killed", + "estimatedNetTime": 2, + "hitCount": 30, + "static": false, + "testsCompleted": 1, + "killedBy": ["21"], + "coveredBy": ["21", "22", "24", "35", "39"], + "location": { "end": { "column": 14, "line": 15 }, "start": { "column": 5, "line": 14 } } + }, + { + "id": "103", + "mutatorName": "StringLiteral", + "replacement": "\"\"", + "statusReason": "src/find-unserializables.ts(8,54): error TS7030: Not all code paths return a value.\nsrc/find-unserializables.ts(18,10): error TS2678: Type '\"\"' is not comparable to type '\"string\" | \"number\" | \"bigint\" | \"boolean\" | \"symbol\" | \"undefined\" | \"object\" | \"function\"'.\n", + "status": "CompileError", + "estimatedNetTime": 3, + "hitCount": 39, + "static": false, + "coveredBy": ["23", "25", "26", "27", "28", "34", "35", "36", "37", "38", "39", "41", "42", "43", "44"], + "location": { "end": { "column": 18, "line": 18 }, "start": { "column": 10, "line": 18 } } + }, + { + "id": "102", + "mutatorName": "ConditionalExpression", + "replacement": "case 'symbol':", + "statusReason": "expected 'Value is an instance of \"BigInt\", this detail will get lost in translation during serialization' to equal 'Primitive type \"bigint\" has no JSON representation'", + "status": "Killed", + "estimatedNetTime": 3, + "hitCount": 8, + "static": false, + "testsCompleted": 8, + "killedBy": ["40"], + "coveredBy": ["28", "29", "30", "36", "37", "38", "39", "40"], + "location": { "end": { "column": 9, "line": 24 }, "start": { "column": 5, "line": 18 } } + }, + { + "id": "105", + "mutatorName": "ObjectLiteral", + "replacement": "{}", + "statusReason": "src/find-unserializables.ts(20,9): error TS2739: Type '{}' is missing the following properties from type 'UnserializableDescription': path, reason\n", + "status": "CompileError", + "estimatedNetTime": 3, + "hitCount": 8, + "static": false, + "coveredBy": ["28", "29", "30", "36", "37", "38", "39", "40"], + "location": { "end": { "column": 10, "line": 23 }, "start": { "column": 9, "line": 20 } } + }, + { + "id": "104", + "mutatorName": "ArrayDeclaration", + "replacement": "[]", + "statusReason": "expected undefined to deeply equal [ 'symbol' ]", + "status": "Killed", + "estimatedNetTime": 3, + "hitCount": 8, + "static": false, + "testsCompleted": 4, + "killedBy": ["36"], + "coveredBy": ["28", "29", "30", "36", "37", "38", "39", "40"], + "location": { "end": { "column": 8, "line": 24 }, "start": { "column": 14, "line": 19 } } + }, + { + "id": "108", + "mutatorName": "ConditionalExpression", + "replacement": "case 'object':", + "statusReason": "src/find-unserializables.ts(8,54): error TS7030: Not all code paths return a value.\n", + "status": "CompileError", + "estimatedNetTime": 3, + "hitCount": 34, + "static": false, + "coveredBy": ["23", "25", "26", "27", "34", "35", "36", "37", "38", "39", "41", "42", "43", "44"], + "location": { "end": { "column": 9, "line": 59 }, "start": { "column": 5, "line": 25 } } + }, + { + "id": "106", + "mutatorName": "ArrayDeclaration", + "replacement": "[\"Stryker was here\"]", + "statusReason": "expected [ 'symbol', 'Stryker was here' ] to deeply equal [ 'symbol' ]", + "status": "Killed", + "estimatedNetTime": 3, + "hitCount": 8, + "static": false, + "testsCompleted": 4, + "killedBy": ["36"], + "coveredBy": ["28", "29", "30", "36", "37", "38", "39", "40"], + "location": { "end": { "column": 19, "line": 21 }, "start": { "column": 17, "line": 21 } } + }, + { + "id": "109", + "mutatorName": "StringLiteral", + "replacement": "\"\"", + "statusReason": "src/find-unserializables.ts(8,54): error TS7030: Not all code paths return a value.\nsrc/find-unserializables.ts(25,10): error TS2678: Type '\"\"' is not comparable to type '\"string\" | \"number\" | \"bigint\" | \"boolean\" | \"symbol\" | \"undefined\" | \"object\" | \"function\"'.\nsrc/find-unserializables.ts(43,39): error TS2769: No overload matches this call.\n Overload 1 of 2, '(o: { [s: string]: unknown; } | ArrayLike): [string, unknown][]', gave the following error.\n Argument of type 'unknown' is not assignable to parameter of type '{ [s: string]: unknown; } | ArrayLike'.\n Type 'unknown' is not assignable to type 'ArrayLike'.\n Overload 2 of 2, '(o: {}): [string, any][]', gave the following error.\n Argument of type 'unknown' is not assignable to parameter of type '{}'.\nsrc/find-unserializables.ts(53,30): error TS2571: Object is of type 'unknown'.\n", + "status": "CompileError", + "estimatedNetTime": 3, + "hitCount": 34, + "static": false, + "coveredBy": ["23", "25", "26", "27", "34", "35", "36", "37", "38", "39", "41", "42", "43", "44"], + "location": { "end": { "column": 18, "line": 25 }, "start": { "column": 10, "line": 25 } } + }, + { + "id": "107", + "mutatorName": "StringLiteral", + "replacement": "``", + "statusReason": "expected '' to equal 'Primitive type \"bigint\" has no JSON representation'", + "status": "Killed", + "estimatedNetTime": 3, + "hitCount": 8, + "static": false, + "testsCompleted": 8, + "killedBy": ["40"], + "coveredBy": ["28", "29", "30", "36", "37", "38", "39", "40"], + "location": { "end": { "column": 80, "line": 22 }, "start": { "column": 19, "line": 22 } } + }, + { + "id": "110", + "mutatorName": "ConditionalExpression", + "replacement": "true", + "statusReason": "src/find-unserializables.ts(31,24): error TS2571: Object is of type 'unknown'.\nsrc/find-unserializables.ts(32,21): error TS7006: Parameter 'child' implicitly has an 'any' type.\nsrc/find-unserializables.ts(32,28): error TS7006: Parameter 'index' implicitly has an 'any' type.\nsrc/find-unserializables.ts(43,39): error TS2769: No overload matches this call.\n Overload 1 of 2, '(o: { [s: string]: unknown; } | ArrayLike): [string, unknown][]', gave the following error.\n Argument of type 'unknown' is not assignable to parameter of type '{ [s: string]: unknown; } | ArrayLike'.\n Type 'unknown' is not assignable to type 'ArrayLike'.\n Overload 2 of 2, '(o: {}): [string, any][]', gave the following error.\n Argument of type 'unknown' is not assignable to parameter of type '{}'.\nsrc/find-unserializables.ts(53,30): error TS2571: Object is of type 'unknown'.\n", + "status": "CompileError", + "estimatedNetTime": 3, + "hitCount": 34, + "static": false, + "coveredBy": ["23", "25", "26", "27", "34", "35", "36", "37", "38", "39", "41", "42", "43", "44"], + "location": { "end": { "column": 25, "line": 27 }, "start": { "column": 11, "line": 27 } } + }, + { + "id": "111", + "mutatorName": "ConditionalExpression", + "replacement": "false", + "statusReason": "src/find-unserializables.ts(43,39): error TS2769: No overload matches this call.\n Overload 1 of 2, '(o: { [s: string]: unknown; } | ArrayLike): [string, unknown][]', gave the following error.\n Argument of type 'object | null' is not assignable to parameter of type '{ [s: string]: unknown; } | ArrayLike'.\n Type 'null' is not assignable to type '{ [s: string]: unknown; } | ArrayLike'.\n Overload 2 of 2, '(o: {}): [string, any][]', gave the following error.\n Argument of type 'object | null' is not assignable to parameter of type '{}'.\n Type 'null' is not assignable to type '{}'.\nsrc/find-unserializables.ts(53,30): error TS2531: Object is possibly 'null'.\n", + "status": "CompileError", + "estimatedNetTime": 3, + "hitCount": 34, + "static": false, + "coveredBy": ["23", "25", "26", "27", "34", "35", "36", "37", "38", "39", "41", "42", "43", "44"], + "location": { "end": { "column": 25, "line": 27 }, "start": { "column": 11, "line": 27 } } + }, + { + "id": "112", + "mutatorName": "EqualityOperator", + "replacement": "thing !== null", + "statusReason": "src/find-unserializables.ts(32,12): error TS2339: Property 'flatMap' does not exist on type 'never'.\nsrc/find-unserializables.ts(32,21): error TS7006: Parameter 'child' implicitly has an 'any' type.\nsrc/find-unserializables.ts(32,28): error TS7006: Parameter 'index' implicitly has an 'any' type.\nsrc/find-unserializables.ts(43,39): error TS2769: No overload matches this call.\n Overload 1 of 2, '(o: { [s: string]: unknown; } | ArrayLike): [string, unknown][]', gave the following error.\n Argument of type 'null' is not assignable to parameter of type '{ [s: string]: unknown; } | ArrayLike'.\n Overload 2 of 2, '(o: {}): [string, any][]', gave the following error.\n Argument of type 'null' is not assignable to parameter of type '{}'.\nsrc/find-unserializables.ts(53,30): error TS2531: Object is possibly 'null'.\n", + "status": "CompileError", + "estimatedNetTime": 3, + "hitCount": 34, + "static": false, + "coveredBy": ["23", "25", "26", "27", "34", "35", "36", "37", "38", "39", "41", "42", "43", "44"], + "location": { "end": { "column": 25, "line": 27 }, "start": { "column": 11, "line": 27 } } + }, + { + "id": "113", + "mutatorName": "BlockStatement", + "replacement": "{}", + "statusReason": "src/find-unserializables.ts(41,39): error TS2769: No overload matches this call.\n Overload 1 of 2, '(o: { [s: string]: unknown; } | ArrayLike): [string, unknown][]', gave the following error.\n Argument of type 'object | null' is not assignable to parameter of type '{ [s: string]: unknown; } | ArrayLike'.\n Type 'null' is not assignable to type '{ [s: string]: unknown; } | ArrayLike'.\n Overload 2 of 2, '(o: {}): [string, any][]', gave the following error.\n Argument of type 'object | null' is not assignable to parameter of type '{}'.\n Type 'null' is not assignable to type '{}'.\nsrc/find-unserializables.ts(51,30): error TS2531: Object is possibly 'null'.\n", + "status": "CompileError", + "estimatedNetTime": 1, + "hitCount": 3, + "static": false, + "coveredBy": ["23", "35"], + "location": { "end": { "column": 8, "line": 29 }, "start": { "column": 27, "line": 27 } } + }, + { + "id": "114", + "mutatorName": "ConditionalExpression", + "replacement": "true", + "statusReason": "src/find-unserializables.ts(32,12): error TS2339: Property 'flatMap' does not exist on type 'object'.\nsrc/find-unserializables.ts(32,21): error TS7006: Parameter 'child' implicitly has an 'any' type.\nsrc/find-unserializables.ts(32,28): error TS7006: Parameter 'index' implicitly has an 'any' type.\nsrc/find-unserializables.ts(43,39): error TS2769: No overload matches this call.\n Overload 1 of 2, '(o: { [s: string]: unknown; } | ArrayLike): [string, unknown][]', gave the following error.\n Argument of type 'unknown' is not assignable to parameter of type '{ [s: string]: unknown; } | ArrayLike'.\n Type 'unknown' is not assignable to type 'ArrayLike'.\n Overload 2 of 2, '(o: {}): [string, any][]', gave the following error.\n Argument of type 'unknown' is not assignable to parameter of type '{}'.\nsrc/find-unserializables.ts(53,30): error TS2571: Object is of type 'unknown'.\n", + "status": "CompileError", + "estimatedNetTime": 3, + "hitCount": 31, + "static": false, + "coveredBy": ["25", "26", "27", "34", "35", "36", "37", "38", "39", "41", "42", "43", "44"], + "location": { "end": { "column": 31, "line": 30 }, "start": { "column": 11, "line": 30 } } + }, + { + "id": "115", + "mutatorName": "ConditionalExpression", + "replacement": "false", + "statusReason": "src/find-unserializables.ts(31,24): error TS2571: Object is of type 'unknown'.\nsrc/find-unserializables.ts(32,21): error TS7006: Parameter 'child' implicitly has an 'any' type.\nsrc/find-unserializables.ts(32,28): error TS7006: Parameter 'index' implicitly has an 'any' type.\n", + "status": "CompileError", + "estimatedNetTime": 3, + "hitCount": 31, + "static": false, + "coveredBy": ["25", "26", "27", "34", "35", "36", "37", "38", "39", "41", "42", "43", "44"], + "location": { "end": { "column": 31, "line": 30 }, "start": { "column": 11, "line": 30 } } + }, + { + "id": "117", + "mutatorName": "ArrowFunction", + "replacement": "() => undefined", + "statusReason": "src/find-unserializables.ts(35,9): error TS2322: Type 'undefined[] | undefined' is not assignable to type 'UnserializableDescription[] | undefined'.\n Type 'undefined[]' is not assignable to type 'UnserializableDescription[]'.\n Type 'undefined' is not assignable to type 'UnserializableDescription'.\n", + "status": "CompileError", + "estimatedNetTime": 2, + "hitCount": 13, + "static": false, + "coveredBy": ["26", "35", "38", "39"], + "location": { "end": { "column": 15, "line": 36 }, "start": { "column": 20, "line": 32 } } + }, + { + "id": "118", + "mutatorName": "OptionalChaining", + "replacement": "findUnserializables(child).map", + "statusReason": "src/find-unserializables.ts(33,13): error TS2532: Object is possibly 'undefined'.\n", + "status": "CompileError", + "estimatedNetTime": 2, + "hitCount": 10, + "static": false, + "coveredBy": ["35", "38", "39"], + "location": { "end": { "column": 44, "line": 33 }, "start": { "column": 13, "line": 33 } } + }, + { + "id": "116", + "mutatorName": "BlockStatement", + "replacement": "{}", + "statusReason": "expected [ Array(1) ] to be undefined", + "status": "Killed", + "estimatedNetTime": 2, + "hitCount": 13, + "static": false, + "testsCompleted": 1, + "killedBy": ["26"], + "coveredBy": ["26", "35", "38", "39"], + "location": { "end": { "column": 8, "line": 40 }, "start": { "column": 33, "line": 30 } } + }, + { + "id": "119", + "mutatorName": "BlockStatement", + "replacement": "{}", + "statusReason": "src/find-unserializables.ts(36,9): error TS2322: Type 'void[] | undefined' is not assignable to type 'UnserializableDescription[] | undefined'.\n Type 'void[]' is not assignable to type 'UnserializableDescription[]'.\n Type 'void' is not assignable to type 'UnserializableDescription'.\n", + "status": "CompileError", + "estimatedNetTime": 1, + "hitCount": 3, + "static": false, + "coveredBy": ["38", "39"], + "location": { "end": { "column": 14, "line": 36 }, "start": { "column": 62, "line": 33 } } + }, + { + "id": "120", + "mutatorName": "ConditionalExpression", + "replacement": "true", + "statusReason": "src/find-unserializables.ts(53,30): error TS2571: Object is of type 'unknown'.\n", + "status": "CompileError", + "estimatedNetTime": 2, + "hitCount": 18, + "static": false, + "coveredBy": ["25", "27", "34", "35", "36", "37", "41", "42", "43", "44"], + "location": { "end": { "column": 65, "line": 42 }, "start": { "column": 11, "line": 42 } } + }, + { + "id": "121", + "mutatorName": "ConditionalExpression", + "replacement": "false", + "statusReason": "src/find-unserializables.ts(43,39): error TS2769: No overload matches this call.\n Overload 1 of 2, '(o: { [s: string]: unknown; } | ArrayLike): [string, unknown][]', gave the following error.\n Argument of type 'unknown' is not assignable to parameter of type '{ [s: string]: unknown; } | ArrayLike'.\n Type 'unknown' is not assignable to type 'ArrayLike'.\n Overload 2 of 2, '(o: {}): [string, any][]', gave the following error.\n Argument of type 'unknown' is not assignable to parameter of type '{}'.\n", + "status": "CompileError", + "estimatedNetTime": 2, + "hitCount": 18, + "static": false, + "coveredBy": ["25", "27", "34", "35", "36", "37", "41", "42", "43", "44"], + "location": { "end": { "column": 65, "line": 42 }, "start": { "column": 11, "line": 42 } } + }, + { + "id": "123", + "mutatorName": "ConditionalExpression", + "replacement": "true", + "statusReason": "src/find-unserializables.ts(53,30): error TS2571: Object is of type 'unknown'.\n", + "status": "CompileError", + "estimatedNetTime": 2, + "hitCount": 18, + "static": false, + "coveredBy": ["25", "27", "34", "35", "36", "37", "41", "42", "43", "44"], + "location": { "end": { "column": 42, "line": 42 }, "start": { "column": 11, "line": 42 } } + }, + { + "id": "122", + "mutatorName": "LogicalOperator", + "replacement": "thingProto === Object.prototype && thingProto === null", + "statusReason": "expected [ Array(1) ] to be undefined", + "status": "Killed", + "estimatedNetTime": 2, + "hitCount": 18, + "static": false, + "testsCompleted": 1, + "killedBy": ["25"], + "coveredBy": ["25", "27", "34", "35", "36", "37", "41", "42", "43", "44"], + "location": { "end": { "column": 65, "line": 42 }, "start": { "column": 11, "line": 42 } } + }, + { + "id": "124", + "mutatorName": "ConditionalExpression", + "replacement": "false", + "statusReason": "expected [ Array(1) ] to be undefined", + "status": "Killed", + "estimatedNetTime": 2, + "hitCount": 18, + "static": false, + "testsCompleted": 1, + "killedBy": ["25"], + "coveredBy": ["25", "27", "34", "35", "36", "37", "41", "42", "43", "44"], + "location": { "end": { "column": 42, "line": 42 }, "start": { "column": 11, "line": 42 } } + }, + { + "id": "125", + "mutatorName": "EqualityOperator", + "replacement": "thingProto !== Object.prototype", + "statusReason": "expected [ Array(1) ] to be undefined", + "status": "Killed", + "estimatedNetTime": 2, + "hitCount": 18, + "static": false, + "testsCompleted": 1, + "killedBy": ["25"], + "coveredBy": ["25", "27", "34", "35", "36", "37", "41", "42", "43", "44"], + "location": { "end": { "column": 42, "line": 42 }, "start": { "column": 11, "line": 42 } } + }, + { + "id": "126", + "mutatorName": "ConditionalExpression", + "replacement": "true", + "statusReason": "src/find-unserializables.ts(53,30): error TS2571: Object is of type 'unknown'.\n", + "status": "CompileError", + "estimatedNetTime": 1, + "hitCount": 6, + "static": false, + "coveredBy": ["27", "34", "41", "42", "43", "44"], + "location": { "end": { "column": 65, "line": 42 }, "start": { "column": 46, "line": 42 } } + }, + { + "id": "127", + "mutatorName": "ConditionalExpression", + "replacement": "false", + "statusReason": "Cannot read property 'name' of undefined", + "status": "Killed", + "estimatedNetTime": 1, + "hitCount": 6, + "static": false, + "testsCompleted": 1, + "killedBy": ["27"], + "coveredBy": ["27", "34", "41", "42", "43", "44"], + "location": { "end": { "column": 65, "line": 42 }, "start": { "column": 46, "line": 42 } } + }, + { + "id": "130", + "mutatorName": "ArrowFunction", + "replacement": "() => undefined", + "statusReason": "src/find-unserializables.ts(47,9): error TS2322: Type 'undefined[] | undefined' is not assignable to type 'UnserializableDescription[] | undefined'.\n Type 'undefined[]' is not assignable to type 'UnserializableDescription[]'.\n Type 'undefined' is not assignable to type 'UnserializableDescription'.\n", + "status": "CompileError", + "estimatedNetTime": 1, + "hitCount": 13, + "static": false, + "coveredBy": ["25", "27", "35", "36", "37"], + "location": { "end": { "column": 15, "line": 48 }, "start": { "column": 20, "line": 44 } } + }, + { + "id": "128", + "mutatorName": "EqualityOperator", + "replacement": "thingProto !== null", + "statusReason": "Cannot read property 'name' of undefined", + "status": "Killed", + "estimatedNetTime": 1, + "hitCount": 6, + "static": false, + "testsCompleted": 1, + "killedBy": ["27"], + "coveredBy": ["27", "34", "41", "42", "43", "44"], + "location": { "end": { "column": 65, "line": 42 }, "start": { "column": 46, "line": 42 } } + }, + { + "id": "129", + "mutatorName": "BlockStatement", + "replacement": "{}", + "statusReason": "expected [ Array(1) ] to be undefined", + "status": "Killed", + "estimatedNetTime": 1, + "hitCount": 13, + "static": false, + "testsCompleted": 1, + "killedBy": ["25"], + "coveredBy": ["25", "27", "35", "36", "37"], + "location": { "end": { "column": 8, "line": 52 }, "start": { "column": 67, "line": 42 } } + }, + { + "id": "131", + "mutatorName": "OptionalChaining", + "replacement": "findUnserializables(val).map", + "statusReason": "src/find-unserializables.ts(45,13): error TS2532: Object is possibly 'undefined'.\n", + "status": "CompileError", + "estimatedNetTime": 1, + "hitCount": 49, + "static": false, + "coveredBy": ["35", "36", "37"], + "location": { "end": { "column": 42, "line": 45 }, "start": { "column": 13, "line": 45 } } + }, + { + "id": "132", + "mutatorName": "BlockStatement", + "replacement": "{}", + "statusReason": "src/find-unserializables.ts(48,9): error TS2322: Type 'void[] | undefined' is not assignable to type 'UnserializableDescription[] | undefined'.\n Type 'void[]' is not assignable to type 'UnserializableDescription[]'.\n Type 'void' is not assignable to type 'UnserializableDescription'.\n", + "status": "CompileError", + "estimatedNetTime": 0, + "hitCount": 3, + "static": false, + "coveredBy": ["36", "37"], + "location": { "end": { "column": 14, "line": 48 }, "start": { "column": 60, "line": 45 } } + }, + { + "id": "133", + "mutatorName": "ConditionalExpression", + "replacement": "true", + "statusReason": "expected 'Value is an instance of \"true\", this detail will get lost in translation during serialization' to equal 'Value is an instance of \"Person\", this detail will get lost in translation during serialization'", + "status": "Killed", + "estimatedNetTime": 1, + "hitCount": 5, + "static": false, + "testsCompleted": 2, + "killedBy": ["41"], + "coveredBy": ["34", "41", "42", "43", "44"], + "location": { "end": { "column": 75, "line": 53 }, "start": { "column": 30, "line": 53 } } + }, + { + "id": "134", + "mutatorName": "ConditionalExpression", + "replacement": "false", + "statusReason": "expected 'Value is an instance of \"false\", this detail will get lost in translation during serialization' to equal 'Value is an instance of \"Person\", this detail will get lost in translation during serialization'", + "status": "Killed", + "estimatedNetTime": 1, + "hitCount": 5, + "static": false, + "testsCompleted": 2, + "killedBy": ["41"], + "coveredBy": ["34", "41", "42", "43", "44"], + "location": { "end": { "column": 75, "line": 53 }, "start": { "column": 30, "line": 53 } } + }, + { + "id": "135", + "mutatorName": "LogicalOperator", + "replacement": "thing.constructor.name && ''", + "statusReason": "expected 'Value is an instance of \"\", this detail will get lost in translation during serialization' to equal 'Value is an instance of \"Person\", this detail will get lost in translation during serialization'", + "status": "Killed", + "estimatedNetTime": 1, + "hitCount": 5, + "static": false, + "testsCompleted": 2, + "killedBy": ["41"], + "coveredBy": ["34", "41", "42", "43", "44"], + "location": { "end": { "column": 75, "line": 53 }, "start": { "column": 30, "line": 53 } } + }, + { + "id": "136", + "mutatorName": "StringLiteral", + "replacement": "\"\"", + "statusReason": "expected 'Value is an instance of \"\", this detail will get lost in translation during serialization' to equal 'Value is an instance of \"\", this detail will get lost in translation during serialization'", + "status": "Killed", + "estimatedNetTime": 0, + "hitCount": 1, + "static": false, + "testsCompleted": 1, + "killedBy": ["42"], + "coveredBy": ["42"], + "location": { "end": { "column": 75, "line": 53 }, "start": { "column": 56, "line": 53 } } + }, + { + "id": "138", + "mutatorName": "ObjectLiteral", + "replacement": "{}", + "statusReason": "src/find-unserializables.ts(55,9): error TS2739: Type '{}' is missing the following properties from type 'UnserializableDescription': path, reason\n", + "status": "CompileError", + "estimatedNetTime": 1, + "hitCount": 5, + "static": false, + "coveredBy": ["34", "41", "42", "43", "44"], + "location": { "end": { "column": 10, "line": 58 }, "start": { "column": 9, "line": 55 } } + }, + { + "id": "137", + "mutatorName": "ArrayDeclaration", + "replacement": "[]", + "statusReason": "Cannot read property 'reason' of undefined", + "status": "Killed", + "estimatedNetTime": 1, + "hitCount": 5, + "static": false, + "testsCompleted": 2, + "killedBy": ["41"], + "coveredBy": ["34", "41", "42", "43", "44"], + "location": { "end": { "column": 8, "line": 59 }, "start": { "column": 14, "line": 54 } } + }, + { + "id": "139", + "mutatorName": "ArrayDeclaration", + "replacement": "[\"Stryker was here\"]", + "status": "Survived", + "estimatedNetTime": 1, + "hitCount": 5, + "static": false, + "testsCompleted": 5, + "coveredBy": ["34", "41", "42", "43", "44"], + "location": { "end": { "column": 19, "line": 56 }, "start": { "column": 17, "line": 56 } } + }, + { + "id": "140", + "mutatorName": "StringLiteral", + "replacement": "``", + "statusReason": "expected '' to equal 'Value is an instance of \"Person\", this detail will get lost in translation during serialization'", + "status": "Killed", + "estimatedNetTime": 1, + "hitCount": 5, + "static": false, + "testsCompleted": 2, + "killedBy": ["41"], + "coveredBy": ["34", "41", "42", "43", "44"], + "location": { "end": { "column": 127, "line": 57 }, "start": { "column": 19, "line": 57 } } + } + ], + "source": "import { notEmpty } from './not-empty';\n\nexport interface UnserializableDescription {\n path: string[];\n reason: string;\n}\n\nexport function findUnserializables(thing: unknown): UnserializableDescription[] | undefined {\n switch (typeof thing) {\n case 'number':\n return !isFinite(thing) ? [{ reason: `Number value \\`${thing}\\` has no JSON representation`, path: [] }] : undefined;\n case 'string':\n case 'boolean':\n case 'undefined':\n return;\n case 'bigint':\n case 'function':\n case 'symbol':\n return [\n {\n path: [],\n reason: `Primitive type \"${typeof thing}\" has no JSON representation`,\n },\n ];\n case 'object':\n // Either a plain object, null, array or instance of a class\n if (thing === null) {\n return;\n }\n if (Array.isArray(thing)) {\n const things = thing\n .flatMap((child, index) =>\n findUnserializables(child)?.map((description) => {\n description.path.unshift(index.toString());\n return description;\n })\n )\n .filter(notEmpty);\n return things.length ? things : undefined;\n }\n const thingProto = Object.getPrototypeOf(thing);\n if (thingProto === Object.prototype || thingProto === null) {\n const things = Object.entries(thing)\n .flatMap(([key, val]) =>\n findUnserializables(val)?.map((description) => {\n description.path.unshift(key);\n return description;\n })\n )\n .filter(notEmpty);\n return things.length ? things : undefined;\n }\n const protoClassName = thing.constructor.name || '';\n return [\n {\n path: [],\n reason: `Value is an instance of \"${protoClassName}\", this detail will get lost in translation during serialization`,\n },\n ];\n }\n}\n" + }, + "/home/nicojs/github/stryker-js/packages/util/src/immutable.ts": { + "language": "typescript", + "mutants": [ + { + "id": "141", + "mutatorName": "BlockStatement", + "replacement": "{}", + "statusReason": "src/immutable.ts(20,43): error TS2355: A function whose declared type is neither 'void' nor 'any' must return a value.\n", + "status": "CompileError", + "estimatedNetTime": 6, + "hitCount": 28, + "static": false, + "coveredBy": ["46", "47", "48", "49", "50", "51", "52", "53", "54"], + "location": { "end": { "column": 2, "line": 47 }, "start": { "column": 56, "line": 20 } } + }, + { + "id": "142", + "mutatorName": "ConditionalExpression", + "replacement": "case 'object':", + "statusReason": "expected { foo: 'bar', baz: 42 } to be frozen", + "status": "Killed", + "estimatedNetTime": 6, + "hitCount": 15, + "static": false, + "testsCompleted": 2, + "killedBy": ["47"], + "coveredBy": ["46", "47", "48", "50", "51", "52", "53", "54"], + "location": { "end": { "column": 10, "line": 43 }, "start": { "column": 5, "line": 22 } } + }, + { + "id": "143", + "mutatorName": "StringLiteral", + "replacement": "\"\"", + "statusReason": "src/immutable.ts(22,10): error TS2678: Type '\"\"' is not comparable to type '\"string\" | \"number\" | \"bigint\" | \"boolean\" | \"symbol\" | \"undefined\" | \"object\" | \"function\"'.\n", + "status": "CompileError", + "estimatedNetTime": 6, + "hitCount": 28, + "static": false, + "coveredBy": ["46", "47", "48", "49", "50", "51", "52", "53", "54"], + "location": { "end": { "column": 18, "line": 22 }, "start": { "column": 10, "line": 22 } } + }, + { + "id": "144", + "mutatorName": "ConditionalExpression", + "replacement": "true", + "statusReason": "src/immutable.ts(24,31): error TS2352: Conversion of type 'T' to type 'any[]' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first.\nsrc/immutable.ts(27,49): error TS2339: Property 'entries' does not exist on type 'T'.\nsrc/immutable.ts(36,49): error TS2339: Property 'values' does not exist on type 'T'.\n", + "status": "CompileError", + "estimatedNetTime": 6, + "hitCount": 15, + "static": false, + "coveredBy": ["46", "47", "48", "50", "51", "52", "53", "54"], + "location": { "end": { "column": 32, "line": 23 }, "start": { "column": 11, "line": 23 } } + }, + { + "id": "145", + "mutatorName": "ConditionalExpression", + "replacement": "false", + "statusReason": "src/immutable.ts(24,31): error TS2352: Conversion of type 'T' to type 'any[]' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first.\n", + "status": "CompileError", + "estimatedNetTime": 6, + "hitCount": 15, + "static": false, + "coveredBy": ["46", "47", "48", "50", "51", "52", "53", "54"], + "location": { "end": { "column": 32, "line": 23 }, "start": { "column": 11, "line": 23 } } + }, + { + "id": "147", + "mutatorName": "ConditionalExpression", + "replacement": "true", + "statusReason": "src/immutable.ts(27,49): error TS2339: Property 'entries' does not exist on type 'T'.\nsrc/immutable.ts(36,49): error TS2339: Property 'values' does not exist on type 'T'.\n", + "status": "CompileError", + "estimatedNetTime": 6, + "hitCount": 14, + "static": false, + "coveredBy": ["46", "47", "48", "50", "51", "52", "53", "54"], + "location": { "end": { "column": 32, "line": 26 }, "start": { "column": 11, "line": 26 } } + }, + { + "id": "148", + "mutatorName": "ConditionalExpression", + "replacement": "false", + "statusReason": "src/immutable.ts(27,49): error TS2339: Property 'entries' does not exist on type 'T'.\n", + "status": "CompileError", + "estimatedNetTime": 6, + "hitCount": 14, + "static": false, + "coveredBy": ["46", "47", "48", "50", "51", "52", "53", "54"], + "location": { "end": { "column": 32, "line": 26 }, "start": { "column": 11, "line": 26 } } + }, + { + "id": "146", + "mutatorName": "BlockStatement", + "replacement": "{}", + "statusReason": "expected { Object (0, 1) } to be an instance of Array", + "status": "Killed", + "estimatedNetTime": 1, + "hitCount": 1, + "static": false, + "testsCompleted": 1, + "killedBy": ["51"], + "coveredBy": ["51"], + "location": { "end": { "column": 8, "line": 25 }, "start": { "column": 34, "line": 23 } } + }, + { + "id": "149", + "mutatorName": "BlockStatement", + "replacement": "{}", + "statusReason": "expected {} to have property 'length'", + "status": "Killed", + "estimatedNetTime": 1, + "hitCount": 1, + "static": false, + "testsCompleted": 1, + "killedBy": ["52"], + "coveredBy": ["52"], + "location": { "end": { "column": 8, "line": 28 }, "start": { "column": 34, "line": 26 } } + }, + { + "id": "150", + "mutatorName": "ConditionalExpression", + "replacement": "true", + "statusReason": "src/immutable.ts(36,49): error TS2339: Property 'values' does not exist on type 'T'.\n", + "status": "CompileError", + "estimatedNetTime": 6, + "hitCount": 13, + "static": false, + "coveredBy": ["46", "47", "48", "50", "51", "52", "53", "54"], + "location": { "end": { "column": 35, "line": 29 }, "start": { "column": 11, "line": 29 } } + }, + { + "id": "151", + "mutatorName": "ConditionalExpression", + "replacement": "false", + "statusReason": "expected {} to be an instance of RegExp", + "status": "Killed", + "estimatedNetTime": 6, + "hitCount": 13, + "static": false, + "testsCompleted": 8, + "killedBy": ["54"], + "coveredBy": ["46", "47", "48", "50", "51", "52", "53", "54"], + "location": { "end": { "column": 35, "line": 29 }, "start": { "column": 11, "line": 29 } } + }, + { + "id": "152", + "mutatorName": "BlockStatement", + "replacement": "{}", + "statusReason": "expected {} to be an instance of RegExp", + "status": "Killed", + "estimatedNetTime": 1, + "hitCount": 1, + "static": false, + "testsCompleted": 1, + "killedBy": ["54"], + "coveredBy": ["54"], + "location": { "end": { "column": 8, "line": 31 }, "start": { "column": 37, "line": 29 } } + }, + { + "id": "153", + "mutatorName": "ConditionalExpression", + "replacement": "true", + "statusReason": "src/immutable.ts(36,49): error TS2339: Property 'values' does not exist on type 'T'.\n", + "status": "CompileError", + "estimatedNetTime": 5, + "hitCount": 12, + "static": false, + "coveredBy": ["46", "47", "48", "50", "51", "52", "53"], + "location": { "end": { "column": 26, "line": 32 }, "start": { "column": 11, "line": 32 } } + }, + { + "id": "154", + "mutatorName": "ConditionalExpression", + "replacement": "false", + "statusReason": "Cannot convert undefined or null to object", + "status": "Killed", + "estimatedNetTime": 5, + "hitCount": 12, + "static": false, + "testsCompleted": 3, + "killedBy": ["48"], + "coveredBy": ["46", "47", "48", "50", "51", "52", "53"], + "location": { "end": { "column": 26, "line": 32 }, "start": { "column": 11, "line": 32 } } + }, + { + "id": "157", + "mutatorName": "ConditionalExpression", + "replacement": "true", + "statusReason": "src/immutable.ts(36,49): error TS2339: Property 'values' does not exist on type 'T'.\n", + "status": "CompileError", + "estimatedNetTime": 4, + "hitCount": 11, + "static": false, + "coveredBy": ["46", "47", "50", "51", "52", "53"], + "location": { "end": { "column": 32, "line": 35 }, "start": { "column": 11, "line": 35 } } + }, + { + "id": "155", + "mutatorName": "EqualityOperator", + "replacement": "target !== null", + "statusReason": "expected null to deeply equal { foo: 'bar', baz: 42 }", + "status": "Killed", + "estimatedNetTime": 5, + "hitCount": 12, + "static": false, + "testsCompleted": 2, + "killedBy": ["47"], + "coveredBy": ["46", "47", "48", "50", "51", "52", "53"], + "location": { "end": { "column": 26, "line": 32 }, "start": { "column": 11, "line": 32 } } + }, + { + "id": "156", + "mutatorName": "BlockStatement", + "replacement": "{}", + "statusReason": "Cannot convert undefined or null to object", + "status": "Killed", + "estimatedNetTime": 1, + "hitCount": 1, + "static": false, + "testsCompleted": 1, + "killedBy": ["48"], + "coveredBy": ["48"], + "location": { "end": { "column": 8, "line": 34 }, "start": { "column": 28, "line": 32 } } + }, + { + "id": "158", + "mutatorName": "ConditionalExpression", + "replacement": "false", + "statusReason": "src/immutable.ts(36,49): error TS2339: Property 'values' does not exist on type 'T'.\n", + "status": "CompileError", + "estimatedNetTime": 4, + "hitCount": 11, + "static": false, + "coveredBy": ["46", "47", "50", "51", "52", "53"], + "location": { "end": { "column": 32, "line": 35 }, "start": { "column": 11, "line": 35 } } + }, + { + "id": "160", + "mutatorName": "ObjectLiteral", + "replacement": "{}", + "statusReason": "src/immutable.ts(38,7): error TS2322: Type 'Readonly<{}>' is not assignable to type 'Immutable'.\n", + "status": "CompileError", + "estimatedNetTime": 4, + "hitCount": 10, + "static": false, + "coveredBy": ["46", "47", "50", "51", "52", "53"], + "location": { "end": { "column": 8, "line": 43 }, "start": { "column": 28, "line": 38 } } + }, + { + "id": "159", + "mutatorName": "BlockStatement", + "replacement": "{}", + "statusReason": "expected {} to have property 'length'", + "status": "Killed", + "estimatedNetTime": 0, + "hitCount": 1, + "static": false, + "testsCompleted": 1, + "killedBy": ["53"], + "coveredBy": ["53"], + "location": { "end": { "column": 8, "line": 37 }, "start": { "column": 34, "line": 35 } } + }, + { + "id": "162", + "mutatorName": "ConditionalExpression", + "replacement": "default:", + "statusReason": "src/immutable.ts(20,43): error TS2366: Function lacks ending return statement and return type does not include 'undefined'.\n", + "status": "CompileError", + "estimatedNetTime": 4, + "hitCount": 13, + "static": false, + "coveredBy": ["47", "48", "49", "50", "51", "52", "53"], + "location": { "end": { "column": 37, "line": 45 }, "start": { "column": 5, "line": 44 } } + }, + { + "id": "161", + "mutatorName": "BlockStatement", + "replacement": "{}", + "statusReason": "expected {} to deeply equal { foo: 'bar', baz: 42 }", + "status": "Killed", + "estimatedNetTime": 3, + "hitCount": 10, + "static": false, + "testsCompleted": 1, + "killedBy": ["47"], + "coveredBy": ["47", "50", "51", "52", "53"], + "location": { "end": { "column": 10, "line": 42 }, "start": { "column": 72, "line": 39 } } + } + ], + "source": "import { Primitive } from './primitive';\n\ntype ImmutablePrimitive = Primitive | ((...args: any[]) => any);\n\nexport type Immutable = T extends ImmutablePrimitive\n ? T\n : T extends Array\n ? ImmutableArray\n : T extends Map\n ? ImmutableMap\n : T extends Set\n ? ImmutableSet\n : ImmutableObject;\n\nexport type ImmutableArray = ReadonlyArray>;\nexport type ImmutableMap = ReadonlyMap, Immutable>;\nexport type ImmutableSet = ReadonlySet>;\nexport type ImmutableObject = { readonly [K in keyof T]: Immutable };\n\nexport function deepFreeze(target: T): Immutable {\n switch (typeof target) {\n case 'object':\n if (Array.isArray(target)) {\n return Object.freeze((target as any[]).map(deepFreeze)) as Immutable;\n }\n if (target instanceof Map) {\n return Object.freeze(new Map([...target.entries()].map(([k, v]) => [deepFreeze(k), deepFreeze(v)]))) as unknown as Immutable;\n }\n if (target instanceof RegExp) {\n return Object.freeze(target) as Immutable;\n }\n if (target === null) {\n return null as Immutable;\n }\n if (target instanceof Set) {\n return Object.freeze(new Set([...target.values()].map(deepFreeze))) as unknown as Immutable;\n }\n return Object.freeze({\n ...Object.entries(target).reduce((result, [prop, val]) => {\n result[prop] = deepFreeze(val);\n return result;\n }, {}),\n });\n default:\n return target as Immutable;\n }\n}\n" + }, + "/home/nicojs/github/stryker-js/packages/util/src/noop-logger.ts": { + "language": "typescript", + "mutants": [ + { + "id": "164", + "mutatorName": "BlockStatement", + "replacement": "{}", + "statusReason": "src/noop-logger.ts(2,21): error TS2355: A function whose declared type is neither 'void' nor 'any' must return a value.\n", + "status": "CompileError", + "estimatedNetTime": 0, + "hitCount": 1, + "static": false, + "coveredBy": ["55"], + "location": { "end": { "column": 4, "line": 4 }, "start": { "column": 29, "line": 2 } } + }, + { + "id": "166", + "mutatorName": "BlockStatement", + "replacement": "{}", + "statusReason": "src/noop-logger.ts(5,21): error TS2355: A function whose declared type is neither 'void' nor 'any' must return a value.\n", + "status": "CompileError", + "estimatedNetTime": 0, + "hitCount": 1, + "static": false, + "coveredBy": ["55"], + "location": { "end": { "column": 4, "line": 7 }, "start": { "column": 29, "line": 5 } } + }, + { + "id": "163", + "mutatorName": "ObjectLiteral", + "replacement": "{}", + "statusReason": "test/unit/noop-logger.spec.ts(9,23): error TS2339: Property 'isTraceEnabled' does not exist on type '{}'.\ntest/unit/noop-logger.spec.ts(10,23): error TS2339: Property 'isDebugEnabled' does not exist on type '{}'.\ntest/unit/noop-logger.spec.ts(11,23): error TS2339: Property 'isInfoEnabled' does not exist on type '{}'.\ntest/unit/noop-logger.spec.ts(12,23): error TS2339: Property 'isWarnEnabled' does not exist on type '{}'.\ntest/unit/noop-logger.spec.ts(13,23): error TS2339: Property 'isErrorEnabled' does not exist on type '{}'.\ntest/unit/noop-logger.spec.ts(14,23): error TS2339: Property 'isFatalEnabled' does not exist on type '{}'.\ntest/unit/noop-logger.spec.ts(19,16): error TS2339: Property 'trace' does not exist on type '{}'.\ntest/unit/noop-logger.spec.ts(20,16): error TS2339: Property 'debug' does not exist on type '{}'.\ntest/unit/noop-logger.spec.ts(21,16): error TS2339: Property 'info' does not exist on type '{}'.\ntest/unit/noop-logger.spec.ts(22,16): error TS2339: Property 'warn' does not exist on type '{}'.\ntest/unit/noop-logger.spec.ts(23,16): error TS2339: Property 'error' does not exist on type '{}'.\ntest/unit/noop-logger.spec.ts(24,16): error TS2339: Property 'fatal' does not exist on type '{}'.\n", + "status": "CompileError", + "estimatedNetTime": 73, + "hitCount": 1, + "static": true, + "location": { "end": { "column": 2, "line": 38 }, "start": { "column": 27, "line": 1 } } + }, + { + "id": "165", + "mutatorName": "BooleanLiteral", + "replacement": "true", + "statusReason": "expected true to be false", + "status": "Killed", + "estimatedNetTime": 0, + "hitCount": 1, + "static": false, + "testsCompleted": 1, + "killedBy": ["55"], + "coveredBy": ["55"], + "location": { "end": { "column": 17, "line": 3 }, "start": { "column": 12, "line": 3 } } + }, + { + "id": "168", + "mutatorName": "BlockStatement", + "replacement": "{}", + "statusReason": "src/noop-logger.ts(8,20): error TS2355: A function whose declared type is neither 'void' nor 'any' must return a value.\n", + "status": "CompileError", + "estimatedNetTime": 0, + "hitCount": 1, + "static": false, + "coveredBy": ["55"], + "location": { "end": { "column": 4, "line": 10 }, "start": { "column": 28, "line": 8 } } + }, + { + "id": "167", + "mutatorName": "BooleanLiteral", + "replacement": "true", + "statusReason": "expected true to be false", + "status": "Killed", + "estimatedNetTime": 0, + "hitCount": 1, + "static": false, + "testsCompleted": 1, + "killedBy": ["55"], + "coveredBy": ["55"], + "location": { "end": { "column": 17, "line": 6 }, "start": { "column": 12, "line": 6 } } + }, + { + "id": "170", + "mutatorName": "BlockStatement", + "replacement": "{}", + "statusReason": "src/noop-logger.ts(11,20): error TS2355: A function whose declared type is neither 'void' nor 'any' must return a value.\ntest/unit/noop-logger.spec.ts(9,23): error TS2339: Property 'isTraceEnabled' does not exist on type '{}'.\ntest/unit/noop-logger.spec.ts(10,23): error TS2339: Property 'isDebugEnabled' does not exist on type '{}'.\ntest/unit/noop-logger.spec.ts(11,23): error TS2339: Property 'isInfoEnabled' does not exist on type '{}'.\ntest/unit/noop-logger.spec.ts(12,23): error TS2339: Property 'isWarnEnabled' does not exist on type '{}'.\ntest/unit/noop-logger.spec.ts(13,23): error TS2339: Property 'isErrorEnabled' does not exist on type '{}'.\ntest/unit/noop-logger.spec.ts(14,23): error TS2339: Property 'isFatalEnabled' does not exist on type '{}'.\ntest/unit/noop-logger.spec.ts(19,16): error TS2339: Property 'trace' does not exist on type '{}'.\ntest/unit/noop-logger.spec.ts(20,16): error TS2339: Property 'debug' does not exist on type '{}'.\ntest/unit/noop-logger.spec.ts(21,16): error TS2339: Property 'info' does not exist on type '{}'.\ntest/unit/noop-logger.spec.ts(22,16): error TS2339: Property 'warn' does not exist on type '{}'.\ntest/unit/noop-logger.spec.ts(23,16): error TS2339: Property 'error' does not exist on type '{}'.\ntest/unit/noop-logger.spec.ts(24,16): error TS2339: Property 'fatal' does not exist on type '{}'.\n", + "status": "CompileError", + "estimatedNetTime": 0, + "hitCount": 1, + "static": false, + "coveredBy": ["55"], + "location": { "end": { "column": 4, "line": 13 }, "start": { "column": 28, "line": 11 } } + }, + { + "id": "169", + "mutatorName": "BooleanLiteral", + "replacement": "true", + "statusReason": "expected true to be false", + "status": "Killed", + "estimatedNetTime": 0, + "hitCount": 1, + "static": false, + "testsCompleted": 1, + "killedBy": ["55"], + "coveredBy": ["55"], + "location": { "end": { "column": 17, "line": 9 }, "start": { "column": 12, "line": 9 } } + }, + { + "id": "172", + "mutatorName": "BlockStatement", + "replacement": "{}", + "statusReason": "src/noop-logger.ts(14,21): error TS2355: A function whose declared type is neither 'void' nor 'any' must return a value.\n", + "status": "CompileError", + "estimatedNetTime": 0, + "hitCount": 1, + "static": false, + "coveredBy": ["55"], + "location": { "end": { "column": 4, "line": 16 }, "start": { "column": 29, "line": 14 } } + }, + { + "id": "171", + "mutatorName": "BooleanLiteral", + "replacement": "true", + "statusReason": "expected true to be false", + "status": "Killed", + "estimatedNetTime": 0, + "hitCount": 1, + "static": false, + "testsCompleted": 1, + "killedBy": ["55"], + "coveredBy": ["55"], + "location": { "end": { "column": 17, "line": 12 }, "start": { "column": 12, "line": 12 } } + }, + { + "id": "174", + "mutatorName": "BlockStatement", + "replacement": "{}", + "statusReason": "src/noop-logger.ts(17,21): error TS2355: A function whose declared type is neither 'void' nor 'any' must return a value.\n", + "status": "CompileError", + "estimatedNetTime": 0, + "hitCount": 1, + "static": false, + "coveredBy": ["55"], + "location": { "end": { "column": 4, "line": 19 }, "start": { "column": 29, "line": 17 } } + }, + { + "id": "175", + "mutatorName": "BooleanLiteral", + "replacement": "true", + "statusReason": "expected true to be false", + "status": "Killed", + "estimatedNetTime": 0, + "hitCount": 1, + "static": false, + "testsCompleted": 1, + "killedBy": ["55"], + "coveredBy": ["55"], + "location": { "end": { "column": 17, "line": 18 }, "start": { "column": 12, "line": 18 } } + }, + { + "id": "173", + "mutatorName": "BooleanLiteral", + "replacement": "true", + "statusReason": "expected true to be false", + "status": "Killed", + "estimatedNetTime": 0, + "hitCount": 1, + "static": false, + "testsCompleted": 1, + "killedBy": ["55"], + "coveredBy": ["55"], + "location": { "end": { "column": 17, "line": 15 }, "start": { "column": 12, "line": 15 } } + } + ], + "source": "export const noopLogger = {\n isTraceEnabled(): boolean {\n return false;\n },\n isDebugEnabled(): boolean {\n return false;\n },\n isInfoEnabled(): boolean {\n return false;\n },\n isWarnEnabled(): boolean {\n return false;\n },\n isErrorEnabled(): boolean {\n return false;\n },\n isFatalEnabled(): boolean {\n return false;\n },\n trace(): void {\n // noop\n },\n debug(): void {\n // noop\n },\n info(): void {\n // noop\n },\n warn(): void {\n // noop\n },\n error(): void {\n // noop\n },\n fatal(): void {\n // noop\n },\n};\n" + }, + "/home/nicojs/github/stryker-js/packages/util/src/not-empty.ts": { + "language": "typescript", + "mutants": [ + { + "id": "176", + "mutatorName": "BlockStatement", + "replacement": "{}", + "statusReason": "src/not-empty.ts(1,58): error TS2355: A function whose declared type is neither 'void' nor 'any' must return a value.\n", + "status": "CompileError", + "estimatedNetTime": 26, + "hitCount": 83, + "static": false, + "coveredBy": ["5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "35", "36", "37", "38", "39", "57", "58", "59"], + "location": { "end": { "column": 2, "line": 3 }, "start": { "column": 68, "line": 1 } } + }, + { + "id": "177", + "mutatorName": "ConditionalExpression", + "replacement": "true", + "statusReason": "Attempted to wrap cwd which is already wrapped", + "status": "Killed", + "estimatedNetTime": 26, + "hitCount": 83, + "static": false, + "testsCompleted": 1, + "killedBy": ["5"], + "coveredBy": ["5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "35", "36", "37", "38", "39", "57", "58", "59"], + "location": { "end": { "column": 45, "line": 2 }, "start": { "column": 10, "line": 2 } } + }, + { + "id": "178", + "mutatorName": "ConditionalExpression", + "replacement": "false", + "statusReason": "Attempted to wrap cwd which is already wrapped", + "status": "Killed", + "estimatedNetTime": 26, + "hitCount": 83, + "static": false, + "testsCompleted": 1, + "killedBy": ["5"], + "coveredBy": ["5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "35", "36", "37", "38", "39", "57", "58", "59"], + "location": { "end": { "column": 45, "line": 2 }, "start": { "column": 10, "line": 2 } } + }, + { + "id": "179", + "mutatorName": "LogicalOperator", + "replacement": "item !== undefined || item !== null", + "statusReason": "Attempted to wrap cwd which is already wrapped", + "status": "Killed", + "estimatedNetTime": 26, + "hitCount": 83, + "static": false, + "testsCompleted": 1, + "killedBy": ["5"], + "coveredBy": ["5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "35", "36", "37", "38", "39", "57", "58", "59"], + "location": { "end": { "column": 45, "line": 2 }, "start": { "column": 10, "line": 2 } } + }, + { + "id": "180", + "mutatorName": "ConditionalExpression", + "replacement": "true", + "statusReason": "Cannot read property 'path' of undefined", + "status": "Killed", + "estimatedNetTime": 26, + "hitCount": 83, + "static": false, + "testsCompleted": 12, + "killedBy": ["35"], + "coveredBy": ["5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "35", "36", "37", "38", "39", "57", "58", "59"], + "location": { "end": { "column": 28, "line": 2 }, "start": { "column": 10, "line": 2 } } + }, + { + "id": "181", + "mutatorName": "ConditionalExpression", + "replacement": "false", + "statusReason": "Attempted to wrap cwd which is already wrapped", + "status": "Killed", + "estimatedNetTime": 26, + "hitCount": 83, + "static": false, + "testsCompleted": 1, + "killedBy": ["5"], + "coveredBy": ["5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "35", "36", "37", "38", "39", "57", "58", "59"], + "location": { "end": { "column": 28, "line": 2 }, "start": { "column": 10, "line": 2 } } + }, + { + "id": "182", + "mutatorName": "EqualityOperator", + "replacement": "item === undefined", + "statusReason": "Attempted to wrap cwd which is already wrapped", + "status": "Killed", + "estimatedNetTime": 26, + "hitCount": 83, + "static": false, + "testsCompleted": 1, + "killedBy": ["5"], + "coveredBy": ["5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "35", "36", "37", "38", "39", "57", "58", "59"], + "location": { "end": { "column": 28, "line": 2 }, "start": { "column": 10, "line": 2 } } + }, + { + "id": "183", + "mutatorName": "ConditionalExpression", + "replacement": "true", + "statusReason": "expected true to be false", + "status": "Killed", + "estimatedNetTime": 21, + "hitCount": 25, + "static": false, + "testsCompleted": 14, + "killedBy": ["58"], + "coveredBy": ["5", "6", "7", "8", "9", "10", "11", "12", "36", "37", "38", "39", "57", "58"], + "location": { "end": { "column": 45, "line": 2 }, "start": { "column": 32, "line": 2 } } + }, + { + "id": "184", + "mutatorName": "ConditionalExpression", + "replacement": "false", + "statusReason": "Attempted to wrap cwd which is already wrapped", + "status": "Killed", + "estimatedNetTime": 21, + "hitCount": 25, + "static": false, + "testsCompleted": 1, + "killedBy": ["5"], + "coveredBy": ["5", "6", "7", "8", "9", "10", "11", "12", "36", "37", "38", "39", "57", "58"], + "location": { "end": { "column": 45, "line": 2 }, "start": { "column": 32, "line": 2 } } + }, + { + "id": "185", + "mutatorName": "EqualityOperator", + "replacement": "item === null", + "statusReason": "Attempted to wrap cwd which is already wrapped", + "status": "Killed", + "estimatedNetTime": 21, + "hitCount": 25, + "static": false, + "testsCompleted": 1, + "killedBy": ["5"], + "coveredBy": ["5", "6", "7", "8", "9", "10", "11", "12", "36", "37", "38", "39", "57", "58"], + "location": { "end": { "column": 45, "line": 2 }, "start": { "column": 32, "line": 2 } } + } + ], + "source": "export function notEmpty(item: T | null | undefined): item is T {\n return item !== undefined && item !== null;\n}\n" + }, + "/home/nicojs/github/stryker-js/packages/util/src/platform.ts": { + "language": "typescript", + "mutants": [ + { + "id": "186", + "mutatorName": "BlockStatement", + "replacement": "{}", + "statusReason": "src/platform.ts(6,36): error TS2355: A function whose declared type is neither 'void' nor 'any' must return a value.\n", + "status": "CompileError", + "estimatedNetTime": 20, + "hitCount": 9, + "static": false, + "coveredBy": ["5", "6", "7", "8", "9", "10", "11", "12", "13"], + "location": { "end": { "column": 2, "line": 8 }, "start": { "column": 44, "line": 6 } } + }, + { + "id": "187", + "mutatorName": "ConditionalExpression", + "replacement": "true", + "status": "Survived", + "estimatedNetTime": 20, + "hitCount": 9, + "static": false, + "testsCompleted": 9, + "coveredBy": ["5", "6", "7", "8", "9", "10", "11", "12", "13"], + "location": { "end": { "column": 37, "line": 7 }, "start": { "column": 10, "line": 7 } } + }, + { + "id": "188", + "mutatorName": "ConditionalExpression", + "replacement": "false", + "statusReason": "Attempted to wrap cwd which is already wrapped", + "status": "Killed", + "estimatedNetTime": 20, + "hitCount": 9, + "static": false, + "testsCompleted": 1, + "killedBy": ["5"], + "coveredBy": ["5", "6", "7", "8", "9", "10", "11", "12", "13"], + "location": { "end": { "column": 37, "line": 7 }, "start": { "column": 10, "line": 7 } } + }, + { + "id": "190", + "mutatorName": "StringLiteral", + "replacement": "\"\"", + "statusReason": "src/platform.ts(7,10): error TS2367: This condition will always return 'true' since the types 'Platform' and '\"\"' have no overlap.\n", + "status": "CompileError", + "estimatedNetTime": 20, + "hitCount": 9, + "static": false, + "coveredBy": ["5", "6", "7", "8", "9", "10", "11", "12", "13"], + "location": { "end": { "column": 37, "line": 7 }, "start": { "column": 30, "line": 7 } } + }, + { + "id": "189", + "mutatorName": "EqualityOperator", + "replacement": "process.platform == 'win32'", + "statusReason": "Attempted to wrap cwd which is already wrapped", + "status": "Killed", + "estimatedNetTime": 20, + "hitCount": 9, + "static": false, + "testsCompleted": 1, + "killedBy": ["5"], + "coveredBy": ["5", "6", "7", "8", "9", "10", "11", "12", "13"], + "location": { "end": { "column": 37, "line": 7 }, "start": { "column": 10, "line": 7 } } + } + ], + "source": "/**\n * Tells whether the filesystem is case sensitive.\n *\n * @returns false on Win32, true elsewhere\n */\nexport function caseSensitiveFs(): boolean {\n return process.platform != 'win32';\n}\n" + }, + "/home/nicojs/github/stryker-js/packages/util/src/require-resolve.ts": { + "language": "typescript", + "mutants": [ + { + "id": "191", + "mutatorName": "BlockStatement", + "replacement": "{}", + "statusReason": "src/require-resolve.ts(5,67): error TS2355: A function whose declared type is neither 'void' nor 'any' must return a value.\n", + "status": "CompileError", + "estimatedNetTime": 0, + "static": false, + "coveredBy": [], + "location": { "end": { "column": 2, "line": 8 }, "start": { "column": 75, "line": 5 } } + }, + { + "id": "192", + "mutatorName": "ObjectLiteral", + "replacement": "{}", + "status": "NoCoverage", + "estimatedNetTime": 0, + "static": false, + "coveredBy": [], + "location": { "end": { "column": 55, "line": 7 }, "start": { "column": 38, "line": 7 } } + }, + { + "id": "193", + "mutatorName": "ArrayDeclaration", + "replacement": "[]", + "status": "NoCoverage", + "estimatedNetTime": 0, + "static": false, + "coveredBy": [], + "location": { "end": { "column": 53, "line": 7 }, "start": { "column": 47, "line": 7 } } + } + ], + "source": "/**\n * Require a module from the current working directory (or a different base dir)\n * @see https://nodejs.org/api/modules.html#modules_require_resolve_paths_request\n */\nexport function requireResolve(id: string, from = process.cwd()): unknown {\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n return require(require.resolve(id, { paths: [from] }));\n}\n" + }, + "/home/nicojs/github/stryker-js/packages/util/src/string-utils.ts": { + "language": "typescript", + "mutants": [ + { + "id": "194", + "mutatorName": "BlockStatement", + "replacement": "{}", + "statusReason": "src/string-utils.ts(10,52): error TS2355: A function whose declared type is neither 'void' nor 'any' must return a value.\n", + "status": "CompileError", + "estimatedNetTime": 1, + "hitCount": 3, + "static": false, + "coveredBy": ["60", "61", "62"], + "location": { "end": { "column": 2, "line": 12 }, "start": { "column": 59, "line": 10 } } + }, + { + "id": "195", + "mutatorName": "Regex", + "replacement": "/\\s/g", + "statusReason": "expected 'foo bar baz' to equal 'foo bar baz'", + "status": "Killed", + "estimatedNetTime": 1, + "hitCount": 3, + "static": false, + "testsCompleted": 2, + "killedBy": ["61"], + "coveredBy": ["60", "61", "62"], + "location": { "end": { "column": 28, "line": 11 }, "start": { "column": 22, "line": 11 } } + }, + { + "id": "198", + "mutatorName": "BlockStatement", + "replacement": "{}", + "statusReason": "src/string-utils.ts(18,54): error TS2355: A function whose declared type is neither 'void' nor 'any' must return a value.\n", + "status": "CompileError", + "estimatedNetTime": 1, + "hitCount": 2, + "static": false, + "coveredBy": ["65", "66"], + "location": { "end": { "column": 2, "line": 20 }, "start": { "column": 61, "line": 18 } } + }, + { + "id": "196", + "mutatorName": "Regex", + "replacement": "/\\S+/g", + "statusReason": "expected '' to equal 'foo bar baz'", + "status": "Killed", + "estimatedNetTime": 1, + "hitCount": 3, + "static": false, + "testsCompleted": 1, + "killedBy": ["60"], + "coveredBy": ["60", "61", "62"], + "location": { "end": { "column": 28, "line": 11 }, "start": { "column": 22, "line": 11 } } + }, + { + "id": "199", + "mutatorName": "BlockStatement", + "replacement": "{}", + "statusReason": "src/string-utils.ts(32,91): error TS2355: A function whose declared type is neither 'void' nor 'any' must return a value.\n", + "status": "CompileError", + "estimatedNetTime": 1, + "hitCount": 4, + "static": false, + "coveredBy": ["63", "64"], + "location": { "end": { "column": 4, "line": 34 }, "start": { "column": 146, "line": 32 } } + }, + { + "id": "197", + "mutatorName": "StringLiteral", + "replacement": "\"\"", + "statusReason": "expected 'foobarbaz' to equal 'foo bar baz'", + "status": "Killed", + "estimatedNetTime": 1, + "hitCount": 3, + "static": false, + "testsCompleted": 1, + "killedBy": ["60"], + "coveredBy": ["60", "61", "62"], + "location": { "end": { "column": 33, "line": 11 }, "start": { "column": 30, "line": 11 } } + }, + { + "id": "201", + "mutatorName": "BlockStatement", + "replacement": "{}", + "statusReason": "src/string-utils.ts(39,19): error TS2355: A function whose declared type is neither 'void' nor 'any' must return a value.\n", + "status": "CompileError", + "estimatedNetTime": 1, + "hitCount": 2, + "static": false, + "coveredBy": ["63"], + "location": { "end": { "column": 4, "line": 41 }, "start": { "column": 26, "line": 39 } } + }, + { + "id": "203", + "mutatorName": "BlockStatement", + "replacement": "{}", + "statusReason": "src/string-utils.ts(46,30): error TS2355: A function whose declared type is neither 'void' nor 'any' must return a value.\n", + "status": "CompileError", + "estimatedNetTime": 1, + "hitCount": 2, + "static": false, + "coveredBy": ["63", "64"], + "location": { "end": { "column": 4, "line": 48 }, "start": { "column": 53, "line": 46 } } + }, + { + "id": "200", + "mutatorName": "ArrayDeclaration", + "replacement": "[]", + "statusReason": "expected '' to equal 'bar.baz'", + "status": "Killed", + "estimatedNetTime": 1, + "hitCount": 4, + "static": false, + "testsCompleted": 1, + "killedBy": ["63"], + "coveredBy": ["63", "64"], + "location": { "end": { "column": 107, "line": 33 }, "start": { "column": 71, "line": 33 } } + }, + { + "id": "202", + "mutatorName": "StringLiteral", + "replacement": "\"\"", + "statusReason": "expected 'barbaz' to equal 'bar.baz'", + "status": "Killed", + "estimatedNetTime": 1, + "hitCount": 2, + "static": false, + "testsCompleted": 1, + "killedBy": ["63"], + "coveredBy": ["63"], + "location": { "end": { "column": 35, "line": 40 }, "start": { "column": 32, "line": 40 } } + }, + { + "id": "205", + "mutatorName": "BlockStatement", + "replacement": "{}", + "statusReason": "src/string-utils.ts(50,22): error TS2355: A function whose declared type is neither 'void' nor 'any' must return a value.\n", + "status": "CompileError", + "estimatedNetTime": 1, + "hitCount": 1, + "static": false, + "coveredBy": ["63"], + "location": { "end": { "column": 4, "line": 52 }, "start": { "column": 29, "line": 50 } } + }, + { + "id": "206", + "mutatorName": "BlockStatement", + "replacement": "{}", + "statusReason": "src/string-utils.ts(58,53): error TS2355: A function whose declared type is neither 'void' nor 'any' must return a value.\n", + "status": "CompileError", + "estimatedNetTime": 4, + "hitCount": 17, + "static": false, + "coveredBy": ["67", "68", "69", "70", "71", "72", "73", "74", "75", "76", "77", "78", "79", "80", "81", "82", "83"], + "location": { "end": { "column": 2, "line": 60 }, "start": { "column": 60, "line": 58 } } + }, + { + "id": "204", + "mutatorName": "ArrayDeclaration", + "replacement": "[\"Stryker was here\"]", + "statusReason": "expected 'Stryker was here.bar.baz' to equal 'bar.baz'", + "status": "Killed", + "estimatedNetTime": 1, + "hitCount": 2, + "static": false, + "testsCompleted": 1, + "killedBy": ["63"], + "coveredBy": ["63", "64"], + "location": { "end": { "column": 41, "line": 47 }, "start": { "column": 39, "line": 47 } } + }, + { + "id": "209", + "mutatorName": "BlockStatement", + "replacement": "{}", + "statusReason": "src/string-utils.ts(65,46): error TS2355: A function whose declared type is neither 'void' nor 'any' must return a value.\n", + "status": "CompileError", + "estimatedNetTime": 4, + "hitCount": 17, + "static": false, + "coveredBy": ["84", "85", "86", "87", "88", "89", "90", "91", "92", "93", "94", "95", "96", "97", "98", "99", "100"], + "location": { "end": { "column": 2, "line": 67 }, "start": { "column": 53, "line": 65 } } + }, + { + "id": "207", + "mutatorName": "Regex", + "replacement": "/[^.*+\\-?^${}()|[\\]\\\\/]/g", + "statusReason": "expected '\\\\s\\\\o\\\\m\\\\e\\\\t\\\\h\\\\i\\\\n\\\\g\\\\ \\\\n\\\\o\\\\r\\\\m\\\\a\\\\l' to equal 'something normal'", + "status": "Killed", + "estimatedNetTime": 4, + "hitCount": 17, + "static": false, + "testsCompleted": 1, + "killedBy": ["67"], + "coveredBy": ["67", "68", "69", "70", "71", "72", "73", "74", "75", "76", "77", "78", "79", "80", "81", "82", "83"], + "location": { "end": { "column": 48, "line": 59 }, "start": { "column": 24, "line": 59 } } + }, + { + "id": "208", + "mutatorName": "StringLiteral", + "replacement": "\"\"", + "statusReason": "expected '' to equal '\\\\.'", + "status": "Killed", + "estimatedNetTime": 4, + "hitCount": 17, + "static": false, + "testsCompleted": 2, + "killedBy": ["68"], + "coveredBy": ["67", "68", "69", "70", "71", "72", "73", "74", "75", "76", "77", "78", "79", "80", "81", "82", "83"], + "location": { "end": { "column": 56, "line": 59 }, "start": { "column": 50, "line": 59 } } + }, + { + "id": "210", + "mutatorName": "Regex", + "replacement": "/[^.*+\\-?^${}()|[\\]\\\\]/g", + "statusReason": "expected '\\\\s\\\\o\\\\m\\\\e\\\\t\\\\h\\\\i\\\\n\\\\g\\\\ \\\\n\\\\o\\\\r\\\\m\\\\a\\\\l' to equal 'something normal'", + "status": "Killed", + "estimatedNetTime": 4, + "hitCount": 17, + "static": false, + "testsCompleted": 1, + "killedBy": ["84"], + "coveredBy": ["84", "85", "86", "87", "88", "89", "90", "91", "92", "93", "94", "95", "96", "97", "98", "99", "100"], + "location": { "end": { "column": 47, "line": 66 }, "start": { "column": 24, "line": 66 } } + }, + { + "id": "211", + "mutatorName": "StringLiteral", + "replacement": "\"\"", + "statusReason": "expected '' to equal '\\\\.'", + "status": "Killed", + "estimatedNetTime": 4, + "hitCount": 17, + "static": false, + "testsCompleted": 3, + "killedBy": ["86"], + "coveredBy": ["84", "85", "86", "87", "88", "89", "90", "91", "92", "93", "94", "95", "96", "97", "98", "99", "100"], + "location": { "end": { "column": 55, "line": 66 }, "start": { "column": 49, "line": 66 } } + } + ], + "source": "import { KnownKeys } from './known-keys';\nimport { Primitive } from './primitive';\n\ntype OnlyObject = Exclude;\n\n/**\n * Consolidates multiple consecutive white spaces into a single space.\n * @param str The string to be normalized\n */\nexport function normalizeWhitespaces(str: string): string {\n return str.replace(/\\s+/g, ' ').trim();\n}\n\n/**\n * Given a base type, allows type safe access to the name of a property.\n * @param prop The property name\n */\nexport function propertyPath(prop: KnownKeys): string {\n return String(prop);\n}\n\n/**\n * A helper class to allow you to get type safe access to the name of a deep property of `T`\n * @example\n * ```ts\n * PropertyPathBuilder('warnings').prop('unknownOptions').build()\n * ```\n */\nexport class PropertyPathBuilder {\n constructor(private readonly pathSoFar: string[]) {}\n\n public prop> & keyof OnlyObject>(prop: TProp): PropertyPathBuilder, TProp>[TProp]> {\n return new PropertyPathBuilder, TProp>[TProp]>([...this.pathSoFar, prop.toString()]);\n }\n\n /**\n * Build the (deep) path to the property name\n */\n public build(): string {\n return this.pathSoFar.join('.');\n }\n\n /**\n * Creates a new `PropertyPathBuilder` for type T\n */\n public static create(): PropertyPathBuilder {\n return new PropertyPathBuilder([]);\n }\n\n public toString(): string {\n return this.build();\n }\n}\n\n/**\n * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#Escaping\n */\nexport function escapeRegExpLiteral(input: string): string {\n return input.replace(/[.*+\\-?^${}()|[\\]\\\\/]/g, '\\\\$&'); // $& means the whole matched string\n}\n\n/**\n * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#Escaping\n */\nexport function escapeRegExp(input: string): string {\n return input.replace(/[.*+\\-?^${}()|[\\]\\\\]/g, '\\\\$&'); // $& means the whole matched string\n}\n" + }, + "/home/nicojs/github/stryker-js/packages/util/src/stryker-error.ts": { + "language": "typescript", + "mutants": [ + { + "id": "212", + "mutatorName": "StringLiteral", + "replacement": "``", + "statusReason": "expected '' to equal 'some message. Inner error: Error: \\nError: \\n at Context. (/home/nicojs/github/stryker-js/packages/util/.stryker-tmp/sandbox8696228/test/unit/stryker-error.spec.ts:15:24)\\n at callFn (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runnable.js:366:21)\\n at Test.Runnable.run (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runnable.js:354:5)\\n at Runner.runTest (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:681:10)\\n at /home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:804:12\\n at next (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:596:14)\\n at /home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:606:7\\n at next (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:489:14)\\n at Immediate._onImmediate (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:574:5)\\n at processImmediate (internal/timers.js:464:21)'", + "status": "Killed", + "estimatedNetTime": 4, + "hitCount": 3, + "static": false, + "testsCompleted": 2, + "killedBy": ["102"], + "coveredBy": ["101", "102", "103"], + "location": { "end": { "column": 89, "line": 5 }, "start": { "column": 11, "line": 5 } } + }, + { + "id": "213", + "mutatorName": "StringLiteral", + "replacement": "``", + "statusReason": "expected 'some message' to equal 'some message. Inner error: Error: \\nError: \\n at Context. (/home/nicojs/github/stryker-js/packages/util/.stryker-tmp/sandbox8696228/test/unit/stryker-error.spec.ts:15:24)\\n at callFn (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runnable.js:366:21)\\n at Test.Runnable.run (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runnable.js:354:5)\\n at Runner.runTest (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:681:10)\\n at /home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:804:12\\n at next (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:596:14)\\n at /home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:606:7\\n at next (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:489:14)\\n at Immediate._onImmediate (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:574:5)\\n at processImmediate (internal/timers.js:464:21)'", + "status": "Killed", + "estimatedNetTime": 4, + "hitCount": 2, + "static": false, + "testsCompleted": 2, + "killedBy": ["102"], + "coveredBy": ["101", "102"], + "location": { "end": { "column": 82, "line": 5 }, "start": { "column": 37, "line": 5 } } + }, + { + "id": "214", + "mutatorName": "StringLiteral", + "replacement": "\"Stryker was here!\"", + "statusReason": "expected 'foo barStryker was here!' to equal 'foo bar'", + "status": "Killed", + "estimatedNetTime": 0, + "hitCount": 1, + "static": false, + "testsCompleted": 1, + "killedBy": ["103"], + "coveredBy": ["103"], + "location": { "end": { "column": 87, "line": 5 }, "start": { "column": 85, "line": 5 } } + } + ], + "source": "import { errorToString } from './errors';\n\nexport class StrykerError extends Error {\n constructor(message: string, public readonly innerError?: unknown) {\n super(`${message}${innerError ? `. Inner error: ${errorToString(innerError)}` : ''}`);\n }\n}\n" + }, + "/home/nicojs/github/stryker-js/packages/util/src/task.ts": { + "language": "typescript", + "mutants": [ + { + "id": "216", + "mutatorName": "BlockStatement", + "replacement": "{}", + "statusReason": "src/task.ts(5,13): error TS2564: Property '_promise' has no initializer and is not definitely assigned in the constructor.\n", + "status": "CompileError", + "estimatedNetTime": 6, + "hitCount": 8, + "static": false, + "coveredBy": ["104", "105", "106", "107", "108", "109", "110", "111"], + "location": { "end": { "column": 4, "line": 15 }, "start": { "column": 17, "line": 10 } } + }, + { + "id": "215", + "mutatorName": "BooleanLiteral", + "replacement": "true", + "statusReason": "Invalid Chai property: rejectedWith", + "status": "Killed", + "estimatedNetTime": 6, + "hitCount": 8, + "static": false, + "testsCompleted": 3, + "killedBy": ["106"], + "coveredBy": ["104", "105", "106", "107", "108", "109", "110", "111"], + "location": { "end": { "column": 31, "line": 8 }, "start": { "column": 26, "line": 8 } } + }, + { + "id": "218", + "mutatorName": "BlockStatement", + "replacement": "{}", + "statusReason": "src/task.ts(17,14): error TS2378: A 'get' accessor must return a value.\nsrc/task.ts(17,25): error TS2355: A function whose declared type is neither 'void' nor 'any' must return a value.\n", + "status": "CompileError", + "estimatedNetTime": 6, + "hitCount": 7, + "static": false, + "coveredBy": ["104", "105", "106", "108", "109", "110", "111"], + "location": { "end": { "column": 4, "line": 19 }, "start": { "column": 36, "line": 17 } } + }, + { + "id": "217", + "mutatorName": "BlockStatement", + "replacement": "{}", + "statusReason": "this.resolveFn is not a function", + "status": "Killed", + "estimatedNetTime": 6, + "hitCount": 8, + "static": false, + "testsCompleted": 1, + "killedBy": ["104"], + "coveredBy": ["104", "105", "106", "107", "108", "109", "110", "111"], + "location": { "end": { "column": 6, "line": 14 }, "start": { "column": 57, "line": 11 } } + }, + { + "id": "219", + "mutatorName": "BlockStatement", + "replacement": "{}", + "statusReason": "src/task.ts(21,14): error TS2378: A 'get' accessor must return a value.\nsrc/task.ts(21,29): error TS2355: A function whose declared type is neither 'void' nor 'any' must return a value.\n", + "status": "CompileError", + "estimatedNetTime": 0, + "hitCount": 2, + "static": false, + "coveredBy": ["107"], + "location": { "end": { "column": 4, "line": 23 }, "start": { "column": 37, "line": 21 } } + }, + { + "id": "221", + "mutatorName": "BooleanLiteral", + "replacement": "false", + "statusReason": "expected false to be true", + "status": "Killed", + "estimatedNetTime": 3, + "hitCount": 5, + "static": false, + "testsCompleted": 3, + "killedBy": ["107"], + "coveredBy": ["104", "105", "107", "109", "111"], + "location": { "end": { "column": 29, "line": 26 }, "start": { "column": 25, "line": 26 } } + }, + { + "id": "222", + "mutatorName": "BlockStatement", + "replacement": "{}", + "statusReason": "Invalid Chai property: rejectedWith", + "status": "Killed", + "estimatedNetTime": 1, + "hitCount": 2, + "static": false, + "testsCompleted": 1, + "killedBy": ["106"], + "coveredBy": ["106", "110"], + "location": { "end": { "column": 4, "line": 33 }, "start": { "column": 65, "line": 30 } } + }, + { + "id": "223", + "mutatorName": "BooleanLiteral", + "replacement": "false", + "statusReason": "Invalid Chai property: rejectedWith", + "status": "Killed", + "estimatedNetTime": 1, + "hitCount": 2, + "static": false, + "testsCompleted": 1, + "killedBy": ["106"], + "coveredBy": ["106", "110"], + "location": { "end": { "column": 29, "line": 31 }, "start": { "column": 25, "line": 31 } } + }, + { + "id": "225", + "mutatorName": "BlockStatement", + "replacement": "{}", + "statusReason": "src/task.ts(47,62): error TS2355: A function whose declared type is neither 'void' nor 'any' must return a value.\n", + "status": "CompileError", + "estimatedNetTime": 6, + "hitCount": 5, + "static": false, + "coveredBy": ["108", "109", "110", "111", "112"], + "location": { "end": { "column": 4, "line": 61 }, "start": { "column": 111, "line": 47 } } + }, + { + "id": "224", + "mutatorName": "StringLiteral", + "replacement": "\"\"", + "statusReason": "Attempted to wrap cwd which is already wrapped", + "status": "Killed", + "estimatedNetTime": 73, + "hitCount": 1, + "static": true, + "testsCompleted": 6, + "killedBy": ["5"], + "location": { "end": { "column": 81, "line": 40 }, "start": { "column": 65, "line": 40 } } + }, + { + "id": "228", + "mutatorName": "BlockStatement", + "replacement": "{}", + "statusReason": "expected Symbol(TimeoutExpired) to equal 'in time'", + "status": "Killed", + "estimatedNetTime": 4, + "hitCount": 3, + "static": false, + "testsCompleted": 1, + "killedBy": ["109"], + "coveredBy": ["109", "111", "112"], + "location": { "end": { "column": 10, "line": 54 }, "start": { "column": 27, "line": 51 } } + }, + { + "id": "229", + "mutatorName": "BlockStatement", + "replacement": "{}", + "statusReason": "expected promise to be rejected with 'Error: expected error' but it was fulfilled with Symbol(TimeoutExpired)", + "status": "Killed", + "estimatedNetTime": 0, + "hitCount": 1, + "static": false, + "testsCompleted": 1, + "killedBy": ["110"], + "coveredBy": ["110"], + "location": { "end": { "column": 10, "line": 58 }, "start": { "column": 27, "line": 55 } } + }, + { + "id": "220", + "mutatorName": "BlockStatement", + "replacement": "{}", + "status": "Timeout", + "estimatedNetTime": 3, + "hitCount": 5, + "static": false, + "coveredBy": ["104", "105", "107", "109", "111"], + "location": { "end": { "column": 4, "line": 28 }, "start": { "column": 58, "line": 25 } } + }, + { + "id": "226", + "mutatorName": "BlockStatement", + "replacement": "{}", + "status": "Timeout", + "estimatedNetTime": 6, + "hitCount": 5, + "static": false, + "coveredBy": ["108", "109", "110", "111", "112"], + "location": { "end": { "column": 6, "line": 59 }, "start": { "column": 86, "line": 48 } } + }, + { + "id": "227", + "mutatorName": "ArrowFunction", + "replacement": "() => undefined", + "status": "Timeout", + "estimatedNetTime": 6, + "hitCount": 5, + "static": false, + "coveredBy": ["108", "109", "110", "111", "112"], + "location": { "end": { "column": 71, "line": 49 }, "start": { "column": 32, "line": 49 } } + } + ], + "source": "/**\n * Wraps a promise in a Task api for convenience.\n */\nexport class Task {\n protected _promise: Promise;\n private resolveFn!: (value: PromiseLike | T) => void;\n private rejectFn!: (reason: any) => void;\n private _isCompleted = false;\n\n constructor() {\n this._promise = new Promise((resolve, reject) => {\n this.resolveFn = resolve;\n this.rejectFn = reject;\n });\n }\n\n public get promise(): Promise {\n return this._promise;\n }\n\n public get isCompleted(): boolean {\n return this._isCompleted;\n }\n\n public resolve = (result: PromiseLike | T): void => {\n this._isCompleted = true;\n this.resolveFn(result);\n };\n\n public reject: (reason: any) => void = (reason: any): void => {\n this._isCompleted = true;\n this.rejectFn(reason);\n };\n}\n\n/**\n * A task that can expire after the given time.\n */\nexport class ExpirableTask extends Task {\n public static readonly TimeoutExpired: unique symbol = Symbol('TimeoutExpired');\n\n constructor(timeoutMS: number) {\n super();\n this._promise = ExpirableTask.timeout(this._promise, timeoutMS);\n }\n\n public static timeout(promise: Promise, ms: number): Promise {\n const sleep = new Promise((res, rej) => {\n const timer = setTimeout(() => res(ExpirableTask.TimeoutExpired), ms);\n promise\n .then((result) => {\n clearTimeout(timer);\n res(result);\n })\n .catch((error) => {\n clearTimeout(timer);\n rej(error);\n });\n });\n return sleep;\n }\n}\n" + } + }, + "schemaVersion": "1.0", + "thresholds": { "high": 80, "low": 60, "break": null }, + "testFiles": { + "": { + "tests": [ + { "id": "0", "name": "childProcessAsPromised should expose promisified exec" }, + { "id": "1", "name": "deepMerge should merge overrides into the target object" }, + { "id": "2", "name": "deepMerge should deep merge overrides into the target object" }, + { "id": "3", "name": "deepMerge should override arrays without merging them" }, + { "id": "4", "name": "deepMerge should not override with `undefined`" }, + { "id": "5", "name": "DirectoryRequireCache should clear recorded files" }, + { "id": "6", "name": "DirectoryRequireCache should only record the first time (perf optimization)" }, + { "id": "7", "name": "DirectoryRequireCache should clear recorded children from their respective parent" }, + { "id": "8", "name": "DirectoryRequireCache should clear recorded separate unique parents" }, + { "id": "9", "name": "DirectoryRequireCache should not break when clearing a graph" }, + { "id": "10", "name": "DirectoryRequireCache should not throw when the parent module was unloaded" }, + { "id": "11", "name": "DirectoryRequireCache should not throw when the parent module is one of the modules to being cleared" }, + { "id": "12", "name": "DirectoryRequireCache should not clear files from node_modules" }, + { "id": "13", "name": "DirectoryRequireCache should not fail when recorded file doesn't have a parent" }, + { "id": "14", "name": "DirectoryRequireCache should support case-insensitive filesystems" }, + { "id": "15", "name": "DirectoryRequireCache should support case-sensitive filesystems" }, + { "id": "16", "name": "errors errorToString should return empty string if error is undefined" }, + { "id": "17", "name": "errors errorToString should convert a nodejs Errno error to string" }, + { "id": "18", "name": "errors errorToString should convert a regular error to string" }, + { "id": "19", "name": "errors errorToString should convert an error without a stack trace to string" }, + { "id": "20", "name": "findUnserializables should mark 4 as serializable" }, + { "id": "21", "name": "findUnserializables should mark true as serializable" }, + { "id": "22", "name": "findUnserializables should mark undefined as serializable" }, + { "id": "23", "name": "findUnserializables should mark null as serializable" }, + { "id": "24", "name": "findUnserializables should mark \"str\" as serializable" }, + { "id": "25", "name": "findUnserializables should mark {} as serializable" }, + { "id": "26", "name": "findUnserializables should mark [] as serializable" }, + { "id": "27", "name": "findUnserializables should mark plain object without a prototype as serializable" }, + { "id": "28", "name": "findUnserializables should mark primitive type symbol as unserializable" }, + { "id": "29", "name": "findUnserializables should mark primitive type bigint as unserializable" }, + { "id": "30", "name": "findUnserializables should mark primitive type function as unserializable" }, + { "id": "31", "name": "findUnserializables should mark number value NaN as unserializable" }, + { "id": "32", "name": "findUnserializables should mark number value Infinity as unserializable" }, + { "id": "33", "name": "findUnserializables should mark number value -Infinity as unserializable" }, + { "id": "34", "name": "findUnserializables should mark class instances as unserializable" }, + { "id": "35", "name": "findUnserializables should mark the default stryker options as \"serializable\"" }, + { "id": "36", "name": "findUnserializables path should be provided in a shallow object" }, + { "id": "37", "name": "findUnserializables path should be provided in a deep object" }, + { "id": "38", "name": "findUnserializables path should be provided in a shallow array" }, + { "id": "39", "name": "findUnserializables path should be provided in a deep array" }, + { "id": "40", "name": "findUnserializables reason should be provided for an unserializable primitive value" }, + { "id": "41", "name": "findUnserializables reason should be provided for a class instance" }, + { "id": "42", "name": "findUnserializables reason should be provided for an anonymous class instance" }, + { "id": "43", "name": "findUnserializables reason should be provided for a RegExp" }, + { "id": "44", "name": "findUnserializables reason should be provided for a Date" }, + { "id": "45", "name": "findUnserializables reason should be provided for unserializable numbers" }, + { "id": "46", "name": "deepFreeze should not change the input object" }, + { "id": "47", "name": "deepFreeze should freeze objects" }, + { "id": "48", "name": "deepFreeze should work for `null` and `undefined`" }, + { "id": "49", "name": "deepFreeze should work for primitives" }, + { "id": "50", "name": "deepFreeze should deeply freeze objects" }, + { "id": "51", "name": "deepFreeze should work for Arrays" }, + { "id": "52", "name": "deepFreeze should work for Maps" }, + { "id": "53", "name": "deepFreeze should work for Sets" }, + { "id": "54", "name": "deepFreeze should work for RegExps" }, + { "id": "55", "name": "noopLogger should not enable any logging" }, + { "id": "56", "name": "noopLogger should not do any actual logging" }, + { "id": "57", "name": "notEmpty should return true when not null or undefined" }, + { "id": "58", "name": "notEmpty should return false when null" }, + { "id": "59", "name": "notEmpty should return false when undefined" }, + { "id": "60", "name": "stringUtils normalizeWhitespaces should not change strings without consecutive whitespaces" }, + { "id": "61", "name": "stringUtils normalizeWhitespaces should normalize a string with multiple consecutive spaces" }, + { "id": "62", "name": "stringUtils normalizeWhitespaces should normalize a string with multiple consecutive spaces, tabs and new lines" }, + { "id": "63", "name": "stringUtils PropertyPathBuilder should be able to point to a path" }, + { "id": "64", "name": "stringUtils PropertyPathBuilder should not be able to point to a path non-existing path" }, + { "id": "65", "name": "stringUtils propertyPath should be able to point to a path" }, + { "id": "66", "name": "stringUtils propertyPath should not be able to point to a non-existing path" }, + { "id": "67", "name": "stringUtils escapeRegExpLiteral should return input if no special chars are found" }, + { "id": "68", "name": "stringUtils escapeRegExpLiteral should escape \".\"" }, + { "id": "69", "name": "stringUtils escapeRegExpLiteral should escape \"*\"" }, + { "id": "70", "name": "stringUtils escapeRegExpLiteral should escape \"+\"" }, + { "id": "71", "name": "stringUtils escapeRegExpLiteral should escape \"-\"" }, + { "id": "72", "name": "stringUtils escapeRegExpLiteral should escape \"?\"" }, + { "id": "73", "name": "stringUtils escapeRegExpLiteral should escape \"^\"" }, + { "id": "74", "name": "stringUtils escapeRegExpLiteral should escape \"$\"" }, + { "id": "75", "name": "stringUtils escapeRegExpLiteral should escape \"{\"" }, + { "id": "76", "name": "stringUtils escapeRegExpLiteral should escape \"}\"" }, + { "id": "77", "name": "stringUtils escapeRegExpLiteral should escape \"(\"" }, + { "id": "78", "name": "stringUtils escapeRegExpLiteral should escape \")\"" }, + { "id": "79", "name": "stringUtils escapeRegExpLiteral should escape \"|\"" }, + { "id": "80", "name": "stringUtils escapeRegExpLiteral should escape \"[\"" }, + { "id": "81", "name": "stringUtils escapeRegExpLiteral should escape \"]\"" }, + { "id": "82", "name": "stringUtils escapeRegExpLiteral should escape \"\\\"" }, + { "id": "83", "name": "stringUtils escapeRegExpLiteral should escape \"/\"" }, + { "id": "84", "name": "stringUtils escapeRegExp should return input if no special chars are found" }, + { "id": "85", "name": "stringUtils escapeRegExp should not escape `/` (that's only needed for regex literals)" }, + { "id": "86", "name": "stringUtils escapeRegExp should escape \".\"" }, + { "id": "87", "name": "stringUtils escapeRegExp should escape \"*\"" }, + { "id": "88", "name": "stringUtils escapeRegExp should escape \"+\"" }, + { "id": "89", "name": "stringUtils escapeRegExp should escape \"-\"" }, + { "id": "90", "name": "stringUtils escapeRegExp should escape \"?\"" }, + { "id": "91", "name": "stringUtils escapeRegExp should escape \"^\"" }, + { "id": "92", "name": "stringUtils escapeRegExp should escape \"$\"" }, + { "id": "93", "name": "stringUtils escapeRegExp should escape \"{\"" }, + { "id": "94", "name": "stringUtils escapeRegExp should escape \"}\"" }, + { "id": "95", "name": "stringUtils escapeRegExp should escape \"(\"" }, + { "id": "96", "name": "stringUtils escapeRegExp should escape \")\"" }, + { "id": "97", "name": "stringUtils escapeRegExp should escape \"|\"" }, + { "id": "98", "name": "stringUtils escapeRegExp should escape \"[\"" }, + { "id": "99", "name": "stringUtils escapeRegExp should escape \"]\"" }, + { "id": "100", "name": "stringUtils escapeRegExp should escape \"\\\"" }, + { "id": "101", "name": "StrykerError should set inner error" }, + { "id": "102", "name": "StrykerError should add inner error to the message" }, + { "id": "103", "name": "StrykerError should work without an inner error" }, + { "id": "104", "name": "Task should give access to underlying promise" }, + { "id": "105", "name": "Task should be able to resolve the underlying promise" }, + { "id": "106", "name": "Task should be able to reject the underlying promise" }, + { "id": "107", "name": "Task should be able to know if it isCompleted" }, + { "id": "108", "name": "ExpirableTask instance should timeout after set period" }, + { "id": "109", "name": "ExpirableTask instance should be able to resolve within time" }, + { "id": "110", "name": "ExpirableTask instance should be able to reject within time" }, + { "id": "111", "name": "ExpirableTask timeout should timeout a promise after a set period" }, + { "id": "112", "name": "ExpirableTask timeout should remove any nodejs timers when promise resolves" } + ] + } + }, + "projectRoot": "/home/nicojs/github/stryker-js/packages/util", + "config": { + "$schema": "./packages/core/schema/stryker-schema.json", + "coverageAnalysis": "perTest", + "testRunner": "mocha", + "reporters": ["json", "progress", "html", "dashboard"], + "plugins": [ + "/home/nicojs/github/stryker-js/packages/mocha-runner", + "/home/nicojs/github/stryker-js/packages/typescript-checker", + "/home/nicojs/github/stryker-js/packages/core/dist/src/reporters/index.js" + ], + "checkers": ["typescript"], + "dashboard": { "module": "util", "baseUrl": "https://dashboard.stryker-mutator.io/api/reports", "reportType": "full" }, + "buildCommand": "tsc -b", + "mochaOptions": { "spec": ["dist/test/unit/**/*.js"] }, + "allowConsoleColors": true, + "checkerNodeArgs": [], + "maxTestRunnerReuse": 0, + "commandRunner": { "command": "npm test" }, + "clearTextReporter": { "allowColor": true, "logTests": true, "maxTestsToLog": 3 }, + "eventReporter": { "baseDir": "reports/mutation/events" }, + "ignorePatterns": [], + "fileLogLevel": "off", + "inPlace": false, + "logLevel": "info", + "maxConcurrentTestRunners": 9007199254740991, + "mutate": [ + "{src,lib}/**/!(*.+(s|S)pec|*.+(t|T)est).+(cjs|mjs|js|ts|jsx|tsx|html|vue)", + "!{src,lib}/**/__tests__/**/*.+(cjs|mjs|js|ts|jsx|tsx|html|vue)" + ], + "mutator": { "plugins": null, "excludedMutations": [] }, + "appendPlugins": [], + "jsonReporter": { "fileName": "reports/mutation/mutation.json" }, + "disableTypeChecks": "{test,src,lib}/**/*.{js,ts,jsx,tsx,html,vue}", + "symlinkNodeModules": true, + "tempDirName": ".stryker-tmp", + "cleanTempDir": true, + "testRunnerNodeArgs": [], + "thresholds": { "high": 80, "low": 60, "break": null }, + "timeoutFactor": 1.5, + "timeoutMS": 5000, + "dryRunTimeoutMinutes": 5, + "tsconfigFile": "tsconfig.json", + "warnings": true, + "disableBail": false, + "configFile": "/home/nicojs/github/stryker-js/packages/util/stryker.conf.js" + }, + "framework": { + "name": "StrykerJS", + "version": "5.4.1", + "branding": { + "homepageUrl": "https://stryker-mutator.io", + "imageUrl": "data:image/svg+xml;utf8,%3Csvg viewBox='0 0 1458 1458' xmlns='http://www.w3.org/2000/svg' fill-rule='evenodd' clip-rule='evenodd' stroke-linejoin='round' stroke-miterlimit='2'%3E%3Cpath fill='none' d='M0 0h1458v1458H0z'/%3E%3CclipPath id='a'%3E%3Cpath d='M0 0h1458v1458H0z'/%3E%3C/clipPath%3E%3Cg clip-path='url(%23a)'%3E%3Cpath d='M1458 729c0 402.655-326.345 729-729 729S0 1131.655 0 729C0 326.445 326.345 0 729 0s729 326.345 729 729' fill='%23e74c3c' fill-rule='nonzero'/%3E%3Cpath d='M778.349 1456.15L576.6 1254.401l233-105 85-78.668v-64.332l-257-257-44-187-50-208 251.806-82.793L1076.6 389.401l380.14 379.15c-19.681 367.728-311.914 663.049-678.391 687.599z' fill-opacity='.3'/%3E%3Cpath d='M753.4 329.503c41.79 0 74.579 7.83 97.925 25.444 23.571 18.015 41.69 43.956 55.167 77.097l11.662 28.679 165.733-58.183-14.137-32.13c-26.688-60.655-64.896-108.61-114.191-144.011-49.329-35.423-117.458-54.302-204.859-54.302-50.78 0-95.646 7.376-134.767 21.542-40.093 14.671-74.09 34.79-102.239 60.259-28.84 26.207-50.646 57.06-65.496 92.701-14.718 35.052-22.101 72.538-22.101 112.401 0 72.536 20.667 133.294 61.165 182.704 38.624 47.255 98.346 88.037 179.861 121.291 42.257 17.475 78.715 33.125 109.227 46.994 27.193 12.361 49.294 26.124 66.157 41.751 15.309 14.186 26.497 30.584 33.63 49.258 7.721 20.214 11.16 45.69 11.16 76.402 0 28.021-4.251 51.787-13.591 71.219-8.832 18.374-20.171 33.178-34.523 44.219-14.787 11.374-31.193 19.591-49.393 24.466-19.68 5.359-39.14 7.993-58.69 7.993-29.359 0-54.387-3.407-75.182-10.747-20.112-7.013-37.144-16.144-51.259-27.486-13.618-11.009-24.971-23.766-33.744-38.279-9.64-15.8-17.272-31.924-23.032-48.408l-10.965-31.376-161.669 60.585 10.734 30.124c10.191 28.601 24.197 56.228 42.059 82.748 18.208 27.144 41.322 51.369 69.525 72.745 27.695 21.075 60.904 38.218 99.481 51.041 37.777 12.664 82.004 19.159 132.552 19.159 49.998 0 95.818-8.321 137.611-24.622 42.228-16.471 78.436-38.992 108.835-67.291 30.719-28.597 54.631-62.103 71.834-100.642 17.263-38.56 25.923-79.392 25.923-122.248 0-54.339-8.368-100.37-24.208-138.32-16.29-38.759-38.252-71.661-65.948-98.797-26.965-26.418-58.269-48.835-93.858-67.175-33.655-17.241-69.196-33.11-106.593-47.533-35.934-13.429-65.822-26.601-89.948-39.525-22.153-11.868-40.009-24.21-53.547-37.309-11.429-11.13-19.83-23.678-24.718-37.664-5.413-15.49-7.98-33.423-7.98-53.577 0-40.883 11.293-71.522 37.086-90.539 28.443-20.825 64.985-30.658 109.311-30.658z' fill='%23f1c40f' fill-rule='nonzero'/%3E%3Cpath d='M720 0h18v113h-18zM1458 738v-18h-113v18h113zM720 1345h18v113h-18zM113 738v-18H0v18h113z'/%3E%3C/g%3E%3C/svg%3E" + }, + "dependencies": { "mocha": "9.1.3", "jasmine": "3.10.0", "jasmine-core": "3.10.1", "typescript": "4.4.4" } + } +} diff --git a/resources/mutation-testing-report-schema.json b/resources/mutation-testing-report-schema.json new file mode 100644 index 000000000..292fb64f4 --- /dev/null +++ b/resources/mutation-testing-report-schema.json @@ -0,0 +1,353 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "http://stryker-mutator.io/report.schema.json", + "title": "MutationTestResult", + "description": "Schema for a mutation testing report.", + "type": "object", + "required": ["schemaVersion", "thresholds", "files"], + "properties": { + "config": { + "description": "Free-format object that represents the configuration used to run mutation testing.", + "type": "object" + }, + "schemaVersion": { + "type": "string", + "pattern": "^1(\\.\\d*)?$", + "description": "Major version of this report. Used for compatibility.", + "examples": ["1"] + }, + "files": { + "type": "object", + "title": "FileResultDictionary", + "description": "All mutated files.", + "additionalProperties": { + "type": "object", + "title": "FileResult", + "description": "Mutated file, with the relative path of the file as the key.", + "required": ["language", "source", "mutants"], + "properties": { + "language": { + "description": "Programming language that is used. Used for code highlighting, see https://prismjs.com/#examples.", + "examples": ["javascript", "typescript", "cs", "scala", "java"], + "type": "string" + }, + "mutants": { + "type": "array", + "uniqueItems": true, + "items": { + "type": "object", + "title": "MutantResult", + "description": "Single mutation.", + "required": ["id", "mutatorName", "location", "status"], + "properties": { + "coveredBy": { + "type": "array", + "description": "The test ids that covered this mutant. If a mutation testing framework doesn't measure this information, it can simply be left out.", + "items": { + "type": "string" + } + }, + "description": { + "type": "string", + "description": "Description of the applied mutation.", + "examples": ["removed call to java/io/Writer::write"] + }, + "duration": { + "type": "number", + "description": "The net time it took to test this mutant in milliseconds. This is the time measurement without overhead from the mutation testing framework." + }, + "id": { + "type": "string", + "description": "Unique id, can be used to correlate this mutant across reports.", + "examples": ["321321"] + }, + "killedBy": { + "type": "array", + "description": "The test ids that killed this mutant. It is a best practice to \"bail\" on first failing test, in which case you can fill this array with that one test.", + "items": { + "type": "string" + } + }, + "location": { + "$ref": "#/definitions/location" + }, + "mutatorName": { + "type": "string", + "description": "Category of the mutation.", + "examples": ["ConditionalExpression", "EqualityOperator", "LogicalOperator"] + }, + "replacement": { + "type": "string", + "description": "Actual mutation that has been applied.", + "examples": ["-", "+", "&&", "||"] + }, + "static": { + "type": "boolean", + "description": "A static mutant means that it was loaded once at during initialization, this makes it slow or even impossible to test, depending on the mutation testing framework." + }, + "status": { + "type": "string", + "title": "MutantStatus", + "description": "Result of the mutation.", + "enum": ["Killed", "Survived", "NoCoverage", "CompileError", "RuntimeError", "Timeout", "Ignored"] + }, + "statusReason": { + "type": "string", + "description": "The reason that this mutant has this status. In the case of a killed mutant, this should be filled with the failure message(s) of the failing tests. In case of an error mutant, this should be filled with the error message." + }, + "testsCompleted": { + "type": "number", + "description": "The number of tests actually completed in order to test this mutant. Can differ from \"coveredBy\" because of bailing a mutant test run after first failing test." + } + } + } + }, + "source": { + "description": "Full source code of the original file (without mutants), this is used to display exactly what was changed for each mutant.", + "examples": ["using System; using....."], + "type": "string" + } + } + } + }, + "testFiles": { + "type": "object", + "title": "TestFileDefinitionDictionary", + "description": "Test file definitions by file path OR class name.", + "additionalProperties": { + "type": "object", + "title": "TestFile", + "description": "A file containing one or more tests", + "required": ["tests"], + "properties": { + "source": { + "description": "Full source code of the test file, this can be used to display in the report.", + "type": "string" + }, + "tests": { + "type": "array", + "items": { + "type": "object", + "title": "TestDefinition", + "required": ["id", "name"], + "description": "A test in your test file.", + "properties": { + "id": { + "type": "string", + "description": "Unique id of the test, used to correlate what test killed a mutant." + }, + "name": { + "type": "string", + "description": "Name of the test, used to display the test." + }, + "location": { + "$ref": "#/definitions/openEndLocation" + } + } + } + } + } + } + }, + "thresholds": { + "type": "object", + "title": "Thresholds", + "description": "Thresholds for the status of the reported application.", + "required": ["high", "low"], + "properties": { + "high": { + "type": "integer", + "description": "Higher bound threshold.", + "minimum": 0, + "maximum": 100, + "examples": [80] + }, + "low": { + "type": "integer", + "description": "Lower bound threshold.", + "minimum": 0, + "maximum": 100, + "examples": [60] + } + } + }, + "projectRoot": { + "type": "string", + "description": "The optional location of the project root.", + "examples": ["C:\\Projects\\project-under-test", "/home/user/projects/project-under-test"] + }, + "performance": { + "type": "object", + "title": "PerformanceStatistics", + "description": "The performance statistics per phase. Total time should be roughly equal to the sum of all these.", + "required": ["setup", "initialRun", "mutation"], + "properties": { + "setup": { + "type": "number", + "description": "Time it took to run the setup phase in milliseconds." + }, + "initialRun": { + "type": "number", + "description": "Time it took to run the initial test phase (dry-run) in milliseconds." + }, + "mutation": { + "type": "number", + "description": "Time it took to run the mutation test phase in milliseconds." + } + } + }, + "framework": { + "type": "object", + "title": "FrameworkInformation", + "description": "Extra information about the framework used", + "required": ["name"], + "properties": { + "name": { + "type": "string", + "description": "Name of the framework used.", + "examples": ["Stryker", "Stryker4s", "Stryker.NET", "Infection PHP", "Pitest"] + }, + "version": { + "type": "string", + "description": "Version of the framework." + }, + "branding": { + "type": "object", + "title": "BrandingInformation", + "description": "Extra branding information about the framework used.", + "required": ["homepageUrl"], + "properties": { + "homepageUrl": { + "type": "string", + "format": "uri", + "description": "URL to the homepage of the framework." + }, + "imageUrl": { + "type": "string", + "description": "URL to an image for the framework, can be a data URL." + } + } + }, + "dependencies": { + "type": "object", + "title": "Dependencies", + "description": "Dependencies used by the framework. Key-value pair of dependencies and their versions.", + "additionalProperties": { + "type": "string" + } + } + } + }, + "system": { + "type": "object", + "title": "SystemInformation", + "description": "Information about the system that performed mutation testing.", + "required": ["ci"], + "properties": { + "ci": { + "description": "Did mutation testing run in a Continuous Integration environment (pipeline)? Note that there is no way of knowing this for sure. It's done on a best-effort basis.", + "type": "boolean" + }, + "os": { + "type": "object", + "title": "OSInformation", + "required": ["platform"], + "properties": { + "description": { + "type": "string", + "description": "Human-readable description of the OS", + "examples": ["Windows 10 Pro", "Debian Buster", "Ubuntu 20.04.1 LTS"] + }, + "platform": { + "type": "string", + "description": "Platform identifier", + "examples": ["linux", "win32"] + }, + "version": { + "type": "string", + "description": "Version of the OS or distribution", + "examples": ["10.0.19041"] + } + } + }, + "cpu": { + "type": "object", + "title": "CpuInformation", + "required": ["logicalCores"], + "properties": { + "baseClock": { + "type": "number", + "description": "Clock speed in MHz" + }, + "logicalCores": { + "type": "number" + }, + "model": { + "type": "string", + "examples": ["Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz"] + } + } + }, + "ram": { + "title": "RamInformation", + "type": "object", + "required": ["total"], + "properties": { + "total": { + "type": "number", + "description": "The total RAM of the system that performed mutation testing in MB." + } + } + } + } + } + }, + "definitions": { + "position": { + "type": "object", + "title": "Position", + "description": "Position of a mutation. Both line and column start at one.", + "required": ["line", "column"], + "properties": { + "line": { + "type": "integer", + "minimum": 1, + "examples": [4] + }, + "column": { + "type": "integer", + "minimum": 1, + "examples": [3] + } + } + }, + "location": { + "type": "object", + "title": "Location", + "description": "A location with start and end. Start is inclusive, end is exclusive.", + "required": ["start", "end"], + "properties": { + "start": { + "$ref": "#/definitions/position" + }, + "end": { + "$ref": "#/definitions/position" + } + } + }, + "openEndLocation": { + "type": "object", + "title": "OpenEndLocation", + "description": "A location where \"end\" is not required. Start is inclusive, end is exclusive.", + "required": ["start"], + "properties": { + "start": { + "$ref": "#/definitions/position" + }, + "end": { + "$ref": "#/definitions/position" + } + } + } + } +} diff --git a/resources/schema.json b/resources/schema.json index a17f81b67..e583f4a3d 100644 --- a/resources/schema.json +++ b/resources/schema.json @@ -52,12 +52,16 @@ }, "summary": { "type": "string", - "definition": "Summary log file, which display the amount of mutants per category, (Killed, Errored, Escaped, Timed Out & Not Covered). More intended for internal purposes." + "definition": "Summary log file, which displays the amount of mutants per category, (Killed, Errored, Escaped, Timed Out & Not Covered). More intended for internal purposes." }, "json": { "type": "string", "definition": "JSON log file, which contains information about all mutants, as well as the source and mutated code and test framework output. Useful for using on CI servers to be able to programmatically analyze it." }, + "html": { + "type": "string", + "definition": "HTML report, which displays MSI values as well as mutated files with Killed and Escaped mutants with diffs for them. Human readable report, similar to PHPUnit HTML report." + }, "debug": { "type": "string", "description": "Debug log file, which displays what mutations were found on what line, per category. More intended for internal purposes." diff --git a/src/Configuration/Entry/Logs.php b/src/Configuration/Entry/Logs.php index e042a1fff..33fed796d 100644 --- a/src/Configuration/Entry/Logs.php +++ b/src/Configuration/Entry/Logs.php @@ -42,6 +42,7 @@ class Logs { private ?string $textLogFilePath; + private ?string $htmlLogFilePath; private ?string $summaryLogFilePath; private ?string $jsonLogFilePath; private ?string $debugLogFilePath; @@ -51,6 +52,7 @@ class Logs public function __construct( ?string $textLogFilePath, + ?string $htmlLogFilePath, ?string $summaryLogFilePath, ?string $jsonLogFilePath, ?string $debugLogFilePath, @@ -59,6 +61,7 @@ public function __construct( ?Badge $badge ) { $this->textLogFilePath = $textLogFilePath; + $this->htmlLogFilePath = $htmlLogFilePath; $this->summaryLogFilePath = $summaryLogFilePath; $this->jsonLogFilePath = $jsonLogFilePath; $this->debugLogFilePath = $debugLogFilePath; @@ -75,6 +78,7 @@ public static function createEmpty(): self null, null, null, + null, false, null ); @@ -85,6 +89,11 @@ public function getTextLogFilePath(): ?string return $this->textLogFilePath; } + public function getHtmlLogFilePath(): ?string + { + return $this->htmlLogFilePath; + } + public function getSummaryLogFilePath(): ?string { return $this->summaryLogFilePath; diff --git a/src/Configuration/Schema/SchemaConfigurationFactory.php b/src/Configuration/Schema/SchemaConfigurationFactory.php index 4e0d7565d..2c0afcb60 100644 --- a/src/Configuration/Schema/SchemaConfigurationFactory.php +++ b/src/Configuration/Schema/SchemaConfigurationFactory.php @@ -82,6 +82,7 @@ private static function createLogs(stdClass $logs): Logs { return new Logs( self::normalizeString($logs->text ?? null), + self::normalizeString($logs->html ?? null), self::normalizeString($logs->summary ?? null), self::normalizeString($logs->json ?? null), self::normalizeString($logs->debug ?? null), diff --git a/src/Container.php b/src/Container.php index 689f8dd78..fcab36e0e 100644 --- a/src/Container.php +++ b/src/Container.php @@ -35,6 +35,7 @@ namespace Infection; +use Infection\Logger\Html\StrykerHtmlReportBuilder; use function array_filter; use function array_key_exists; use Closure; @@ -564,7 +565,8 @@ public static function create(): self $config->getLogVerbosity(), $config->isDebugEnabled(), $config->mutateOnlyCoveredCode(), - $container->getLogger() + $container->getLogger(), + $container->getStrykerHtmlReportBuilder() ); }, MutationTestingResultsLogger::class => static function (self $container): MutationTestingResultsLogger { @@ -577,6 +579,9 @@ public static function create(): self ), ])); }, + StrykerHtmlReportBuilder::class => static function (self $container): StrykerHtmlReportBuilder { + return new StrykerHtmlReportBuilder($container->getMetricsCalculator(), $container->getResultsCollector()); + }, TargetDetectionStatusesProvider::class => static function (self $container): TargetDetectionStatusesProvider { $config = $container->getConfiguration(); @@ -1298,6 +1303,11 @@ public function getGitDiffFileProvider(): GitDiffFileProvider return $this->get(GitDiffFileProvider::class); } + public function getStrykerHtmlReportBuilder(): StrykerHtmlReportBuilder + { + return $this->get(StrykerHtmlReportBuilder::class); + } + /** * @param class-string $id * @param Closure(self): object $value diff --git a/src/Logger/FileLoggerFactory.php b/src/Logger/FileLoggerFactory.php index 2376f8216..769f719cf 100644 --- a/src/Logger/FileLoggerFactory.php +++ b/src/Logger/FileLoggerFactory.php @@ -37,6 +37,8 @@ use Infection\Configuration\Entry\Logs; use Infection\Console\LogVerbosity; +use Infection\Logger\Html\HtmlFileLogger; +use Infection\Logger\Html\StrykerHtmlReportBuilder; use Infection\Metrics\MetricsCalculator; use Infection\Metrics\ResultsCollector; use Psr\Log\LoggerInterface; @@ -56,6 +58,7 @@ class FileLoggerFactory private bool $debugMode; private bool $onlyCoveredCode; private LoggerInterface $logger; + private StrykerHtmlReportBuilder $strykerHtmlReportBuilder; public function __construct( MetricsCalculator $metricsCalculator, @@ -64,7 +67,8 @@ public function __construct( string $logVerbosity, bool $debugMode, bool $onlyCoveredCode, - LoggerInterface $logger + LoggerInterface $logger, + StrykerHtmlReportBuilder $strykerHtmlReportBuilder ) { $this->metricsCalculator = $metricsCalculator; $this->resultsCollector = $resultsCollector; @@ -73,6 +77,7 @@ public function __construct( $this->debugMode = $debugMode; $this->onlyCoveredCode = $onlyCoveredCode; $this->logger = $logger; + $this->strykerHtmlReportBuilder = $strykerHtmlReportBuilder; } public function createFromLogEntries(Logs $logConfig): MutationTestingResultsLogger @@ -101,6 +106,8 @@ private function createLineLoggers(Logs $logConfig): iterable yield $logConfig->getTextLogFilePath() => $this->createTextLogger(); + yield $logConfig->getHtmlLogFilePath() => $this->createHtmlLogger(); + yield $logConfig->getSummaryLogFilePath() => $this->createSummaryLogger(); yield $logConfig->getJsonLogFilePath() => $this->createJsonLogger(); @@ -134,6 +141,13 @@ private function createTextLogger(): LineMutationTestingResultsLogger ); } + private function createHtmlLogger(): LineMutationTestingResultsLogger + { + return new HtmlFileLogger( + $this->strykerHtmlReportBuilder, + ); + } + private function createSummaryLogger(): LineMutationTestingResultsLogger { return new SummaryFileLogger($this->metricsCalculator); diff --git a/src/Logger/Html/HtmlFileLogger.php b/src/Logger/Html/HtmlFileLogger.php new file mode 100644 index 000000000..bbca18ae5 --- /dev/null +++ b/src/Logger/Html/HtmlFileLogger.php @@ -0,0 +1,79 @@ +strykerHtmlReportBuilder = $strykerHtmlReportBuilder; + } + + public function getLogLines(): array + { + return [ + <<<"HTML" + + + + Back + + + + + + HTML + ]; + } + + public function getMutationTestingReport(): string + { + return json_encode($this->strykerHtmlReportBuilder->build()); + } +} diff --git a/src/Logger/Html/StrykerHtmlReportBuilder.php b/src/Logger/Html/StrykerHtmlReportBuilder.php new file mode 100644 index 000000000..88d0ac0be --- /dev/null +++ b/src/Logger/Html/StrykerHtmlReportBuilder.php @@ -0,0 +1,324 @@ + 'Killed', + DetectionStatus::ESCAPED => 'Survived', + DetectionStatus::ERROR => 'RuntimeError', + DetectionStatus::TIMED_OUT => 'Timeout', + DetectionStatus::NOT_COVERED => 'NoCoverage', + DetectionStatus::SYNTAX_ERROR => 'CompileError', + DetectionStatus::IGNORED => 'Ignored', + ]; + + private const PLUS_LENGTH = 1; + + private MetricsCalculator $metricsCalculator; + private ResultsCollector $resultsCollector; + + public function __construct( + MetricsCalculator $metricsCalculator, + ResultsCollector $resultsCollector + ) + { + $this->metricsCalculator = $metricsCalculator; + $this->resultsCollector = $resultsCollector; + } + + + public function build(): array + { + return [ + 'schemaVersion' => '1', + 'thresholds' => [ + 'high' => 90, + 'low' => 50, + ], + 'files' => $this->getFiles(), +// 'testFiles' => $this->getTestFiles(), + // 'performance' => [], todo + 'framework' => [ + 'name' => 'Infection', + 'branding' => [ + 'homepageUrl' => 'https://infection.github.io/', + 'imageUrl' => 'https://infection.github.io/images/logo.png' + ] + ] + ]; + } + + private function getTestFiles(): \ArrayObject + { + $testFiles = []; + + $allTests = []; + + foreach ($this->resultsCollector->getAllExecutionResults() as $result) { + $allTests[] = $result->getTests(); + } + + $allTests = array_merge(...$allTests); + + $usedTests = []; + + $uniqueTests = array_reduce($allTests, static function (array $carry, TestLocation $testLocation) use (&$usedTests) { + $key = $testLocation->getFilePath() . $testLocation->getMethod(); + + if (!array_key_exists($key, $usedTests)) { + $carry[] = $testLocation; + + $usedTests[$key] = true; + } + + return $carry; + }, []); + + foreach ($uniqueTests as $testLocation) { + if (!array_key_exists($testLocation->getFilePath(), $testFiles)) { + $testFiles[$testLocation->getFilePath()]= [ + 'tests' => [ + [ + 'id' => md5($testLocation->getMethod()), + 'name' => $testLocation->getMethod() + ] + ] + ]; + } else { + $testFiles[$testLocation->getFilePath()]['tests'][] = [ + 'id' => md5($testLocation->getMethod()), + 'name' => $testLocation->getMethod() + ]; + } + } + + return new \ArrayObject($testFiles); + } + + private function getFiles(): \ArrayObject + { + $files = new \ArrayObject(); + + if ($this->metricsCalculator->getTotalMutantsCount() !== 0) { + $resultsByPath = $this->retrieveResultsByPath(); + $basePath = Path::getLongestCommonBasePath(array_keys($resultsByPath)); + + $files = $this->retrieveFiles($resultsByPath, $basePath); + } + + return $files; + } + + + /** + * @param array $resultsByPath + */ + private function retrieveFiles(array $resultsByPath, string $basePath): \ArrayObject + { + $files = new \ArrayObject(); + + foreach ($resultsByPath as $path => $results) { + $relativePath = $path === $basePath ? $path : Path::makeRelative($path, $basePath); + + $result = current($results); + Assert::isInstanceOf($result, MutantExecutionResult::class); + + $originalCode = file_get_contents($path); + + Assert::string($originalCode); + + $files[$relativePath] = [ + 'language' => 'php', + 'source' => file_get_contents($path), + 'mutants' => $this->retrieveMutants($results, $originalCode) + ]; + } + + return $files; + } + + /** + * @return array + */ + private function retrieveResultsByPath(): array + { + $results = []; + + foreach ($this->resultsCollector->getAllExecutionResults() as $result) { + $results[$result->getOriginalFilePath()][] = $result; + } + + return $results; + } + + /** + * @param MutantExecutionResult[] $results + */ + private function retrieveMutants(array $results, string $originalCode): array + { + return array_map( + function (MutantExecutionResult $result) use ($originalCode): array { + $fileAsArrayOfLines = explode(PHP_EOL, $originalCode); + $replacement = $this->retrieveReplacementFromDiff($result->getMutantDiff()); + + $originalCodeLine = $fileAsArrayOfLines[$result->getOriginalStartingLine() - 1]; + $originalCodeLineLength = strlen($originalCodeLine) + 1; + + $startingColumn = $originalCodeLineLength - strlen(ltrim($originalCodeLine)); + $endingColumn = $originalCodeLineLength; + + $methodSignatureMutators = [ + MutatorFactory::getMutatorNameForClassName(PublicVisibility::class), + MutatorFactory::getMutatorNameForClassName(ProtectedVisibility::class), + ]; + + $endingLine = in_array($result->getMutatorName(), $methodSignatureMutators, true) + ? $result->getOriginalStartingLine() + : $result->getOriginalEndingLine(); + + // needed when remove method is on multiple lines + if ($result->getMutatorName() === MutatorFactory::getMutatorNameForClassName(MethodCallRemoval::class)) { + $endingColumn = $result->getOriginalEndingColumn($originalCode) + 1; + } + +// var_dump($result->getMutatorName()); +// var_dump($replacement); +// var_dump($result->getOriginalStartingLine()); +// var_dump($endingLine); +// var_dump($startingColumn); +// var_dump($endingColumn); +// var_dump($result->getOriginalStartingColumn($originalCode)); +// var_dump($result->getOriginalEndingColumn($originalCode)); + + return [ + 'id' => $result->getMutantHash(), + 'mutatorName' => $result->getMutatorName(), + 'replacement' => ltrim($replacement), + 'description' => $this->getMutatorDescription($result->getMutatorName()), + 'location' => [ + 'start' => [ + 'line' => $result->getOriginalStartingLine(), + 'column' => $startingColumn, + ], + 'end' => [ + 'line' => $endingLine, + 'column' => $endingColumn, + ], + ], + 'status' => self::DETECTION_STATUS_MAP[$result->getDetectionStatus()], + 'statusReason' => $result->getProcessOutput(), + 'coveredBy' => array_unique(array_map( // todo unique? ask @sanmai + static fn (TestLocation $testLocation): string => md5($testLocation->getMethod()), + $result->getTests() + )), + 'killedBy' => $this->getKilledBy($result->getProcessOutput()), + 'testsCompleted' => $this->getTestsCompleted($result->getProcessOutput()), + ]; + }, + $results + ); + } + + private function retrieveReplacementFromDiff(string $diff): string + { + $lines = explode(PHP_EOL, $diff); + + $lines = array_map( + static function (string $line): string { + return isset($line[0]) ? substr($line, self::PLUS_LENGTH) : $line; + }, + array_filter( + /** + --- Original + +++ New + @@ @@ + */ + array_slice($lines, 3), + static function (string $line): bool { + return isset($line[0]) && strpos($line, '+') === 0; + } + ) + ); + + return implode(PHP_EOL, $lines); + } + + /** + * @return array + */ + private function getKilledBy(string $processOutput): array + { + $matches = []; + + if (preg_match('/(?\S+::\S+)(?:(? with data set (?:#\d+|"[^"]+"))\s\()?/', $processOutput, $matches)) { + return [md5($matches['name'] . ($matches['dataname'] ?? ''))]; + } + + return []; + } + + private function getTestsCompleted(string $processOutput): int + { + $matches = []; + + if (preg_match('/Tests:\s(\d+),\sAssertions/', $processOutput, $matches)) { + return (int) ($matches[1] ?? 0); + } + + return 0; + } + + private function getMutatorDescription(string $mutatorName): string + { + Assert::keyExists(ProfileList::ALL_MUTATORS, $mutatorName); + + /** @var Mutator $mutatorClass */ + $mutatorClass = ProfileList::ALL_MUTATORS[$mutatorName]; + + $definition = $mutatorClass::getDefinition(); + + Assert::notNull($definition); + + return $definition->getDescription(); + } +} diff --git a/src/Metrics/TargetDetectionStatusesProvider.php b/src/Metrics/TargetDetectionStatusesProvider.php index d8eb068af..7c38e5f16 100644 --- a/src/Metrics/TargetDetectionStatusesProvider.php +++ b/src/Metrics/TargetDetectionStatusesProvider.php @@ -111,6 +111,13 @@ private function findRequired(): Generator return; } + // HTML logger needs all mutation results to make a summary. + if ($this->logConfig->getHtmlLogFilePath() !== null) { + yield from DetectionStatus::ALL; + + return; + } + if ($this->logConfig->getUseGitHubAnnotationsLogger()) { yield DetectionStatus::ESCAPED; } diff --git a/src/Mutant/MutantExecutionResult.php b/src/Mutant/MutantExecutionResult.php index ba9b396d9..0c2efa2b9 100644 --- a/src/Mutant/MutantExecutionResult.php +++ b/src/Mutant/MutantExecutionResult.php @@ -35,10 +35,13 @@ namespace Infection\Mutant; +use Infection\AbstractTestFramework\Coverage\TestLocation; use function array_keys; use Infection\Mutator\ProfileList; use Later\Interfaces\Deferred; use Webmozart\Assert\Assert; +use function strlen; +use function strrpos; /** * @internal @@ -54,35 +57,48 @@ class MutantExecutionResult * @var Deferred */ private Deferred $mutantDiff; + private string $mutantHash; private string $mutatorName; private string $originalFilePath; private int $originalStartingLine; + private int $originalEndingLine; /** * @var Deferred */ private Deferred $originalCode; - /** * @var Deferred */ private Deferred $mutatedCode; + /** + * @var TestLocation[] + */ + private array $tests; + private int $originalStartFilePosition; + private int $originalEndFilePosition; /** * @param Deferred $mutantDiff * @param Deferred $originalCode * @param Deferred $mutatedCode + * @param TestLocation[] $tests */ public function __construct( string $processCommandLine, string $processOutput, string $detectionStatus, Deferred $mutantDiff, + string $mutantHash, string $mutatorName, string $originalFilePath, int $originalStartingLine, + int $originalEndingLine, + int $originalStartFilePosition, + int $originalEndFilePosition, Deferred $originalCode, - Deferred $mutatedCode + Deferred $mutatedCode, + array $tests ) { Assert::oneOf($detectionStatus, DetectionStatus::ALL); Assert::oneOf($mutatorName, array_keys(ProfileList::ALL_MUTATORS)); @@ -91,11 +107,16 @@ public function __construct( $this->processOutput = $processOutput; $this->detectionStatus = $detectionStatus; $this->mutantDiff = $mutantDiff; + $this->mutantHash = $mutantHash; $this->mutatorName = $mutatorName; $this->originalFilePath = $originalFilePath; $this->originalStartingLine = $originalStartingLine; + $this->originalEndingLine = $originalEndingLine; $this->originalCode = $originalCode; $this->mutatedCode = $mutatedCode; + $this->tests = $tests; + $this->originalStartFilePosition = $originalStartFilePosition; + $this->originalEndFilePosition = $originalEndFilePosition; } public static function createFromNonCoveredMutant(Mutant $mutant): self @@ -133,6 +154,11 @@ public function getMutantDiff(): string return $this->mutantDiff->get(); } + public function getMutantHash(): string + { + return $this->mutantHash; + } + public function getMutatorName(): string { return $this->mutatorName; @@ -148,6 +174,34 @@ public function getOriginalStartingLine(): int return $this->originalStartingLine; } + public function getOriginalEndingLine(): int + { + return $this->originalEndingLine; + } + + public function getOriginalStartingColumn(string $originalCode): int + { + return $this->toColumn($originalCode, $this->originalStartFilePosition); + } + + public function getOriginalEndingColumn(string $originalCode): int + { + return $this->toColumn($originalCode, $this->originalEndFilePosition); + } + + private function toColumn(string $code, int $pos) : int { + if ($pos > strlen($code)) { + throw new \RuntimeException('Invalid position information'); + } + + $lineStartPos = strrpos($code, "\n", $pos - strlen($code)); + if (false === $lineStartPos) { + $lineStartPos = -1; + } + + return $pos - $lineStartPos; + } + public function getOriginalCode(): string { return $this->originalCode->get(); @@ -158,6 +212,14 @@ public function getMutatedCode(): string return $this->mutatedCode->get(); } + /** + * @return TestLocation[] + */ + public function getTests(): array + { + return $this->tests; + } + private static function createFromMutant(Mutant $mutant, string $detectionStatus): self { $mutation = $mutant->getMutation(); @@ -167,11 +229,16 @@ private static function createFromMutant(Mutant $mutant, string $detectionStatus '', $detectionStatus, $mutant->getDiff(), + $mutant->getMutation()->getHash(), $mutant->getMutation()->getMutatorName(), $mutation->getOriginalFilePath(), $mutation->getOriginalStartingLine(), + $mutation->getOriginalEndingLine(), + $mutation->getOriginalStartFilePosition(), + $mutation->getOriginalEndFilePosition(), $mutant->getPrettyPrintedOriginalCode(), - $mutant->getMutatedCode() + $mutant->getMutatedCode(), + $mutant->getTests() ); } } diff --git a/src/Mutant/MutantExecutionResultFactory.php b/src/Mutant/MutantExecutionResultFactory.php index cc47a010f..81174582c 100644 --- a/src/Mutant/MutantExecutionResultFactory.php +++ b/src/Mutant/MutantExecutionResultFactory.php @@ -66,11 +66,16 @@ public function createFromProcess(MutantProcess $mutantProcess): MutantExecution $this->retrieveProcessOutput($process), $this->retrieveDetectionStatus($mutantProcess), $mutant->getDiff(), + $mutation->getHash(), $mutation->getMutatorName(), $mutation->getOriginalFilePath(), $mutation->getOriginalStartingLine(), + $mutation->getOriginalEndingLine(), + $mutation->getOriginalStartFilePosition(), + $mutation->getOriginalEndFilePosition(), $mutant->getPrettyPrintedOriginalCode(), - $mutant->getMutatedCode() + $mutant->getMutatedCode(), + $mutant->getTests() ); } diff --git a/src/Mutation/Mutation.php b/src/Mutation/Mutation.php index 517f26121..17d18b323 100644 --- a/src/Mutation/Mutation.php +++ b/src/Mutation/Mutation.php @@ -46,6 +46,8 @@ use PhpParser\Node; use function Safe\array_flip; use Webmozart\Assert\Assert; +use function strlen; +use function strrpos; /** * @internal @@ -132,6 +134,21 @@ public function getOriginalStartingLine(): int return (int) $this->attributes['startLine']; } + public function getOriginalEndingLine(): int + { + return (int) $this->attributes['endLine']; + } + + public function getOriginalStartFilePosition(): int + { + return (int) $this->attributes['startFilePos']; + } + + public function getOriginalEndFilePosition(): int + { + return (int) $this->attributes['endFilePos']; + } + public function getMutatedNodeClass(): string { return $this->mutatedNodeClass; diff --git a/stryker-report.html b/stryker-report.html new file mode 100644 index 000000000..9d5fc600b --- /dev/null +++ b/stryker-report.html @@ -0,0 +1,3353 @@ + + + + Test files example - Mutation test elements + + + + + +Back + + + + diff --git a/tests/e2e/Example_Test/infection.json b/tests/e2e/Example_Test/infection.json index a5d873d67..670b967c9 100644 --- a/tests/e2e/Example_Test/infection.json +++ b/tests/e2e/Example_Test/infection.json @@ -7,7 +7,8 @@ ] }, "logs": { - "summary": "infection.log" + "html": "infection.html", + "text": "infection.log" }, "tmpDir": "." } diff --git a/tests/e2e/Example_Test/src/SourceClass.php b/tests/e2e/Example_Test/src/SourceClass.php index 148b0a253..f1b99bdc2 100644 --- a/tests/e2e/Example_Test/src/SourceClass.php +++ b/tests/e2e/Example_Test/src/SourceClass.php @@ -4,8 +4,12 @@ class SourceClass { + private const TWO = 2; + public function hello(): string { + $a = 1 + self::TWO; + return 'hello'; } } diff --git a/tests/e2e/Example_Test/tests/SourceClassTest.php b/tests/e2e/Example_Test/tests/SourceClassTest.php index 4742835af..3b4a9877b 100644 --- a/tests/e2e/Example_Test/tests/SourceClassTest.php +++ b/tests/e2e/Example_Test/tests/SourceClassTest.php @@ -12,4 +12,12 @@ public function test_hello() $sourceClass = new SourceClass(); $this->assertSame('hello', $sourceClass->hello()); } + + public function test_this_test_case_kills_nothing(): void + { + $sourceClass = new SourceClass(); + $sourceClass->hello(); + + $this->assertTrue(true); + } } diff --git a/tests/phpunit/Configuration/ConfigurationAssertions.php b/tests/phpunit/Configuration/ConfigurationAssertions.php index 31237a8d8..d243b348c 100644 --- a/tests/phpunit/Configuration/ConfigurationAssertions.php +++ b/tests/phpunit/Configuration/ConfigurationAssertions.php @@ -99,6 +99,7 @@ private function assertConfigurationStateIs( $this->assertLogsStateIs( $configuration->getLogs(), $expectedLogs->getTextLogFilePath(), + $expectedLogs->getHtmlLogFilePath(), $expectedLogs->getSummaryLogFilePath(), $expectedLogs->getJsonLogFilePath(), $expectedLogs->getDebugLogFilePath(), diff --git a/tests/phpunit/Configuration/ConfigurationFactoryTest.php b/tests/phpunit/Configuration/ConfigurationFactoryTest.php index 14c7d9f3f..bcc487384 100644 --- a/tests/phpunit/Configuration/ConfigurationFactoryTest.php +++ b/tests/phpunit/Configuration/ConfigurationFactoryTest.php @@ -738,6 +738,7 @@ public function valueProvider(): iterable new Source(['src/'], ['vendor/']), new Logs( 'text.log', + 'report.html', 'summary.log', 'json.log', 'debug.log', @@ -792,6 +793,7 @@ public function valueProvider(): iterable ['vendor/'], new Logs( 'text.log', + 'report.html', 'summary.log', 'json.log', 'debug.log', diff --git a/tests/phpunit/Configuration/ConfigurationTest.php b/tests/phpunit/Configuration/ConfigurationTest.php index 10b494cfc..0d7d3233d 100644 --- a/tests/phpunit/Configuration/ConfigurationTest.php +++ b/tests/phpunit/Configuration/ConfigurationTest.php @@ -209,6 +209,7 @@ public function valueProvider(): iterable ['exclude-dir'], new Logs( 'text.log', + 'report.html', 'summary.log', 'json.log', 'debug.log', diff --git a/tests/phpunit/Configuration/Entry/LogsAssertions.php b/tests/phpunit/Configuration/Entry/LogsAssertions.php index b3c918457..2e2ca9185 100644 --- a/tests/phpunit/Configuration/Entry/LogsAssertions.php +++ b/tests/phpunit/Configuration/Entry/LogsAssertions.php @@ -43,6 +43,7 @@ trait LogsAssertions private function assertLogsStateIs( Logs $logs, ?string $expectedTextLogFilePath, + ?string $expectedHtmlLogFilePath, ?string $expectedSummaryLogFilePath, ?string $expectedJsonLogFilePath, ?string $expectedDebugLogFilePath, @@ -51,6 +52,7 @@ private function assertLogsStateIs( ?Badge $expectedBadge ): void { $this->assertSame($expectedTextLogFilePath, $logs->getTextLogFilePath()); + $this->assertSame($expectedHtmlLogFilePath, $logs->getHtmlLogFilePath()); $this->assertSame($expectedSummaryLogFilePath, $logs->getSummaryLogFilePath()); $this->assertSame($expectedJsonLogFilePath, $logs->getJsonLogFilePath()); $this->assertSame($expectedDebugLogFilePath, $logs->getDebugLogFilePath()); diff --git a/tests/phpunit/Configuration/Entry/LogsTest.php b/tests/phpunit/Configuration/Entry/LogsTest.php index cd60b882e..a4db7eec3 100644 --- a/tests/phpunit/Configuration/Entry/LogsTest.php +++ b/tests/phpunit/Configuration/Entry/LogsTest.php @@ -48,6 +48,7 @@ final class LogsTest extends TestCase */ public function test_it_can_be_instantiated( ?string $textLogFilePath, + ?string $htmlLogFilePath, ?string $summaryLogFilePath, ?string $jsonLogFilePath, ?string $debugLogFilePath, @@ -57,6 +58,7 @@ public function test_it_can_be_instantiated( ): void { $logs = new Logs( $textLogFilePath, + $htmlLogFilePath, $summaryLogFilePath, $jsonLogFilePath, $debugLogFilePath, @@ -68,6 +70,7 @@ public function test_it_can_be_instantiated( $this->assertLogsStateIs( $logs, $textLogFilePath, + $htmlLogFilePath, $summaryLogFilePath, $jsonLogFilePath, $debugLogFilePath, @@ -88,6 +91,7 @@ public function test_it_can_be_instantiated_without_any_values(): void null, null, null, + null, false, null ); @@ -101,12 +105,14 @@ public function valuesProvider(): iterable null, null, null, + null, false, null, ]; yield 'complete' => [ 'text.log', + 'report.html', 'summary.log', 'json.log', 'debug.log', diff --git a/tests/phpunit/Configuration/Schema/SchemaConfigurationFactoryTest.php b/tests/phpunit/Configuration/Schema/SchemaConfigurationFactoryTest.php index 69f0cda33..02a817ab1 100644 --- a/tests/phpunit/Configuration/Schema/SchemaConfigurationFactoryTest.php +++ b/tests/phpunit/Configuration/Schema/SchemaConfigurationFactoryTest.php @@ -230,6 +230,34 @@ public function provideRawConfig(): iterable null, null, null, + null, + false, + null + ), + ]), + ]; + + yield '[logs][html] nominal' => [ + <<<'JSON' +{ + "source": { + "directories": ["src"] + }, + "logs": { + "html": "report.html" + } +} +JSON + , + self::createConfig([ + 'source' => new Source(['src'], []), + 'logs' => new Logs( + null, + 'report.html', + null, + null, + null, + null, false, null ), @@ -251,6 +279,7 @@ public function provideRawConfig(): iterable self::createConfig([ 'source' => new Source(['src'], []), 'logs' => new Logs( + null, null, 'summary.log', null, @@ -277,6 +306,7 @@ public function provideRawConfig(): iterable self::createConfig([ 'source' => new Source(['src'], []), 'logs' => new Logs( + null, null, null, 'json.log', @@ -306,6 +336,7 @@ public function provideRawConfig(): iterable null, null, null, + null, 'debug.log', null, false, @@ -333,6 +364,7 @@ public function provideRawConfig(): iterable null, null, null, + null, 'perMutator.log', false, null @@ -362,6 +394,7 @@ public function provideRawConfig(): iterable null, null, null, + null, false, new Badge('master') ), @@ -390,6 +423,7 @@ public function provideRawConfig(): iterable null, null, null, + null, false, new Badge('/^foo$/') ), @@ -404,6 +438,7 @@ public function provideRawConfig(): iterable }, "logs": { "text": "text.log", + "html": "report.html", "summary": "summary.log", "json": "json.log", "debug": "debug.log", @@ -420,6 +455,7 @@ public function provideRawConfig(): iterable 'source' => new Source(['src'], []), 'logs' => new Logs( 'text.log', + 'report.html', 'summary.log', 'json.log', 'debug.log', @@ -486,6 +522,7 @@ public function provideRawConfig(): iterable }, "logs": { "text": " text.log ", + "html": " report.html ", "summary": " summary.log ", "json": " json.log ", "debug": " debug.log ", @@ -502,6 +539,7 @@ public function provideRawConfig(): iterable 'source' => new Source(['src'], []), 'logs' => new Logs( 'text.log', + 'report.html', 'summary.log', 'json.log', 'debug.log', @@ -2134,6 +2172,7 @@ public function provideRawConfig(): iterable }, "logs": { "text": "text.log", + "html": "report.html", "summary": "summary.log", "json": "json.log", "debug": "debug.log", @@ -2372,6 +2411,7 @@ public function provideRawConfig(): iterable ), 'logs' => new Logs( 'text.log', + 'report.html', 'summary.log', 'json.log', 'debug.log', diff --git a/tests/phpunit/Configuration/Schema/SchemaConfigurationTest.php b/tests/phpunit/Configuration/Schema/SchemaConfigurationTest.php index fb72194ee..7cefcd901 100644 --- a/tests/phpunit/Configuration/Schema/SchemaConfigurationTest.php +++ b/tests/phpunit/Configuration/Schema/SchemaConfigurationTest.php @@ -121,6 +121,7 @@ public function valueProvider(): iterable new Source(['src', 'lib'], ['fixtures', 'tests']), new Logs( 'text.log', + 'report.html', 'summary.log', 'json.log', 'debug.log', diff --git a/tests/phpunit/Fixtures/EmptyClass.php b/tests/phpunit/Fixtures/EmptyClass.php new file mode 100644 index 000000000..36f318221 --- /dev/null +++ b/tests/phpunit/Fixtures/EmptyClass.php @@ -0,0 +1,12 @@ + [ new Logs( 'text', + 'html', 'summary', 'json', 'debug', diff --git a/tests/phpunit/Logger/CreateMetricsCalculator.php b/tests/phpunit/Logger/CreateMetricsCalculator.php index 2e8380ea6..1cff381b6 100644 --- a/tests/phpunit/Logger/CreateMetricsCalculator.php +++ b/tests/phpunit/Logger/CreateMetricsCalculator.php @@ -189,11 +189,16 @@ private function createMutantExecutionResult( DIFF )), + 'a1b2c3', MutatorName::getName($mutatorClassName), 'foo/bar', 10 - $i, + 20 - $i, + 10 - $i, + 20 - $i, now(' [ + new Logs( + null, + 'html', + null, + null, + null, + null, + false, + null + ), + [HtmlFileLogger::class], + ]; + yield 'summary logger' => [ new Logs( + null, null, 'summary_file', null, @@ -165,6 +184,7 @@ public function logsProvider(): iterable null, null, null, + null, 'debug_file', null, false, @@ -175,6 +195,7 @@ public function logsProvider(): iterable yield 'json logger' => [ new Logs( + null, null, null, 'json_file', @@ -192,6 +213,7 @@ public function logsProvider(): iterable null, null, null, + null, 'per_muator', false, null @@ -206,6 +228,7 @@ public function logsProvider(): iterable null, null, null, + null, true, null ), @@ -215,6 +238,7 @@ public function logsProvider(): iterable yield 'all loggers' => [ new Logs( 'text', + 'html', 'summary', 'json', 'debug', @@ -224,6 +248,7 @@ public function logsProvider(): iterable ), [ TextFileLogger::class, + HtmlFileLogger::class, SummaryFileLogger::class, JsonLogger::class, DebugFileLogger::class, @@ -246,6 +271,7 @@ private function createLoggerFactory( $debugMode, $onlyCoveredCode, new FakeLogger(), + new StrykerHtmlReportBuilder($this->metricsCalculator, $this->resultsCollector) ); } diff --git a/tests/phpunit/Logger/Html/StrykerHtmlReportBuilderTest.php b/tests/phpunit/Logger/Html/StrykerHtmlReportBuilderTest.php new file mode 100644 index 000000000..b4e046e4f --- /dev/null +++ b/tests/phpunit/Logger/Html/StrykerHtmlReportBuilderTest.php @@ -0,0 +1,191 @@ +markTestSkipped(); + $report = (new StrykerHtmlReportBuilder($metricsCalculator, $resultsCollector))->build(); + + $this->assertSame($expectedReport, json_decode(json_encode($report), true)); + $this->assertJsonDocumentMatchesSchema($report); + } + + public function metricsProvider() + { + yield 'no mutations' => [ + new MetricsCalculator(2), + new ResultsCollector(), + [ + 'schemaVersion' => '1', + 'thresholds' => [ + 'high' => 90, + 'low' => 50, + ], + 'files' => [], + 'testFiles' => [], + 'framework' => [ + 'name' => 'Infection', + 'branding' => [ + 'homepageUrl' => 'https://infection.github.io/', + 'imageUrl' => 'https://infection.github.io/images/logo.png' + ] + ] + ], + ]; + + yield 'one mutation' => [ + $this->createIgnoredMetricsCalculator(), + $this->createIgnoredResultsCollector(), + [ + 'schemaVersion' => '1', + 'thresholds' => [ + 'high' => 90, + 'low' => 50, + ], + 'files' => [], + 'testFiles' => [], + 'framework' => [ + 'name' => 'Infection', + 'branding' => [ + 'homepageUrl' => 'https://infection.github.io/', + 'imageUrl' => 'https://infection.github.io/images/logo.png' + ] + ] + ], + ]; + } + + private function createIgnoredMetricsCalculator(): MetricsCalculator + { + $collector = new MetricsCalculator(2); + + $this->initIgnoredCollector($collector); + + return $collector; + } + + private function createIgnoredResultsCollector(): ResultsCollector + { + $collector = new ResultsCollector(); + + $this->initIgnoredCollector($collector); + + return $collector; + } + + private function assertJsonDocumentMatchesSchema($report): void + { + $resultReport = json_decode(json_encode($report)); + + $validator = new Validator(); + + $validator->validate($resultReport, (object)['$ref' => self::SCHEMA_FILE]); + + $normalizedErrors = array_map( + static function (array $error): string { + return sprintf('[%s] %s%s', $error['property'], $error['message'], PHP_EOL); + }, + $validator->getErrors() + ); + + $this->assertTrue( + $validator->isValid(), + sprintf( + 'Expected the given JSON to be valid but is violating the following rules of' + . ' the schema: %s- %s', + PHP_EOL, + implode('- ', $normalizedErrors) + ) + ); + } + + private function createCollectorWithOneMutant(): ResultsCollector + { + $collector = new ResultsCollector(); + + $this->initIgnoredCollector($collector); + + return $collector; + } + + private function initIgnoredCollector(Collector $collector): void + { + $collector->collect( + $this->createMutantExecutionResult( + 0, + For_::class, + DetectionStatus::IGNORED, + 'ignored#0' + ), + ); + } + + private function createMutantExecutionResult( + int $i, + string $mutatorClassName, + string $detectionStatus, + string $echoMutatedMessage + ): MutantExecutionResult { + return new MutantExecutionResult( + 'bin/phpunit --configuration infection-tmp-phpunit.xml --filter "tests/Acme/FooTest.php"', + 'process output', + $detectionStatus, + now(normalize_trailing_spaces( + <<assertResultStateIs( From 0b2f06fb53255eba67eaf0ba0d474d61ed6763a8 Mon Sep 17 00:00:00 2001 From: maks-rafalko Date: Sun, 19 Dec 2021 18:04:30 +0300 Subject: [PATCH 2/8] Add execution result from the real file --- src/Container.php | 2 +- src/Logger/Html/HtmlFileLogger.php | 58 +-- src/Logger/Html/StrykerHtmlReportBuilder.php | 140 +++++--- src/Mutant/MutantExecutionResult.php | 38 +- src/Mutation/Mutation.php | 2 - tests/phpunit/Fixtures/EmptyClass.php | 12 - tests/phpunit/Fixtures/ForHtmlReport.php | 46 +++ tests/phpunit/Fixtures/ForHtmlReport2.php | 14 + .../phpunit/Logger/FileLoggerFactoryTest.php | 4 +- .../Html/StrykerHtmlReportBuilderTest.php | 330 ++++++++++++++---- 10 files changed, 469 insertions(+), 177 deletions(-) delete mode 100644 tests/phpunit/Fixtures/EmptyClass.php create mode 100644 tests/phpunit/Fixtures/ForHtmlReport.php create mode 100644 tests/phpunit/Fixtures/ForHtmlReport2.php diff --git a/src/Container.php b/src/Container.php index fcab36e0e..c3e7fc5aa 100644 --- a/src/Container.php +++ b/src/Container.php @@ -35,7 +35,6 @@ namespace Infection; -use Infection\Logger\Html\StrykerHtmlReportBuilder; use function array_filter; use function array_key_exists; use Closure; @@ -83,6 +82,7 @@ use Infection\Logger\FederatedLogger; use Infection\Logger\FileLoggerFactory; use Infection\Logger\GitHub\GitDiffFileProvider; +use Infection\Logger\Html\StrykerHtmlReportBuilder; use Infection\Logger\MutationTestingResultsLogger; use Infection\Metrics\FilteringResultsCollectorFactory; use Infection\Metrics\MetricsCalculator; diff --git a/src/Logger/Html/HtmlFileLogger.php b/src/Logger/Html/HtmlFileLogger.php index bbca18ae5..8b5bad01d 100644 --- a/src/Logger/Html/HtmlFileLogger.php +++ b/src/Logger/Html/HtmlFileLogger.php @@ -1,35 +1,42 @@ strykerHtmlReportBuilder = $strykerHtmlReportBuilder; } diff --git a/src/Logger/Html/StrykerHtmlReportBuilder.php b/src/Logger/Html/StrykerHtmlReportBuilder.php index 88d0ac0be..dba0853a4 100644 --- a/src/Logger/Html/StrykerHtmlReportBuilder.php +++ b/src/Logger/Html/StrykerHtmlReportBuilder.php @@ -1,24 +1,40 @@ metricsCalculator = $metricsCalculator; $this->resultsCollector = $resultsCollector; } - public function build(): array { return [ @@ -76,22 +105,21 @@ public function build(): array 'low' => 50, ], 'files' => $this->getFiles(), -// 'testFiles' => $this->getTestFiles(), + 'testFiles' => $this->getTestFiles(), // 'performance' => [], todo 'framework' => [ 'name' => 'Infection', 'branding' => [ 'homepageUrl' => 'https://infection.github.io/', - 'imageUrl' => 'https://infection.github.io/images/logo.png' - ] - ] + 'imageUrl' => 'https://infection.github.io/images/logo.png', + ], + ], ]; } - private function getTestFiles(): \ArrayObject + private function getTestFiles(): ArrayObject { $testFiles = []; - $allTests = []; foreach ($this->resultsCollector->getAllExecutionResults() as $result) { @@ -116,28 +144,20 @@ private function getTestFiles(): \ArrayObject foreach ($uniqueTests as $testLocation) { if (!array_key_exists($testLocation->getFilePath(), $testFiles)) { - $testFiles[$testLocation->getFilePath()]= [ - 'tests' => [ - [ - 'id' => md5($testLocation->getMethod()), - 'name' => $testLocation->getMethod() - ] - ] + $testFiles[$testLocation->getFilePath()] = [ + 'tests' => [$this->buildTest($testLocation)], ]; } else { - $testFiles[$testLocation->getFilePath()]['tests'][] = [ - 'id' => md5($testLocation->getMethod()), - 'name' => $testLocation->getMethod() - ]; + $testFiles[$testLocation->getFilePath()]['tests'][] = $this->buildTest($testLocation); } } - return new \ArrayObject($testFiles); + return new ArrayObject($testFiles); } - private function getFiles(): \ArrayObject + private function getFiles(): ArrayObject { - $files = new \ArrayObject(); + $files = new ArrayObject(); if ($this->metricsCalculator->getTotalMutantsCount() !== 0) { $resultsByPath = $this->retrieveResultsByPath(); @@ -149,13 +169,12 @@ private function getFiles(): \ArrayObject return $files; } - /** * @param array $resultsByPath */ - private function retrieveFiles(array $resultsByPath, string $basePath): \ArrayObject + private function retrieveFiles(array $resultsByPath, string $basePath): ArrayObject { - $files = new \ArrayObject(); + $files = new ArrayObject(); foreach ($resultsByPath as $path => $results) { $relativePath = $path === $basePath ? $path : Path::makeRelative($path, $basePath); @@ -170,7 +189,7 @@ private function retrieveFiles(array $resultsByPath, string $basePath): \ArrayOb $files[$relativePath] = [ 'language' => 'php', 'source' => file_get_contents($path), - 'mutants' => $this->retrieveMutants($results, $originalCode) + 'mutants' => $this->retrieveMutants($results, $originalCode), ]; } @@ -189,6 +208,7 @@ private function retrieveResultsByPath(): array } return $results; +// return count($results) > 1 ? array_slice($results, 0, 1, true) : $results; } /** @@ -222,8 +242,11 @@ function (MutantExecutionResult $result) use ($originalCode): array { } // var_dump($result->getMutatorName()); -// var_dump($replacement); +// var_dump($result->getMutantDiff()); // var_dump($result->getOriginalStartingLine()); +// var_dump($result->getOriginalEndingLine()); +// var_dump($result->originalStartFilePosition); +// var_dump($result->originalEndFilePosition); // var_dump($endingLine); // var_dump($startingColumn); // var_dump($endingColumn); @@ -236,19 +259,13 @@ function (MutantExecutionResult $result) use ($originalCode): array { 'replacement' => ltrim($replacement), 'description' => $this->getMutatorDescription($result->getMutatorName()), 'location' => [ - 'start' => [ - 'line' => $result->getOriginalStartingLine(), - 'column' => $startingColumn, - ], - 'end' => [ - 'line' => $endingLine, - 'column' => $endingColumn, - ], + 'start' => ['line' => $result->getOriginalStartingLine(), 'column' => $startingColumn], + 'end' => ['line' => $endingLine, 'column' => $endingColumn], ], 'status' => self::DETECTION_STATUS_MAP[$result->getDetectionStatus()], 'statusReason' => $result->getProcessOutput(), 'coveredBy' => array_unique(array_map( // todo unique? ask @sanmai - static fn (TestLocation $testLocation): string => md5($testLocation->getMethod()), + fn (TestLocation $testLocation): string => $this->buildTestMethodId($testLocation->getMethod()), $result->getTests() )), 'killedBy' => $this->getKilledBy($result->getProcessOutput()), @@ -268,7 +285,7 @@ static function (string $line): string { return isset($line[0]) ? substr($line, self::PLUS_LENGTH) : $line; }, array_filter( - /** + /* --- Original +++ New @@ @@ @@ -291,7 +308,7 @@ private function getKilledBy(string $processOutput): array $matches = []; if (preg_match('/(?\S+::\S+)(?:(? with data set (?:#\d+|"[^"]+"))\s\()?/', $processOutput, $matches)) { - return [md5($matches['name'] . ($matches['dataname'] ?? ''))]; + return [$this->buildTestMethodId($matches['name'] . ($matches['dataname'] ?? ''))]; } return []; @@ -321,4 +338,17 @@ private function getMutatorDescription(string $mutatorName): string return $definition->getDescription(); } + + private function buildTest($testLocation): array + { + return [ + 'id' => $this->buildTestMethodId($testLocation->getMethod()), + 'name' => $testLocation->getMethod(), + ]; + } + + private function buildTestMethodId(string $testMethod): string + { + return md5($testMethod); + } } diff --git a/src/Mutant/MutantExecutionResult.php b/src/Mutant/MutantExecutionResult.php index 0c2efa2b9..0143c975b 100644 --- a/src/Mutant/MutantExecutionResult.php +++ b/src/Mutant/MutantExecutionResult.php @@ -35,13 +35,14 @@ namespace Infection\Mutant; -use Infection\AbstractTestFramework\Coverage\TestLocation; use function array_keys; +use Infection\AbstractTestFramework\Coverage\TestLocation; use Infection\Mutator\ProfileList; use Later\Interfaces\Deferred; -use Webmozart\Assert\Assert; +use RuntimeException; use function strlen; use function strrpos; +use Webmozart\Assert\Assert; /** * @internal @@ -49,6 +50,9 @@ */ class MutantExecutionResult { + // todo private + public int $originalStartFilePosition; + public int $originalEndFilePosition; private string $processCommandLine; private string $processOutput; private string $detectionStatus; @@ -75,8 +79,6 @@ class MutantExecutionResult * @var TestLocation[] */ private array $tests; - private int $originalStartFilePosition; - private int $originalEndFilePosition; /** * @param Deferred $mutantDiff @@ -189,19 +191,6 @@ public function getOriginalEndingColumn(string $originalCode): int return $this->toColumn($originalCode, $this->originalEndFilePosition); } - private function toColumn(string $code, int $pos) : int { - if ($pos > strlen($code)) { - throw new \RuntimeException('Invalid position information'); - } - - $lineStartPos = strrpos($code, "\n", $pos - strlen($code)); - if (false === $lineStartPos) { - $lineStartPos = -1; - } - - return $pos - $lineStartPos; - } - public function getOriginalCode(): string { return $this->originalCode->get(); @@ -220,6 +209,21 @@ public function getTests(): array return $this->tests; } + private function toColumn(string $code, int $pos): int + { + if ($pos > strlen($code)) { + throw new RuntimeException('Invalid position information'); + } + + $lineStartPos = strrpos($code, "\n", $pos - strlen($code)); + + if ($lineStartPos === false) { + $lineStartPos = -1; + } + + return $pos - $lineStartPos; + } + private static function createFromMutant(Mutant $mutant, string $detectionStatus): self { $mutation = $mutant->getMutation(); diff --git a/src/Mutation/Mutation.php b/src/Mutation/Mutation.php index 17d18b323..64d06b8f9 100644 --- a/src/Mutation/Mutation.php +++ b/src/Mutation/Mutation.php @@ -46,8 +46,6 @@ use PhpParser\Node; use function Safe\array_flip; use Webmozart\Assert\Assert; -use function strlen; -use function strrpos; /** * @internal diff --git a/tests/phpunit/Fixtures/EmptyClass.php b/tests/phpunit/Fixtures/EmptyClass.php deleted file mode 100644 index 36f318221..000000000 --- a/tests/phpunit/Fixtures/EmptyClass.php +++ /dev/null @@ -1,12 +0,0 @@ -inner('3'); + + $this->inner( + '3' + ); + + switch (true) { + case 0 !== 1: + break; + default: + break; + } + + $this->innerArray(array_keys(['a' => '1', 'b' => '2'])); + + if ($this instanceof ForHtmlReport) { + // ... + } + + return $a + $b; + } + + private function inner(string $a): void + { + // do nothing + } + + private function innerArray(array $keys): void + { + // do nothing + } +} diff --git a/tests/phpunit/Fixtures/ForHtmlReport2.php b/tests/phpunit/Fixtures/ForHtmlReport2.php new file mode 100644 index 000000000..2beebdd90 --- /dev/null +++ b/tests/phpunit/Fixtures/ForHtmlReport2.php @@ -0,0 +1,14 @@ +markTestSkipped(); + ): void { $report = (new StrykerHtmlReportBuilder($metricsCalculator, $resultsCollector))->build(); $this->assertSame($expectedReport, json_decode(json_encode($report), true)); @@ -62,48 +94,126 @@ public function metricsProvider() 'name' => 'Infection', 'branding' => [ 'homepageUrl' => 'https://infection.github.io/', - 'imageUrl' => 'https://infection.github.io/images/logo.png' - ] - ] + 'imageUrl' => 'https://infection.github.io/images/logo.png', + ], + ], ], ]; + $realPath = realpath(__DIR__ . '/../../Fixtures/ForHtmlReport.php'); + yield 'one mutation' => [ - $this->createIgnoredMetricsCalculator(), - $this->createIgnoredResultsCollector(), + $this->createFullHtmlReportMetricsCalculator(), + $this->createFullHtmlReportResultsCollector(), [ 'schemaVersion' => '1', 'thresholds' => [ 'high' => 90, 'low' => 50, ], - 'files' => [], - 'testFiles' => [], + 'files' => [ + $realPath => [ + 'language' => 'php', + 'source' => file_get_contents($realPath), + 'mutants' => [ + [ + 'id' => '32f68ca331c9262cc97322271d88d06d', + 'mutatorName' => 'PublicVisibility', + 'replacement' => 'protected function add(int $a, int $b) : int', + 'description' => 'Replaces the `public` method visibility keyword with `protected`.', + 'location' => ['start' => ['line' => 13, 'column' => 5], 'end' => ['line' => 13, 'column' => 45]], + 'status' => 'Killed', + 'statusReason' => 'PHPUnit output. Tests: 1, Assertions: 3', + 'coveredBy' => ['06a6c58caae5aa33e9b787f064618f5e'], + 'killedBy' => [], + 'testsCompleted' => 1, + ], + [ + 'id' => 'fd66aff56e903645c21271264b062b4f', + 'mutatorName' => 'MethodCallRemoval', + 'replacement' => '', + 'description' => 'Removes the method call.', + 'location' => ['start' => ['line' => 15, 'column' => 9], 'end' => ['line' => 15, 'column' => 27]], + 'status' => 'Survived', + 'statusReason' => 'PHPUnit output. Tests: 1, Assertions: 3', + 'coveredBy' => ['06a6c58caae5aa33e9b787f064618f5e'], + 'killedBy' => [], + 'testsCompleted' => 1, + ], + [ + 'id' => '746519c01522ddc7da799a9b7927e4c2', + 'mutatorName' => 'MethodCallRemoval', + 'replacement' => '', + 'description' => 'Removes the method call.', + 'location' => ['start' => ['line' => 17, 'column' => 9], 'end' => ['line' => 19, 'column' => 11]], + 'status' => 'Survived', + 'statusReason' => 'PHPUnit output. Tests: 1, Assertions: 3', + 'coveredBy' => ['06a6c58caae5aa33e9b787f064618f5e'], + 'killedBy' => [], + 'testsCompleted' => 1, + ], + [ + 'id' => '633b144fb6d55bbc60430df68a952388', + 'mutatorName' => 'ArrayItemRemoval', + 'replacement' => '$this->innerArray(array_keys([\'b\' => \'2\']));', + 'description' => "Removes an element of an array literal. For example:\n\n```php\n\$x = [0, 1, 2];\n```\n\nWill be mutated to:\n\n```php\n\$x = [1, 2];\n```\n\nAnd:\n\n```php\n\$x = [0, 2];\n```\n\nAnd:\n\n```php\n\$x = [0, 1];\n```\n\nWhich elements it removes or how many elements it will attempt to remove will depend on its\nconfiguration.\n", + 'location' => ['start' => ['line' => 28, 'column' => 9], 'end' => ['line' => 28, 'column' => 65]], + 'status' => 'Survived', + 'statusReason' => 'PHPUnit output. Tests: 1, Assertions: 3', + 'coveredBy' => ['06a6c58caae5aa33e9b787f064618f5e', '949bee6dd4ac608462995babbe81ee12', '2733f8c97b5ba92b1aacb77d46837b0e'], + 'killedBy' => [], + 'testsCompleted' => 1, + ], + ], + ], + ], + 'testFiles' => [ + '/infection/path/to/TestClass.php' => [ + 'tests' => [ + [ + 'id' => '06a6c58caae5aa33e9b787f064618f5e', + 'name' => 'TestClass::test_method1', + ], + ], + ], + '/infection/path/to/TestClass2.php' => [ + 'tests' => [ + [ + 'id' => '949bee6dd4ac608462995babbe81ee12', + 'name' => 'TestClass2::test_method2', + ], + [ + 'id' => '2733f8c97b5ba92b1aacb77d46837b0e', + 'name' => 'TestClass2::test_method3', + ], + ], + ], + ], 'framework' => [ 'name' => 'Infection', 'branding' => [ 'homepageUrl' => 'https://infection.github.io/', - 'imageUrl' => 'https://infection.github.io/images/logo.png' - ] - ] + 'imageUrl' => 'https://infection.github.io/images/logo.png', + ], + ], ], ]; } - private function createIgnoredMetricsCalculator(): MetricsCalculator + private function createFullHtmlReportMetricsCalculator(): MetricsCalculator { $collector = new MetricsCalculator(2); - $this->initIgnoredCollector($collector); + $this->initHtmlReportCollector($collector); return $collector; } - private function createIgnoredResultsCollector(): ResultsCollector + private function createFullHtmlReportResultsCollector(): ResultsCollector { $collector = new ResultsCollector(); - $this->initIgnoredCollector($collector); + $this->initHtmlReportCollector($collector); return $collector; } @@ -114,7 +224,7 @@ private function assertJsonDocumentMatchesSchema($report): void $validator = new Validator(); - $validator->validate($resultReport, (object)['$ref' => self::SCHEMA_FILE]); + $validator->validate($resultReport, (object) ['$ref' => self::SCHEMA_FILE]); $normalizedErrors = array_map( static function (array $error): string { @@ -134,58 +244,154 @@ static function (array $error): string { ); } - private function createCollectorWithOneMutant(): ResultsCollector - { - $collector = new ResultsCollector(); - - $this->initIgnoredCollector($collector); - - return $collector; - } - - private function initIgnoredCollector(Collector $collector): void + private function initHtmlReportCollector(Collector $collector): void { $collector->collect( + // this tests diffs on the method signature line + $this->createMutantExecutionResult( + DetectionStatus::KILLED, + <<<'DIFF' + --- Original + +++ New + @@ @@ + use function array_fill_keys; + final class ForHtmlReport + { + - public function add(int $a, int $b) : int + + protected function add(int $a, int $b) : int + { + $this->inner('3'); + $this->inner('3'); + DIFF, + '32f68ca331c9262cc97322271d88d06d', + PublicVisibility::class, + realpath(__DIR__ . '/../../Fixtures/ForHtmlReport.php'), + 13, + 35, + 124, + 547, + [ + new TestLocation('TestClass::test_method1', '/infection/path/to/TestClass.php', 0.123), + // check that duplicate values are moved in the report + new TestLocation('TestClass::test_method1', '/infection/path/to/TestClass.php', 0.123), + ] + ), + // this tests diff on the one-line method call removal + $this->createMutantExecutionResult( + DetectionStatus::ESCAPED, + <<<'DIFF' + --- Original + +++ New + @@ @@ + { + public function add(int $a, int $b) : int + { + - $this->inner('3'); + + + $this->inner('3'); + switch (true) { + case 1 !== 1: + DIFF, + 'fd66aff56e903645c21271264b062b4f', + MethodCallRemoval::class, + realpath(__DIR__ . '/../../Fixtures/ForHtmlReport.php'), + 15, + 15, + 179, + 196, + [ + new TestLocation('TestClass::test_method1', '/infection/path/to/TestClass.php', 0.123), + ] + ), + // this tests diff on the multi-line (in original source code) method call removal + $this->createMutantExecutionResult( + DetectionStatus::ESCAPED, + <<<'DIFF' + --- Original + +++ New + @@ @@ + public function add(int $a, int $b) : int + { + $this->inner('3'); + - $this->inner('3'); + + + switch (true) { + case 0 !== 1: + break; + DIFF, + '746519c01522ddc7da799a9b7927e4c2', + MethodCallRemoval::class, + realpath(__DIR__ . '/../../Fixtures/ForHtmlReport.php'), + 17, + 19, + 207, + 246, + [ + new TestLocation('TestClass::test_method1', '/infection/path/to/TestClass.php', 0.123), + ] + ), + // this tests diff on the one-line diff with array item removal $this->createMutantExecutionResult( - 0, - For_::class, - DetectionStatus::IGNORED, - 'ignored#0' + DetectionStatus::ESCAPED, + <<<'DIFF' + --- Original + +++ New + @@ @@ + default: + break; + } + - $this->innerArray(array_keys(['a' => '1', 'b' => '2'])); + + $this->innerArray(array_keys(['b' => '2'])); + if ($this instanceof ForHtmlReport) { + // ... + } + DIFF, + '633b144fb6d55bbc60430df68a952388', + ArrayItemRemoval::class, + realpath(__DIR__ . '/../../Fixtures/ForHtmlReport.php'), + 28, + 28, + 414, + 437, + [ + new TestLocation('TestClass::test_method1', '/infection/path/to/TestClass.php', 0.123), + new TestLocation('TestClass2::test_method2', '/infection/path/to/TestClass2.php', 0.456), + new TestLocation('TestClass2::test_method3', '/infection/path/to/TestClass2.php', 0.789), + ] ), ); } + /** + * @param array $testLocations + */ private function createMutantExecutionResult( - int $i, - string $mutatorClassName, string $detectionStatus, - string $echoMutatedMessage + string $diff, + string $mutantHash, + string $mutatorClassName, + string $originalFileRealPath, + int $originalStartingLine, + int $originalEndingLine, + int $originalStartFilePosition, + int $originalEndFilePosition, + array $testLocations ): MutantExecutionResult { return new MutantExecutionResult( 'bin/phpunit --configuration infection-tmp-phpunit.xml --filter "tests/Acme/FooTest.php"', - 'process output', + 'PHPUnit output. Tests: 1, Assertions: 3', $detectionStatus, - now(normalize_trailing_spaces( - << Date: Sun, 19 Dec 2021 19:42:15 +0300 Subject: [PATCH 3/8] Add another files to the test suite to cover more logic by tests --- devTools/phpstan-src.neon | 6 + infection.json | 3 +- report.json | 3330 ---------------- src/Logger/Html/HtmlFileLogger.php | 4 +- src/Logger/Html/StrykerHtmlReportBuilder.php | 53 +- src/Mutant/MutantExecutionResult.php | 18 +- stryker-report.html | 3353 ----------------- tests/e2e/Example_Test/infection.json | 3 +- tests/e2e/Example_Test/src/SourceClass.php | 4 - .../Example_Test/tests/SourceClassTest.php | 8 - .../Logger/Html/HtmlFileLoggerTest.php | 77 + .../Html/StrykerHtmlReportBuilderTest.php | 95 +- 12 files changed, 199 insertions(+), 6755 deletions(-) delete mode 100644 report.json delete mode 100644 stryker-report.html create mode 100644 tests/phpunit/Logger/Html/HtmlFileLoggerTest.php diff --git a/devTools/phpstan-src.neon b/devTools/phpstan-src.neon index dcd4b8605..16a3a6d7a 100644 --- a/devTools/phpstan-src.neon +++ b/devTools/phpstan-src.neon @@ -37,6 +37,12 @@ parameters: - path: '../src/Differ/DiffChangedLinesParser.php' message: '#Method Infection\\Differ\\DiffChangedLinesParser::parse\(\) should return array\\>#' + - + path: '../src/Logger/Html/StrykerHtmlReportBuilder.php' + message: '#return type has no value type specified in iterable type array#' + - + path: '../src/Logger/Html/StrykerHtmlReportBuilder.php' + message: '#return type with generic class ArrayObject does not specify its types\: TKey, TValue#' level: 8 paths: - ../src diff --git a/infection.json b/infection.json index b2fc6725c..789682b19 100644 --- a/infection.json +++ b/infection.json @@ -9,8 +9,7 @@ "logs": { "badge": { "branch": "master" - }, - "html": "infection.html" + } }, "mutators": { "global-ignoreSourceCodeByRegex": [ diff --git a/report.json b/report.json deleted file mode 100644 index 2719cab5f..000000000 --- a/report.json +++ /dev/null @@ -1,3330 +0,0 @@ -{ - "files": { - "/home/nicojs/github/stryker-js/packages/util/src/deep-merge.ts": { - "language": "typescript", - "mutants": [ - { - "id": "3", - "mutatorName": "ConditionalExpression", - "replacement": "true", - "statusReason": "expected { foo: undefined } to deeply equal { foo: '1' }", - "status": "Killed", - "estimatedNetTime": 3, - "hitCount": 5, - "static": false, - "testsCompleted": 4, - "killedBy": ["4"], - "coveredBy": ["1", "2", "3", "4"], - "location": { "end": { "column": 36, "line": 14 }, "start": { "column": 9, "line": 14 } } - }, - { - "id": "2", - "mutatorName": "BlockStatement", - "replacement": "{}", - "statusReason": "expected { foo: 'bar' } to deeply equal { foo: 'bar', baz: 42 }", - "status": "Killed", - "estimatedNetTime": 3, - "hitCount": 5, - "static": false, - "testsCompleted": 1, - "killedBy": ["1"], - "coveredBy": ["1", "2", "3", "4"], - "location": { "end": { "column": 4, "line": 21 }, "start": { "column": 43, "line": 11 } } - }, - { - "id": "1", - "mutatorName": "BlockStatement", - "replacement": "{}", - "statusReason": "expected { foo: 'bar' } to deeply equal { foo: 'bar', baz: 42 }", - "status": "Killed", - "estimatedNetTime": 3, - "hitCount": 5, - "static": false, - "testsCompleted": 1, - "killedBy": ["1"], - "coveredBy": ["1", "2", "3", "4"], - "location": { "end": { "column": 2, "line": 22 }, "start": { "column": 76, "line": 10 } } - }, - { - "id": "4", - "mutatorName": "ConditionalExpression", - "replacement": "false", - "statusReason": "expected { foo: 'bar' } to deeply equal { foo: 'bar', baz: 42 }", - "status": "Killed", - "estimatedNetTime": 3, - "hitCount": 5, - "static": false, - "testsCompleted": 1, - "killedBy": ["1"], - "coveredBy": ["1", "2", "3", "4"], - "location": { "end": { "column": 36, "line": 14 }, "start": { "column": 9, "line": 14 } } - }, - { - "id": "6", - "mutatorName": "BlockStatement", - "replacement": "{}", - "statusReason": "expected { foo: 'bar' } to deeply equal { foo: 'bar', baz: 42 }", - "status": "Killed", - "estimatedNetTime": 2, - "hitCount": 4, - "static": false, - "testsCompleted": 1, - "killedBy": ["1"], - "coveredBy": ["1", "2", "3"], - "location": { "end": { "column": 6, "line": 20 }, "start": { "column": 38, "line": 14 } } - }, - { - "id": "7", - "mutatorName": "ConditionalExpression", - "replacement": "true", - "statusReason": "expected { child: { baz: 42 } } to deeply equal { child: { foo: 'child', baz: 42 } }", - "status": "Killed", - "estimatedNetTime": 2, - "hitCount": 4, - "static": false, - "testsCompleted": 2, - "killedBy": ["2"], - "coveredBy": ["1", "2", "3"], - "location": { "end": { "column": 141, "line": 15 }, "start": { "column": 11, "line": 15 } } - }, - { - "id": "8", - "mutatorName": "ConditionalExpression", - "replacement": "false", - "statusReason": "expected { foo: 'bar' } to deeply equal { foo: 'bar', baz: 42 }", - "status": "Killed", - "estimatedNetTime": 2, - "hitCount": 4, - "static": false, - "testsCompleted": 1, - "killedBy": ["1"], - "coveredBy": ["1", "2", "3"], - "location": { "end": { "column": 141, "line": 15 }, "start": { "column": 11, "line": 15 } } - }, - { - "id": "9", - "mutatorName": "LogicalOperator", - "replacement": "(defaultValue === undefined || typeof defaultValue !== 'object' || typeof overrideValue !== 'object') && Array.isArray(defaultValue)", - "statusReason": "expected { foo: 'bar' } to deeply equal { foo: 'bar', baz: 42 }", - "status": "Killed", - "estimatedNetTime": 2, - "hitCount": 4, - "static": false, - "testsCompleted": 1, - "killedBy": ["1"], - "coveredBy": ["1", "2", "3"], - "location": { "end": { "column": 141, "line": 15 }, "start": { "column": 11, "line": 15 } } - }, - { - "id": "10", - "mutatorName": "ConditionalExpression", - "replacement": "true", - "statusReason": "expected { child: { baz: 42 } } to deeply equal { child: { foo: 'child', baz: 42 } }", - "status": "Killed", - "estimatedNetTime": 2, - "hitCount": 4, - "static": false, - "testsCompleted": 2, - "killedBy": ["2"], - "coveredBy": ["1", "2", "3"], - "location": { "end": { "column": 110, "line": 15 }, "start": { "column": 11, "line": 15 } } - }, - { - "id": "5", - "mutatorName": "EqualityOperator", - "replacement": "overrideValue === undefined", - "statusReason": "expected { foo: 'bar' } to deeply equal { foo: 'bar', baz: 42 }", - "status": "Killed", - "estimatedNetTime": 3, - "hitCount": 5, - "static": false, - "testsCompleted": 1, - "killedBy": ["1"], - "coveredBy": ["1", "2", "3", "4"], - "location": { "end": { "column": 36, "line": 14 }, "start": { "column": 9, "line": 14 } } - }, - { - "id": "11", - "mutatorName": "ConditionalExpression", - "replacement": "false", - "statusReason": "expected { foo: 'bar' } to deeply equal { foo: 'bar', baz: 42 }", - "status": "Killed", - "estimatedNetTime": 2, - "hitCount": 4, - "static": false, - "testsCompleted": 1, - "killedBy": ["1"], - "coveredBy": ["1", "2", "3"], - "location": { "end": { "column": 110, "line": 15 }, "start": { "column": 11, "line": 15 } } - }, - { - "id": "12", - "mutatorName": "LogicalOperator", - "replacement": "(defaultValue === undefined || typeof defaultValue !== 'object') && typeof overrideValue !== 'object'", - "status": "Survived", - "estimatedNetTime": 2, - "hitCount": 4, - "static": false, - "testsCompleted": 3, - "coveredBy": ["1", "2", "3"], - "location": { "end": { "column": 110, "line": 15 }, "start": { "column": 11, "line": 15 } } - }, - { - "id": "13", - "mutatorName": "ConditionalExpression", - "replacement": "true", - "statusReason": "expected { child: { baz: 42 } } to deeply equal { child: { foo: 'child', baz: 42 } }", - "status": "Killed", - "estimatedNetTime": 2, - "hitCount": 4, - "static": false, - "testsCompleted": 2, - "killedBy": ["2"], - "coveredBy": ["1", "2", "3"], - "location": { "end": { "column": 73, "line": 15 }, "start": { "column": 11, "line": 15 } } - }, - { - "id": "14", - "mutatorName": "ConditionalExpression", - "replacement": "false", - "status": "Survived", - "estimatedNetTime": 2, - "hitCount": 4, - "static": false, - "testsCompleted": 3, - "coveredBy": ["1", "2", "3"], - "location": { "end": { "column": 73, "line": 15 }, "start": { "column": 11, "line": 15 } } - }, - { - "id": "15", - "mutatorName": "LogicalOperator", - "replacement": "defaultValue === undefined && typeof defaultValue !== 'object'", - "status": "Survived", - "estimatedNetTime": 2, - "hitCount": 4, - "static": false, - "testsCompleted": 3, - "coveredBy": ["1", "2", "3"], - "location": { "end": { "column": 73, "line": 15 }, "start": { "column": 11, "line": 15 } } - }, - { - "id": "16", - "mutatorName": "ConditionalExpression", - "replacement": "true", - "statusReason": "expected { child: { baz: 42 } } to deeply equal { child: { foo: 'child', baz: 42 } }", - "status": "Killed", - "estimatedNetTime": 2, - "hitCount": 4, - "static": false, - "testsCompleted": 2, - "killedBy": ["2"], - "coveredBy": ["1", "2", "3"], - "location": { "end": { "column": 37, "line": 15 }, "start": { "column": 11, "line": 15 } } - }, - { - "id": "17", - "mutatorName": "ConditionalExpression", - "replacement": "false", - "status": "Survived", - "estimatedNetTime": 2, - "hitCount": 4, - "static": false, - "testsCompleted": 3, - "coveredBy": ["1", "2", "3"], - "location": { "end": { "column": 37, "line": 15 }, "start": { "column": 11, "line": 15 } } - }, - { - "id": "18", - "mutatorName": "EqualityOperator", - "replacement": "defaultValue !== undefined", - "statusReason": "expected { child: { baz: 42 } } to deeply equal { child: { foo: 'child', baz: 42 } }", - "status": "Killed", - "estimatedNetTime": 2, - "hitCount": 4, - "static": false, - "testsCompleted": 2, - "killedBy": ["2"], - "coveredBy": ["1", "2", "3"], - "location": { "end": { "column": 37, "line": 15 }, "start": { "column": 11, "line": 15 } } - }, - { - "id": "19", - "mutatorName": "ConditionalExpression", - "replacement": "true", - "statusReason": "expected { child: { baz: 42 } } to deeply equal { child: { foo: 'child', baz: 42 } }", - "status": "Killed", - "estimatedNetTime": 0, - "hitCount": 2, - "static": false, - "testsCompleted": 1, - "killedBy": ["2"], - "coveredBy": ["2", "3"], - "location": { "end": { "column": 73, "line": 15 }, "start": { "column": 41, "line": 15 } } - }, - { - "id": "22", - "mutatorName": "StringLiteral", - "replacement": "\"\"", - "statusReason": "src/deep-merge.ts(15,41): error TS2367: This condition will always return 'true' since the types '\"string\" | \"number\" | \"bigint\" | \"boolean\" | \"symbol\" | \"undefined\" | \"object\" | \"function\"' and '\"\"' have no overlap.\n", - "status": "CompileError", - "estimatedNetTime": 0, - "hitCount": 2, - "static": false, - "coveredBy": ["2", "3"], - "location": { "end": { "column": 73, "line": 15 }, "start": { "column": 65, "line": 15 } } - }, - { - "id": "20", - "mutatorName": "ConditionalExpression", - "replacement": "false", - "status": "Survived", - "estimatedNetTime": 0, - "hitCount": 2, - "static": false, - "testsCompleted": 2, - "coveredBy": ["2", "3"], - "location": { "end": { "column": 73, "line": 15 }, "start": { "column": 41, "line": 15 } } - }, - { - "id": "21", - "mutatorName": "EqualityOperator", - "replacement": "typeof defaultValue === 'object'", - "statusReason": "expected { child: { baz: 42 } } to deeply equal { child: { foo: 'child', baz: 42 } }", - "status": "Killed", - "estimatedNetTime": 0, - "hitCount": 2, - "static": false, - "testsCompleted": 1, - "killedBy": ["2"], - "coveredBy": ["2", "3"], - "location": { "end": { "column": 73, "line": 15 }, "start": { "column": 41, "line": 15 } } - }, - { - "id": "23", - "mutatorName": "ConditionalExpression", - "replacement": "true", - "statusReason": "expected { child: { baz: 42 } } to deeply equal { child: { foo: 'child', baz: 42 } }", - "status": "Killed", - "estimatedNetTime": 0, - "hitCount": 2, - "static": false, - "testsCompleted": 1, - "killedBy": ["2"], - "coveredBy": ["2", "3"], - "location": { "end": { "column": 110, "line": 15 }, "start": { "column": 77, "line": 15 } } - }, - { - "id": "26", - "mutatorName": "StringLiteral", - "replacement": "\"\"", - "statusReason": "src/deep-merge.ts(15,77): error TS2367: This condition will always return 'true' since the types '\"string\" | \"number\" | \"bigint\" | \"boolean\" | \"symbol\" | \"undefined\" | \"object\" | \"function\"' and '\"\"' have no overlap.\n", - "status": "CompileError", - "estimatedNetTime": 0, - "hitCount": 2, - "static": false, - "coveredBy": ["2", "3"], - "location": { "end": { "column": 110, "line": 15 }, "start": { "column": 102, "line": 15 } } - }, - { - "id": "25", - "mutatorName": "EqualityOperator", - "replacement": "typeof overrideValue === 'object'", - "statusReason": "expected { child: { baz: 42 } } to deeply equal { child: { foo: 'child', baz: 42 } }", - "status": "Killed", - "estimatedNetTime": 0, - "hitCount": 2, - "static": false, - "testsCompleted": 1, - "killedBy": ["2"], - "coveredBy": ["2", "3"], - "location": { "end": { "column": 110, "line": 15 }, "start": { "column": 77, "line": 15 } } - }, - { - "id": "24", - "mutatorName": "ConditionalExpression", - "replacement": "false", - "status": "Survived", - "estimatedNetTime": 0, - "hitCount": 2, - "static": false, - "testsCompleted": 2, - "coveredBy": ["2", "3"], - "location": { "end": { "column": 110, "line": 15 }, "start": { "column": 77, "line": 15 } } - }, - { - "id": "27", - "mutatorName": "BlockStatement", - "replacement": "{}", - "statusReason": "expected { foo: 'bar' } to deeply equal { foo: 'bar', baz: 42 }", - "status": "Killed", - "estimatedNetTime": 2, - "hitCount": 3, - "static": false, - "testsCompleted": 1, - "killedBy": ["1"], - "coveredBy": ["1", "2", "3"], - "location": { "end": { "column": 8, "line": 17 }, "start": { "column": 143, "line": 15 } } - }, - { - "id": "28", - "mutatorName": "BlockStatement", - "replacement": "{}", - "statusReason": "expected { child: { foo: 'child' } } to deeply equal { child: { foo: 'child', baz: 42 } }", - "status": "Killed", - "estimatedNetTime": 0, - "hitCount": 1, - "static": false, - "testsCompleted": 1, - "killedBy": ["2"], - "coveredBy": ["2"], - "location": { "end": { "column": 8, "line": 19 }, "start": { "column": 14, "line": 17 } } - } - ], - "source": "export type DeepPartial = {\n [P in keyof T]?: T[P] extends Record ? DeepPartial : T[P];\n};\n\n/**\n *\n * @param defaults\n * @param overrides\n */\nexport function deepMerge(defaults: T, overrides: DeepPartial): void {\n Object.keys(overrides).forEach((key) => {\n const defaultValue = (defaults as any)[key];\n const overrideValue = (overrides as any)[key];\n if (overrideValue !== undefined) {\n if (defaultValue === undefined || typeof defaultValue !== 'object' || typeof overrideValue !== 'object' || Array.isArray(defaultValue)) {\n (defaults as any)[key] = overrideValue;\n } else {\n deepMerge(defaultValue, overrideValue as DeepPartial);\n }\n }\n });\n}\n" - }, - "/home/nicojs/github/stryker-js/packages/util/src/child-process-as-promised.ts": { - "language": "typescript", - "mutants": [ - { - "id": "0", - "mutatorName": "ObjectLiteral", - "replacement": "{}", - "statusReason": "test/unit/child-process-as-promised.spec.ts(11,35): error TS2339: Property 'exec' does not exist on type '{}'.\n", - "status": "CompileError", - "estimatedNetTime": 73, - "hitCount": 1, - "static": true, - "location": { "end": { "column": 2, "line": 6 }, "start": { "column": 39, "line": 4 } } - } - ], - "source": "import * as childProcess from 'child_process';\nimport { promisify } from 'util';\n\nexport const childProcessAsPromised = {\n exec: promisify(childProcess.exec),\n};\n" - }, - "/home/nicojs/github/stryker-js/packages/util/src/directory-require-cache.ts": { - "language": "typescript", - "mutants": [ - { - "id": "29", - "mutatorName": "BlockStatement", - "replacement": "{}", - "statusReason": "expected { Object (exports, children, ...) } to be undefined", - "status": "Killed", - "estimatedNetTime": 23, - "hitCount": 12, - "static": false, - "testsCompleted": 1, - "killedBy": ["5"], - "coveredBy": ["5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15"], - "location": { "end": { "column": 4, "line": 43 }, "start": { "column": 25, "line": 22 } } - }, - { - "id": "30", - "mutatorName": "BooleanLiteral", - "replacement": "this.cache", - "statusReason": "expected { Object (exports, children, ...) } to be undefined", - "status": "Killed", - "estimatedNetTime": 23, - "hitCount": 12, - "static": false, - "testsCompleted": 1, - "killedBy": ["5"], - "coveredBy": ["5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15"], - "location": { "end": { "column": 20, "line": 23 }, "start": { "column": 9, "line": 23 } } - }, - { - "id": "31", - "mutatorName": "ConditionalExpression", - "replacement": "true", - "statusReason": "expected undefined not to be undefined", - "status": "Killed", - "estimatedNetTime": 23, - "hitCount": 12, - "static": false, - "testsCompleted": 2, - "killedBy": ["6"], - "coveredBy": ["5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15"], - "location": { "end": { "column": 20, "line": 23 }, "start": { "column": 9, "line": 23 } } - }, - { - "id": "32", - "mutatorName": "ConditionalExpression", - "replacement": "false", - "statusReason": "expected { Object (exports, children, ...) } to be undefined", - "status": "Killed", - "estimatedNetTime": 23, - "hitCount": 12, - "static": false, - "testsCompleted": 1, - "killedBy": ["5"], - "coveredBy": ["5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15"], - "location": { "end": { "column": 20, "line": 23 }, "start": { "column": 9, "line": 23 } } - }, - { - "id": "33", - "mutatorName": "BlockStatement", - "replacement": "{}", - "statusReason": "expected { Object (exports, children, ...) } to be undefined", - "status": "Killed", - "estimatedNetTime": 23, - "hitCount": 11, - "static": false, - "testsCompleted": 1, - "killedBy": ["5"], - "coveredBy": ["5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15"], - "location": { "end": { "column": 6, "line": 42 }, "start": { "column": 22, "line": 23 } } - }, - { - "id": "34", - "mutatorName": "ArrowFunction", - "replacement": "() => undefined", - "statusReason": "expected { Object (exports, children, ...) } to be undefined", - "status": "Killed", - "estimatedNetTime": 23, - "hitCount": 11, - "static": false, - "testsCompleted": 10, - "killedBy": ["14"], - "coveredBy": ["5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15"], - "location": { "end": { "column": 134, "line": 26 }, "start": { "column": 41, "line": 26 } } - }, - { - "id": "35", - "mutatorName": "ArrowFunction", - "replacement": "() => undefined", - "statusReason": "expected { Object (exports, children, ...) } to be undefined", - "status": "Killed", - "estimatedNetTime": 23, - "hitCount": 11, - "static": false, - "testsCompleted": 1, - "killedBy": ["5"], - "coveredBy": ["5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15"], - "location": { "end": { "column": 104, "line": 27 }, "start": { "column": 39, "line": 27 } } - }, - { - "id": "36", - "mutatorName": "ArrowFunction", - "replacement": "() => undefined", - "statusReason": "expected { Object (exports, children, ...) } to be undefined", - "status": "Killed", - "estimatedNetTime": 23, - "hitCount": 11, - "static": false, - "testsCompleted": 1, - "killedBy": ["5"], - "coveredBy": ["5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15"], - "location": { "end": { "column": 129, "line": 30 }, "start": { "column": 17, "line": 30 } } - }, - { - "id": "37", - "mutatorName": "ConditionalExpression", - "replacement": "true", - "statusReason": "expected undefined to equal 'baz'", - "status": "Killed", - "estimatedNetTime": 23, - "hitCount": 14611, - "static": false, - "testsCompleted": 1, - "killedBy": ["5"], - "coveredBy": ["5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15"], - "location": { "end": { "column": 129, "line": 30 }, "start": { "column": 31, "line": 30 } } - }, - { - "id": "38", - "mutatorName": "ConditionalExpression", - "replacement": "false", - "statusReason": "expected { Object (exports, children, ...) } to be undefined", - "status": "Killed", - "estimatedNetTime": 23, - "hitCount": 14611, - "static": false, - "testsCompleted": 1, - "killedBy": ["5"], - "coveredBy": ["5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15"], - "location": { "end": { "column": 129, "line": 30 }, "start": { "column": 31, "line": 30 } } - }, - { - "id": "39", - "mutatorName": "LogicalOperator", - "replacement": "startsWith(fileName, `${cwd}${path.sep}`) || !startsWith(fileName, path.join(cwd, 'node_modules'))", - "statusReason": "expected undefined to equal 'baz'", - "status": "Killed", - "estimatedNetTime": 23, - "hitCount": 14611, - "static": false, - "testsCompleted": 1, - "killedBy": ["5"], - "coveredBy": ["5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15"], - "location": { "end": { "column": 129, "line": 30 }, "start": { "column": 31, "line": 30 } } - }, - { - "id": "40", - "mutatorName": "StringLiteral", - "replacement": "``", - "statusReason": "expected undefined to equal 'baz'", - "status": "Killed", - "estimatedNetTime": 23, - "hitCount": 14611, - "static": false, - "testsCompleted": 1, - "killedBy": ["5"], - "coveredBy": ["5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15"], - "location": { "end": { "column": 71, "line": 30 }, "start": { "column": 52, "line": 30 } } - }, - { - "id": "41", - "mutatorName": "BooleanLiteral", - "replacement": "startsWith(fileName, path.join(cwd, 'node_modules'))", - "statusReason": "expected { Object (exports, children, ...) } to be undefined", - "status": "Killed", - "estimatedNetTime": 23, - "hitCount": 19, - "static": false, - "testsCompleted": 1, - "killedBy": ["5"], - "coveredBy": ["5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15"], - "location": { "end": { "column": 129, "line": 30 }, "start": { "column": 76, "line": 30 } } - }, - { - "id": "44", - "mutatorName": "ArrowFunction", - "replacement": "() => undefined", - "statusReason": "src/directory-require-cache.ts(33,7): error TS2322: Type 'Set' is not assignable to type 'Set'.\n Type 'undefined' is not assignable to type 'string'.\nsrc/directory-require-cache.ts(40,50): error TS2345: Argument of type 'undefined' is not assignable to parameter of type 'string'.\n", - "status": "CompileError", - "estimatedNetTime": 23, - "hitCount": 11, - "static": false, - "coveredBy": ["5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15"], - "location": { "end": { "column": 71, "line": 37 }, "start": { "column": 16, "line": 37 } } - }, - { - "id": "42", - "mutatorName": "StringLiteral", - "replacement": "\"\"", - "statusReason": "expected { Object (exports, children, ...) } to be undefined", - "status": "Killed", - "estimatedNetTime": 23, - "hitCount": 19, - "static": false, - "testsCompleted": 1, - "killedBy": ["5"], - "coveredBy": ["5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15"], - "location": { "end": { "column": 127, "line": 30 }, "start": { "column": 113, "line": 30 } } - }, - { - "id": "45", - "mutatorName": "OptionalChaining", - "replacement": "require.cache[fileName]?.parent.filename", - "statusReason": "src/directory-require-cache.ts(37,30): error TS2533: Object is possibly 'null' or 'undefined'.\n", - "status": "CompileError", - "estimatedNetTime": 23, - "hitCount": 18, - "static": false, - "coveredBy": ["5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15"], - "location": { "end": { "column": 71, "line": 37 }, "start": { "column": 30, "line": 37 } } - }, - { - "id": "46", - "mutatorName": "OptionalChaining", - "replacement": "require.cache[fileName].parent", - "statusReason": "src/directory-require-cache.ts(37,30): error TS2532: Object is possibly 'undefined'.\n", - "status": "CompileError", - "estimatedNetTime": 23, - "hitCount": 18, - "static": false, - "coveredBy": ["5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15"], - "location": { "end": { "column": 61, "line": 37 }, "start": { "column": 30, "line": 37 } } - }, - { - "id": "43", - "mutatorName": "ArrowFunction", - "replacement": "() => undefined", - "statusReason": "Attempted to wrap cwd which is already wrapped", - "status": "Killed", - "estimatedNetTime": 23, - "hitCount": 11, - "static": false, - "testsCompleted": 1, - "killedBy": ["5"], - "coveredBy": ["5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15"], - "location": { "end": { "column": 43, "line": 31 }, "start": { "column": 18, "line": 31 } } - }, - { - "id": "47", - "mutatorName": "ArrowFunction", - "replacement": "() => undefined", - "statusReason": "expected [ Array(2) ] to have a length of 1 but got 2", - "status": "Killed", - "estimatedNetTime": 23, - "hitCount": 11, - "static": false, - "testsCompleted": 2, - "killedBy": ["6"], - "coveredBy": ["5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15"], - "location": { "end": { "column": 65, "line": 40 }, "start": { "column": 19, "line": 40 } } - }, - { - "id": "50", - "mutatorName": "ConditionalExpression", - "replacement": "true", - "statusReason": "src/directory-require-cache.ts(48,7): error TS2532: Object is possibly 'undefined'.\nsrc/directory-require-cache.ts(51,82): error TS2532: Object is possibly 'undefined'.\nsrc/directory-require-cache.ts(54,7): error TS2532: Object is possibly 'undefined'.\n", - "status": "CompileError", - "estimatedNetTime": 23, - "hitCount": 11, - "static": false, - "coveredBy": ["5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15"], - "location": { "end": { "column": 35, "line": 46 }, "start": { "column": 9, "line": 46 } } - }, - { - "id": "48", - "mutatorName": "BooleanLiteral", - "replacement": "cache.has(parentFileName)", - "statusReason": "Attempted to wrap cwd which is already wrapped", - "status": "Killed", - "estimatedNetTime": 19, - "hitCount": 14, - "static": false, - "testsCompleted": 1, - "killedBy": ["5"], - "coveredBy": ["5", "6", "7", "8", "9", "10", "11", "12"], - "location": { "end": { "column": 65, "line": 40 }, "start": { "column": 39, "line": 40 } } - }, - { - "id": "49", - "mutatorName": "BlockStatement", - "replacement": "{}", - "statusReason": "Attempted to wrap cwd which is already wrapped", - "status": "Killed", - "estimatedNetTime": 23, - "hitCount": 11, - "static": false, - "testsCompleted": 1, - "killedBy": ["5"], - "coveredBy": ["5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15"], - "location": { "end": { "column": 4, "line": 56 }, "start": { "column": 24, "line": 45 } } - }, - { - "id": "51", - "mutatorName": "ConditionalExpression", - "replacement": "false", - "statusReason": "src/directory-require-cache.ts(48,7): error TS2532: Object is possibly 'undefined'.\nsrc/directory-require-cache.ts(51,82): error TS2532: Object is possibly 'undefined'.\nsrc/directory-require-cache.ts(54,7): error TS2532: Object is possibly 'undefined'.\n", - "status": "CompileError", - "estimatedNetTime": 23, - "hitCount": 11, - "static": false, - "coveredBy": ["5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15"], - "location": { "end": { "column": 35, "line": 46 }, "start": { "column": 9, "line": 46 } } - }, - { - "id": "52", - "mutatorName": "LogicalOperator", - "replacement": "this.cache || this.parents", - "statusReason": "src/directory-require-cache.ts(48,7): error TS2532: Object is possibly 'undefined'.\nsrc/directory-require-cache.ts(51,82): error TS2532: Object is possibly 'undefined'.\nsrc/directory-require-cache.ts(54,7): error TS2532: Object is possibly 'undefined'.\n", - "status": "CompileError", - "estimatedNetTime": 23, - "hitCount": 11, - "static": false, - "coveredBy": ["5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15"], - "location": { "end": { "column": 35, "line": 46 }, "start": { "column": 9, "line": 46 } } - }, - { - "id": "55", - "mutatorName": "ConditionalExpression", - "replacement": "true", - "statusReason": "src/directory-require-cache.ts(51,11): error TS2532: Object is possibly 'undefined'.\nsrc/directory-require-cache.ts(51,35): error TS2532: Object is possibly 'undefined'.\n", - "status": "CompileError", - "estimatedNetTime": 19, - "hitCount": 9, - "static": false, - "coveredBy": ["5", "6", "7", "8", "9", "10", "11", "12"], - "location": { "end": { "column": 25, "line": 50 }, "start": { "column": 13, "line": 50 } } - }, - { - "id": "56", - "mutatorName": "ConditionalExpression", - "replacement": "false", - "statusReason": "src/directory-require-cache.ts(51,11): error TS2532: Object is possibly 'undefined'.\nsrc/directory-require-cache.ts(51,35): error TS2532: Object is possibly 'undefined'.\n", - "status": "CompileError", - "estimatedNetTime": 19, - "hitCount": 9, - "static": false, - "coveredBy": ["5", "6", "7", "8", "9", "10", "11", "12"], - "location": { "end": { "column": 25, "line": 50 }, "start": { "column": 13, "line": 50 } } - }, - { - "id": "54", - "mutatorName": "BlockStatement", - "replacement": "{}", - "statusReason": "Attempted to wrap cwd which is already wrapped", - "status": "Killed", - "estimatedNetTime": 19, - "hitCount": 9, - "static": false, - "testsCompleted": 1, - "killedBy": ["5"], - "coveredBy": ["5", "6", "7", "8", "9", "10", "11", "12"], - "location": { "end": { "column": 8, "line": 53 }, "start": { "column": 40, "line": 48 } } - }, - { - "id": "53", - "mutatorName": "BlockStatement", - "replacement": "{}", - "statusReason": "expected { Object (exports, children, ...) } to be undefined", - "status": "Killed", - "estimatedNetTime": 23, - "hitCount": 11, - "static": false, - "testsCompleted": 1, - "killedBy": ["5"], - "coveredBy": ["5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15"], - "location": { "end": { "column": 6, "line": 55 }, "start": { "column": 37, "line": 46 } } - }, - { - "id": "57", - "mutatorName": "BlockStatement", - "replacement": "{}", - "statusReason": "Attempted to wrap cwd which is already wrapped", - "status": "Killed", - "estimatedNetTime": 18, - "hitCount": 8, - "static": false, - "testsCompleted": 1, - "killedBy": ["5"], - "coveredBy": ["5", "6", "7", "8", "9", "11", "12"], - "location": { "end": { "column": 10, "line": 52 }, "start": { "column": 27, "line": 50 } } - }, - { - "id": "58", - "mutatorName": "ArrowFunction", - "replacement": "() => undefined", - "statusReason": "Attempted to wrap cwd which is already wrapped", - "status": "Killed", - "estimatedNetTime": 18, - "hitCount": 8, - "static": false, - "testsCompleted": 1, - "killedBy": ["5"], - "coveredBy": ["5", "6", "7", "8", "9", "11", "12"], - "location": { "end": { "column": 107, "line": 51 }, "start": { "column": 64, "line": 51 } } - }, - { - "id": "59", - "mutatorName": "BooleanLiteral", - "replacement": "cache.has(childModule.id)", - "statusReason": "expected [ Array(2) ] to have a length of 1 but got 2", - "status": "Killed", - "estimatedNetTime": 18, - "hitCount": 14, - "static": false, - "testsCompleted": 3, - "killedBy": ["7"], - "coveredBy": ["5", "6", "7", "8", "9", "11", "12"], - "location": { "end": { "column": 107, "line": 51 }, "start": { "column": 81, "line": 51 } } - }, - { - "id": "60", - "mutatorName": "ArrowFunction", - "replacement": "() => undefined", - "statusReason": "Attempted to wrap cwd which is already wrapped", - "status": "Killed", - "estimatedNetTime": 23, - "hitCount": 11, - "static": false, - "testsCompleted": 1, - "killedBy": ["5"], - "coveredBy": ["5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15"], - "location": { "end": { "column": 65, "line": 54 }, "start": { "column": 21, "line": 54 } } - } - ], - "source": "import path from 'path';\n\nimport { notEmpty } from './not-empty';\nimport { caseSensitiveFs } from './platform';\n\n/**\n * A helper class that can be used by test runners.\n * The first time you call `record`, it will fill the internal registry with the files required in the current working directory (excluding node_modules)\n * Then each time you call `clear` it will clear those files from the require cache\n *\n * It will also delete the `module.children` property of the root module.\n * @see https://github.com/stryker-mutator/stryker-js/issues/2461\n */\nexport class DirectoryRequireCache {\n private cache: Set | undefined;\n private parents: Set | undefined;\n\n /**\n * Records the files required in the current working directory (excluding node_modules)\n * Only does so the first time, any subsequent calls will be ignored\n */\n public record(): void {\n if (!this.cache) {\n const cache = (this.cache = new Set());\n const cwd = process.cwd();\n const startsWithCaseInsensitive = (filename: string, prefix: string) => filename.toLowerCase().startsWith(prefix.toLowerCase());\n const startsWithCaseSensitive = (filename: string, prefix: string) => filename.startsWith(prefix);\n const startsWith = caseSensitiveFs() ? startsWithCaseSensitive : startsWithCaseInsensitive;\n Object.keys(require.cache)\n .filter((fileName) => startsWith(fileName, `${cwd}${path.sep}`) && !startsWith(fileName, path.join(cwd, 'node_modules')))\n .forEach((file) => cache.add(file));\n\n this.parents = new Set(\n Array.from(cache)\n // `module.parent` is deprecated, but seems to work fine, might never be removed.\n // See https://nodejs.org/api/modules.html#modules_module_parent\n .map((fileName) => require.cache[fileName]?.parent?.filename)\n .filter(notEmpty)\n // Filter out any parents that are in the current cache, since they will be removed anyway\n .filter((parentFileName) => !cache.has(parentFileName))\n );\n }\n }\n\n public clear(): void {\n if (this.cache && this.parents) {\n const cache = this.cache;\n this.parents.forEach((parent) => {\n const parentModule = require.cache[parent];\n if (parentModule) {\n parentModule.children = parentModule.children.filter((childModule) => !cache.has(childModule.id));\n }\n });\n cache.forEach((fileName) => delete require.cache[fileName]);\n }\n }\n}\n" - }, - "/home/nicojs/github/stryker-js/packages/util/src/errors.ts": { - "language": "typescript", - "mutants": [ - { - "id": "61", - "mutatorName": "BlockStatement", - "replacement": "{}", - "statusReason": "src/errors.ts(1,51): error TS2355: A function whose declared type is neither 'void' nor 'any' must return a value.\n", - "status": "CompileError", - "estimatedNetTime": 10, - "hitCount": 6, - "static": false, - "coveredBy": ["17", "18", "19", "101", "102"], - "location": { "end": { "column": 2, "line": 3 }, "start": { "column": 82, "line": 1 } } - }, - { - "id": "62", - "mutatorName": "ConditionalExpression", - "replacement": "true", - "statusReason": "expected 'Error: undefined (undefined) Error: expected error\\n at Context. (/home/nicojs/github/stryker-js/packages/util/.stryker-tmp/sandbox8696228/test/unit/errors.spec.ts:24:21)\\n at callFn (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runnable.js:366:21)\\n at Test.Runnable.run (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runnable.js:354:5)\\n at Runner.runTest (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:681:10)\\n at /home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:804:12\\n at next (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:596:14)\\n at /home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:606:7\\n at next (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:489:14)\\n at Immediate._onImmediate (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:574:5)\\n at processImmediate (internal/timers.js:464:21)' to equal 'Error: expected error\\nError: expected error\\n at Context. (/home/nicojs/github/stryker-js/packages/util/.stryker-tmp/sandbox8696228/test/unit/errors.spec.ts:24:21)\\n at callFn (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runnable.js:366:21)\\n at Test.Runnable.run (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runnable.js:354:5)\\n at Runner.runTest (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:681:10)\\n at /home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:804:12\\n at next (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:596:14)\\n at /home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:606:7\\n at next (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:489:14)\\n at Immediate._onImmediate (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:574:5)\\n at processImmediate (internal/timers.js:464:21)'", - "status": "Killed", - "estimatedNetTime": 10, - "hitCount": 6, - "static": false, - "testsCompleted": 2, - "killedBy": ["18"], - "coveredBy": ["17", "18", "19", "101", "102"], - "location": { "end": { "column": 93, "line": 2 }, "start": { "column": 10, "line": 2 } } - }, - { - "id": "63", - "mutatorName": "ConditionalExpression", - "replacement": "false", - "statusReason": "expected 'name: message\\nqux' to equal 'name: foo (baz) qux'", - "status": "Killed", - "estimatedNetTime": 10, - "hitCount": 6, - "static": false, - "testsCompleted": 1, - "killedBy": ["17"], - "coveredBy": ["17", "18", "19", "101", "102"], - "location": { "end": { "column": 93, "line": 2 }, "start": { "column": 10, "line": 2 } } - }, - { - "id": "64", - "mutatorName": "LogicalOperator", - "replacement": "error instanceof Error || typeof (error as NodeJS.ErrnoException).code === 'string'", - "statusReason": "expected 'Error: undefined (undefined) Error: expected error\\n at Context. (/home/nicojs/github/stryker-js/packages/util/.stryker-tmp/sandbox8696228/test/unit/errors.spec.ts:24:21)\\n at callFn (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runnable.js:366:21)\\n at Test.Runnable.run (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runnable.js:354:5)\\n at Runner.runTest (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:681:10)\\n at /home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:804:12\\n at next (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:596:14)\\n at /home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:606:7\\n at next (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:489:14)\\n at Immediate._onImmediate (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:574:5)\\n at processImmediate (internal/timers.js:464:21)' to equal 'Error: expected error\\nError: expected error\\n at Context. (/home/nicojs/github/stryker-js/packages/util/.stryker-tmp/sandbox8696228/test/unit/errors.spec.ts:24:21)\\n at callFn (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runnable.js:366:21)\\n at Test.Runnable.run (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runnable.js:354:5)\\n at Runner.runTest (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:681:10)\\n at /home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:804:12\\n at next (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:596:14)\\n at /home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:606:7\\n at next (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:489:14)\\n at Immediate._onImmediate (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:574:5)\\n at processImmediate (internal/timers.js:464:21)'", - "status": "Killed", - "estimatedNetTime": 10, - "hitCount": 6, - "static": false, - "testsCompleted": 2, - "killedBy": ["18"], - "coveredBy": ["17", "18", "19", "101", "102"], - "location": { "end": { "column": 93, "line": 2 }, "start": { "column": 10, "line": 2 } } - }, - { - "id": "65", - "mutatorName": "ConditionalExpression", - "replacement": "true", - "statusReason": "expected 'Error: undefined (undefined) Error: expected error\\n at Context. (/home/nicojs/github/stryker-js/packages/util/.stryker-tmp/sandbox8696228/test/unit/errors.spec.ts:24:21)\\n at callFn (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runnable.js:366:21)\\n at Test.Runnable.run (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runnable.js:354:5)\\n at Runner.runTest (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:681:10)\\n at /home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:804:12\\n at next (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:596:14)\\n at /home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:606:7\\n at next (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:489:14)\\n at Immediate._onImmediate (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:574:5)\\n at processImmediate (internal/timers.js:464:21)' to equal 'Error: expected error\\nError: expected error\\n at Context. (/home/nicojs/github/stryker-js/packages/util/.stryker-tmp/sandbox8696228/test/unit/errors.spec.ts:24:21)\\n at callFn (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runnable.js:366:21)\\n at Test.Runnable.run (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runnable.js:354:5)\\n at Runner.runTest (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:681:10)\\n at /home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:804:12\\n at next (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:596:14)\\n at /home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:606:7\\n at next (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:489:14)\\n at Immediate._onImmediate (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:574:5)\\n at processImmediate (internal/timers.js:464:21)'", - "status": "Killed", - "estimatedNetTime": 10, - "hitCount": 6, - "static": false, - "testsCompleted": 2, - "killedBy": ["18"], - "coveredBy": ["17", "18", "19", "101", "102"], - "location": { "end": { "column": 93, "line": 2 }, "start": { "column": 36, "line": 2 } } - }, - { - "id": "68", - "mutatorName": "StringLiteral", - "replacement": "\"\"", - "statusReason": "src/errors.ts(2,36): error TS2367: This condition will always return 'false' since the types '\"string\" | \"number\" | \"bigint\" | \"boolean\" | \"symbol\" | \"undefined\" | \"object\" | \"function\"' and '\"\"' have no overlap.\n", - "status": "CompileError", - "estimatedNetTime": 10, - "hitCount": 6, - "static": false, - "coveredBy": ["17", "18", "19", "101", "102"], - "location": { "end": { "column": 93, "line": 2 }, "start": { "column": 85, "line": 2 } } - }, - { - "id": "66", - "mutatorName": "ConditionalExpression", - "replacement": "false", - "statusReason": "expected 'name: message\\nqux' to equal 'name: foo (baz) qux'", - "status": "Killed", - "estimatedNetTime": 10, - "hitCount": 6, - "static": false, - "testsCompleted": 1, - "killedBy": ["17"], - "coveredBy": ["17", "18", "19", "101", "102"], - "location": { "end": { "column": 93, "line": 2 }, "start": { "column": 36, "line": 2 } } - }, - { - "id": "69", - "mutatorName": "BlockStatement", - "replacement": "{}", - "statusReason": "src/errors.ts(6,44): error TS2355: A function whose declared type is neither 'void' nor 'any' must return a value.\n", - "status": "CompileError", - "estimatedNetTime": 10, - "hitCount": 7, - "static": false, - "coveredBy": ["16", "17", "18", "19", "101", "102"], - "location": { "end": { "column": 2, "line": 22 }, "start": { "column": 51, "line": 6 } } - }, - { - "id": "67", - "mutatorName": "EqualityOperator", - "replacement": "typeof (error as NodeJS.ErrnoException).code !== 'string'", - "statusReason": "expected 'name: message\\nqux' to equal 'name: foo (baz) qux'", - "status": "Killed", - "estimatedNetTime": 10, - "hitCount": 6, - "static": false, - "testsCompleted": 1, - "killedBy": ["17"], - "coveredBy": ["17", "18", "19", "101", "102"], - "location": { "end": { "column": 93, "line": 2 }, "start": { "column": 36, "line": 2 } } - }, - { - "id": "70", - "mutatorName": "BooleanLiteral", - "replacement": "error", - "statusReason": "Cannot read property 'toString' of undefined", - "status": "Killed", - "estimatedNetTime": 10, - "hitCount": 7, - "static": false, - "testsCompleted": 1, - "killedBy": ["16"], - "coveredBy": ["16", "17", "18", "19", "101", "102"], - "location": { "end": { "column": 13, "line": 7 }, "start": { "column": 7, "line": 7 } } - }, - { - "id": "71", - "mutatorName": "ConditionalExpression", - "replacement": "true", - "statusReason": "expected '' to equal 'name: foo (baz) qux'", - "status": "Killed", - "estimatedNetTime": 10, - "hitCount": 7, - "static": false, - "testsCompleted": 2, - "killedBy": ["17"], - "coveredBy": ["16", "17", "18", "19", "101", "102"], - "location": { "end": { "column": 13, "line": 7 }, "start": { "column": 7, "line": 7 } } - }, - { - "id": "73", - "mutatorName": "BlockStatement", - "replacement": "{}", - "statusReason": "Cannot read property 'toString' of undefined", - "status": "Killed", - "estimatedNetTime": 0, - "hitCount": 1, - "static": false, - "testsCompleted": 1, - "killedBy": ["16"], - "coveredBy": ["16"], - "location": { "end": { "column": 4, "line": 9 }, "start": { "column": 15, "line": 7 } } - }, - { - "id": "72", - "mutatorName": "ConditionalExpression", - "replacement": "false", - "statusReason": "Cannot read property 'toString' of undefined", - "status": "Killed", - "estimatedNetTime": 10, - "hitCount": 7, - "static": false, - "testsCompleted": 1, - "killedBy": ["16"], - "coveredBy": ["16", "17", "18", "19", "101", "102"], - "location": { "end": { "column": 13, "line": 7 }, "start": { "column": 7, "line": 7 } } - }, - { - "id": "74", - "mutatorName": "StringLiteral", - "replacement": "\"Stryker was here!\"", - "statusReason": "expected 'Stryker was here!' to equal ''", - "status": "Killed", - "estimatedNetTime": 0, - "hitCount": 1, - "static": false, - "testsCompleted": 1, - "killedBy": ["16"], - "coveredBy": ["16"], - "location": { "end": { "column": 14, "line": 8 }, "start": { "column": 12, "line": 8 } } - }, - { - "id": "75", - "mutatorName": "ConditionalExpression", - "replacement": "true", - "status": "Survived", - "estimatedNetTime": 10, - "hitCount": 6, - "static": false, - "testsCompleted": 5, - "coveredBy": ["17", "18", "19", "101", "102"], - "location": { "end": { "column": 29, "line": 10 }, "start": { "column": 7, "line": 10 } } - }, - { - "id": "76", - "mutatorName": "ConditionalExpression", - "replacement": "false", - "statusReason": "expected 'name: message' to equal 'name: foo (baz) qux'", - "status": "Killed", - "estimatedNetTime": 10, - "hitCount": 6, - "static": false, - "testsCompleted": 1, - "killedBy": ["17"], - "coveredBy": ["17", "18", "19", "101", "102"], - "location": { "end": { "column": 29, "line": 10 }, "start": { "column": 7, "line": 10 } } - }, - { - "id": "77", - "mutatorName": "BlockStatement", - "replacement": "{}", - "statusReason": "expected 'name: message' to equal 'name: foo (baz) qux'", - "status": "Killed", - "estimatedNetTime": 10, - "hitCount": 6, - "static": false, - "testsCompleted": 1, - "killedBy": ["17"], - "coveredBy": ["17", "18", "19", "101", "102"], - "location": { "end": { "column": 4, "line": 20 }, "start": { "column": 31, "line": 10 } } - }, - { - "id": "78", - "mutatorName": "ConditionalExpression", - "replacement": "true", - "statusReason": "src/errors.ts(12,38): error TS2339: Property 'code' does not exist on type 'Error'.\nsrc/errors.ts(12,53): error TS2339: Property 'syscall' does not exist on type 'Error'.\n", - "status": "CompileError", - "estimatedNetTime": 10, - "hitCount": 6, - "static": false, - "coveredBy": ["17", "18", "19", "101", "102"], - "location": { "end": { "column": 32, "line": 11 }, "start": { "column": 9, "line": 11 } } - }, - { - "id": "79", - "mutatorName": "ConditionalExpression", - "replacement": "false", - "statusReason": "expected 'name: message\\nqux' to equal 'name: foo (baz) qux'", - "status": "Killed", - "estimatedNetTime": 10, - "hitCount": 6, - "static": false, - "testsCompleted": 1, - "killedBy": ["17"], - "coveredBy": ["17", "18", "19", "101", "102"], - "location": { "end": { "column": 32, "line": 11 }, "start": { "column": 9, "line": 11 } } - }, - { - "id": "80", - "mutatorName": "BlockStatement", - "replacement": "{}", - "statusReason": "expected 'name: message\\nqux' to equal 'name: foo (baz) qux'", - "status": "Killed", - "estimatedNetTime": 1, - "hitCount": 1, - "static": false, - "testsCompleted": 1, - "killedBy": ["17"], - "coveredBy": ["17"], - "location": { "end": { "column": 6, "line": 13 }, "start": { "column": 34, "line": 11 } } - }, - { - "id": "81", - "mutatorName": "StringLiteral", - "replacement": "``", - "statusReason": "expected '' to equal 'name: foo (baz) qux'", - "status": "Killed", - "estimatedNetTime": 1, - "hitCount": 1, - "static": false, - "testsCompleted": 1, - "killedBy": ["17"], - "coveredBy": ["17"], - "location": { "end": { "column": 78, "line": 12 }, "start": { "column": 14, "line": 12 } } - }, - { - "id": "82", - "mutatorName": "StringLiteral", - "replacement": "``", - "statusReason": "expected '\\nError: expected error\\n at Context. (/home/nicojs/github/stryker-js/packages/util/.stryker-tmp/sandbox8696228/test/unit/errors.spec.ts:24:21)\\n at callFn (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runnable.js:366:21)\\n at Test.Runnable.run (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runnable.js:354:5)\\n at Runner.runTest (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:681:10)\\n at /home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:804:12\\n at next (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:596:14)\\n at /home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:606:7\\n at next (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:489:14)\\n at Immediate._onImmediate (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:574:5)\\n at processImmediate (internal/timers.js:464:21)' to equal 'Error: expected error\\nError: expected error\\n at Context. (/home/nicojs/github/stryker-js/packages/util/.stryker-tmp/sandbox8696228/test/unit/errors.spec.ts:24:21)\\n at callFn (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runnable.js:366:21)\\n at Test.Runnable.run (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runnable.js:354:5)\\n at Runner.runTest (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:681:10)\\n at /home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:804:12\\n at next (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:596:14)\\n at /home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:606:7\\n at next (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:489:14)\\n at Immediate._onImmediate (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:574:5)\\n at processImmediate (internal/timers.js:464:21)'", - "status": "Killed", - "estimatedNetTime": 9, - "hitCount": 5, - "static": false, - "testsCompleted": 1, - "killedBy": ["18"], - "coveredBy": ["18", "19", "101", "102"], - "location": { "end": { "column": 54, "line": 14 }, "start": { "column": 21, "line": 14 } } - }, - { - "id": "83", - "mutatorName": "ConditionalExpression", - "replacement": "true", - "statusReason": "src/errors.ts(16,29): error TS2532: Object is possibly 'undefined'.\n", - "status": "CompileError", - "estimatedNetTime": 9, - "hitCount": 5, - "static": false, - "coveredBy": ["18", "19", "101", "102"], - "location": { "end": { "column": 20, "line": 15 }, "start": { "column": 9, "line": 15 } } - }, - { - "id": "84", - "mutatorName": "ConditionalExpression", - "replacement": "false", - "statusReason": "expected 'Error: expected error' to equal 'Error: expected error\\nError: expected error\\n at Context. (/home/nicojs/github/stryker-js/packages/util/.stryker-tmp/sandbox8696228/test/unit/errors.spec.ts:24:21)\\n at callFn (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runnable.js:366:21)\\n at Test.Runnable.run (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runnable.js:354:5)\\n at Runner.runTest (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:681:10)\\n at /home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:804:12\\n at next (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:596:14)\\n at /home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:606:7\\n at next (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:489:14)\\n at Immediate._onImmediate (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:574:5)\\n at processImmediate (internal/timers.js:464:21)'", - "status": "Killed", - "estimatedNetTime": 9, - "hitCount": 5, - "static": false, - "testsCompleted": 1, - "killedBy": ["18"], - "coveredBy": ["18", "19", "101", "102"], - "location": { "end": { "column": 20, "line": 15 }, "start": { "column": 9, "line": 15 } } - }, - { - "id": "85", - "mutatorName": "BlockStatement", - "replacement": "{}", - "statusReason": "expected 'Error: expected error' to equal 'Error: expected error\\nError: expected error\\n at Context. (/home/nicojs/github/stryker-js/packages/util/.stryker-tmp/sandbox8696228/test/unit/errors.spec.ts:24:21)\\n at callFn (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runnable.js:366:21)\\n at Test.Runnable.run (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runnable.js:354:5)\\n at Runner.runTest (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:681:10)\\n at /home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:804:12\\n at next (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:596:14)\\n at /home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:606:7\\n at next (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:489:14)\\n at Immediate._onImmediate (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:574:5)\\n at processImmediate (internal/timers.js:464:21)'", - "status": "Killed", - "estimatedNetTime": 9, - "hitCount": 4, - "static": false, - "testsCompleted": 1, - "killedBy": ["18"], - "coveredBy": ["18", "101", "102"], - "location": { "end": { "column": 6, "line": 17 }, "start": { "column": 22, "line": 15 } } - }, - { - "id": "86", - "mutatorName": "StringLiteral", - "replacement": "``", - "statusReason": "expected '' to equal 'Error: expected error\\nError: expected error\\n at Context. (/home/nicojs/github/stryker-js/packages/util/.stryker-tmp/sandbox8696228/test/unit/errors.spec.ts:24:21)\\n at callFn (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runnable.js:366:21)\\n at Test.Runnable.run (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runnable.js:354:5)\\n at Runner.runTest (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:681:10)\\n at /home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:804:12\\n at next (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:596:14)\\n at /home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:606:7\\n at next (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:489:14)\\n at Immediate._onImmediate (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:574:5)\\n at processImmediate (internal/timers.js:464:21)'", - "status": "Killed", - "estimatedNetTime": 9, - "hitCount": 4, - "static": false, - "testsCompleted": 1, - "killedBy": ["18"], - "coveredBy": ["18", "101", "102"], - "location": { "end": { "column": 53, "line": 16 }, "start": { "column": 14, "line": 16 } } - }, - { - "id": "87", - "mutatorName": "BlockStatement", - "replacement": "{}", - "status": "Survived", - "estimatedNetTime": 0, - "hitCount": 1, - "static": false, - "testsCompleted": 1, - "coveredBy": ["19"], - "location": { "end": { "column": 6, "line": 19 }, "start": { "column": 12, "line": 17 } } - } - ], - "source": "export function isErrnoException(error: unknown): error is NodeJS.ErrnoException {\n return error instanceof Error && typeof (error as NodeJS.ErrnoException).code === 'string';\n}\n\n// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types\nexport function errorToString(error: any): string {\n if (!error) {\n return '';\n }\n if (error instanceof Error) {\n if (isErrnoException(error)) {\n return `${error.name}: ${error.code} (${error.syscall}) ${error.stack}`;\n }\n const message = `${error.name}: ${error.message}`;\n if (error.stack) {\n return `${message}\\n${error.stack.toString()}`;\n } else {\n return message;\n }\n }\n return error.toString();\n}\n" - }, - "/home/nicojs/github/stryker-js/packages/util/src/find-unserializables.ts": { - "language": "typescript", - "mutants": [ - { - "id": "88", - "mutatorName": "BlockStatement", - "replacement": "{}", - "statusReason": "src/find-unserializables.ts(8,54): error TS2355: A function whose declared type is neither 'void' nor 'any' must return a value.\n", - "status": "CompileError", - "estimatedNetTime": 8, - "hitCount": 85, - "static": false, - "coveredBy": [ - "20", - "21", - "22", - "23", - "24", - "25", - "26", - "27", - "28", - "29", - "30", - "31", - "32", - "33", - "34", - "35", - "36", - "37", - "38", - "39", - "40", - "41", - "42", - "43", - "44", - "45" - ], - "location": { "end": { "column": 2, "line": 61 }, "start": { "column": 94, "line": 8 } } - }, - { - "id": "90", - "mutatorName": "StringLiteral", - "replacement": "\"\"", - "statusReason": "src/find-unserializables.ts(8,54): error TS7030: Not all code paths return a value.\nsrc/find-unserializables.ts(10,10): error TS2678: Type '\"\"' is not comparable to type '\"string\" | \"number\" | \"bigint\" | \"boolean\" | \"symbol\" | \"undefined\" | \"object\" | \"function\"'.\nsrc/find-unserializables.ts(11,24): error TS2345: Argument of type 'unknown' is not assignable to parameter of type 'number'.\n", - "status": "CompileError", - "estimatedNetTime": 8, - "hitCount": 85, - "static": false, - "coveredBy": [ - "20", - "21", - "22", - "23", - "24", - "25", - "26", - "27", - "28", - "29", - "30", - "31", - "32", - "33", - "34", - "35", - "36", - "37", - "38", - "39", - "40", - "41", - "42", - "43", - "44", - "45" - ], - "location": { "end": { "column": 18, "line": 10 }, "start": { "column": 10, "line": 10 } } - }, - { - "id": "89", - "mutatorName": "ConditionalExpression", - "replacement": "case 'number':", - "statusReason": "expected undefined to be truthy", - "status": "Killed", - "estimatedNetTime": 3, - "hitCount": 13, - "static": false, - "testsCompleted": 2, - "killedBy": ["31"], - "coveredBy": ["20", "31", "32", "33", "35", "45"], - "location": { "end": { "column": 124, "line": 11 }, "start": { "column": 5, "line": 10 } } - }, - { - "id": "91", - "mutatorName": "BooleanLiteral", - "replacement": "isFinite(thing)", - "statusReason": "expected [ Array(1) ] to be undefined", - "status": "Killed", - "estimatedNetTime": 3, - "hitCount": 13, - "static": false, - "testsCompleted": 1, - "killedBy": ["20"], - "coveredBy": ["20", "31", "32", "33", "35", "45"], - "location": { "end": { "column": 30, "line": 11 }, "start": { "column": 14, "line": 11 } } - }, - { - "id": "93", - "mutatorName": "ObjectLiteral", - "replacement": "{}", - "statusReason": "src/find-unserializables.ts(11,7): error TS2322: Type '{}[] | undefined' is not assignable to type 'UnserializableDescription[] | undefined'.\n Type '{}[]' is not assignable to type 'UnserializableDescription[]'.\n Type '{}' is missing the following properties from type 'UnserializableDescription': path, reason\n", - "status": "CompileError", - "estimatedNetTime": 1, - "hitCount": 4, - "static": false, - "coveredBy": ["31", "32", "33", "45"], - "location": { "end": { "column": 110, "line": 11 }, "start": { "column": 34, "line": 11 } } - }, - { - "id": "92", - "mutatorName": "ArrayDeclaration", - "replacement": "[]", - "statusReason": "Cannot read property 'reason' of undefined", - "status": "Killed", - "estimatedNetTime": 1, - "hitCount": 4, - "static": false, - "testsCompleted": 4, - "killedBy": ["45"], - "coveredBy": ["31", "32", "33", "45"], - "location": { "end": { "column": 111, "line": 11 }, "start": { "column": 33, "line": 11 } } - }, - { - "id": "96", - "mutatorName": "StringLiteral", - "replacement": "\"\"", - "statusReason": "src/find-unserializables.ts(8,54): error TS7030: Not all code paths return a value.\nsrc/find-unserializables.ts(12,10): error TS2678: Type '\"\"' is not comparable to type '\"string\" | \"number\" | \"bigint\" | \"boolean\" | \"symbol\" | \"undefined\" | \"object\" | \"function\"'.\n", - "status": "CompileError", - "estimatedNetTime": 6, - "hitCount": 72, - "static": false, - "coveredBy": ["21", "22", "23", "24", "25", "26", "27", "28", "29", "30", "34", "35", "36", "37", "38", "39", "40", "41", "42", "43", "44"], - "location": { "end": { "column": 18, "line": 12 }, "start": { "column": 10, "line": 12 } } - }, - { - "id": "94", - "mutatorName": "StringLiteral", - "replacement": "``", - "statusReason": "expected '' to equal 'Number value `NaN` has no JSON representation'", - "status": "Killed", - "estimatedNetTime": 1, - "hitCount": 4, - "static": false, - "testsCompleted": 4, - "killedBy": ["45"], - "coveredBy": ["31", "32", "33", "45"], - "location": { "end": { "column": 98, "line": 11 }, "start": { "column": 44, "line": 11 } } - }, - { - "id": "97", - "mutatorName": "StringLiteral", - "replacement": "\"\"", - "statusReason": "src/find-unserializables.ts(8,54): error TS7030: Not all code paths return a value.\nsrc/find-unserializables.ts(13,10): error TS2678: Type '\"\"' is not comparable to type '\"string\" | \"number\" | \"bigint\" | \"boolean\" | \"symbol\" | \"undefined\" | \"object\" | \"function\"'.\n", - "status": "CompileError", - "estimatedNetTime": 5, - "hitCount": 52, - "static": false, - "coveredBy": ["21", "22", "23", "25", "26", "27", "28", "29", "30", "34", "35", "36", "37", "38", "39", "40", "41", "42", "43", "44"], - "location": { "end": { "column": 19, "line": 13 }, "start": { "column": 10, "line": 13 } } - }, - { - "id": "95", - "mutatorName": "ArrayDeclaration", - "replacement": "[\"Stryker was here\"]", - "status": "Survived", - "estimatedNetTime": 1, - "hitCount": 4, - "static": false, - "testsCompleted": 4, - "coveredBy": ["31", "32", "33", "45"], - "location": { "end": { "column": 108, "line": 11 }, "start": { "column": 106, "line": 11 } } - }, - { - "id": "99", - "mutatorName": "StringLiteral", - "replacement": "\"\"", - "statusReason": "src/find-unserializables.ts(8,54): error TS7030: Not all code paths return a value.\nsrc/find-unserializables.ts(14,10): error TS2678: Type '\"\"' is not comparable to type '\"string\" | \"number\" | \"bigint\" | \"boolean\" | \"symbol\" | \"undefined\" | \"object\" | \"function\"'.\n", - "status": "CompileError", - "estimatedNetTime": 5, - "hitCount": 43, - "static": false, - "coveredBy": ["22", "23", "25", "26", "27", "28", "29", "30", "34", "35", "36", "37", "38", "39", "40", "41", "42", "43", "44"], - "location": { "end": { "column": 21, "line": 14 }, "start": { "column": 10, "line": 14 } } - }, - { - "id": "100", - "mutatorName": "StringLiteral", - "replacement": "\"\"", - "statusReason": "src/find-unserializables.ts(8,54): error TS7030: Not all code paths return a value.\nsrc/find-unserializables.ts(16,10): error TS2678: Type '\"\"' is not comparable to type '\"string\" | \"number\" | \"bigint\" | \"boolean\" | \"symbol\" | \"undefined\" | \"object\" | \"function\"'.\n", - "status": "CompileError", - "estimatedNetTime": 5, - "hitCount": 42, - "static": false, - "coveredBy": ["23", "25", "26", "27", "28", "29", "30", "34", "35", "36", "37", "38", "39", "40", "41", "42", "43", "44"], - "location": { "end": { "column": 18, "line": 16 }, "start": { "column": 10, "line": 16 } } - }, - { - "id": "101", - "mutatorName": "StringLiteral", - "replacement": "\"\"", - "statusReason": "src/find-unserializables.ts(8,54): error TS7030: Not all code paths return a value.\nsrc/find-unserializables.ts(17,10): error TS2678: Type '\"\"' is not comparable to type '\"string\" | \"number\" | \"bigint\" | \"boolean\" | \"symbol\" | \"undefined\" | \"object\" | \"function\"'.\n", - "status": "CompileError", - "estimatedNetTime": 4, - "hitCount": 40, - "static": false, - "coveredBy": ["23", "25", "26", "27", "28", "30", "34", "35", "36", "37", "38", "39", "41", "42", "43", "44"], - "location": { "end": { "column": 20, "line": 17 }, "start": { "column": 10, "line": 17 } } - }, - { - "id": "98", - "mutatorName": "ConditionalExpression", - "replacement": "case 'undefined':", - "statusReason": "expected [ Array(1) ] to be undefined", - "status": "Killed", - "estimatedNetTime": 2, - "hitCount": 30, - "static": false, - "testsCompleted": 1, - "killedBy": ["21"], - "coveredBy": ["21", "22", "24", "35", "39"], - "location": { "end": { "column": 14, "line": 15 }, "start": { "column": 5, "line": 14 } } - }, - { - "id": "103", - "mutatorName": "StringLiteral", - "replacement": "\"\"", - "statusReason": "src/find-unserializables.ts(8,54): error TS7030: Not all code paths return a value.\nsrc/find-unserializables.ts(18,10): error TS2678: Type '\"\"' is not comparable to type '\"string\" | \"number\" | \"bigint\" | \"boolean\" | \"symbol\" | \"undefined\" | \"object\" | \"function\"'.\n", - "status": "CompileError", - "estimatedNetTime": 3, - "hitCount": 39, - "static": false, - "coveredBy": ["23", "25", "26", "27", "28", "34", "35", "36", "37", "38", "39", "41", "42", "43", "44"], - "location": { "end": { "column": 18, "line": 18 }, "start": { "column": 10, "line": 18 } } - }, - { - "id": "102", - "mutatorName": "ConditionalExpression", - "replacement": "case 'symbol':", - "statusReason": "expected 'Value is an instance of \"BigInt\", this detail will get lost in translation during serialization' to equal 'Primitive type \"bigint\" has no JSON representation'", - "status": "Killed", - "estimatedNetTime": 3, - "hitCount": 8, - "static": false, - "testsCompleted": 8, - "killedBy": ["40"], - "coveredBy": ["28", "29", "30", "36", "37", "38", "39", "40"], - "location": { "end": { "column": 9, "line": 24 }, "start": { "column": 5, "line": 18 } } - }, - { - "id": "105", - "mutatorName": "ObjectLiteral", - "replacement": "{}", - "statusReason": "src/find-unserializables.ts(20,9): error TS2739: Type '{}' is missing the following properties from type 'UnserializableDescription': path, reason\n", - "status": "CompileError", - "estimatedNetTime": 3, - "hitCount": 8, - "static": false, - "coveredBy": ["28", "29", "30", "36", "37", "38", "39", "40"], - "location": { "end": { "column": 10, "line": 23 }, "start": { "column": 9, "line": 20 } } - }, - { - "id": "104", - "mutatorName": "ArrayDeclaration", - "replacement": "[]", - "statusReason": "expected undefined to deeply equal [ 'symbol' ]", - "status": "Killed", - "estimatedNetTime": 3, - "hitCount": 8, - "static": false, - "testsCompleted": 4, - "killedBy": ["36"], - "coveredBy": ["28", "29", "30", "36", "37", "38", "39", "40"], - "location": { "end": { "column": 8, "line": 24 }, "start": { "column": 14, "line": 19 } } - }, - { - "id": "108", - "mutatorName": "ConditionalExpression", - "replacement": "case 'object':", - "statusReason": "src/find-unserializables.ts(8,54): error TS7030: Not all code paths return a value.\n", - "status": "CompileError", - "estimatedNetTime": 3, - "hitCount": 34, - "static": false, - "coveredBy": ["23", "25", "26", "27", "34", "35", "36", "37", "38", "39", "41", "42", "43", "44"], - "location": { "end": { "column": 9, "line": 59 }, "start": { "column": 5, "line": 25 } } - }, - { - "id": "106", - "mutatorName": "ArrayDeclaration", - "replacement": "[\"Stryker was here\"]", - "statusReason": "expected [ 'symbol', 'Stryker was here' ] to deeply equal [ 'symbol' ]", - "status": "Killed", - "estimatedNetTime": 3, - "hitCount": 8, - "static": false, - "testsCompleted": 4, - "killedBy": ["36"], - "coveredBy": ["28", "29", "30", "36", "37", "38", "39", "40"], - "location": { "end": { "column": 19, "line": 21 }, "start": { "column": 17, "line": 21 } } - }, - { - "id": "109", - "mutatorName": "StringLiteral", - "replacement": "\"\"", - "statusReason": "src/find-unserializables.ts(8,54): error TS7030: Not all code paths return a value.\nsrc/find-unserializables.ts(25,10): error TS2678: Type '\"\"' is not comparable to type '\"string\" | \"number\" | \"bigint\" | \"boolean\" | \"symbol\" | \"undefined\" | \"object\" | \"function\"'.\nsrc/find-unserializables.ts(43,39): error TS2769: No overload matches this call.\n Overload 1 of 2, '(o: { [s: string]: unknown; } | ArrayLike): [string, unknown][]', gave the following error.\n Argument of type 'unknown' is not assignable to parameter of type '{ [s: string]: unknown; } | ArrayLike'.\n Type 'unknown' is not assignable to type 'ArrayLike'.\n Overload 2 of 2, '(o: {}): [string, any][]', gave the following error.\n Argument of type 'unknown' is not assignable to parameter of type '{}'.\nsrc/find-unserializables.ts(53,30): error TS2571: Object is of type 'unknown'.\n", - "status": "CompileError", - "estimatedNetTime": 3, - "hitCount": 34, - "static": false, - "coveredBy": ["23", "25", "26", "27", "34", "35", "36", "37", "38", "39", "41", "42", "43", "44"], - "location": { "end": { "column": 18, "line": 25 }, "start": { "column": 10, "line": 25 } } - }, - { - "id": "107", - "mutatorName": "StringLiteral", - "replacement": "``", - "statusReason": "expected '' to equal 'Primitive type \"bigint\" has no JSON representation'", - "status": "Killed", - "estimatedNetTime": 3, - "hitCount": 8, - "static": false, - "testsCompleted": 8, - "killedBy": ["40"], - "coveredBy": ["28", "29", "30", "36", "37", "38", "39", "40"], - "location": { "end": { "column": 80, "line": 22 }, "start": { "column": 19, "line": 22 } } - }, - { - "id": "110", - "mutatorName": "ConditionalExpression", - "replacement": "true", - "statusReason": "src/find-unserializables.ts(31,24): error TS2571: Object is of type 'unknown'.\nsrc/find-unserializables.ts(32,21): error TS7006: Parameter 'child' implicitly has an 'any' type.\nsrc/find-unserializables.ts(32,28): error TS7006: Parameter 'index' implicitly has an 'any' type.\nsrc/find-unserializables.ts(43,39): error TS2769: No overload matches this call.\n Overload 1 of 2, '(o: { [s: string]: unknown; } | ArrayLike): [string, unknown][]', gave the following error.\n Argument of type 'unknown' is not assignable to parameter of type '{ [s: string]: unknown; } | ArrayLike'.\n Type 'unknown' is not assignable to type 'ArrayLike'.\n Overload 2 of 2, '(o: {}): [string, any][]', gave the following error.\n Argument of type 'unknown' is not assignable to parameter of type '{}'.\nsrc/find-unserializables.ts(53,30): error TS2571: Object is of type 'unknown'.\n", - "status": "CompileError", - "estimatedNetTime": 3, - "hitCount": 34, - "static": false, - "coveredBy": ["23", "25", "26", "27", "34", "35", "36", "37", "38", "39", "41", "42", "43", "44"], - "location": { "end": { "column": 25, "line": 27 }, "start": { "column": 11, "line": 27 } } - }, - { - "id": "111", - "mutatorName": "ConditionalExpression", - "replacement": "false", - "statusReason": "src/find-unserializables.ts(43,39): error TS2769: No overload matches this call.\n Overload 1 of 2, '(o: { [s: string]: unknown; } | ArrayLike): [string, unknown][]', gave the following error.\n Argument of type 'object | null' is not assignable to parameter of type '{ [s: string]: unknown; } | ArrayLike'.\n Type 'null' is not assignable to type '{ [s: string]: unknown; } | ArrayLike'.\n Overload 2 of 2, '(o: {}): [string, any][]', gave the following error.\n Argument of type 'object | null' is not assignable to parameter of type '{}'.\n Type 'null' is not assignable to type '{}'.\nsrc/find-unserializables.ts(53,30): error TS2531: Object is possibly 'null'.\n", - "status": "CompileError", - "estimatedNetTime": 3, - "hitCount": 34, - "static": false, - "coveredBy": ["23", "25", "26", "27", "34", "35", "36", "37", "38", "39", "41", "42", "43", "44"], - "location": { "end": { "column": 25, "line": 27 }, "start": { "column": 11, "line": 27 } } - }, - { - "id": "112", - "mutatorName": "EqualityOperator", - "replacement": "thing !== null", - "statusReason": "src/find-unserializables.ts(32,12): error TS2339: Property 'flatMap' does not exist on type 'never'.\nsrc/find-unserializables.ts(32,21): error TS7006: Parameter 'child' implicitly has an 'any' type.\nsrc/find-unserializables.ts(32,28): error TS7006: Parameter 'index' implicitly has an 'any' type.\nsrc/find-unserializables.ts(43,39): error TS2769: No overload matches this call.\n Overload 1 of 2, '(o: { [s: string]: unknown; } | ArrayLike): [string, unknown][]', gave the following error.\n Argument of type 'null' is not assignable to parameter of type '{ [s: string]: unknown; } | ArrayLike'.\n Overload 2 of 2, '(o: {}): [string, any][]', gave the following error.\n Argument of type 'null' is not assignable to parameter of type '{}'.\nsrc/find-unserializables.ts(53,30): error TS2531: Object is possibly 'null'.\n", - "status": "CompileError", - "estimatedNetTime": 3, - "hitCount": 34, - "static": false, - "coveredBy": ["23", "25", "26", "27", "34", "35", "36", "37", "38", "39", "41", "42", "43", "44"], - "location": { "end": { "column": 25, "line": 27 }, "start": { "column": 11, "line": 27 } } - }, - { - "id": "113", - "mutatorName": "BlockStatement", - "replacement": "{}", - "statusReason": "src/find-unserializables.ts(41,39): error TS2769: No overload matches this call.\n Overload 1 of 2, '(o: { [s: string]: unknown; } | ArrayLike): [string, unknown][]', gave the following error.\n Argument of type 'object | null' is not assignable to parameter of type '{ [s: string]: unknown; } | ArrayLike'.\n Type 'null' is not assignable to type '{ [s: string]: unknown; } | ArrayLike'.\n Overload 2 of 2, '(o: {}): [string, any][]', gave the following error.\n Argument of type 'object | null' is not assignable to parameter of type '{}'.\n Type 'null' is not assignable to type '{}'.\nsrc/find-unserializables.ts(51,30): error TS2531: Object is possibly 'null'.\n", - "status": "CompileError", - "estimatedNetTime": 1, - "hitCount": 3, - "static": false, - "coveredBy": ["23", "35"], - "location": { "end": { "column": 8, "line": 29 }, "start": { "column": 27, "line": 27 } } - }, - { - "id": "114", - "mutatorName": "ConditionalExpression", - "replacement": "true", - "statusReason": "src/find-unserializables.ts(32,12): error TS2339: Property 'flatMap' does not exist on type 'object'.\nsrc/find-unserializables.ts(32,21): error TS7006: Parameter 'child' implicitly has an 'any' type.\nsrc/find-unserializables.ts(32,28): error TS7006: Parameter 'index' implicitly has an 'any' type.\nsrc/find-unserializables.ts(43,39): error TS2769: No overload matches this call.\n Overload 1 of 2, '(o: { [s: string]: unknown; } | ArrayLike): [string, unknown][]', gave the following error.\n Argument of type 'unknown' is not assignable to parameter of type '{ [s: string]: unknown; } | ArrayLike'.\n Type 'unknown' is not assignable to type 'ArrayLike'.\n Overload 2 of 2, '(o: {}): [string, any][]', gave the following error.\n Argument of type 'unknown' is not assignable to parameter of type '{}'.\nsrc/find-unserializables.ts(53,30): error TS2571: Object is of type 'unknown'.\n", - "status": "CompileError", - "estimatedNetTime": 3, - "hitCount": 31, - "static": false, - "coveredBy": ["25", "26", "27", "34", "35", "36", "37", "38", "39", "41", "42", "43", "44"], - "location": { "end": { "column": 31, "line": 30 }, "start": { "column": 11, "line": 30 } } - }, - { - "id": "115", - "mutatorName": "ConditionalExpression", - "replacement": "false", - "statusReason": "src/find-unserializables.ts(31,24): error TS2571: Object is of type 'unknown'.\nsrc/find-unserializables.ts(32,21): error TS7006: Parameter 'child' implicitly has an 'any' type.\nsrc/find-unserializables.ts(32,28): error TS7006: Parameter 'index' implicitly has an 'any' type.\n", - "status": "CompileError", - "estimatedNetTime": 3, - "hitCount": 31, - "static": false, - "coveredBy": ["25", "26", "27", "34", "35", "36", "37", "38", "39", "41", "42", "43", "44"], - "location": { "end": { "column": 31, "line": 30 }, "start": { "column": 11, "line": 30 } } - }, - { - "id": "117", - "mutatorName": "ArrowFunction", - "replacement": "() => undefined", - "statusReason": "src/find-unserializables.ts(35,9): error TS2322: Type 'undefined[] | undefined' is not assignable to type 'UnserializableDescription[] | undefined'.\n Type 'undefined[]' is not assignable to type 'UnserializableDescription[]'.\n Type 'undefined' is not assignable to type 'UnserializableDescription'.\n", - "status": "CompileError", - "estimatedNetTime": 2, - "hitCount": 13, - "static": false, - "coveredBy": ["26", "35", "38", "39"], - "location": { "end": { "column": 15, "line": 36 }, "start": { "column": 20, "line": 32 } } - }, - { - "id": "118", - "mutatorName": "OptionalChaining", - "replacement": "findUnserializables(child).map", - "statusReason": "src/find-unserializables.ts(33,13): error TS2532: Object is possibly 'undefined'.\n", - "status": "CompileError", - "estimatedNetTime": 2, - "hitCount": 10, - "static": false, - "coveredBy": ["35", "38", "39"], - "location": { "end": { "column": 44, "line": 33 }, "start": { "column": 13, "line": 33 } } - }, - { - "id": "116", - "mutatorName": "BlockStatement", - "replacement": "{}", - "statusReason": "expected [ Array(1) ] to be undefined", - "status": "Killed", - "estimatedNetTime": 2, - "hitCount": 13, - "static": false, - "testsCompleted": 1, - "killedBy": ["26"], - "coveredBy": ["26", "35", "38", "39"], - "location": { "end": { "column": 8, "line": 40 }, "start": { "column": 33, "line": 30 } } - }, - { - "id": "119", - "mutatorName": "BlockStatement", - "replacement": "{}", - "statusReason": "src/find-unserializables.ts(36,9): error TS2322: Type 'void[] | undefined' is not assignable to type 'UnserializableDescription[] | undefined'.\n Type 'void[]' is not assignable to type 'UnserializableDescription[]'.\n Type 'void' is not assignable to type 'UnserializableDescription'.\n", - "status": "CompileError", - "estimatedNetTime": 1, - "hitCount": 3, - "static": false, - "coveredBy": ["38", "39"], - "location": { "end": { "column": 14, "line": 36 }, "start": { "column": 62, "line": 33 } } - }, - { - "id": "120", - "mutatorName": "ConditionalExpression", - "replacement": "true", - "statusReason": "src/find-unserializables.ts(53,30): error TS2571: Object is of type 'unknown'.\n", - "status": "CompileError", - "estimatedNetTime": 2, - "hitCount": 18, - "static": false, - "coveredBy": ["25", "27", "34", "35", "36", "37", "41", "42", "43", "44"], - "location": { "end": { "column": 65, "line": 42 }, "start": { "column": 11, "line": 42 } } - }, - { - "id": "121", - "mutatorName": "ConditionalExpression", - "replacement": "false", - "statusReason": "src/find-unserializables.ts(43,39): error TS2769: No overload matches this call.\n Overload 1 of 2, '(o: { [s: string]: unknown; } | ArrayLike): [string, unknown][]', gave the following error.\n Argument of type 'unknown' is not assignable to parameter of type '{ [s: string]: unknown; } | ArrayLike'.\n Type 'unknown' is not assignable to type 'ArrayLike'.\n Overload 2 of 2, '(o: {}): [string, any][]', gave the following error.\n Argument of type 'unknown' is not assignable to parameter of type '{}'.\n", - "status": "CompileError", - "estimatedNetTime": 2, - "hitCount": 18, - "static": false, - "coveredBy": ["25", "27", "34", "35", "36", "37", "41", "42", "43", "44"], - "location": { "end": { "column": 65, "line": 42 }, "start": { "column": 11, "line": 42 } } - }, - { - "id": "123", - "mutatorName": "ConditionalExpression", - "replacement": "true", - "statusReason": "src/find-unserializables.ts(53,30): error TS2571: Object is of type 'unknown'.\n", - "status": "CompileError", - "estimatedNetTime": 2, - "hitCount": 18, - "static": false, - "coveredBy": ["25", "27", "34", "35", "36", "37", "41", "42", "43", "44"], - "location": { "end": { "column": 42, "line": 42 }, "start": { "column": 11, "line": 42 } } - }, - { - "id": "122", - "mutatorName": "LogicalOperator", - "replacement": "thingProto === Object.prototype && thingProto === null", - "statusReason": "expected [ Array(1) ] to be undefined", - "status": "Killed", - "estimatedNetTime": 2, - "hitCount": 18, - "static": false, - "testsCompleted": 1, - "killedBy": ["25"], - "coveredBy": ["25", "27", "34", "35", "36", "37", "41", "42", "43", "44"], - "location": { "end": { "column": 65, "line": 42 }, "start": { "column": 11, "line": 42 } } - }, - { - "id": "124", - "mutatorName": "ConditionalExpression", - "replacement": "false", - "statusReason": "expected [ Array(1) ] to be undefined", - "status": "Killed", - "estimatedNetTime": 2, - "hitCount": 18, - "static": false, - "testsCompleted": 1, - "killedBy": ["25"], - "coveredBy": ["25", "27", "34", "35", "36", "37", "41", "42", "43", "44"], - "location": { "end": { "column": 42, "line": 42 }, "start": { "column": 11, "line": 42 } } - }, - { - "id": "125", - "mutatorName": "EqualityOperator", - "replacement": "thingProto !== Object.prototype", - "statusReason": "expected [ Array(1) ] to be undefined", - "status": "Killed", - "estimatedNetTime": 2, - "hitCount": 18, - "static": false, - "testsCompleted": 1, - "killedBy": ["25"], - "coveredBy": ["25", "27", "34", "35", "36", "37", "41", "42", "43", "44"], - "location": { "end": { "column": 42, "line": 42 }, "start": { "column": 11, "line": 42 } } - }, - { - "id": "126", - "mutatorName": "ConditionalExpression", - "replacement": "true", - "statusReason": "src/find-unserializables.ts(53,30): error TS2571: Object is of type 'unknown'.\n", - "status": "CompileError", - "estimatedNetTime": 1, - "hitCount": 6, - "static": false, - "coveredBy": ["27", "34", "41", "42", "43", "44"], - "location": { "end": { "column": 65, "line": 42 }, "start": { "column": 46, "line": 42 } } - }, - { - "id": "127", - "mutatorName": "ConditionalExpression", - "replacement": "false", - "statusReason": "Cannot read property 'name' of undefined", - "status": "Killed", - "estimatedNetTime": 1, - "hitCount": 6, - "static": false, - "testsCompleted": 1, - "killedBy": ["27"], - "coveredBy": ["27", "34", "41", "42", "43", "44"], - "location": { "end": { "column": 65, "line": 42 }, "start": { "column": 46, "line": 42 } } - }, - { - "id": "130", - "mutatorName": "ArrowFunction", - "replacement": "() => undefined", - "statusReason": "src/find-unserializables.ts(47,9): error TS2322: Type 'undefined[] | undefined' is not assignable to type 'UnserializableDescription[] | undefined'.\n Type 'undefined[]' is not assignable to type 'UnserializableDescription[]'.\n Type 'undefined' is not assignable to type 'UnserializableDescription'.\n", - "status": "CompileError", - "estimatedNetTime": 1, - "hitCount": 13, - "static": false, - "coveredBy": ["25", "27", "35", "36", "37"], - "location": { "end": { "column": 15, "line": 48 }, "start": { "column": 20, "line": 44 } } - }, - { - "id": "128", - "mutatorName": "EqualityOperator", - "replacement": "thingProto !== null", - "statusReason": "Cannot read property 'name' of undefined", - "status": "Killed", - "estimatedNetTime": 1, - "hitCount": 6, - "static": false, - "testsCompleted": 1, - "killedBy": ["27"], - "coveredBy": ["27", "34", "41", "42", "43", "44"], - "location": { "end": { "column": 65, "line": 42 }, "start": { "column": 46, "line": 42 } } - }, - { - "id": "129", - "mutatorName": "BlockStatement", - "replacement": "{}", - "statusReason": "expected [ Array(1) ] to be undefined", - "status": "Killed", - "estimatedNetTime": 1, - "hitCount": 13, - "static": false, - "testsCompleted": 1, - "killedBy": ["25"], - "coveredBy": ["25", "27", "35", "36", "37"], - "location": { "end": { "column": 8, "line": 52 }, "start": { "column": 67, "line": 42 } } - }, - { - "id": "131", - "mutatorName": "OptionalChaining", - "replacement": "findUnserializables(val).map", - "statusReason": "src/find-unserializables.ts(45,13): error TS2532: Object is possibly 'undefined'.\n", - "status": "CompileError", - "estimatedNetTime": 1, - "hitCount": 49, - "static": false, - "coveredBy": ["35", "36", "37"], - "location": { "end": { "column": 42, "line": 45 }, "start": { "column": 13, "line": 45 } } - }, - { - "id": "132", - "mutatorName": "BlockStatement", - "replacement": "{}", - "statusReason": "src/find-unserializables.ts(48,9): error TS2322: Type 'void[] | undefined' is not assignable to type 'UnserializableDescription[] | undefined'.\n Type 'void[]' is not assignable to type 'UnserializableDescription[]'.\n Type 'void' is not assignable to type 'UnserializableDescription'.\n", - "status": "CompileError", - "estimatedNetTime": 0, - "hitCount": 3, - "static": false, - "coveredBy": ["36", "37"], - "location": { "end": { "column": 14, "line": 48 }, "start": { "column": 60, "line": 45 } } - }, - { - "id": "133", - "mutatorName": "ConditionalExpression", - "replacement": "true", - "statusReason": "expected 'Value is an instance of \"true\", this detail will get lost in translation during serialization' to equal 'Value is an instance of \"Person\", this detail will get lost in translation during serialization'", - "status": "Killed", - "estimatedNetTime": 1, - "hitCount": 5, - "static": false, - "testsCompleted": 2, - "killedBy": ["41"], - "coveredBy": ["34", "41", "42", "43", "44"], - "location": { "end": { "column": 75, "line": 53 }, "start": { "column": 30, "line": 53 } } - }, - { - "id": "134", - "mutatorName": "ConditionalExpression", - "replacement": "false", - "statusReason": "expected 'Value is an instance of \"false\", this detail will get lost in translation during serialization' to equal 'Value is an instance of \"Person\", this detail will get lost in translation during serialization'", - "status": "Killed", - "estimatedNetTime": 1, - "hitCount": 5, - "static": false, - "testsCompleted": 2, - "killedBy": ["41"], - "coveredBy": ["34", "41", "42", "43", "44"], - "location": { "end": { "column": 75, "line": 53 }, "start": { "column": 30, "line": 53 } } - }, - { - "id": "135", - "mutatorName": "LogicalOperator", - "replacement": "thing.constructor.name && ''", - "statusReason": "expected 'Value is an instance of \"\", this detail will get lost in translation during serialization' to equal 'Value is an instance of \"Person\", this detail will get lost in translation during serialization'", - "status": "Killed", - "estimatedNetTime": 1, - "hitCount": 5, - "static": false, - "testsCompleted": 2, - "killedBy": ["41"], - "coveredBy": ["34", "41", "42", "43", "44"], - "location": { "end": { "column": 75, "line": 53 }, "start": { "column": 30, "line": 53 } } - }, - { - "id": "136", - "mutatorName": "StringLiteral", - "replacement": "\"\"", - "statusReason": "expected 'Value is an instance of \"\", this detail will get lost in translation during serialization' to equal 'Value is an instance of \"\", this detail will get lost in translation during serialization'", - "status": "Killed", - "estimatedNetTime": 0, - "hitCount": 1, - "static": false, - "testsCompleted": 1, - "killedBy": ["42"], - "coveredBy": ["42"], - "location": { "end": { "column": 75, "line": 53 }, "start": { "column": 56, "line": 53 } } - }, - { - "id": "138", - "mutatorName": "ObjectLiteral", - "replacement": "{}", - "statusReason": "src/find-unserializables.ts(55,9): error TS2739: Type '{}' is missing the following properties from type 'UnserializableDescription': path, reason\n", - "status": "CompileError", - "estimatedNetTime": 1, - "hitCount": 5, - "static": false, - "coveredBy": ["34", "41", "42", "43", "44"], - "location": { "end": { "column": 10, "line": 58 }, "start": { "column": 9, "line": 55 } } - }, - { - "id": "137", - "mutatorName": "ArrayDeclaration", - "replacement": "[]", - "statusReason": "Cannot read property 'reason' of undefined", - "status": "Killed", - "estimatedNetTime": 1, - "hitCount": 5, - "static": false, - "testsCompleted": 2, - "killedBy": ["41"], - "coveredBy": ["34", "41", "42", "43", "44"], - "location": { "end": { "column": 8, "line": 59 }, "start": { "column": 14, "line": 54 } } - }, - { - "id": "139", - "mutatorName": "ArrayDeclaration", - "replacement": "[\"Stryker was here\"]", - "status": "Survived", - "estimatedNetTime": 1, - "hitCount": 5, - "static": false, - "testsCompleted": 5, - "coveredBy": ["34", "41", "42", "43", "44"], - "location": { "end": { "column": 19, "line": 56 }, "start": { "column": 17, "line": 56 } } - }, - { - "id": "140", - "mutatorName": "StringLiteral", - "replacement": "``", - "statusReason": "expected '' to equal 'Value is an instance of \"Person\", this detail will get lost in translation during serialization'", - "status": "Killed", - "estimatedNetTime": 1, - "hitCount": 5, - "static": false, - "testsCompleted": 2, - "killedBy": ["41"], - "coveredBy": ["34", "41", "42", "43", "44"], - "location": { "end": { "column": 127, "line": 57 }, "start": { "column": 19, "line": 57 } } - } - ], - "source": "import { notEmpty } from './not-empty';\n\nexport interface UnserializableDescription {\n path: string[];\n reason: string;\n}\n\nexport function findUnserializables(thing: unknown): UnserializableDescription[] | undefined {\n switch (typeof thing) {\n case 'number':\n return !isFinite(thing) ? [{ reason: `Number value \\`${thing}\\` has no JSON representation`, path: [] }] : undefined;\n case 'string':\n case 'boolean':\n case 'undefined':\n return;\n case 'bigint':\n case 'function':\n case 'symbol':\n return [\n {\n path: [],\n reason: `Primitive type \"${typeof thing}\" has no JSON representation`,\n },\n ];\n case 'object':\n // Either a plain object, null, array or instance of a class\n if (thing === null) {\n return;\n }\n if (Array.isArray(thing)) {\n const things = thing\n .flatMap((child, index) =>\n findUnserializables(child)?.map((description) => {\n description.path.unshift(index.toString());\n return description;\n })\n )\n .filter(notEmpty);\n return things.length ? things : undefined;\n }\n const thingProto = Object.getPrototypeOf(thing);\n if (thingProto === Object.prototype || thingProto === null) {\n const things = Object.entries(thing)\n .flatMap(([key, val]) =>\n findUnserializables(val)?.map((description) => {\n description.path.unshift(key);\n return description;\n })\n )\n .filter(notEmpty);\n return things.length ? things : undefined;\n }\n const protoClassName = thing.constructor.name || '';\n return [\n {\n path: [],\n reason: `Value is an instance of \"${protoClassName}\", this detail will get lost in translation during serialization`,\n },\n ];\n }\n}\n" - }, - "/home/nicojs/github/stryker-js/packages/util/src/immutable.ts": { - "language": "typescript", - "mutants": [ - { - "id": "141", - "mutatorName": "BlockStatement", - "replacement": "{}", - "statusReason": "src/immutable.ts(20,43): error TS2355: A function whose declared type is neither 'void' nor 'any' must return a value.\n", - "status": "CompileError", - "estimatedNetTime": 6, - "hitCount": 28, - "static": false, - "coveredBy": ["46", "47", "48", "49", "50", "51", "52", "53", "54"], - "location": { "end": { "column": 2, "line": 47 }, "start": { "column": 56, "line": 20 } } - }, - { - "id": "142", - "mutatorName": "ConditionalExpression", - "replacement": "case 'object':", - "statusReason": "expected { foo: 'bar', baz: 42 } to be frozen", - "status": "Killed", - "estimatedNetTime": 6, - "hitCount": 15, - "static": false, - "testsCompleted": 2, - "killedBy": ["47"], - "coveredBy": ["46", "47", "48", "50", "51", "52", "53", "54"], - "location": { "end": { "column": 10, "line": 43 }, "start": { "column": 5, "line": 22 } } - }, - { - "id": "143", - "mutatorName": "StringLiteral", - "replacement": "\"\"", - "statusReason": "src/immutable.ts(22,10): error TS2678: Type '\"\"' is not comparable to type '\"string\" | \"number\" | \"bigint\" | \"boolean\" | \"symbol\" | \"undefined\" | \"object\" | \"function\"'.\n", - "status": "CompileError", - "estimatedNetTime": 6, - "hitCount": 28, - "static": false, - "coveredBy": ["46", "47", "48", "49", "50", "51", "52", "53", "54"], - "location": { "end": { "column": 18, "line": 22 }, "start": { "column": 10, "line": 22 } } - }, - { - "id": "144", - "mutatorName": "ConditionalExpression", - "replacement": "true", - "statusReason": "src/immutable.ts(24,31): error TS2352: Conversion of type 'T' to type 'any[]' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first.\nsrc/immutable.ts(27,49): error TS2339: Property 'entries' does not exist on type 'T'.\nsrc/immutable.ts(36,49): error TS2339: Property 'values' does not exist on type 'T'.\n", - "status": "CompileError", - "estimatedNetTime": 6, - "hitCount": 15, - "static": false, - "coveredBy": ["46", "47", "48", "50", "51", "52", "53", "54"], - "location": { "end": { "column": 32, "line": 23 }, "start": { "column": 11, "line": 23 } } - }, - { - "id": "145", - "mutatorName": "ConditionalExpression", - "replacement": "false", - "statusReason": "src/immutable.ts(24,31): error TS2352: Conversion of type 'T' to type 'any[]' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first.\n", - "status": "CompileError", - "estimatedNetTime": 6, - "hitCount": 15, - "static": false, - "coveredBy": ["46", "47", "48", "50", "51", "52", "53", "54"], - "location": { "end": { "column": 32, "line": 23 }, "start": { "column": 11, "line": 23 } } - }, - { - "id": "147", - "mutatorName": "ConditionalExpression", - "replacement": "true", - "statusReason": "src/immutable.ts(27,49): error TS2339: Property 'entries' does not exist on type 'T'.\nsrc/immutable.ts(36,49): error TS2339: Property 'values' does not exist on type 'T'.\n", - "status": "CompileError", - "estimatedNetTime": 6, - "hitCount": 14, - "static": false, - "coveredBy": ["46", "47", "48", "50", "51", "52", "53", "54"], - "location": { "end": { "column": 32, "line": 26 }, "start": { "column": 11, "line": 26 } } - }, - { - "id": "148", - "mutatorName": "ConditionalExpression", - "replacement": "false", - "statusReason": "src/immutable.ts(27,49): error TS2339: Property 'entries' does not exist on type 'T'.\n", - "status": "CompileError", - "estimatedNetTime": 6, - "hitCount": 14, - "static": false, - "coveredBy": ["46", "47", "48", "50", "51", "52", "53", "54"], - "location": { "end": { "column": 32, "line": 26 }, "start": { "column": 11, "line": 26 } } - }, - { - "id": "146", - "mutatorName": "BlockStatement", - "replacement": "{}", - "statusReason": "expected { Object (0, 1) } to be an instance of Array", - "status": "Killed", - "estimatedNetTime": 1, - "hitCount": 1, - "static": false, - "testsCompleted": 1, - "killedBy": ["51"], - "coveredBy": ["51"], - "location": { "end": { "column": 8, "line": 25 }, "start": { "column": 34, "line": 23 } } - }, - { - "id": "149", - "mutatorName": "BlockStatement", - "replacement": "{}", - "statusReason": "expected {} to have property 'length'", - "status": "Killed", - "estimatedNetTime": 1, - "hitCount": 1, - "static": false, - "testsCompleted": 1, - "killedBy": ["52"], - "coveredBy": ["52"], - "location": { "end": { "column": 8, "line": 28 }, "start": { "column": 34, "line": 26 } } - }, - { - "id": "150", - "mutatorName": "ConditionalExpression", - "replacement": "true", - "statusReason": "src/immutable.ts(36,49): error TS2339: Property 'values' does not exist on type 'T'.\n", - "status": "CompileError", - "estimatedNetTime": 6, - "hitCount": 13, - "static": false, - "coveredBy": ["46", "47", "48", "50", "51", "52", "53", "54"], - "location": { "end": { "column": 35, "line": 29 }, "start": { "column": 11, "line": 29 } } - }, - { - "id": "151", - "mutatorName": "ConditionalExpression", - "replacement": "false", - "statusReason": "expected {} to be an instance of RegExp", - "status": "Killed", - "estimatedNetTime": 6, - "hitCount": 13, - "static": false, - "testsCompleted": 8, - "killedBy": ["54"], - "coveredBy": ["46", "47", "48", "50", "51", "52", "53", "54"], - "location": { "end": { "column": 35, "line": 29 }, "start": { "column": 11, "line": 29 } } - }, - { - "id": "152", - "mutatorName": "BlockStatement", - "replacement": "{}", - "statusReason": "expected {} to be an instance of RegExp", - "status": "Killed", - "estimatedNetTime": 1, - "hitCount": 1, - "static": false, - "testsCompleted": 1, - "killedBy": ["54"], - "coveredBy": ["54"], - "location": { "end": { "column": 8, "line": 31 }, "start": { "column": 37, "line": 29 } } - }, - { - "id": "153", - "mutatorName": "ConditionalExpression", - "replacement": "true", - "statusReason": "src/immutable.ts(36,49): error TS2339: Property 'values' does not exist on type 'T'.\n", - "status": "CompileError", - "estimatedNetTime": 5, - "hitCount": 12, - "static": false, - "coveredBy": ["46", "47", "48", "50", "51", "52", "53"], - "location": { "end": { "column": 26, "line": 32 }, "start": { "column": 11, "line": 32 } } - }, - { - "id": "154", - "mutatorName": "ConditionalExpression", - "replacement": "false", - "statusReason": "Cannot convert undefined or null to object", - "status": "Killed", - "estimatedNetTime": 5, - "hitCount": 12, - "static": false, - "testsCompleted": 3, - "killedBy": ["48"], - "coveredBy": ["46", "47", "48", "50", "51", "52", "53"], - "location": { "end": { "column": 26, "line": 32 }, "start": { "column": 11, "line": 32 } } - }, - { - "id": "157", - "mutatorName": "ConditionalExpression", - "replacement": "true", - "statusReason": "src/immutable.ts(36,49): error TS2339: Property 'values' does not exist on type 'T'.\n", - "status": "CompileError", - "estimatedNetTime": 4, - "hitCount": 11, - "static": false, - "coveredBy": ["46", "47", "50", "51", "52", "53"], - "location": { "end": { "column": 32, "line": 35 }, "start": { "column": 11, "line": 35 } } - }, - { - "id": "155", - "mutatorName": "EqualityOperator", - "replacement": "target !== null", - "statusReason": "expected null to deeply equal { foo: 'bar', baz: 42 }", - "status": "Killed", - "estimatedNetTime": 5, - "hitCount": 12, - "static": false, - "testsCompleted": 2, - "killedBy": ["47"], - "coveredBy": ["46", "47", "48", "50", "51", "52", "53"], - "location": { "end": { "column": 26, "line": 32 }, "start": { "column": 11, "line": 32 } } - }, - { - "id": "156", - "mutatorName": "BlockStatement", - "replacement": "{}", - "statusReason": "Cannot convert undefined or null to object", - "status": "Killed", - "estimatedNetTime": 1, - "hitCount": 1, - "static": false, - "testsCompleted": 1, - "killedBy": ["48"], - "coveredBy": ["48"], - "location": { "end": { "column": 8, "line": 34 }, "start": { "column": 28, "line": 32 } } - }, - { - "id": "158", - "mutatorName": "ConditionalExpression", - "replacement": "false", - "statusReason": "src/immutable.ts(36,49): error TS2339: Property 'values' does not exist on type 'T'.\n", - "status": "CompileError", - "estimatedNetTime": 4, - "hitCount": 11, - "static": false, - "coveredBy": ["46", "47", "50", "51", "52", "53"], - "location": { "end": { "column": 32, "line": 35 }, "start": { "column": 11, "line": 35 } } - }, - { - "id": "160", - "mutatorName": "ObjectLiteral", - "replacement": "{}", - "statusReason": "src/immutable.ts(38,7): error TS2322: Type 'Readonly<{}>' is not assignable to type 'Immutable'.\n", - "status": "CompileError", - "estimatedNetTime": 4, - "hitCount": 10, - "static": false, - "coveredBy": ["46", "47", "50", "51", "52", "53"], - "location": { "end": { "column": 8, "line": 43 }, "start": { "column": 28, "line": 38 } } - }, - { - "id": "159", - "mutatorName": "BlockStatement", - "replacement": "{}", - "statusReason": "expected {} to have property 'length'", - "status": "Killed", - "estimatedNetTime": 0, - "hitCount": 1, - "static": false, - "testsCompleted": 1, - "killedBy": ["53"], - "coveredBy": ["53"], - "location": { "end": { "column": 8, "line": 37 }, "start": { "column": 34, "line": 35 } } - }, - { - "id": "162", - "mutatorName": "ConditionalExpression", - "replacement": "default:", - "statusReason": "src/immutable.ts(20,43): error TS2366: Function lacks ending return statement and return type does not include 'undefined'.\n", - "status": "CompileError", - "estimatedNetTime": 4, - "hitCount": 13, - "static": false, - "coveredBy": ["47", "48", "49", "50", "51", "52", "53"], - "location": { "end": { "column": 37, "line": 45 }, "start": { "column": 5, "line": 44 } } - }, - { - "id": "161", - "mutatorName": "BlockStatement", - "replacement": "{}", - "statusReason": "expected {} to deeply equal { foo: 'bar', baz: 42 }", - "status": "Killed", - "estimatedNetTime": 3, - "hitCount": 10, - "static": false, - "testsCompleted": 1, - "killedBy": ["47"], - "coveredBy": ["47", "50", "51", "52", "53"], - "location": { "end": { "column": 10, "line": 42 }, "start": { "column": 72, "line": 39 } } - } - ], - "source": "import { Primitive } from './primitive';\n\ntype ImmutablePrimitive = Primitive | ((...args: any[]) => any);\n\nexport type Immutable = T extends ImmutablePrimitive\n ? T\n : T extends Array\n ? ImmutableArray\n : T extends Map\n ? ImmutableMap\n : T extends Set\n ? ImmutableSet\n : ImmutableObject;\n\nexport type ImmutableArray = ReadonlyArray>;\nexport type ImmutableMap = ReadonlyMap, Immutable>;\nexport type ImmutableSet = ReadonlySet>;\nexport type ImmutableObject = { readonly [K in keyof T]: Immutable };\n\nexport function deepFreeze(target: T): Immutable {\n switch (typeof target) {\n case 'object':\n if (Array.isArray(target)) {\n return Object.freeze((target as any[]).map(deepFreeze)) as Immutable;\n }\n if (target instanceof Map) {\n return Object.freeze(new Map([...target.entries()].map(([k, v]) => [deepFreeze(k), deepFreeze(v)]))) as unknown as Immutable;\n }\n if (target instanceof RegExp) {\n return Object.freeze(target) as Immutable;\n }\n if (target === null) {\n return null as Immutable;\n }\n if (target instanceof Set) {\n return Object.freeze(new Set([...target.values()].map(deepFreeze))) as unknown as Immutable;\n }\n return Object.freeze({\n ...Object.entries(target).reduce((result, [prop, val]) => {\n result[prop] = deepFreeze(val);\n return result;\n }, {}),\n });\n default:\n return target as Immutable;\n }\n}\n" - }, - "/home/nicojs/github/stryker-js/packages/util/src/noop-logger.ts": { - "language": "typescript", - "mutants": [ - { - "id": "164", - "mutatorName": "BlockStatement", - "replacement": "{}", - "statusReason": "src/noop-logger.ts(2,21): error TS2355: A function whose declared type is neither 'void' nor 'any' must return a value.\n", - "status": "CompileError", - "estimatedNetTime": 0, - "hitCount": 1, - "static": false, - "coveredBy": ["55"], - "location": { "end": { "column": 4, "line": 4 }, "start": { "column": 29, "line": 2 } } - }, - { - "id": "166", - "mutatorName": "BlockStatement", - "replacement": "{}", - "statusReason": "src/noop-logger.ts(5,21): error TS2355: A function whose declared type is neither 'void' nor 'any' must return a value.\n", - "status": "CompileError", - "estimatedNetTime": 0, - "hitCount": 1, - "static": false, - "coveredBy": ["55"], - "location": { "end": { "column": 4, "line": 7 }, "start": { "column": 29, "line": 5 } } - }, - { - "id": "163", - "mutatorName": "ObjectLiteral", - "replacement": "{}", - "statusReason": "test/unit/noop-logger.spec.ts(9,23): error TS2339: Property 'isTraceEnabled' does not exist on type '{}'.\ntest/unit/noop-logger.spec.ts(10,23): error TS2339: Property 'isDebugEnabled' does not exist on type '{}'.\ntest/unit/noop-logger.spec.ts(11,23): error TS2339: Property 'isInfoEnabled' does not exist on type '{}'.\ntest/unit/noop-logger.spec.ts(12,23): error TS2339: Property 'isWarnEnabled' does not exist on type '{}'.\ntest/unit/noop-logger.spec.ts(13,23): error TS2339: Property 'isErrorEnabled' does not exist on type '{}'.\ntest/unit/noop-logger.spec.ts(14,23): error TS2339: Property 'isFatalEnabled' does not exist on type '{}'.\ntest/unit/noop-logger.spec.ts(19,16): error TS2339: Property 'trace' does not exist on type '{}'.\ntest/unit/noop-logger.spec.ts(20,16): error TS2339: Property 'debug' does not exist on type '{}'.\ntest/unit/noop-logger.spec.ts(21,16): error TS2339: Property 'info' does not exist on type '{}'.\ntest/unit/noop-logger.spec.ts(22,16): error TS2339: Property 'warn' does not exist on type '{}'.\ntest/unit/noop-logger.spec.ts(23,16): error TS2339: Property 'error' does not exist on type '{}'.\ntest/unit/noop-logger.spec.ts(24,16): error TS2339: Property 'fatal' does not exist on type '{}'.\n", - "status": "CompileError", - "estimatedNetTime": 73, - "hitCount": 1, - "static": true, - "location": { "end": { "column": 2, "line": 38 }, "start": { "column": 27, "line": 1 } } - }, - { - "id": "165", - "mutatorName": "BooleanLiteral", - "replacement": "true", - "statusReason": "expected true to be false", - "status": "Killed", - "estimatedNetTime": 0, - "hitCount": 1, - "static": false, - "testsCompleted": 1, - "killedBy": ["55"], - "coveredBy": ["55"], - "location": { "end": { "column": 17, "line": 3 }, "start": { "column": 12, "line": 3 } } - }, - { - "id": "168", - "mutatorName": "BlockStatement", - "replacement": "{}", - "statusReason": "src/noop-logger.ts(8,20): error TS2355: A function whose declared type is neither 'void' nor 'any' must return a value.\n", - "status": "CompileError", - "estimatedNetTime": 0, - "hitCount": 1, - "static": false, - "coveredBy": ["55"], - "location": { "end": { "column": 4, "line": 10 }, "start": { "column": 28, "line": 8 } } - }, - { - "id": "167", - "mutatorName": "BooleanLiteral", - "replacement": "true", - "statusReason": "expected true to be false", - "status": "Killed", - "estimatedNetTime": 0, - "hitCount": 1, - "static": false, - "testsCompleted": 1, - "killedBy": ["55"], - "coveredBy": ["55"], - "location": { "end": { "column": 17, "line": 6 }, "start": { "column": 12, "line": 6 } } - }, - { - "id": "170", - "mutatorName": "BlockStatement", - "replacement": "{}", - "statusReason": "src/noop-logger.ts(11,20): error TS2355: A function whose declared type is neither 'void' nor 'any' must return a value.\ntest/unit/noop-logger.spec.ts(9,23): error TS2339: Property 'isTraceEnabled' does not exist on type '{}'.\ntest/unit/noop-logger.spec.ts(10,23): error TS2339: Property 'isDebugEnabled' does not exist on type '{}'.\ntest/unit/noop-logger.spec.ts(11,23): error TS2339: Property 'isInfoEnabled' does not exist on type '{}'.\ntest/unit/noop-logger.spec.ts(12,23): error TS2339: Property 'isWarnEnabled' does not exist on type '{}'.\ntest/unit/noop-logger.spec.ts(13,23): error TS2339: Property 'isErrorEnabled' does not exist on type '{}'.\ntest/unit/noop-logger.spec.ts(14,23): error TS2339: Property 'isFatalEnabled' does not exist on type '{}'.\ntest/unit/noop-logger.spec.ts(19,16): error TS2339: Property 'trace' does not exist on type '{}'.\ntest/unit/noop-logger.spec.ts(20,16): error TS2339: Property 'debug' does not exist on type '{}'.\ntest/unit/noop-logger.spec.ts(21,16): error TS2339: Property 'info' does not exist on type '{}'.\ntest/unit/noop-logger.spec.ts(22,16): error TS2339: Property 'warn' does not exist on type '{}'.\ntest/unit/noop-logger.spec.ts(23,16): error TS2339: Property 'error' does not exist on type '{}'.\ntest/unit/noop-logger.spec.ts(24,16): error TS2339: Property 'fatal' does not exist on type '{}'.\n", - "status": "CompileError", - "estimatedNetTime": 0, - "hitCount": 1, - "static": false, - "coveredBy": ["55"], - "location": { "end": { "column": 4, "line": 13 }, "start": { "column": 28, "line": 11 } } - }, - { - "id": "169", - "mutatorName": "BooleanLiteral", - "replacement": "true", - "statusReason": "expected true to be false", - "status": "Killed", - "estimatedNetTime": 0, - "hitCount": 1, - "static": false, - "testsCompleted": 1, - "killedBy": ["55"], - "coveredBy": ["55"], - "location": { "end": { "column": 17, "line": 9 }, "start": { "column": 12, "line": 9 } } - }, - { - "id": "172", - "mutatorName": "BlockStatement", - "replacement": "{}", - "statusReason": "src/noop-logger.ts(14,21): error TS2355: A function whose declared type is neither 'void' nor 'any' must return a value.\n", - "status": "CompileError", - "estimatedNetTime": 0, - "hitCount": 1, - "static": false, - "coveredBy": ["55"], - "location": { "end": { "column": 4, "line": 16 }, "start": { "column": 29, "line": 14 } } - }, - { - "id": "171", - "mutatorName": "BooleanLiteral", - "replacement": "true", - "statusReason": "expected true to be false", - "status": "Killed", - "estimatedNetTime": 0, - "hitCount": 1, - "static": false, - "testsCompleted": 1, - "killedBy": ["55"], - "coveredBy": ["55"], - "location": { "end": { "column": 17, "line": 12 }, "start": { "column": 12, "line": 12 } } - }, - { - "id": "174", - "mutatorName": "BlockStatement", - "replacement": "{}", - "statusReason": "src/noop-logger.ts(17,21): error TS2355: A function whose declared type is neither 'void' nor 'any' must return a value.\n", - "status": "CompileError", - "estimatedNetTime": 0, - "hitCount": 1, - "static": false, - "coveredBy": ["55"], - "location": { "end": { "column": 4, "line": 19 }, "start": { "column": 29, "line": 17 } } - }, - { - "id": "175", - "mutatorName": "BooleanLiteral", - "replacement": "true", - "statusReason": "expected true to be false", - "status": "Killed", - "estimatedNetTime": 0, - "hitCount": 1, - "static": false, - "testsCompleted": 1, - "killedBy": ["55"], - "coveredBy": ["55"], - "location": { "end": { "column": 17, "line": 18 }, "start": { "column": 12, "line": 18 } } - }, - { - "id": "173", - "mutatorName": "BooleanLiteral", - "replacement": "true", - "statusReason": "expected true to be false", - "status": "Killed", - "estimatedNetTime": 0, - "hitCount": 1, - "static": false, - "testsCompleted": 1, - "killedBy": ["55"], - "coveredBy": ["55"], - "location": { "end": { "column": 17, "line": 15 }, "start": { "column": 12, "line": 15 } } - } - ], - "source": "export const noopLogger = {\n isTraceEnabled(): boolean {\n return false;\n },\n isDebugEnabled(): boolean {\n return false;\n },\n isInfoEnabled(): boolean {\n return false;\n },\n isWarnEnabled(): boolean {\n return false;\n },\n isErrorEnabled(): boolean {\n return false;\n },\n isFatalEnabled(): boolean {\n return false;\n },\n trace(): void {\n // noop\n },\n debug(): void {\n // noop\n },\n info(): void {\n // noop\n },\n warn(): void {\n // noop\n },\n error(): void {\n // noop\n },\n fatal(): void {\n // noop\n },\n};\n" - }, - "/home/nicojs/github/stryker-js/packages/util/src/not-empty.ts": { - "language": "typescript", - "mutants": [ - { - "id": "176", - "mutatorName": "BlockStatement", - "replacement": "{}", - "statusReason": "src/not-empty.ts(1,58): error TS2355: A function whose declared type is neither 'void' nor 'any' must return a value.\n", - "status": "CompileError", - "estimatedNetTime": 26, - "hitCount": 83, - "static": false, - "coveredBy": ["5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "35", "36", "37", "38", "39", "57", "58", "59"], - "location": { "end": { "column": 2, "line": 3 }, "start": { "column": 68, "line": 1 } } - }, - { - "id": "177", - "mutatorName": "ConditionalExpression", - "replacement": "true", - "statusReason": "Attempted to wrap cwd which is already wrapped", - "status": "Killed", - "estimatedNetTime": 26, - "hitCount": 83, - "static": false, - "testsCompleted": 1, - "killedBy": ["5"], - "coveredBy": ["5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "35", "36", "37", "38", "39", "57", "58", "59"], - "location": { "end": { "column": 45, "line": 2 }, "start": { "column": 10, "line": 2 } } - }, - { - "id": "178", - "mutatorName": "ConditionalExpression", - "replacement": "false", - "statusReason": "Attempted to wrap cwd which is already wrapped", - "status": "Killed", - "estimatedNetTime": 26, - "hitCount": 83, - "static": false, - "testsCompleted": 1, - "killedBy": ["5"], - "coveredBy": ["5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "35", "36", "37", "38", "39", "57", "58", "59"], - "location": { "end": { "column": 45, "line": 2 }, "start": { "column": 10, "line": 2 } } - }, - { - "id": "179", - "mutatorName": "LogicalOperator", - "replacement": "item !== undefined || item !== null", - "statusReason": "Attempted to wrap cwd which is already wrapped", - "status": "Killed", - "estimatedNetTime": 26, - "hitCount": 83, - "static": false, - "testsCompleted": 1, - "killedBy": ["5"], - "coveredBy": ["5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "35", "36", "37", "38", "39", "57", "58", "59"], - "location": { "end": { "column": 45, "line": 2 }, "start": { "column": 10, "line": 2 } } - }, - { - "id": "180", - "mutatorName": "ConditionalExpression", - "replacement": "true", - "statusReason": "Cannot read property 'path' of undefined", - "status": "Killed", - "estimatedNetTime": 26, - "hitCount": 83, - "static": false, - "testsCompleted": 12, - "killedBy": ["35"], - "coveredBy": ["5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "35", "36", "37", "38", "39", "57", "58", "59"], - "location": { "end": { "column": 28, "line": 2 }, "start": { "column": 10, "line": 2 } } - }, - { - "id": "181", - "mutatorName": "ConditionalExpression", - "replacement": "false", - "statusReason": "Attempted to wrap cwd which is already wrapped", - "status": "Killed", - "estimatedNetTime": 26, - "hitCount": 83, - "static": false, - "testsCompleted": 1, - "killedBy": ["5"], - "coveredBy": ["5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "35", "36", "37", "38", "39", "57", "58", "59"], - "location": { "end": { "column": 28, "line": 2 }, "start": { "column": 10, "line": 2 } } - }, - { - "id": "182", - "mutatorName": "EqualityOperator", - "replacement": "item === undefined", - "statusReason": "Attempted to wrap cwd which is already wrapped", - "status": "Killed", - "estimatedNetTime": 26, - "hitCount": 83, - "static": false, - "testsCompleted": 1, - "killedBy": ["5"], - "coveredBy": ["5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "35", "36", "37", "38", "39", "57", "58", "59"], - "location": { "end": { "column": 28, "line": 2 }, "start": { "column": 10, "line": 2 } } - }, - { - "id": "183", - "mutatorName": "ConditionalExpression", - "replacement": "true", - "statusReason": "expected true to be false", - "status": "Killed", - "estimatedNetTime": 21, - "hitCount": 25, - "static": false, - "testsCompleted": 14, - "killedBy": ["58"], - "coveredBy": ["5", "6", "7", "8", "9", "10", "11", "12", "36", "37", "38", "39", "57", "58"], - "location": { "end": { "column": 45, "line": 2 }, "start": { "column": 32, "line": 2 } } - }, - { - "id": "184", - "mutatorName": "ConditionalExpression", - "replacement": "false", - "statusReason": "Attempted to wrap cwd which is already wrapped", - "status": "Killed", - "estimatedNetTime": 21, - "hitCount": 25, - "static": false, - "testsCompleted": 1, - "killedBy": ["5"], - "coveredBy": ["5", "6", "7", "8", "9", "10", "11", "12", "36", "37", "38", "39", "57", "58"], - "location": { "end": { "column": 45, "line": 2 }, "start": { "column": 32, "line": 2 } } - }, - { - "id": "185", - "mutatorName": "EqualityOperator", - "replacement": "item === null", - "statusReason": "Attempted to wrap cwd which is already wrapped", - "status": "Killed", - "estimatedNetTime": 21, - "hitCount": 25, - "static": false, - "testsCompleted": 1, - "killedBy": ["5"], - "coveredBy": ["5", "6", "7", "8", "9", "10", "11", "12", "36", "37", "38", "39", "57", "58"], - "location": { "end": { "column": 45, "line": 2 }, "start": { "column": 32, "line": 2 } } - } - ], - "source": "export function notEmpty(item: T | null | undefined): item is T {\n return item !== undefined && item !== null;\n}\n" - }, - "/home/nicojs/github/stryker-js/packages/util/src/platform.ts": { - "language": "typescript", - "mutants": [ - { - "id": "186", - "mutatorName": "BlockStatement", - "replacement": "{}", - "statusReason": "src/platform.ts(6,36): error TS2355: A function whose declared type is neither 'void' nor 'any' must return a value.\n", - "status": "CompileError", - "estimatedNetTime": 20, - "hitCount": 9, - "static": false, - "coveredBy": ["5", "6", "7", "8", "9", "10", "11", "12", "13"], - "location": { "end": { "column": 2, "line": 8 }, "start": { "column": 44, "line": 6 } } - }, - { - "id": "187", - "mutatorName": "ConditionalExpression", - "replacement": "true", - "status": "Survived", - "estimatedNetTime": 20, - "hitCount": 9, - "static": false, - "testsCompleted": 9, - "coveredBy": ["5", "6", "7", "8", "9", "10", "11", "12", "13"], - "location": { "end": { "column": 37, "line": 7 }, "start": { "column": 10, "line": 7 } } - }, - { - "id": "188", - "mutatorName": "ConditionalExpression", - "replacement": "false", - "statusReason": "Attempted to wrap cwd which is already wrapped", - "status": "Killed", - "estimatedNetTime": 20, - "hitCount": 9, - "static": false, - "testsCompleted": 1, - "killedBy": ["5"], - "coveredBy": ["5", "6", "7", "8", "9", "10", "11", "12", "13"], - "location": { "end": { "column": 37, "line": 7 }, "start": { "column": 10, "line": 7 } } - }, - { - "id": "190", - "mutatorName": "StringLiteral", - "replacement": "\"\"", - "statusReason": "src/platform.ts(7,10): error TS2367: This condition will always return 'true' since the types 'Platform' and '\"\"' have no overlap.\n", - "status": "CompileError", - "estimatedNetTime": 20, - "hitCount": 9, - "static": false, - "coveredBy": ["5", "6", "7", "8", "9", "10", "11", "12", "13"], - "location": { "end": { "column": 37, "line": 7 }, "start": { "column": 30, "line": 7 } } - }, - { - "id": "189", - "mutatorName": "EqualityOperator", - "replacement": "process.platform == 'win32'", - "statusReason": "Attempted to wrap cwd which is already wrapped", - "status": "Killed", - "estimatedNetTime": 20, - "hitCount": 9, - "static": false, - "testsCompleted": 1, - "killedBy": ["5"], - "coveredBy": ["5", "6", "7", "8", "9", "10", "11", "12", "13"], - "location": { "end": { "column": 37, "line": 7 }, "start": { "column": 10, "line": 7 } } - } - ], - "source": "/**\n * Tells whether the filesystem is case sensitive.\n *\n * @returns false on Win32, true elsewhere\n */\nexport function caseSensitiveFs(): boolean {\n return process.platform != 'win32';\n}\n" - }, - "/home/nicojs/github/stryker-js/packages/util/src/require-resolve.ts": { - "language": "typescript", - "mutants": [ - { - "id": "191", - "mutatorName": "BlockStatement", - "replacement": "{}", - "statusReason": "src/require-resolve.ts(5,67): error TS2355: A function whose declared type is neither 'void' nor 'any' must return a value.\n", - "status": "CompileError", - "estimatedNetTime": 0, - "static": false, - "coveredBy": [], - "location": { "end": { "column": 2, "line": 8 }, "start": { "column": 75, "line": 5 } } - }, - { - "id": "192", - "mutatorName": "ObjectLiteral", - "replacement": "{}", - "status": "NoCoverage", - "estimatedNetTime": 0, - "static": false, - "coveredBy": [], - "location": { "end": { "column": 55, "line": 7 }, "start": { "column": 38, "line": 7 } } - }, - { - "id": "193", - "mutatorName": "ArrayDeclaration", - "replacement": "[]", - "status": "NoCoverage", - "estimatedNetTime": 0, - "static": false, - "coveredBy": [], - "location": { "end": { "column": 53, "line": 7 }, "start": { "column": 47, "line": 7 } } - } - ], - "source": "/**\n * Require a module from the current working directory (or a different base dir)\n * @see https://nodejs.org/api/modules.html#modules_require_resolve_paths_request\n */\nexport function requireResolve(id: string, from = process.cwd()): unknown {\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n return require(require.resolve(id, { paths: [from] }));\n}\n" - }, - "/home/nicojs/github/stryker-js/packages/util/src/string-utils.ts": { - "language": "typescript", - "mutants": [ - { - "id": "194", - "mutatorName": "BlockStatement", - "replacement": "{}", - "statusReason": "src/string-utils.ts(10,52): error TS2355: A function whose declared type is neither 'void' nor 'any' must return a value.\n", - "status": "CompileError", - "estimatedNetTime": 1, - "hitCount": 3, - "static": false, - "coveredBy": ["60", "61", "62"], - "location": { "end": { "column": 2, "line": 12 }, "start": { "column": 59, "line": 10 } } - }, - { - "id": "195", - "mutatorName": "Regex", - "replacement": "/\\s/g", - "statusReason": "expected 'foo bar baz' to equal 'foo bar baz'", - "status": "Killed", - "estimatedNetTime": 1, - "hitCount": 3, - "static": false, - "testsCompleted": 2, - "killedBy": ["61"], - "coveredBy": ["60", "61", "62"], - "location": { "end": { "column": 28, "line": 11 }, "start": { "column": 22, "line": 11 } } - }, - { - "id": "198", - "mutatorName": "BlockStatement", - "replacement": "{}", - "statusReason": "src/string-utils.ts(18,54): error TS2355: A function whose declared type is neither 'void' nor 'any' must return a value.\n", - "status": "CompileError", - "estimatedNetTime": 1, - "hitCount": 2, - "static": false, - "coveredBy": ["65", "66"], - "location": { "end": { "column": 2, "line": 20 }, "start": { "column": 61, "line": 18 } } - }, - { - "id": "196", - "mutatorName": "Regex", - "replacement": "/\\S+/g", - "statusReason": "expected '' to equal 'foo bar baz'", - "status": "Killed", - "estimatedNetTime": 1, - "hitCount": 3, - "static": false, - "testsCompleted": 1, - "killedBy": ["60"], - "coveredBy": ["60", "61", "62"], - "location": { "end": { "column": 28, "line": 11 }, "start": { "column": 22, "line": 11 } } - }, - { - "id": "199", - "mutatorName": "BlockStatement", - "replacement": "{}", - "statusReason": "src/string-utils.ts(32,91): error TS2355: A function whose declared type is neither 'void' nor 'any' must return a value.\n", - "status": "CompileError", - "estimatedNetTime": 1, - "hitCount": 4, - "static": false, - "coveredBy": ["63", "64"], - "location": { "end": { "column": 4, "line": 34 }, "start": { "column": 146, "line": 32 } } - }, - { - "id": "197", - "mutatorName": "StringLiteral", - "replacement": "\"\"", - "statusReason": "expected 'foobarbaz' to equal 'foo bar baz'", - "status": "Killed", - "estimatedNetTime": 1, - "hitCount": 3, - "static": false, - "testsCompleted": 1, - "killedBy": ["60"], - "coveredBy": ["60", "61", "62"], - "location": { "end": { "column": 33, "line": 11 }, "start": { "column": 30, "line": 11 } } - }, - { - "id": "201", - "mutatorName": "BlockStatement", - "replacement": "{}", - "statusReason": "src/string-utils.ts(39,19): error TS2355: A function whose declared type is neither 'void' nor 'any' must return a value.\n", - "status": "CompileError", - "estimatedNetTime": 1, - "hitCount": 2, - "static": false, - "coveredBy": ["63"], - "location": { "end": { "column": 4, "line": 41 }, "start": { "column": 26, "line": 39 } } - }, - { - "id": "203", - "mutatorName": "BlockStatement", - "replacement": "{}", - "statusReason": "src/string-utils.ts(46,30): error TS2355: A function whose declared type is neither 'void' nor 'any' must return a value.\n", - "status": "CompileError", - "estimatedNetTime": 1, - "hitCount": 2, - "static": false, - "coveredBy": ["63", "64"], - "location": { "end": { "column": 4, "line": 48 }, "start": { "column": 53, "line": 46 } } - }, - { - "id": "200", - "mutatorName": "ArrayDeclaration", - "replacement": "[]", - "statusReason": "expected '' to equal 'bar.baz'", - "status": "Killed", - "estimatedNetTime": 1, - "hitCount": 4, - "static": false, - "testsCompleted": 1, - "killedBy": ["63"], - "coveredBy": ["63", "64"], - "location": { "end": { "column": 107, "line": 33 }, "start": { "column": 71, "line": 33 } } - }, - { - "id": "202", - "mutatorName": "StringLiteral", - "replacement": "\"\"", - "statusReason": "expected 'barbaz' to equal 'bar.baz'", - "status": "Killed", - "estimatedNetTime": 1, - "hitCount": 2, - "static": false, - "testsCompleted": 1, - "killedBy": ["63"], - "coveredBy": ["63"], - "location": { "end": { "column": 35, "line": 40 }, "start": { "column": 32, "line": 40 } } - }, - { - "id": "205", - "mutatorName": "BlockStatement", - "replacement": "{}", - "statusReason": "src/string-utils.ts(50,22): error TS2355: A function whose declared type is neither 'void' nor 'any' must return a value.\n", - "status": "CompileError", - "estimatedNetTime": 1, - "hitCount": 1, - "static": false, - "coveredBy": ["63"], - "location": { "end": { "column": 4, "line": 52 }, "start": { "column": 29, "line": 50 } } - }, - { - "id": "206", - "mutatorName": "BlockStatement", - "replacement": "{}", - "statusReason": "src/string-utils.ts(58,53): error TS2355: A function whose declared type is neither 'void' nor 'any' must return a value.\n", - "status": "CompileError", - "estimatedNetTime": 4, - "hitCount": 17, - "static": false, - "coveredBy": ["67", "68", "69", "70", "71", "72", "73", "74", "75", "76", "77", "78", "79", "80", "81", "82", "83"], - "location": { "end": { "column": 2, "line": 60 }, "start": { "column": 60, "line": 58 } } - }, - { - "id": "204", - "mutatorName": "ArrayDeclaration", - "replacement": "[\"Stryker was here\"]", - "statusReason": "expected 'Stryker was here.bar.baz' to equal 'bar.baz'", - "status": "Killed", - "estimatedNetTime": 1, - "hitCount": 2, - "static": false, - "testsCompleted": 1, - "killedBy": ["63"], - "coveredBy": ["63", "64"], - "location": { "end": { "column": 41, "line": 47 }, "start": { "column": 39, "line": 47 } } - }, - { - "id": "209", - "mutatorName": "BlockStatement", - "replacement": "{}", - "statusReason": "src/string-utils.ts(65,46): error TS2355: A function whose declared type is neither 'void' nor 'any' must return a value.\n", - "status": "CompileError", - "estimatedNetTime": 4, - "hitCount": 17, - "static": false, - "coveredBy": ["84", "85", "86", "87", "88", "89", "90", "91", "92", "93", "94", "95", "96", "97", "98", "99", "100"], - "location": { "end": { "column": 2, "line": 67 }, "start": { "column": 53, "line": 65 } } - }, - { - "id": "207", - "mutatorName": "Regex", - "replacement": "/[^.*+\\-?^${}()|[\\]\\\\/]/g", - "statusReason": "expected '\\\\s\\\\o\\\\m\\\\e\\\\t\\\\h\\\\i\\\\n\\\\g\\\\ \\\\n\\\\o\\\\r\\\\m\\\\a\\\\l' to equal 'something normal'", - "status": "Killed", - "estimatedNetTime": 4, - "hitCount": 17, - "static": false, - "testsCompleted": 1, - "killedBy": ["67"], - "coveredBy": ["67", "68", "69", "70", "71", "72", "73", "74", "75", "76", "77", "78", "79", "80", "81", "82", "83"], - "location": { "end": { "column": 48, "line": 59 }, "start": { "column": 24, "line": 59 } } - }, - { - "id": "208", - "mutatorName": "StringLiteral", - "replacement": "\"\"", - "statusReason": "expected '' to equal '\\\\.'", - "status": "Killed", - "estimatedNetTime": 4, - "hitCount": 17, - "static": false, - "testsCompleted": 2, - "killedBy": ["68"], - "coveredBy": ["67", "68", "69", "70", "71", "72", "73", "74", "75", "76", "77", "78", "79", "80", "81", "82", "83"], - "location": { "end": { "column": 56, "line": 59 }, "start": { "column": 50, "line": 59 } } - }, - { - "id": "210", - "mutatorName": "Regex", - "replacement": "/[^.*+\\-?^${}()|[\\]\\\\]/g", - "statusReason": "expected '\\\\s\\\\o\\\\m\\\\e\\\\t\\\\h\\\\i\\\\n\\\\g\\\\ \\\\n\\\\o\\\\r\\\\m\\\\a\\\\l' to equal 'something normal'", - "status": "Killed", - "estimatedNetTime": 4, - "hitCount": 17, - "static": false, - "testsCompleted": 1, - "killedBy": ["84"], - "coveredBy": ["84", "85", "86", "87", "88", "89", "90", "91", "92", "93", "94", "95", "96", "97", "98", "99", "100"], - "location": { "end": { "column": 47, "line": 66 }, "start": { "column": 24, "line": 66 } } - }, - { - "id": "211", - "mutatorName": "StringLiteral", - "replacement": "\"\"", - "statusReason": "expected '' to equal '\\\\.'", - "status": "Killed", - "estimatedNetTime": 4, - "hitCount": 17, - "static": false, - "testsCompleted": 3, - "killedBy": ["86"], - "coveredBy": ["84", "85", "86", "87", "88", "89", "90", "91", "92", "93", "94", "95", "96", "97", "98", "99", "100"], - "location": { "end": { "column": 55, "line": 66 }, "start": { "column": 49, "line": 66 } } - } - ], - "source": "import { KnownKeys } from './known-keys';\nimport { Primitive } from './primitive';\n\ntype OnlyObject = Exclude;\n\n/**\n * Consolidates multiple consecutive white spaces into a single space.\n * @param str The string to be normalized\n */\nexport function normalizeWhitespaces(str: string): string {\n return str.replace(/\\s+/g, ' ').trim();\n}\n\n/**\n * Given a base type, allows type safe access to the name of a property.\n * @param prop The property name\n */\nexport function propertyPath(prop: KnownKeys): string {\n return String(prop);\n}\n\n/**\n * A helper class to allow you to get type safe access to the name of a deep property of `T`\n * @example\n * ```ts\n * PropertyPathBuilder('warnings').prop('unknownOptions').build()\n * ```\n */\nexport class PropertyPathBuilder {\n constructor(private readonly pathSoFar: string[]) {}\n\n public prop> & keyof OnlyObject>(prop: TProp): PropertyPathBuilder, TProp>[TProp]> {\n return new PropertyPathBuilder, TProp>[TProp]>([...this.pathSoFar, prop.toString()]);\n }\n\n /**\n * Build the (deep) path to the property name\n */\n public build(): string {\n return this.pathSoFar.join('.');\n }\n\n /**\n * Creates a new `PropertyPathBuilder` for type T\n */\n public static create(): PropertyPathBuilder {\n return new PropertyPathBuilder([]);\n }\n\n public toString(): string {\n return this.build();\n }\n}\n\n/**\n * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#Escaping\n */\nexport function escapeRegExpLiteral(input: string): string {\n return input.replace(/[.*+\\-?^${}()|[\\]\\\\/]/g, '\\\\$&'); // $& means the whole matched string\n}\n\n/**\n * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#Escaping\n */\nexport function escapeRegExp(input: string): string {\n return input.replace(/[.*+\\-?^${}()|[\\]\\\\]/g, '\\\\$&'); // $& means the whole matched string\n}\n" - }, - "/home/nicojs/github/stryker-js/packages/util/src/stryker-error.ts": { - "language": "typescript", - "mutants": [ - { - "id": "212", - "mutatorName": "StringLiteral", - "replacement": "``", - "statusReason": "expected '' to equal 'some message. Inner error: Error: \\nError: \\n at Context. (/home/nicojs/github/stryker-js/packages/util/.stryker-tmp/sandbox8696228/test/unit/stryker-error.spec.ts:15:24)\\n at callFn (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runnable.js:366:21)\\n at Test.Runnable.run (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runnable.js:354:5)\\n at Runner.runTest (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:681:10)\\n at /home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:804:12\\n at next (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:596:14)\\n at /home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:606:7\\n at next (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:489:14)\\n at Immediate._onImmediate (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:574:5)\\n at processImmediate (internal/timers.js:464:21)'", - "status": "Killed", - "estimatedNetTime": 4, - "hitCount": 3, - "static": false, - "testsCompleted": 2, - "killedBy": ["102"], - "coveredBy": ["101", "102", "103"], - "location": { "end": { "column": 89, "line": 5 }, "start": { "column": 11, "line": 5 } } - }, - { - "id": "213", - "mutatorName": "StringLiteral", - "replacement": "``", - "statusReason": "expected 'some message' to equal 'some message. Inner error: Error: \\nError: \\n at Context. (/home/nicojs/github/stryker-js/packages/util/.stryker-tmp/sandbox8696228/test/unit/stryker-error.spec.ts:15:24)\\n at callFn (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runnable.js:366:21)\\n at Test.Runnable.run (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runnable.js:354:5)\\n at Runner.runTest (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:681:10)\\n at /home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:804:12\\n at next (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:596:14)\\n at /home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:606:7\\n at next (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:489:14)\\n at Immediate._onImmediate (/home/nicojs/github/stryker-js/node_modules/mocha/lib/runner.js:574:5)\\n at processImmediate (internal/timers.js:464:21)'", - "status": "Killed", - "estimatedNetTime": 4, - "hitCount": 2, - "static": false, - "testsCompleted": 2, - "killedBy": ["102"], - "coveredBy": ["101", "102"], - "location": { "end": { "column": 82, "line": 5 }, "start": { "column": 37, "line": 5 } } - }, - { - "id": "214", - "mutatorName": "StringLiteral", - "replacement": "\"Stryker was here!\"", - "statusReason": "expected 'foo barStryker was here!' to equal 'foo bar'", - "status": "Killed", - "estimatedNetTime": 0, - "hitCount": 1, - "static": false, - "testsCompleted": 1, - "killedBy": ["103"], - "coveredBy": ["103"], - "location": { "end": { "column": 87, "line": 5 }, "start": { "column": 85, "line": 5 } } - } - ], - "source": "import { errorToString } from './errors';\n\nexport class StrykerError extends Error {\n constructor(message: string, public readonly innerError?: unknown) {\n super(`${message}${innerError ? `. Inner error: ${errorToString(innerError)}` : ''}`);\n }\n}\n" - }, - "/home/nicojs/github/stryker-js/packages/util/src/task.ts": { - "language": "typescript", - "mutants": [ - { - "id": "216", - "mutatorName": "BlockStatement", - "replacement": "{}", - "statusReason": "src/task.ts(5,13): error TS2564: Property '_promise' has no initializer and is not definitely assigned in the constructor.\n", - "status": "CompileError", - "estimatedNetTime": 6, - "hitCount": 8, - "static": false, - "coveredBy": ["104", "105", "106", "107", "108", "109", "110", "111"], - "location": { "end": { "column": 4, "line": 15 }, "start": { "column": 17, "line": 10 } } - }, - { - "id": "215", - "mutatorName": "BooleanLiteral", - "replacement": "true", - "statusReason": "Invalid Chai property: rejectedWith", - "status": "Killed", - "estimatedNetTime": 6, - "hitCount": 8, - "static": false, - "testsCompleted": 3, - "killedBy": ["106"], - "coveredBy": ["104", "105", "106", "107", "108", "109", "110", "111"], - "location": { "end": { "column": 31, "line": 8 }, "start": { "column": 26, "line": 8 } } - }, - { - "id": "218", - "mutatorName": "BlockStatement", - "replacement": "{}", - "statusReason": "src/task.ts(17,14): error TS2378: A 'get' accessor must return a value.\nsrc/task.ts(17,25): error TS2355: A function whose declared type is neither 'void' nor 'any' must return a value.\n", - "status": "CompileError", - "estimatedNetTime": 6, - "hitCount": 7, - "static": false, - "coveredBy": ["104", "105", "106", "108", "109", "110", "111"], - "location": { "end": { "column": 4, "line": 19 }, "start": { "column": 36, "line": 17 } } - }, - { - "id": "217", - "mutatorName": "BlockStatement", - "replacement": "{}", - "statusReason": "this.resolveFn is not a function", - "status": "Killed", - "estimatedNetTime": 6, - "hitCount": 8, - "static": false, - "testsCompleted": 1, - "killedBy": ["104"], - "coveredBy": ["104", "105", "106", "107", "108", "109", "110", "111"], - "location": { "end": { "column": 6, "line": 14 }, "start": { "column": 57, "line": 11 } } - }, - { - "id": "219", - "mutatorName": "BlockStatement", - "replacement": "{}", - "statusReason": "src/task.ts(21,14): error TS2378: A 'get' accessor must return a value.\nsrc/task.ts(21,29): error TS2355: A function whose declared type is neither 'void' nor 'any' must return a value.\n", - "status": "CompileError", - "estimatedNetTime": 0, - "hitCount": 2, - "static": false, - "coveredBy": ["107"], - "location": { "end": { "column": 4, "line": 23 }, "start": { "column": 37, "line": 21 } } - }, - { - "id": "221", - "mutatorName": "BooleanLiteral", - "replacement": "false", - "statusReason": "expected false to be true", - "status": "Killed", - "estimatedNetTime": 3, - "hitCount": 5, - "static": false, - "testsCompleted": 3, - "killedBy": ["107"], - "coveredBy": ["104", "105", "107", "109", "111"], - "location": { "end": { "column": 29, "line": 26 }, "start": { "column": 25, "line": 26 } } - }, - { - "id": "222", - "mutatorName": "BlockStatement", - "replacement": "{}", - "statusReason": "Invalid Chai property: rejectedWith", - "status": "Killed", - "estimatedNetTime": 1, - "hitCount": 2, - "static": false, - "testsCompleted": 1, - "killedBy": ["106"], - "coveredBy": ["106", "110"], - "location": { "end": { "column": 4, "line": 33 }, "start": { "column": 65, "line": 30 } } - }, - { - "id": "223", - "mutatorName": "BooleanLiteral", - "replacement": "false", - "statusReason": "Invalid Chai property: rejectedWith", - "status": "Killed", - "estimatedNetTime": 1, - "hitCount": 2, - "static": false, - "testsCompleted": 1, - "killedBy": ["106"], - "coveredBy": ["106", "110"], - "location": { "end": { "column": 29, "line": 31 }, "start": { "column": 25, "line": 31 } } - }, - { - "id": "225", - "mutatorName": "BlockStatement", - "replacement": "{}", - "statusReason": "src/task.ts(47,62): error TS2355: A function whose declared type is neither 'void' nor 'any' must return a value.\n", - "status": "CompileError", - "estimatedNetTime": 6, - "hitCount": 5, - "static": false, - "coveredBy": ["108", "109", "110", "111", "112"], - "location": { "end": { "column": 4, "line": 61 }, "start": { "column": 111, "line": 47 } } - }, - { - "id": "224", - "mutatorName": "StringLiteral", - "replacement": "\"\"", - "statusReason": "Attempted to wrap cwd which is already wrapped", - "status": "Killed", - "estimatedNetTime": 73, - "hitCount": 1, - "static": true, - "testsCompleted": 6, - "killedBy": ["5"], - "location": { "end": { "column": 81, "line": 40 }, "start": { "column": 65, "line": 40 } } - }, - { - "id": "228", - "mutatorName": "BlockStatement", - "replacement": "{}", - "statusReason": "expected Symbol(TimeoutExpired) to equal 'in time'", - "status": "Killed", - "estimatedNetTime": 4, - "hitCount": 3, - "static": false, - "testsCompleted": 1, - "killedBy": ["109"], - "coveredBy": ["109", "111", "112"], - "location": { "end": { "column": 10, "line": 54 }, "start": { "column": 27, "line": 51 } } - }, - { - "id": "229", - "mutatorName": "BlockStatement", - "replacement": "{}", - "statusReason": "expected promise to be rejected with 'Error: expected error' but it was fulfilled with Symbol(TimeoutExpired)", - "status": "Killed", - "estimatedNetTime": 0, - "hitCount": 1, - "static": false, - "testsCompleted": 1, - "killedBy": ["110"], - "coveredBy": ["110"], - "location": { "end": { "column": 10, "line": 58 }, "start": { "column": 27, "line": 55 } } - }, - { - "id": "220", - "mutatorName": "BlockStatement", - "replacement": "{}", - "status": "Timeout", - "estimatedNetTime": 3, - "hitCount": 5, - "static": false, - "coveredBy": ["104", "105", "107", "109", "111"], - "location": { "end": { "column": 4, "line": 28 }, "start": { "column": 58, "line": 25 } } - }, - { - "id": "226", - "mutatorName": "BlockStatement", - "replacement": "{}", - "status": "Timeout", - "estimatedNetTime": 6, - "hitCount": 5, - "static": false, - "coveredBy": ["108", "109", "110", "111", "112"], - "location": { "end": { "column": 6, "line": 59 }, "start": { "column": 86, "line": 48 } } - }, - { - "id": "227", - "mutatorName": "ArrowFunction", - "replacement": "() => undefined", - "status": "Timeout", - "estimatedNetTime": 6, - "hitCount": 5, - "static": false, - "coveredBy": ["108", "109", "110", "111", "112"], - "location": { "end": { "column": 71, "line": 49 }, "start": { "column": 32, "line": 49 } } - } - ], - "source": "/**\n * Wraps a promise in a Task api for convenience.\n */\nexport class Task {\n protected _promise: Promise;\n private resolveFn!: (value: PromiseLike | T) => void;\n private rejectFn!: (reason: any) => void;\n private _isCompleted = false;\n\n constructor() {\n this._promise = new Promise((resolve, reject) => {\n this.resolveFn = resolve;\n this.rejectFn = reject;\n });\n }\n\n public get promise(): Promise {\n return this._promise;\n }\n\n public get isCompleted(): boolean {\n return this._isCompleted;\n }\n\n public resolve = (result: PromiseLike | T): void => {\n this._isCompleted = true;\n this.resolveFn(result);\n };\n\n public reject: (reason: any) => void = (reason: any): void => {\n this._isCompleted = true;\n this.rejectFn(reason);\n };\n}\n\n/**\n * A task that can expire after the given time.\n */\nexport class ExpirableTask extends Task {\n public static readonly TimeoutExpired: unique symbol = Symbol('TimeoutExpired');\n\n constructor(timeoutMS: number) {\n super();\n this._promise = ExpirableTask.timeout(this._promise, timeoutMS);\n }\n\n public static timeout(promise: Promise, ms: number): Promise {\n const sleep = new Promise((res, rej) => {\n const timer = setTimeout(() => res(ExpirableTask.TimeoutExpired), ms);\n promise\n .then((result) => {\n clearTimeout(timer);\n res(result);\n })\n .catch((error) => {\n clearTimeout(timer);\n rej(error);\n });\n });\n return sleep;\n }\n}\n" - } - }, - "schemaVersion": "1.0", - "thresholds": { "high": 80, "low": 60, "break": null }, - "testFiles": { - "": { - "tests": [ - { "id": "0", "name": "childProcessAsPromised should expose promisified exec" }, - { "id": "1", "name": "deepMerge should merge overrides into the target object" }, - { "id": "2", "name": "deepMerge should deep merge overrides into the target object" }, - { "id": "3", "name": "deepMerge should override arrays without merging them" }, - { "id": "4", "name": "deepMerge should not override with `undefined`" }, - { "id": "5", "name": "DirectoryRequireCache should clear recorded files" }, - { "id": "6", "name": "DirectoryRequireCache should only record the first time (perf optimization)" }, - { "id": "7", "name": "DirectoryRequireCache should clear recorded children from their respective parent" }, - { "id": "8", "name": "DirectoryRequireCache should clear recorded separate unique parents" }, - { "id": "9", "name": "DirectoryRequireCache should not break when clearing a graph" }, - { "id": "10", "name": "DirectoryRequireCache should not throw when the parent module was unloaded" }, - { "id": "11", "name": "DirectoryRequireCache should not throw when the parent module is one of the modules to being cleared" }, - { "id": "12", "name": "DirectoryRequireCache should not clear files from node_modules" }, - { "id": "13", "name": "DirectoryRequireCache should not fail when recorded file doesn't have a parent" }, - { "id": "14", "name": "DirectoryRequireCache should support case-insensitive filesystems" }, - { "id": "15", "name": "DirectoryRequireCache should support case-sensitive filesystems" }, - { "id": "16", "name": "errors errorToString should return empty string if error is undefined" }, - { "id": "17", "name": "errors errorToString should convert a nodejs Errno error to string" }, - { "id": "18", "name": "errors errorToString should convert a regular error to string" }, - { "id": "19", "name": "errors errorToString should convert an error without a stack trace to string" }, - { "id": "20", "name": "findUnserializables should mark 4 as serializable" }, - { "id": "21", "name": "findUnserializables should mark true as serializable" }, - { "id": "22", "name": "findUnserializables should mark undefined as serializable" }, - { "id": "23", "name": "findUnserializables should mark null as serializable" }, - { "id": "24", "name": "findUnserializables should mark \"str\" as serializable" }, - { "id": "25", "name": "findUnserializables should mark {} as serializable" }, - { "id": "26", "name": "findUnserializables should mark [] as serializable" }, - { "id": "27", "name": "findUnserializables should mark plain object without a prototype as serializable" }, - { "id": "28", "name": "findUnserializables should mark primitive type symbol as unserializable" }, - { "id": "29", "name": "findUnserializables should mark primitive type bigint as unserializable" }, - { "id": "30", "name": "findUnserializables should mark primitive type function as unserializable" }, - { "id": "31", "name": "findUnserializables should mark number value NaN as unserializable" }, - { "id": "32", "name": "findUnserializables should mark number value Infinity as unserializable" }, - { "id": "33", "name": "findUnserializables should mark number value -Infinity as unserializable" }, - { "id": "34", "name": "findUnserializables should mark class instances as unserializable" }, - { "id": "35", "name": "findUnserializables should mark the default stryker options as \"serializable\"" }, - { "id": "36", "name": "findUnserializables path should be provided in a shallow object" }, - { "id": "37", "name": "findUnserializables path should be provided in a deep object" }, - { "id": "38", "name": "findUnserializables path should be provided in a shallow array" }, - { "id": "39", "name": "findUnserializables path should be provided in a deep array" }, - { "id": "40", "name": "findUnserializables reason should be provided for an unserializable primitive value" }, - { "id": "41", "name": "findUnserializables reason should be provided for a class instance" }, - { "id": "42", "name": "findUnserializables reason should be provided for an anonymous class instance" }, - { "id": "43", "name": "findUnserializables reason should be provided for a RegExp" }, - { "id": "44", "name": "findUnserializables reason should be provided for a Date" }, - { "id": "45", "name": "findUnserializables reason should be provided for unserializable numbers" }, - { "id": "46", "name": "deepFreeze should not change the input object" }, - { "id": "47", "name": "deepFreeze should freeze objects" }, - { "id": "48", "name": "deepFreeze should work for `null` and `undefined`" }, - { "id": "49", "name": "deepFreeze should work for primitives" }, - { "id": "50", "name": "deepFreeze should deeply freeze objects" }, - { "id": "51", "name": "deepFreeze should work for Arrays" }, - { "id": "52", "name": "deepFreeze should work for Maps" }, - { "id": "53", "name": "deepFreeze should work for Sets" }, - { "id": "54", "name": "deepFreeze should work for RegExps" }, - { "id": "55", "name": "noopLogger should not enable any logging" }, - { "id": "56", "name": "noopLogger should not do any actual logging" }, - { "id": "57", "name": "notEmpty should return true when not null or undefined" }, - { "id": "58", "name": "notEmpty should return false when null" }, - { "id": "59", "name": "notEmpty should return false when undefined" }, - { "id": "60", "name": "stringUtils normalizeWhitespaces should not change strings without consecutive whitespaces" }, - { "id": "61", "name": "stringUtils normalizeWhitespaces should normalize a string with multiple consecutive spaces" }, - { "id": "62", "name": "stringUtils normalizeWhitespaces should normalize a string with multiple consecutive spaces, tabs and new lines" }, - { "id": "63", "name": "stringUtils PropertyPathBuilder should be able to point to a path" }, - { "id": "64", "name": "stringUtils PropertyPathBuilder should not be able to point to a path non-existing path" }, - { "id": "65", "name": "stringUtils propertyPath should be able to point to a path" }, - { "id": "66", "name": "stringUtils propertyPath should not be able to point to a non-existing path" }, - { "id": "67", "name": "stringUtils escapeRegExpLiteral should return input if no special chars are found" }, - { "id": "68", "name": "stringUtils escapeRegExpLiteral should escape \".\"" }, - { "id": "69", "name": "stringUtils escapeRegExpLiteral should escape \"*\"" }, - { "id": "70", "name": "stringUtils escapeRegExpLiteral should escape \"+\"" }, - { "id": "71", "name": "stringUtils escapeRegExpLiteral should escape \"-\"" }, - { "id": "72", "name": "stringUtils escapeRegExpLiteral should escape \"?\"" }, - { "id": "73", "name": "stringUtils escapeRegExpLiteral should escape \"^\"" }, - { "id": "74", "name": "stringUtils escapeRegExpLiteral should escape \"$\"" }, - { "id": "75", "name": "stringUtils escapeRegExpLiteral should escape \"{\"" }, - { "id": "76", "name": "stringUtils escapeRegExpLiteral should escape \"}\"" }, - { "id": "77", "name": "stringUtils escapeRegExpLiteral should escape \"(\"" }, - { "id": "78", "name": "stringUtils escapeRegExpLiteral should escape \")\"" }, - { "id": "79", "name": "stringUtils escapeRegExpLiteral should escape \"|\"" }, - { "id": "80", "name": "stringUtils escapeRegExpLiteral should escape \"[\"" }, - { "id": "81", "name": "stringUtils escapeRegExpLiteral should escape \"]\"" }, - { "id": "82", "name": "stringUtils escapeRegExpLiteral should escape \"\\\"" }, - { "id": "83", "name": "stringUtils escapeRegExpLiteral should escape \"/\"" }, - { "id": "84", "name": "stringUtils escapeRegExp should return input if no special chars are found" }, - { "id": "85", "name": "stringUtils escapeRegExp should not escape `/` (that's only needed for regex literals)" }, - { "id": "86", "name": "stringUtils escapeRegExp should escape \".\"" }, - { "id": "87", "name": "stringUtils escapeRegExp should escape \"*\"" }, - { "id": "88", "name": "stringUtils escapeRegExp should escape \"+\"" }, - { "id": "89", "name": "stringUtils escapeRegExp should escape \"-\"" }, - { "id": "90", "name": "stringUtils escapeRegExp should escape \"?\"" }, - { "id": "91", "name": "stringUtils escapeRegExp should escape \"^\"" }, - { "id": "92", "name": "stringUtils escapeRegExp should escape \"$\"" }, - { "id": "93", "name": "stringUtils escapeRegExp should escape \"{\"" }, - { "id": "94", "name": "stringUtils escapeRegExp should escape \"}\"" }, - { "id": "95", "name": "stringUtils escapeRegExp should escape \"(\"" }, - { "id": "96", "name": "stringUtils escapeRegExp should escape \")\"" }, - { "id": "97", "name": "stringUtils escapeRegExp should escape \"|\"" }, - { "id": "98", "name": "stringUtils escapeRegExp should escape \"[\"" }, - { "id": "99", "name": "stringUtils escapeRegExp should escape \"]\"" }, - { "id": "100", "name": "stringUtils escapeRegExp should escape \"\\\"" }, - { "id": "101", "name": "StrykerError should set inner error" }, - { "id": "102", "name": "StrykerError should add inner error to the message" }, - { "id": "103", "name": "StrykerError should work without an inner error" }, - { "id": "104", "name": "Task should give access to underlying promise" }, - { "id": "105", "name": "Task should be able to resolve the underlying promise" }, - { "id": "106", "name": "Task should be able to reject the underlying promise" }, - { "id": "107", "name": "Task should be able to know if it isCompleted" }, - { "id": "108", "name": "ExpirableTask instance should timeout after set period" }, - { "id": "109", "name": "ExpirableTask instance should be able to resolve within time" }, - { "id": "110", "name": "ExpirableTask instance should be able to reject within time" }, - { "id": "111", "name": "ExpirableTask timeout should timeout a promise after a set period" }, - { "id": "112", "name": "ExpirableTask timeout should remove any nodejs timers when promise resolves" } - ] - } - }, - "projectRoot": "/home/nicojs/github/stryker-js/packages/util", - "config": { - "$schema": "./packages/core/schema/stryker-schema.json", - "coverageAnalysis": "perTest", - "testRunner": "mocha", - "reporters": ["json", "progress", "html", "dashboard"], - "plugins": [ - "/home/nicojs/github/stryker-js/packages/mocha-runner", - "/home/nicojs/github/stryker-js/packages/typescript-checker", - "/home/nicojs/github/stryker-js/packages/core/dist/src/reporters/index.js" - ], - "checkers": ["typescript"], - "dashboard": { "module": "util", "baseUrl": "https://dashboard.stryker-mutator.io/api/reports", "reportType": "full" }, - "buildCommand": "tsc -b", - "mochaOptions": { "spec": ["dist/test/unit/**/*.js"] }, - "allowConsoleColors": true, - "checkerNodeArgs": [], - "maxTestRunnerReuse": 0, - "commandRunner": { "command": "npm test" }, - "clearTextReporter": { "allowColor": true, "logTests": true, "maxTestsToLog": 3 }, - "eventReporter": { "baseDir": "reports/mutation/events" }, - "ignorePatterns": [], - "fileLogLevel": "off", - "inPlace": false, - "logLevel": "info", - "maxConcurrentTestRunners": 9007199254740991, - "mutate": [ - "{src,lib}/**/!(*.+(s|S)pec|*.+(t|T)est).+(cjs|mjs|js|ts|jsx|tsx|html|vue)", - "!{src,lib}/**/__tests__/**/*.+(cjs|mjs|js|ts|jsx|tsx|html|vue)" - ], - "mutator": { "plugins": null, "excludedMutations": [] }, - "appendPlugins": [], - "jsonReporter": { "fileName": "reports/mutation/mutation.json" }, - "disableTypeChecks": "{test,src,lib}/**/*.{js,ts,jsx,tsx,html,vue}", - "symlinkNodeModules": true, - "tempDirName": ".stryker-tmp", - "cleanTempDir": true, - "testRunnerNodeArgs": [], - "thresholds": { "high": 80, "low": 60, "break": null }, - "timeoutFactor": 1.5, - "timeoutMS": 5000, - "dryRunTimeoutMinutes": 5, - "tsconfigFile": "tsconfig.json", - "warnings": true, - "disableBail": false, - "configFile": "/home/nicojs/github/stryker-js/packages/util/stryker.conf.js" - }, - "framework": { - "name": "StrykerJS", - "version": "5.4.1", - "branding": { - "homepageUrl": "https://stryker-mutator.io", - "imageUrl": "data:image/svg+xml;utf8,%3Csvg viewBox='0 0 1458 1458' xmlns='http://www.w3.org/2000/svg' fill-rule='evenodd' clip-rule='evenodd' stroke-linejoin='round' stroke-miterlimit='2'%3E%3Cpath fill='none' d='M0 0h1458v1458H0z'/%3E%3CclipPath id='a'%3E%3Cpath d='M0 0h1458v1458H0z'/%3E%3C/clipPath%3E%3Cg clip-path='url(%23a)'%3E%3Cpath d='M1458 729c0 402.655-326.345 729-729 729S0 1131.655 0 729C0 326.445 326.345 0 729 0s729 326.345 729 729' fill='%23e74c3c' fill-rule='nonzero'/%3E%3Cpath d='M778.349 1456.15L576.6 1254.401l233-105 85-78.668v-64.332l-257-257-44-187-50-208 251.806-82.793L1076.6 389.401l380.14 379.15c-19.681 367.728-311.914 663.049-678.391 687.599z' fill-opacity='.3'/%3E%3Cpath d='M753.4 329.503c41.79 0 74.579 7.83 97.925 25.444 23.571 18.015 41.69 43.956 55.167 77.097l11.662 28.679 165.733-58.183-14.137-32.13c-26.688-60.655-64.896-108.61-114.191-144.011-49.329-35.423-117.458-54.302-204.859-54.302-50.78 0-95.646 7.376-134.767 21.542-40.093 14.671-74.09 34.79-102.239 60.259-28.84 26.207-50.646 57.06-65.496 92.701-14.718 35.052-22.101 72.538-22.101 112.401 0 72.536 20.667 133.294 61.165 182.704 38.624 47.255 98.346 88.037 179.861 121.291 42.257 17.475 78.715 33.125 109.227 46.994 27.193 12.361 49.294 26.124 66.157 41.751 15.309 14.186 26.497 30.584 33.63 49.258 7.721 20.214 11.16 45.69 11.16 76.402 0 28.021-4.251 51.787-13.591 71.219-8.832 18.374-20.171 33.178-34.523 44.219-14.787 11.374-31.193 19.591-49.393 24.466-19.68 5.359-39.14 7.993-58.69 7.993-29.359 0-54.387-3.407-75.182-10.747-20.112-7.013-37.144-16.144-51.259-27.486-13.618-11.009-24.971-23.766-33.744-38.279-9.64-15.8-17.272-31.924-23.032-48.408l-10.965-31.376-161.669 60.585 10.734 30.124c10.191 28.601 24.197 56.228 42.059 82.748 18.208 27.144 41.322 51.369 69.525 72.745 27.695 21.075 60.904 38.218 99.481 51.041 37.777 12.664 82.004 19.159 132.552 19.159 49.998 0 95.818-8.321 137.611-24.622 42.228-16.471 78.436-38.992 108.835-67.291 30.719-28.597 54.631-62.103 71.834-100.642 17.263-38.56 25.923-79.392 25.923-122.248 0-54.339-8.368-100.37-24.208-138.32-16.29-38.759-38.252-71.661-65.948-98.797-26.965-26.418-58.269-48.835-93.858-67.175-33.655-17.241-69.196-33.11-106.593-47.533-35.934-13.429-65.822-26.601-89.948-39.525-22.153-11.868-40.009-24.21-53.547-37.309-11.429-11.13-19.83-23.678-24.718-37.664-5.413-15.49-7.98-33.423-7.98-53.577 0-40.883 11.293-71.522 37.086-90.539 28.443-20.825 64.985-30.658 109.311-30.658z' fill='%23f1c40f' fill-rule='nonzero'/%3E%3Cpath d='M720 0h18v113h-18zM1458 738v-18h-113v18h113zM720 1345h18v113h-18zM113 738v-18H0v18h113z'/%3E%3C/g%3E%3C/svg%3E" - }, - "dependencies": { "mocha": "9.1.3", "jasmine": "3.10.0", "jasmine-core": "3.10.1", "typescript": "4.4.4" } - } -} diff --git a/src/Logger/Html/HtmlFileLogger.php b/src/Logger/Html/HtmlFileLogger.php index 8b5bad01d..d681e428c 100644 --- a/src/Logger/Html/HtmlFileLogger.php +++ b/src/Logger/Html/HtmlFileLogger.php @@ -36,7 +36,7 @@ namespace Infection\Logger\Html; use Infection\Logger\LineMutationTestingResultsLogger; -use function json_encode; +use function Safe\json_encode; /** * @internal @@ -78,7 +78,7 @@ function updateTheme() { ]; } - public function getMutationTestingReport(): string + private function getMutationTestingReport(): string { return json_encode($this->strykerHtmlReportBuilder->build()); } diff --git a/src/Logger/Html/StrykerHtmlReportBuilder.php b/src/Logger/Html/StrykerHtmlReportBuilder.php index dba0853a4..ed71cf105 100644 --- a/src/Logger/Html/StrykerHtmlReportBuilder.php +++ b/src/Logger/Html/StrykerHtmlReportBuilder.php @@ -44,10 +44,8 @@ use function array_slice; use function array_unique; use ArrayObject; -use function count; use function current; use function explode; -use function file_get_contents; use function implode; use function in_array; use Infection\AbstractTestFramework\Coverage\TestLocation; @@ -64,13 +62,18 @@ use function ltrim; use function md5; use const PHP_EOL; -use function preg_match; +use PhpParser\NodeAbstract; +use function Safe\file_get_contents; +use function Safe\preg_match; +use function Safe\substr; use function strlen; use function strpos; -use function substr; use Webmozart\Assert\Assert; use Webmozart\PathUtil\Path; +/** + * @internal + */ final class StrykerHtmlReportBuilder { private const DETECTION_STATUS_MAP = [ @@ -84,6 +87,7 @@ final class StrykerHtmlReportBuilder ]; private const PLUS_LENGTH = 1; + private const DIFF_HEADERS_LINES_COUNT = 3; private MetricsCalculator $metricsCalculator; private ResultsCollector $resultsCollector; @@ -106,7 +110,6 @@ public function build(): array ], 'files' => $this->getFiles(), 'testFiles' => $this->getTestFiles(), - // 'performance' => [], todo 'framework' => [ 'name' => 'Infection', 'branding' => [ @@ -131,7 +134,7 @@ private function getTestFiles(): ArrayObject $usedTests = []; $uniqueTests = array_reduce($allTests, static function (array $carry, TestLocation $testLocation) use (&$usedTests) { - $key = $testLocation->getFilePath() . $testLocation->getMethod(); + $key = $testLocation->getMethod(); if (!array_key_exists($key, $usedTests)) { $carry[] = $testLocation; @@ -163,6 +166,8 @@ private function getFiles(): ArrayObject $resultsByPath = $this->retrieveResultsByPath(); $basePath = Path::getLongestCommonBasePath(array_keys($resultsByPath)); + Assert::string($basePath, '$basePath must be a string'); + $files = $this->retrieveFiles($resultsByPath, $basePath); } @@ -208,7 +213,6 @@ private function retrieveResultsByPath(): array } return $results; -// return count($results) > 1 ? array_slice($results, 0, 1, true) : $results; } /** @@ -236,23 +240,11 @@ function (MutantExecutionResult $result) use ($originalCode): array { ? $result->getOriginalStartingLine() : $result->getOriginalEndingLine(); - // needed when remove method is on multiple lines + // needed when removed method is on multiple lines if ($result->getMutatorName() === MutatorFactory::getMutatorNameForClassName(MethodCallRemoval::class)) { $endingColumn = $result->getOriginalEndingColumn($originalCode) + 1; } -// var_dump($result->getMutatorName()); -// var_dump($result->getMutantDiff()); -// var_dump($result->getOriginalStartingLine()); -// var_dump($result->getOriginalEndingLine()); -// var_dump($result->originalStartFilePosition); -// var_dump($result->originalEndFilePosition); -// var_dump($endingLine); -// var_dump($startingColumn); -// var_dump($endingColumn); -// var_dump($result->getOriginalStartingColumn($originalCode)); -// var_dump($result->getOriginalEndingColumn($originalCode)); - return [ 'id' => $result->getMutantHash(), 'mutatorName' => $result->getMutatorName(), @@ -264,7 +256,7 @@ function (MutantExecutionResult $result) use ($originalCode): array { ], 'status' => self::DETECTION_STATUS_MAP[$result->getDetectionStatus()], 'statusReason' => $result->getProcessOutput(), - 'coveredBy' => array_unique(array_map( // todo unique? ask @sanmai + 'coveredBy' => array_unique(array_map( fn (TestLocation $testLocation): string => $this->buildTestMethodId($testLocation->getMethod()), $result->getTests() )), @@ -290,9 +282,9 @@ static function (string $line): string { +++ New @@ @@ */ - array_slice($lines, 3), + array_slice($lines, self::DIFF_HEADERS_LINES_COUNT), static function (string $line): bool { - return isset($line[0]) && strpos($line, '+') === 0; + return strpos($line, '+') === 0; } ) ); @@ -307,7 +299,7 @@ private function getKilledBy(string $processOutput): array { $matches = []; - if (preg_match('/(?\S+::\S+)(?:(? with data set (?:#\d+|"[^"]+"))\s\()?/', $processOutput, $matches)) { + if (preg_match('/(?\S+::\S+)(? with data set (?:#\d+|"[^"]+"))?/', $processOutput, $matches) === 1) { return [$this->buildTestMethodId($matches['name'] . ($matches['dataname'] ?? ''))]; } @@ -318,8 +310,10 @@ private function getTestsCompleted(string $processOutput): int { $matches = []; - if (preg_match('/Tests:\s(\d+),\sAssertions/', $processOutput, $matches)) { - return (int) ($matches[1] ?? 0); + if (preg_match('/Tests:\s(\d+),\sAssertions/', $processOutput, $matches) === 1) { + Assert::keyExists($matches, 1); + + return (int) $matches[1]; } return 0; @@ -329,7 +323,7 @@ private function getMutatorDescription(string $mutatorName): string { Assert::keyExists(ProfileList::ALL_MUTATORS, $mutatorName); - /** @var Mutator $mutatorClass */ + /** @var Mutator $mutatorClass */ $mutatorClass = ProfileList::ALL_MUTATORS[$mutatorName]; $definition = $mutatorClass::getDefinition(); @@ -339,7 +333,10 @@ private function getMutatorDescription(string $mutatorName): string return $definition->getDescription(); } - private function buildTest($testLocation): array + /** + * @return array{id: string, name: string} + */ + private function buildTest(TestLocation $testLocation): array { return [ 'id' => $this->buildTestMethodId($testLocation->getMethod()), diff --git a/src/Mutant/MutantExecutionResult.php b/src/Mutant/MutantExecutionResult.php index 0143c975b..fcbb7f104 100644 --- a/src/Mutant/MutantExecutionResult.php +++ b/src/Mutant/MutantExecutionResult.php @@ -50,9 +50,6 @@ */ class MutantExecutionResult { - // todo private - public int $originalStartFilePosition; - public int $originalEndFilePosition; private string $processCommandLine; private string $processOutput; private string $detectionStatus; @@ -66,15 +63,19 @@ class MutantExecutionResult private string $originalFilePath; private int $originalStartingLine; private int $originalEndingLine; + private int $originalStartFilePosition; + private int $originalEndFilePosition; /** * @var Deferred */ private Deferred $originalCode; + /** * @var Deferred */ private Deferred $mutatedCode; + /** * @var TestLocation[] */ @@ -209,19 +210,22 @@ public function getTests(): array return $this->tests; } - private function toColumn(string $code, int $pos): int + /** + * Adopted from https://github.com/nikic/PHP-Parser/blob/4abdcde5f16269959a834e4e58ea0ba0938ab133/lib/PhpParser/Error.php#L155 + */ + private function toColumn(string $code, int $position): int { - if ($pos > strlen($code)) { + if ($position > strlen($code)) { throw new RuntimeException('Invalid position information'); } - $lineStartPos = strrpos($code, "\n", $pos - strlen($code)); + $lineStartPos = strrpos($code, "\n", $position - strlen($code)); if ($lineStartPos === false) { $lineStartPos = -1; } - return $pos - $lineStartPos; + return $position - $lineStartPos; } private static function createFromMutant(Mutant $mutant, string $detectionStatus): self diff --git a/stryker-report.html b/stryker-report.html deleted file mode 100644 index 9d5fc600b..000000000 --- a/stryker-report.html +++ /dev/null @@ -1,3353 +0,0 @@ - - - - Test files example - Mutation test elements - - - - - -Back - - - - diff --git a/tests/e2e/Example_Test/infection.json b/tests/e2e/Example_Test/infection.json index 670b967c9..a5d873d67 100644 --- a/tests/e2e/Example_Test/infection.json +++ b/tests/e2e/Example_Test/infection.json @@ -7,8 +7,7 @@ ] }, "logs": { - "html": "infection.html", - "text": "infection.log" + "summary": "infection.log" }, "tmpDir": "." } diff --git a/tests/e2e/Example_Test/src/SourceClass.php b/tests/e2e/Example_Test/src/SourceClass.php index f1b99bdc2..148b0a253 100644 --- a/tests/e2e/Example_Test/src/SourceClass.php +++ b/tests/e2e/Example_Test/src/SourceClass.php @@ -4,12 +4,8 @@ class SourceClass { - private const TWO = 2; - public function hello(): string { - $a = 1 + self::TWO; - return 'hello'; } } diff --git a/tests/e2e/Example_Test/tests/SourceClassTest.php b/tests/e2e/Example_Test/tests/SourceClassTest.php index 3b4a9877b..4742835af 100644 --- a/tests/e2e/Example_Test/tests/SourceClassTest.php +++ b/tests/e2e/Example_Test/tests/SourceClassTest.php @@ -12,12 +12,4 @@ public function test_hello() $sourceClass = new SourceClass(); $this->assertSame('hello', $sourceClass->hello()); } - - public function test_this_test_case_kills_nothing(): void - { - $sourceClass = new SourceClass(); - $sourceClass->hello(); - - $this->assertTrue(true); - } } diff --git a/tests/phpunit/Logger/Html/HtmlFileLoggerTest.php b/tests/phpunit/Logger/Html/HtmlFileLoggerTest.php new file mode 100644 index 000000000..aa104dfbb --- /dev/null +++ b/tests/phpunit/Logger/Html/HtmlFileLoggerTest.php @@ -0,0 +1,77 @@ +getLogLines(); + + $this->assertSame( + <<<'HTML' + + + + Back + + + + + + HTML, + $logLines[0] + ); + } +} diff --git a/tests/phpunit/Logger/Html/StrykerHtmlReportBuilderTest.php b/tests/phpunit/Logger/Html/StrykerHtmlReportBuilderTest.php index 72876b920..eff0da023 100644 --- a/tests/phpunit/Logger/Html/StrykerHtmlReportBuilderTest.php +++ b/tests/phpunit/Logger/Html/StrykerHtmlReportBuilderTest.php @@ -36,7 +36,6 @@ namespace Infection\Tests\Logger\Html; use function array_map; -use function file_get_contents; use function implode; use Infection\AbstractTestFramework\Coverage\TestLocation; use Infection\Logger\Html\StrykerHtmlReportBuilder; @@ -54,11 +53,15 @@ use function Later\now; use const PHP_EOL; use PHPUnit\Framework\TestCase; -use function realpath; +use function Safe\file_get_contents; use function Safe\json_decode; use function Safe\json_encode; +use function Safe\realpath; use function Safe\sprintf; +/** + * @group integration + */ final class StrykerHtmlReportBuilderTest extends TestCase { private const SCHEMA_FILE = 'file://' . __DIR__ . '/../../../../resources/mutation-testing-report-schema.json'; @@ -100,9 +103,10 @@ public function metricsProvider() ], ]; - $realPath = realpath(__DIR__ . '/../../Fixtures/ForHtmlReport.php'); + $realPathForHtmlReport = realpath(__DIR__ . '/../../Fixtures/ForHtmlReport.php'); + $realPathForHtmlReport2 = realpath(__DIR__ . '/../../Fixtures/ForHtmlReport2.php'); - yield 'one mutation' => [ + yield 'different mutations' => [ $this->createFullHtmlReportMetricsCalculator(), $this->createFullHtmlReportResultsCollector(), [ @@ -112,9 +116,9 @@ public function metricsProvider() 'low' => 50, ], 'files' => [ - $realPath => [ + 'ForHtmlReport.php' => [ 'language' => 'php', - 'source' => file_get_contents($realPath), + 'source' => file_get_contents($realPathForHtmlReport), 'mutants' => [ [ 'id' => '32f68ca331c9262cc97322271d88d06d', @@ -135,9 +139,9 @@ public function metricsProvider() 'description' => 'Removes the method call.', 'location' => ['start' => ['line' => 15, 'column' => 9], 'end' => ['line' => 15, 'column' => 27]], 'status' => 'Survived', - 'statusReason' => 'PHPUnit output. Tests: 1, Assertions: 3', + 'statusReason' => 'PHPUnit output. Tests: 1, Assertions: 3. Failure: 1) TestClass::test_method1 Failed', 'coveredBy' => ['06a6c58caae5aa33e9b787f064618f5e'], - 'killedBy' => [], + 'killedBy' => ['06a6c58caae5aa33e9b787f064618f5e'], 'testsCompleted' => 1, ], [ @@ -147,9 +151,9 @@ public function metricsProvider() 'description' => 'Removes the method call.', 'location' => ['start' => ['line' => 17, 'column' => 9], 'end' => ['line' => 19, 'column' => 11]], 'status' => 'Survived', - 'statusReason' => 'PHPUnit output. Tests: 1, Assertions: 3', - 'coveredBy' => ['06a6c58caae5aa33e9b787f064618f5e'], - 'killedBy' => [], + 'statusReason' => 'PHPUnit output. Tests: 1, Assertions: 3. Failure: 1) TestClass::test_method1 with data set #1', + 'coveredBy' => ['2b67abde50b026f4057311ea32409632'], + 'killedBy' => ['2b67abde50b026f4057311ea32409632'], 'testsCompleted' => 1, ], [ @@ -159,10 +163,28 @@ public function metricsProvider() 'description' => "Removes an element of an array literal. For example:\n\n```php\n\$x = [0, 1, 2];\n```\n\nWill be mutated to:\n\n```php\n\$x = [1, 2];\n```\n\nAnd:\n\n```php\n\$x = [0, 2];\n```\n\nAnd:\n\n```php\n\$x = [0, 1];\n```\n\nWhich elements it removes or how many elements it will attempt to remove will depend on its\nconfiguration.\n", 'location' => ['start' => ['line' => 28, 'column' => 9], 'end' => ['line' => 28, 'column' => 65]], 'status' => 'Survived', - 'statusReason' => 'PHPUnit output. Tests: 1, Assertions: 3', + 'statusReason' => 'PHPUnit output. Tests: 3, Assertions: 3', 'coveredBy' => ['06a6c58caae5aa33e9b787f064618f5e', '949bee6dd4ac608462995babbe81ee12', '2733f8c97b5ba92b1aacb77d46837b0e'], 'killedBy' => [], - 'testsCompleted' => 1, + 'testsCompleted' => 3, + ], + ], + ], + 'ForHtmlReport2.php' => [ + 'language' => 'php', + 'source' => file_get_contents($realPathForHtmlReport2), + 'mutants' => [ + [ + 'id' => '12f68ca331c9262cc97322271d88d06d', + 'mutatorName' => 'PublicVisibility', + 'replacement' => 'protected function add(int $a, int $b) : int', + 'description' => 'Replaces the `public` method visibility keyword with `protected`.', + 'location' => ['start' => ['line' => 13, 'column' => 5], 'end' => ['line' => 13, 'column' => 6]], + 'status' => 'Killed', + 'statusReason' => 'Output without ability to detect the number of executed tests', + 'coveredBy' => ['06a6c58caae5aa33e9b787f064618f5e'], + 'killedBy' => [], + 'testsCompleted' => 0, ], ], ], @@ -174,6 +196,10 @@ public function metricsProvider() 'id' => '06a6c58caae5aa33e9b787f064618f5e', 'name' => 'TestClass::test_method1', ], + [ + 'id' => '2b67abde50b026f4057311ea32409632', + 'name' => 'TestClass::test_method1 with data set #1', + ], ], ], '/infection/path/to/TestClass2.php' => [ @@ -301,7 +327,8 @@ public function add(int $a, int $b) : int 196, [ new TestLocation('TestClass::test_method1', '/infection/path/to/TestClass.php', 0.123), - ] + ], + 'PHPUnit output. Tests: 1, Assertions: 3. Failure: 1) TestClass::test_method1 Failed' ), // this tests diff on the multi-line (in original source code) method call removal $this->createMutantExecutionResult( @@ -327,8 +354,9 @@ public function add(int $a, int $b) : int 207, 246, [ - new TestLocation('TestClass::test_method1', '/infection/path/to/TestClass.php', 0.123), - ] + new TestLocation('TestClass::test_method1 with data set #1', '/infection/path/to/TestClass.php', 0.123), + ], + 'PHPUnit output. Tests: 1, Assertions: 3. Failure: 1) TestClass::test_method1 with data set #1' ), // this tests diff on the one-line diff with array item removal $this->createMutantExecutionResult( @@ -357,7 +385,35 @@ public function add(int $a, int $b) : int new TestLocation('TestClass::test_method1', '/infection/path/to/TestClass.php', 0.123), new TestLocation('TestClass2::test_method2', '/infection/path/to/TestClass2.php', 0.456), new TestLocation('TestClass2::test_method3', '/infection/path/to/TestClass2.php', 0.789), - ] + ], + 'PHPUnit output. Tests: 3, Assertions: 3' + ), + // add one test for the second file + $this->createMutantExecutionResult( + DetectionStatus::KILLED, + <<<'DIFF' + --- Original + +++ New + @@ @@ + use function array_fill_keys; + final class ForHtmlReport2 + { + - public function add(int $a, int $b) : int + + protected function add(int $a, int $b) : int + { + return 0; + DIFF, + '12f68ca331c9262cc97322271d88d06d', + PublicVisibility::class, + realpath(__DIR__ . '/../../Fixtures/ForHtmlReport2.php'), + 13, + 35, + 124, + 547, + [ + new TestLocation('TestClass::test_method1', '/infection/path/to/TestClass.php', 0.123), + ], + 'Output without ability to detect the number of executed tests' ), ); } @@ -375,11 +431,12 @@ private function createMutantExecutionResult( int $originalEndingLine, int $originalStartFilePosition, int $originalEndFilePosition, - array $testLocations + array $testLocations, + ?string $processOutput = 'PHPUnit output. Tests: 1, Assertions: 3' ): MutantExecutionResult { return new MutantExecutionResult( 'bin/phpunit --configuration infection-tmp-phpunit.xml --filter "tests/Acme/FooTest.php"', - 'PHPUnit output. Tests: 1, Assertions: 3', + $processOutput, $detectionStatus, now(normalize_trailing_spaces($diff)), $mutantHash, From e5a36fe73276a902a7629cc6c06309254db8d229 Mon Sep 17 00:00:00 2001 From: maks-rafalko Date: Fri, 24 Dec 2021 17:54:05 +0300 Subject: [PATCH 4/8] Correctly determine the end of line symbols, fixes issue on Windows --- src/Logger/Html/StrykerHtmlReportBuilder.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Logger/Html/StrykerHtmlReportBuilder.php b/src/Logger/Html/StrykerHtmlReportBuilder.php index ed71cf105..99f14774f 100644 --- a/src/Logger/Html/StrykerHtmlReportBuilder.php +++ b/src/Logger/Html/StrykerHtmlReportBuilder.php @@ -65,6 +65,7 @@ use PhpParser\NodeAbstract; use function Safe\file_get_contents; use function Safe\preg_match; +use function Safe\preg_split; use function Safe\substr; use function strlen; use function strpos; @@ -222,7 +223,7 @@ private function retrieveMutants(array $results, string $originalCode): array { return array_map( function (MutantExecutionResult $result) use ($originalCode): array { - $fileAsArrayOfLines = explode(PHP_EOL, $originalCode); + $fileAsArrayOfLines = preg_split('/\n|\r\n?/', $originalCode); $replacement = $this->retrieveReplacementFromDiff($result->getMutantDiff()); $originalCodeLine = $fileAsArrayOfLines[$result->getOriginalStartingLine() - 1]; From 1016820ea04f80998df398405bf1dda2f3c4f8dd Mon Sep 17 00:00:00 2001 From: maks-rafalko Date: Fri, 24 Dec 2021 18:01:39 +0300 Subject: [PATCH 5/8] Correctly determine the end of line symbols for diffs --- src/Logger/Html/StrykerHtmlReportBuilder.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Logger/Html/StrykerHtmlReportBuilder.php b/src/Logger/Html/StrykerHtmlReportBuilder.php index 99f14774f..3ef34bb8e 100644 --- a/src/Logger/Html/StrykerHtmlReportBuilder.php +++ b/src/Logger/Html/StrykerHtmlReportBuilder.php @@ -271,7 +271,7 @@ function (MutantExecutionResult $result) use ($originalCode): array { private function retrieveReplacementFromDiff(string $diff): string { - $lines = explode(PHP_EOL, $diff); + $lines = preg_split('/\n|\r\n?/', $diff); $lines = array_map( static function (string $line): string { From 544efe4e4c46d5f242cb15314448d16dfb5ece95 Mon Sep 17 00:00:00 2001 From: maks-rafalko Date: Fri, 24 Dec 2021 18:06:34 +0300 Subject: [PATCH 6/8] Remove unused function --- src/Logger/Html/StrykerHtmlReportBuilder.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Logger/Html/StrykerHtmlReportBuilder.php b/src/Logger/Html/StrykerHtmlReportBuilder.php index 3ef34bb8e..3d467cee9 100644 --- a/src/Logger/Html/StrykerHtmlReportBuilder.php +++ b/src/Logger/Html/StrykerHtmlReportBuilder.php @@ -45,7 +45,6 @@ use function array_unique; use ArrayObject; use function current; -use function explode; use function implode; use function in_array; use Infection\AbstractTestFramework\Coverage\TestLocation; From e46b4b22c2fee24571ab2de11b500baf75a99586 Mon Sep 17 00:00:00 2001 From: maks-rafalko Date: Sun, 26 Dec 2021 16:23:43 +0300 Subject: [PATCH 7/8] Add `--logger-html='file.html'` CLI option for HTML report --- src/Command/RunCommand.php | 10 ++ src/Configuration/ConfigurationFactory.php | 9 +- src/Configuration/Entry/Logs.php | 5 + src/Container.php | 5 + .../Tracing/provide-traces-closure.php | 1 + .../ConfigurationFactoryTest.php | 135 ++++++++++++++++++ tests/phpunit/ContainerTest.php | 2 + 7 files changed, 165 insertions(+), 2 deletions(-) diff --git a/src/Command/RunCommand.php b/src/Command/RunCommand.php index 8154b78be..3d024f124 100644 --- a/src/Command/RunCommand.php +++ b/src/Command/RunCommand.php @@ -118,6 +118,8 @@ final class RunCommand extends BaseCommand /** @var string */ private const OPTION_LOGGER_GITHUB = 'logger-github'; + private const OPTION_LOGGER_HTML = 'logger-html'; + private const OPTION_USE_NOOP_MUTATORS = 'noop'; private const OPTION_EXECUTE_ONLY_COVERING_TEST_CASES = 'only-covering-test-cases'; @@ -264,6 +266,12 @@ protected function configure(): void InputOption::VALUE_NONE, 'Log escaped Mutants as GitHub Annotations.', ) + ->addOption( + self::OPTION_LOGGER_HTML, + null, + InputOption::VALUE_REQUIRED, + 'Path to HTML report file, similar to PHPUnit HTML report.', + ) ->addOption( self::OPTION_USE_NOOP_MUTATORS, null, @@ -388,6 +396,7 @@ private function createContainer(IO $io, LoggerInterface $logger): Container $testFramework = trim((string) $input->getOption(self::OPTION_TEST_FRAMEWORK)); $testFrameworkExtraOptions = trim((string) $input->getOption(self::OPTION_TEST_FRAMEWORK_OPTIONS)); $initialTestsPhpOptions = trim((string) $input->getOption(self::OPTION_INITIAL_TESTS_PHP_OPTIONS)); + $htmlFileLogPath = trim((string) $input->getOption(self::OPTION_LOGGER_HTML)); /** @var string|null $minMsi */ $minMsi = $input->getOption(self::OPTION_MIN_MSI); @@ -473,6 +482,7 @@ private function createContainer(IO $io, LoggerInterface $logger): Container $isForGitDiffLines, $gitDiffBase, (bool) $input->getOption(self::OPTION_LOGGER_GITHUB), + $htmlFileLogPath === '' ? Container::DEFAULT_HTML_LOGGER_PATH : $htmlFileLogPath, (bool) $input->getOption(self::OPTION_USE_NOOP_MUTATORS), (bool) $input->getOption(self::OPTION_EXECUTE_ONLY_COVERING_TEST_CASES) ); diff --git a/src/Configuration/ConfigurationFactory.php b/src/Configuration/ConfigurationFactory.php index 4e3d09fe1..0b55c91e4 100644 --- a/src/Configuration/ConfigurationFactory.php +++ b/src/Configuration/ConfigurationFactory.php @@ -119,6 +119,7 @@ public function create( bool $isForGitDiffLines, ?string $gitDiffBase, bool $useGitHubLogger, + ?string $htmlLogFilePath, bool $useNoopMutators, bool $executeOnlyCoveringTestCases ): Configuration { @@ -150,7 +151,7 @@ public function create( ), $this->retrieveFilter($filter, $gitDiffFilter, $isForGitDiffLines, $gitDiffBase), $schema->getSource()->getExcludes(), - $this->retrieveLogs($schema->getLogs(), $useGitHubLogger), + $this->retrieveLogs($schema->getLogs(), $useGitHubLogger, $htmlLogFilePath), $logVerbosity, $namespacedTmpDir, $this->retrievePhpUnit($schema, $configDir), @@ -315,12 +316,16 @@ private function retrieveFilter(string $filter, ?string $gitDiffFilter, bool $is return $this->gitDiffFileProvider->provide($gitDiffFilter, $baseBranch); } - private function retrieveLogs(Logs $logs, bool $useGitHubLogger): Logs + private function retrieveLogs(Logs $logs, bool $useGitHubLogger, ?string $htmlLogFilePath): Logs { if ($useGitHubLogger) { $logs->setUseGitHubAnnotationsLogger($useGitHubLogger); } + if ($htmlLogFilePath !== null) { + $logs->setHtmlLogFilePath($htmlLogFilePath); + } + return $logs; } } diff --git a/src/Configuration/Entry/Logs.php b/src/Configuration/Entry/Logs.php index 33fed796d..bc511685f 100644 --- a/src/Configuration/Entry/Logs.php +++ b/src/Configuration/Entry/Logs.php @@ -94,6 +94,11 @@ public function getHtmlLogFilePath(): ?string return $this->htmlLogFilePath; } + public function setHtmlLogFilePath(string $htmlLogFilePath): void + { + $this->htmlLogFilePath = $htmlLogFilePath; + } + public function getSummaryLogFilePath(): ?string { return $this->summaryLogFilePath; diff --git a/src/Container.php b/src/Container.php index c3e7fc5aa..864720a06 100644 --- a/src/Container.php +++ b/src/Container.php @@ -170,6 +170,7 @@ final class Container public const DEFAULT_GIT_DIFF_LINES = false; public const DEFAULT_GIT_DIFF_BASE = null; public const DEFAULT_USE_GITHUB_LOGGER = false; + public const DEFAULT_HTML_LOGGER_PATH = null; public const DEFAULT_USE_NOOP_MUTATORS = false; public const DEFAULT_EXECUTE_ONLY_COVERING_TEST_CASES = false; public const DEFAULT_NO_PROGRESS = false; @@ -710,6 +711,7 @@ public static function create(): self self::DEFAULT_GIT_DIFF_LINES, self::DEFAULT_GIT_DIFF_BASE, self::DEFAULT_USE_GITHUB_LOGGER, + self::DEFAULT_HTML_LOGGER_PATH, self::DEFAULT_USE_NOOP_MUTATORS, self::DEFAULT_EXECUTE_ONLY_COVERING_TEST_CASES ); @@ -743,6 +745,7 @@ public function withValues( bool $isForGitDiffLines, ?string $gitDiffBase, bool $useGitHubLogger, + ?string $htmlLogFilePath, bool $useNoopMutators, bool $executeOnlyCoveringTestCases ): self { @@ -820,6 +823,7 @@ static function (self $container) use ( $isForGitDiffLines, $gitDiffBase, $useGitHubLogger, + $htmlLogFilePath, $useNoopMutators, $executeOnlyCoveringTestCases ): Configuration { @@ -847,6 +851,7 @@ static function (self $container) use ( $isForGitDiffLines, $gitDiffBase, $useGitHubLogger, + $htmlLogFilePath, $useNoopMutators, $executeOnlyCoveringTestCases ); diff --git a/tests/benchmark/Tracing/provide-traces-closure.php b/tests/benchmark/Tracing/provide-traces-closure.php index a741ce153..b022223a0 100644 --- a/tests/benchmark/Tracing/provide-traces-closure.php +++ b/tests/benchmark/Tracing/provide-traces-closure.php @@ -71,6 +71,7 @@ Container::DEFAULT_GIT_DIFF_LINES, Container::DEFAULT_GIT_DIFF_BASE, Container::DEFAULT_USE_GITHUB_LOGGER, + Container::DEFAULT_HTML_LOGGER_PATH, true, Container::DEFAULT_EXECUTE_ONLY_COVERING_TEST_CASES ); diff --git a/tests/phpunit/Configuration/ConfigurationFactoryTest.php b/tests/phpunit/Configuration/ConfigurationFactoryTest.php index bcc487384..201adf38e 100644 --- a/tests/phpunit/Configuration/ConfigurationFactoryTest.php +++ b/tests/phpunit/Configuration/ConfigurationFactoryTest.php @@ -113,6 +113,7 @@ public function test_it_can_create_a_configuration( bool $inputIsForGitDiffLines, string $inputGitDiffBase, bool $inputUseGitHubAnnotationsLogger, + ?string $inputHtmlLogFilePath, bool $inputUseNoopMutators, int $inputMsiPrecision, int $expectedTimeout, @@ -168,6 +169,7 @@ public function test_it_can_create_a_configuration( $inputIsForGitDiffLines, $inputGitDiffBase, $inputUseGitHubAnnotationsLogger, + $inputHtmlLogFilePath, $inputUseNoopMutators, $inputExecuteOnlyCoveringTestCases ) @@ -253,6 +255,7 @@ public function valueProvider(): iterable false, 'master', true, + null, false, 2, 10, @@ -283,6 +286,30 @@ public function valueProvider(): iterable true, ]; + yield 'null html file log path with existing path from config file' => self::createValueForHtmlLogFilePath( + 'from-config.html', + null, + 'from-config.html' + ); + + yield 'override html file log path from CLI option with existing path from config file' => self::createValueForHtmlLogFilePath( + 'from-config.html', + 'from-cli.html', + 'from-cli.html' + ); + + yield 'set html file log path from CLI option when config file has no setting' => self::createValueForHtmlLogFilePath( + null, + 'from-cli.html', + 'from-cli.html' + ); + + yield 'null html file log path in config and CLI' => self::createValueForHtmlLogFilePath( + null, + null, + null + ); + yield 'null timeout' => self::createValueForTimeout( null, 10 @@ -697,6 +724,7 @@ public function valueProvider(): iterable false, 'master', false, + null, false, 2, 10, @@ -781,6 +809,7 @@ public function valueProvider(): iterable false, 'master', false, + null, false, 2, 10, @@ -874,6 +903,7 @@ private static function createValueForTimeout( false, 'master', false, + null, false, 2, $expectedTimeOut, @@ -948,6 +978,7 @@ private static function createValueForTmpDir( false, 'master', false, + null, false, 2, 10, @@ -1023,6 +1054,7 @@ private static function createValueForCoveragePath( false, 'master', false, + null, false, 2, 10, @@ -1097,6 +1129,7 @@ private static function createValueForPhpUnitConfigDir( false, 'master', false, + null, false, 2, 10, @@ -1172,6 +1205,7 @@ private static function createValueForNoProgress( false, 'master', false, + null, false, 2, 10, @@ -1247,6 +1281,7 @@ private static function createValueForIgnoreMsiWithNoMutations( false, 'master', false, + null, false, 2, 10, @@ -1322,6 +1357,7 @@ private static function createValueForMinMsi( false, 'master', false, + null, false, 2, 10, @@ -1397,6 +1433,7 @@ private static function createValueForMinCoveredMsi( false, 'master', false, + null, false, 2, 10, @@ -1473,6 +1510,7 @@ private static function createValueForTestFramework( false, 'master', false, + null, false, 2, 10, @@ -1548,6 +1586,7 @@ private static function createValueForInitialTestsPhpOptions( false, 'master', false, + null, false, 2, 10, @@ -1624,6 +1663,7 @@ private static function createValueForTestFrameworkExtraOptions( false, 'master', false, + null, false, 2, 10, @@ -1699,6 +1739,7 @@ private static function createValueForTestFrameworkKey( false, 'master', false, + null, false, 2, 10, @@ -1778,6 +1819,7 @@ private static function createValueForMutators( false, 'master', false, + null, $useNoopMutatos, 2, 10, @@ -1856,6 +1898,7 @@ private static function createValueForIgnoreSourceCodeByRegex( false, 'master', false, + null, false, 2, 10, @@ -1889,6 +1932,98 @@ private static function createValueForIgnoreSourceCodeByRegex( ]; } + private static function createValueForHtmlLogFilePath(?string $htmlFileLogPathInConfig, ?string $htmlFileLogPathFromCliOption, ?string $expectedHtmlFileLogPath): array + { + $expectedLogs = new Logs( + null, + $expectedHtmlFileLogPath, + null, + null, + null, + null, + true, + null, + ); + + return [ + false, + new SchemaConfiguration( + '/path/to/infection.json', + null, + new Source([], []), + new Logs( + null, + $htmlFileLogPathInConfig, + null, + null, + null, + null, + false, + null, + ), + '', + new PhpUnit(null, null), + null, + null, + null, + [], + null, + null, + null, + null + ), + null, + null, + false, + 'none', + false, + false, + false, + false, + null, + false, + null, + '', + null, + null, + '', + 0, + false, + 'AM', + 'master', + true, + $htmlFileLogPathFromCliOption, + false, + 2, + 10, + [], + [], + 'src/a.php,src/b.php', + [], + $expectedLogs, + 'none', + sys_get_temp_dir() . '/infection', + new PhpUnit('/path/to', null), + self::getDefaultMutators(), + 'phpunit', + null, + null, + false, + '', + sys_get_temp_dir() . '/infection', + false, + false, + false, + false, + false, + null, + false, + null, + [], + true, + ]; + } + /** * @return array */ diff --git a/tests/phpunit/ContainerTest.php b/tests/phpunit/ContainerTest.php index 2a6427db9..7e3049553 100644 --- a/tests/phpunit/ContainerTest.php +++ b/tests/phpunit/ContainerTest.php @@ -96,6 +96,7 @@ public function test_it_can_build_lazy_source_file_data_factory_that_fails_on_us Container::DEFAULT_GIT_DIFF_LINES, Container::DEFAULT_GIT_DIFF_BASE, Container::DEFAULT_USE_GITHUB_LOGGER, + Container::DEFAULT_HTML_LOGGER_PATH, Container::DEFAULT_USE_NOOP_MUTATORS, Container::DEFAULT_EXECUTE_ONLY_COVERING_TEST_CASES ); @@ -145,6 +146,7 @@ public function test_it_provides_a_friendly_error_when_attempting_to_configure_i Container::DEFAULT_GIT_DIFF_LINES, Container::DEFAULT_GIT_DIFF_BASE, Container::DEFAULT_USE_GITHUB_LOGGER, + Container::DEFAULT_HTML_LOGGER_PATH, Container::DEFAULT_USE_NOOP_MUTATORS, Container::DEFAULT_EXECUTE_ONLY_COVERING_TEST_CASES, ); From 62936a2101de6f59f07b69d798d2eafa6a54f931 Mon Sep 17 00:00:00 2001 From: maks-rafalko Date: Sat, 8 Jan 2022 02:41:04 +0300 Subject: [PATCH 8/8] Update tests after rebasing on `master` --- tests/phpunit/Configuration/ConfigurationFactoryTest.php | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/phpunit/Configuration/ConfigurationFactoryTest.php b/tests/phpunit/Configuration/ConfigurationFactoryTest.php index 201adf38e..e3fa52c25 100644 --- a/tests/phpunit/Configuration/ConfigurationFactoryTest.php +++ b/tests/phpunit/Configuration/ConfigurationFactoryTest.php @@ -1990,6 +1990,7 @@ private static function createValueForHtmlLogFilePath(?string $htmlFileLogPathIn 0, false, 'AM', + false, 'master', true, $htmlFileLogPathFromCliOption,