Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

feat(mutators) Avoid creating some unnecessary mutators for (a && b) … #3346

Merged
merged 1 commit into from
Jan 17, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions e2e/test/babel-transpiling/verify/verify.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ import { expectMetricsJson } from '../../../helpers';
describe('Verify stryker has ran correctly', () => {
it('should report expected score', async () => {
// File | % score | # killed | # timeout | # survived | # no cov | # error |
// All files | 57.45 | 27 | 0 | 20 | 0 | 1 |
// All files | 55.56 | 25 | 0 | 20 | 0 | 1 |
await expectMetricsJson({
killed: 27,
mutationScore: 57.45,
killed: 25,
mutationScore: 55.56,
runtimeErrors: 1,
survived: 20,
noCoverage: 0,
Expand Down
6 changes: 3 additions & 3 deletions e2e/test/cucumber-ts/verify/verify.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,17 @@ describe('After running stryker on a cucumber-ts project', () => {
await expectMetricsJson({
killed: 64,
ignored: 0,
survived: 48,
survived: 40,
timeout: 1,
noCoverage: 39,
runtimeErrors: 16,
mutationScore: 42.76,
mutationScore: 45.14,
});
/*
-----------|---------|----------|-----------|------------|----------|---------|
File | % score | # killed | # timeout | # survived | # no cov | # error |
-----------|---------|----------|-----------|------------|----------|---------|
All files | 42.76 | 64 | 1 | 48 | 39 | 16 |
All files | 45.14 | 64 | 1 | 40 | 39 | 16 |
-----------|---------|----------|-----------|------------|----------|---------|*/
});
});
8 changes: 4 additions & 4 deletions e2e/test/ignore-project/verify/verify.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,17 @@ describe('After running stryker on jest-react project', () => {
it('should report expected scores', async () => {
await expectMetricsJson({
killed: 8,
ignored: 29,
ignored: 28,
mutationScore: 53.33,
});
});

/*
-----------|---------|----------|-----------|------------|----------|---------|
File | % score | # killed | # timeout | # survived | # no cov | # error |
-----------|---------|----------|-----------|------------|----------|---------|
All files | 53.33 | 8 | 0 | 0 | 7 | 0 |*/


it('should report mutants that are disabled by a comment with correct ignore reason', async () => {
const actualMetricsResult = await readMutationTestingJsonResult();
Expand All @@ -33,7 +33,7 @@ describe('After running stryker on jest-react project', () => {
expect(conditionalMutant.status).eq(MutantStatus.Ignored);
expect(conditionalMutant.statusReason).eq('Ignore boolean and conditions');
});

equalityOperatorMutants.forEach((equalityMutant) => {
expect(equalityMutant.status).eq(MutantStatus.NoCoverage);
});
Expand Down
6 changes: 3 additions & 3 deletions e2e/test/jest-react-ts/verify/verify.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ import { expectMetricsJson } from '../../../helpers';
describe('After running stryker on jest-react-ts project', () => {
it('should report expected scores', async () => {
await expectMetricsJson({
killed: 63,
noCoverage: 19,
survived: 25,
killed: 61,
noCoverage: 18,
survived: 24,
timeout: 5,
});
});
Expand Down
4 changes: 2 additions & 2 deletions e2e/test/jest-with-ts/verify/verify.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ describe('Verify stryker has ran correctly', () => {
it('should report correct score', async () => {
await expectMetricsJson({
ignored: 0,
killed: 17,
mutationScore: 62.96,
killed: 14,
mutationScore: 58.33,
noCoverage: 0,
survived: 10,
timeout: 0,
Expand Down
4 changes: 2 additions & 2 deletions e2e/test/karma-webpack-with-ts/verify/verify.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ describe('Verify stryker has ran correctly', () => {

it('should report correct score', async () => {
await expectMetrics({
mutationScore: 51.67,
mutationScore: 50.85,
compileErrors: 0,
ignored: 0,
killed: 30,
killed: 29,
noCoverage: 15,
runtimeErrors: 0,
timeout: 1,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,22 @@ export const conditionalExpressionMutator: NodeMutator = {
yield types.booleanLiteral(true);
yield types.booleanLiteral(false);
} else if (isBooleanExpression(path)) {
if (path.parent?.type === 'LogicalExpression') {
// For (x || y), do not generate the (true || y) mutation as it
// has the same behavior as the (true) mutator, handled in the
// isTestOfCondition branch above
if (path.parent.operator === '||') {
yield types.booleanLiteral(false);
return;
}
// For (x && y), do not generate the (false && y) mutation as it
// has the same behavior as the (false) mutator, handled in the
// isTestOfCondition branch above
if (path.parent.operator === '&&') {
yield types.booleanLiteral(true);
return;
}
}
yield types.booleanLiteral(true);
yield types.booleanLiteral(false);
} else if (path.isForStatement() && !path.node.test) {
Expand Down
8 changes: 6 additions & 2 deletions packages/instrumenter/test/helpers/expect-mutation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@ export function expectJSMutation(sut: NodeMutator, originalCode: string, ...expe
}
},
});
expect(mutants).lengthOf(expectedReplacements.length);
expectedReplacements.forEach((expected) => expect(mutants, `was: ${mutants.join(',')}`).to.include(expected));
/* eslint-disable @typescript-eslint/require-array-sort-compare */
/* because we know mutants and expectedReplacements are strings */
mutants.sort();
edi9999 marked this conversation as resolved.
Show resolved Hide resolved
expectedReplacements.sort();
/* eslint-enable @typescript-eslint/require-array-sort-compare */
expect(mutants).to.deep.equal(expectedReplacements);
}
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,50 @@ describe(sut.name, () => {
);
});

it('should not mutate (a || b) condition to (a || true)', () => {
expectJSMutation(
sut,
'if (b === 5 || c === 3) { a++ }',
'if (true) { a++ }',
'if (false) { a++ }',
'if (false || c === 3) { a++ }',
'if (b === 5 || false) { a++ }'
);
});

it('should not mutate (a && b) condition to (a && false)', () => {
expectJSMutation(
sut,
'if (b === 5 && c === 3) { a++ }',
'if (true) { a++ }',
'if (false) { a++ }',
'if (true && c === 3) { a++ }',
'if (b === 5 && true) { a++ }'
);
});

it('should mutate ((c1 && c2) || (c3 && c4))', () => {
expectJSMutation(
sut,
'if ((c1 && c2) || (c3 && c4)) { a++ }',
'if (true) { a++ }',
'if (false) { a++ }',
'if ((false) || (c3 && c4)) { a++ }',
'if ((c1 && c2) || (false)) { a++ }'
);
});

it('should mutate ((c1 || c2) && (c3 || c4))', () => {
expectJSMutation(
sut,
'if ((c1 || c2) && (c3 || c4)) { a++ }',
'if (true) { a++ }',
'if (false) { a++ }',
'if ((true) && (c3 || c4)) { a++ }',
'if ((c1 || c2) && (true)) { a++ }'
);
});

it('should mutate an expression to `true` and `false`', () => {
expectJSMutation(sut, 'if (something) { a++ }', 'if (true) { a++ }', 'if (false) { a++ }');
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -186,11 +186,11 @@ export class MutationTestReportTotalsComponent extends LitElement {
stryCov_9fa48(\\"17\\");
let fullName: string = childResult.name;
while (stryMutAct_9fa48(\\"19\\") ? !childResult.file || childResult.childResults.length === 1 : stryMutAct_9fa48(\\"18\\") ? false : (stryCov_9fa48(\\"18\\", \\"19\\"), (stryMutAct_9fa48(\\"20\\") ? childResult.file : (stryCov_9fa48(\\"20\\"), !childResult.file)) && (stryMutAct_9fa48(\\"23\\") ? childResult.childResults.length !== 1 : stryMutAct_9fa48(\\"22\\") ? false : stryMutAct_9fa48(\\"21\\") ? true : (stryCov_9fa48(\\"21\\", \\"22\\", \\"23\\"), childResult.childResults.length === 1)))) {
if (stryMutAct_9fa48(\\"24\\")) {
while (stryMutAct_9fa48(\\"19\\") ? !childResult.file || childResult.childResults.length === 1 : stryMutAct_9fa48(\\"18\\") ? false : (stryCov_9fa48(\\"18\\", \\"19\\"), (stryMutAct_9fa48(\\"20\\") ? childResult.file : (stryCov_9fa48(\\"20\\"), !childResult.file)) && (stryMutAct_9fa48(\\"22\\") ? childResult.childResults.length !== 1 : stryMutAct_9fa48(\\"21\\") ? true : (stryCov_9fa48(\\"21\\", \\"22\\"), childResult.childResults.length === 1)))) {
if (stryMutAct_9fa48(\\"23\\")) {
{}
} else {
stryCov_9fa48(\\"24\\");
stryCov_9fa48(\\"23\\");
childResult = childResult.childResults[0];
fullName = pathJoin(fullName, childResult.name);
}
Expand All @@ -204,7 +204,7 @@ export class MutationTestReportTotalsComponent extends LitElement {
}
};
return stryMutAct_9fa48(\\"25\\") ? html\`\` : (stryCov_9fa48(\\"25\\"), html\`
return stryMutAct_9fa48(\\"24\\") ? html\`\` : (stryCov_9fa48(\\"24\\"), html\`
<tbody>
\${this.renderRow(model.name, model, undefined)} \${renderChildren()}
</tbody>
Expand All @@ -213,26 +213,26 @@ export class MutationTestReportTotalsComponent extends LitElement {
}
private renderRow(name: string, row: MetricsResult, path: string | undefined) {
if (stryMutAct_9fa48(\\"26\\")) {
if (stryMutAct_9fa48(\\"25\\")) {
{}
} else {
stryCov_9fa48(\\"26\\");
stryCov_9fa48(\\"25\\");
const {
mutationScore
} = row.metrics;
const scoreIsPresent = stryMutAct_9fa48(\\"27\\") ? isNaN(mutationScore) : (stryCov_9fa48(\\"27\\"), !isNaN(mutationScore));
const scoreIsPresent = stryMutAct_9fa48(\\"26\\") ? isNaN(mutationScore) : (stryCov_9fa48(\\"26\\"), !isNaN(mutationScore));
const coloringClass = this.determineColoringClass(mutationScore);
const mutationScoreRounded = mutationScore.toFixed(2);
const progressBarStyle = stryMutAct_9fa48(\\"28\\") ? \`\` : (stryCov_9fa48(\\"28\\"), \`width: \${mutationScore}%\`);
return stryMutAct_9fa48(\\"29\\") ? html\`\` : (stryCov_9fa48(\\"29\\"), html\` <tr title=\\"\${row.name}\\">
const progressBarStyle = stryMutAct_9fa48(\\"27\\") ? \`\` : (stryCov_9fa48(\\"27\\"), \`width: \${mutationScore}%\`);
return stryMutAct_9fa48(\\"28\\") ? html\`\` : (stryCov_9fa48(\\"28\\"), html\` <tr title=\\"\${row.name}\\">
<td style=\\"width: 32px;\\" class=\\"icon no-border-right\\"
>\${row.file ? this.fileIcon : this.directoryIcon}</td
>
<td width=\\"\\" class=\\"no-border-left\\"
>\${(stryMutAct_9fa48(\\"32\\") ? typeof path !== 'string' : stryMutAct_9fa48(\\"31\\") ? false : stryMutAct_9fa48(\\"30\\") ? true : (stryCov_9fa48(\\"30\\", \\"31\\", \\"32\\"), typeof path === (stryMutAct_9fa48(\\"33\\") ? \\"\\" : (stryCov_9fa48(\\"33\\"), 'string')))) ? stryMutAct_9fa48(\\"34\\") ? html\`\` : (stryCov_9fa48(\\"34\\"), html\`<a href=\\"\${toAbsoluteUrl(path)}\\">\${name}</a>\`) : stryMutAct_9fa48(\\"35\\") ? html\`\` : (stryCov_9fa48(\\"35\\"), html\`<span>\${row.name}</span>\`)}</td
>\${(stryMutAct_9fa48(\\"31\\") ? typeof path !== 'string' : stryMutAct_9fa48(\\"30\\") ? false : stryMutAct_9fa48(\\"29\\") ? true : (stryCov_9fa48(\\"29\\", \\"30\\", \\"31\\"), typeof path === (stryMutAct_9fa48(\\"32\\") ? \\"\\" : (stryCov_9fa48(\\"32\\"), 'string')))) ? stryMutAct_9fa48(\\"33\\") ? html\`\` : (stryCov_9fa48(\\"33\\"), html\`<a href=\\"\${toAbsoluteUrl(path)}\\">\${name}</a>\`) : stryMutAct_9fa48(\\"34\\") ? html\`\` : (stryCov_9fa48(\\"34\\"), html\`<span>\${row.name}</span>\`)}</td
>
<td class=\\"no-border-right vertical-middle\\">
\${scoreIsPresent ? stryMutAct_9fa48(\\"36\\") ? html\`\` : (stryCov_9fa48(\\"36\\"), html\` <div class=\\"progress\\">
\${scoreIsPresent ? stryMutAct_9fa48(\\"35\\") ? html\`\` : (stryCov_9fa48(\\"35\\"), html\` <div class=\\"progress\\">
<div
class=\\"progress-bar bg-\${coloringClass}\\"
role=\\"progressbar\\"
Expand All @@ -243,7 +243,7 @@ export class MutationTestReportTotalsComponent extends LitElement {
>
\${mutationScoreRounded}%
</div>
</div>\`) : stryMutAct_9fa48(\\"37\\") ? html\`\` : (stryCov_9fa48(\\"37\\"), html\` <span class=\\"font-weight-bold text-muted\\">N/A</span> \`)}
</div>\`) : stryMutAct_9fa48(\\"36\\") ? html\`\` : (stryCov_9fa48(\\"36\\"), html\` <span class=\\"font-weight-bold text-muted\\">N/A</span> \`)}
</td>
<td style=\\"width: 50px;\\" class=\\"no-border-left font-weight-bold text-center text-\${coloringClass}\\">
\${scoreIsPresent ? mutationScoreRounded : undefined}
Expand All @@ -263,46 +263,46 @@ export class MutationTestReportTotalsComponent extends LitElement {
}
private determineColoringClass(mutationScore: number) {
if (stryMutAct_9fa48(\\"38\\")) {
if (stryMutAct_9fa48(\\"37\\")) {
{}
} else {
stryCov_9fa48(\\"38\\");
stryCov_9fa48(\\"37\\");
if (stryMutAct_9fa48(\\"41\\") ? !isNaN(mutationScore) || this.thresholds : stryMutAct_9fa48(\\"40\\") ? false : stryMutAct_9fa48(\\"39\\") ? true : (stryCov_9fa48(\\"39\\", \\"40\\", \\"41\\"), (stryMutAct_9fa48(\\"42\\") ? isNaN(mutationScore) : (stryCov_9fa48(\\"42\\"), !isNaN(mutationScore))) && this.thresholds)) {
if (stryMutAct_9fa48(\\"43\\")) {
if (stryMutAct_9fa48(\\"40\\") ? !isNaN(mutationScore) || this.thresholds : stryMutAct_9fa48(\\"39\\") ? false : stryMutAct_9fa48(\\"38\\") ? true : (stryCov_9fa48(\\"38\\", \\"39\\", \\"40\\"), (stryMutAct_9fa48(\\"41\\") ? isNaN(mutationScore) : (stryCov_9fa48(\\"41\\"), !isNaN(mutationScore))) && this.thresholds)) {
if (stryMutAct_9fa48(\\"42\\")) {
{}
} else {
stryCov_9fa48(\\"43\\");
stryCov_9fa48(\\"42\\");
if (stryMutAct_9fa48(\\"47\\") ? mutationScore >= this.thresholds.low : stryMutAct_9fa48(\\"46\\") ? mutationScore <= this.thresholds.low : stryMutAct_9fa48(\\"45\\") ? false : stryMutAct_9fa48(\\"44\\") ? true : (stryCov_9fa48(\\"44\\", \\"45\\", \\"46\\", \\"47\\"), mutationScore < this.thresholds.low)) {
if (stryMutAct_9fa48(\\"48\\")) {
if (stryMutAct_9fa48(\\"46\\") ? mutationScore >= this.thresholds.low : stryMutAct_9fa48(\\"45\\") ? mutationScore <= this.thresholds.low : stryMutAct_9fa48(\\"44\\") ? false : stryMutAct_9fa48(\\"43\\") ? true : (stryCov_9fa48(\\"43\\", \\"44\\", \\"45\\", \\"46\\"), mutationScore < this.thresholds.low)) {
if (stryMutAct_9fa48(\\"47\\")) {
{}
} else {
stryCov_9fa48(\\"48\\");
return stryMutAct_9fa48(\\"49\\") ? \\"\\" : (stryCov_9fa48(\\"49\\"), 'danger');
stryCov_9fa48(\\"47\\");
return stryMutAct_9fa48(\\"48\\") ? \\"\\" : (stryCov_9fa48(\\"48\\"), 'danger');
}
} else if (stryMutAct_9fa48(\\"53\\") ? mutationScore >= this.thresholds.high : stryMutAct_9fa48(\\"52\\") ? mutationScore <= this.thresholds.high : stryMutAct_9fa48(\\"51\\") ? false : stryMutAct_9fa48(\\"50\\") ? true : (stryCov_9fa48(\\"50\\", \\"51\\", \\"52\\", \\"53\\"), mutationScore < this.thresholds.high)) {
if (stryMutAct_9fa48(\\"54\\")) {
} else if (stryMutAct_9fa48(\\"52\\") ? mutationScore >= this.thresholds.high : stryMutAct_9fa48(\\"51\\") ? mutationScore <= this.thresholds.high : stryMutAct_9fa48(\\"50\\") ? false : stryMutAct_9fa48(\\"49\\") ? true : (stryCov_9fa48(\\"49\\", \\"50\\", \\"51\\", \\"52\\"), mutationScore < this.thresholds.high)) {
if (stryMutAct_9fa48(\\"53\\")) {
{}
} else {
stryCov_9fa48(\\"54\\");
return stryMutAct_9fa48(\\"55\\") ? \\"\\" : (stryCov_9fa48(\\"55\\"), 'warning');
stryCov_9fa48(\\"53\\");
return stryMutAct_9fa48(\\"54\\") ? \\"\\" : (stryCov_9fa48(\\"54\\"), 'warning');
}
} else {
if (stryMutAct_9fa48(\\"56\\")) {
if (stryMutAct_9fa48(\\"55\\")) {
{}
} else {
stryCov_9fa48(\\"56\\");
return stryMutAct_9fa48(\\"57\\") ? \\"\\" : (stryCov_9fa48(\\"57\\"), 'success');
stryCov_9fa48(\\"55\\");
return stryMutAct_9fa48(\\"56\\") ? \\"\\" : (stryCov_9fa48(\\"56\\"), 'success');
}
}
}
} else {
if (stryMutAct_9fa48(\\"58\\")) {
if (stryMutAct_9fa48(\\"57\\")) {
{}
} else {
stryCov_9fa48(\\"58\\");
return stryMutAct_9fa48(\\"59\\") ? \\"\\" : (stryCov_9fa48(\\"59\\"), 'default');
stryCov_9fa48(\\"57\\");
return stryMutAct_9fa48(\\"58\\") ? \\"\\" : (stryCov_9fa48(\\"58\\"), 'default');
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,11 +66,11 @@ function stryMutAct_9fa48(id) {
const a = stryMutAct_9fa48(\\"0\\") ? 1 - 1 : (stryCov_9fa48(\\"0\\"), 1 + 1);
const b = 1 - 1;
if ((stryMutAct_9fa48(\\"3\\") ? a !== 2 : stryMutAct_9fa48(\\"2\\") ? false : stryMutAct_9fa48(\\"1\\") ? true : (stryCov_9fa48(\\"1\\", \\"2\\", \\"3\\"), a === 2)) && b === 0) {
if ((stryMutAct_9fa48(\\"2\\") ? a !== 2 : stryMutAct_9fa48(\\"1\\") ? true : (stryCov_9fa48(\\"1\\", \\"2\\"), a === 2)) && b === 0) {
console.log('a');
}
if (a === 2 && (stryMutAct_9fa48(\\"6\\") ? b !== 0 : stryMutAct_9fa48(\\"5\\") ? false : stryMutAct_9fa48(\\"4\\") ? true : (stryCov_9fa48(\\"4\\", \\"5\\", \\"6\\"), b === 0))) {
if (a === 2 && (stryMutAct_9fa48(\\"4\\") ? b !== 0 : stryMutAct_9fa48(\\"3\\") ? true : (stryCov_9fa48(\\"3\\", \\"4\\"), b === 0))) {
console.log('b');
}
Expand All @@ -80,5 +80,5 @@ const itemWithLongName = {
longPropertyName3: 3
};
const item = () => stryMutAct_9fa48(\\"9\\") ? itemWithLongName.longPropertyName1 === itemWithLongName.longPropertyName2 || itemWithLongName.longPropertyName1 === itemWithLongName.longPropertyName3 : stryMutAct_9fa48(\\"8\\") ? false : stryMutAct_9fa48(\\"7\\") ? true : (stryCov_9fa48(\\"7\\", \\"8\\", \\"9\\"), (stryMutAct_9fa48(\\"12\\") ? itemWithLongName.longPropertyName1 !== itemWithLongName.longPropertyName2 : stryMutAct_9fa48(\\"11\\") ? false : stryMutAct_9fa48(\\"10\\") ? true : (stryCov_9fa48(\\"10\\", \\"11\\", \\"12\\"), itemWithLongName.longPropertyName1 === itemWithLongName.longPropertyName2)) && (stryMutAct_9fa48(\\"15\\") ? itemWithLongName.longPropertyName1 !== itemWithLongName.longPropertyName3 : stryMutAct_9fa48(\\"14\\") ? false : stryMutAct_9fa48(\\"13\\") ? true : (stryCov_9fa48(\\"13\\", \\"14\\", \\"15\\"), itemWithLongName.longPropertyName1 === itemWithLongName.longPropertyName3)));"
const item = () => stryMutAct_9fa48(\\"7\\") ? itemWithLongName.longPropertyName1 === itemWithLongName.longPropertyName2 || itemWithLongName.longPropertyName1 === itemWithLongName.longPropertyName3 : stryMutAct_9fa48(\\"6\\") ? false : stryMutAct_9fa48(\\"5\\") ? true : (stryCov_9fa48(\\"5\\", \\"6\\", \\"7\\"), (stryMutAct_9fa48(\\"9\\") ? itemWithLongName.longPropertyName1 !== itemWithLongName.longPropertyName2 : stryMutAct_9fa48(\\"8\\") ? true : (stryCov_9fa48(\\"8\\", \\"9\\"), itemWithLongName.longPropertyName1 === itemWithLongName.longPropertyName2)) && (stryMutAct_9fa48(\\"11\\") ? itemWithLongName.longPropertyName1 !== itemWithLongName.longPropertyName3 : stryMutAct_9fa48(\\"10\\") ? true : (stryCov_9fa48(\\"10\\", \\"11\\"), itemWithLongName.longPropertyName1 === itemWithLongName.longPropertyName3)));"
`;