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

Add restriction for string literals #43

Merged
merged 3 commits into from
Nov 26, 2023
Merged
Show file tree
Hide file tree
Changes from 2 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
9 changes: 7 additions & 2 deletions packages/api/schema/stryker-core.json
Original file line number Diff line number Diff line change
Expand Up @@ -681,9 +681,14 @@
"description": "Replace ```\"\"``` with ```\"Stryker was here!\"```."
},
{
"const": "Interpolation",
"title": "InterpolationMutator",
"const": "EmptyInterpolation",
"title": "EmptyInterpolation",
"description": "Replace ```s\"foo ${bar}\"``` with ```s\"\"```."
},
{
"const": "FillInterpolation",
"title": "FillInterpolation",
"description": "Replace ```s\"\"``` with ```s\"Stryker was here!\"```."
}
]
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ import { MutationLevel } from '@stryker-mutator/api/core';
export interface RunLevelOptions {
runLevel?: MutationLevel;
}
export type MutationOperator = Record<string, { replacementOperator: any; mutatorName: string }>;
32 changes: 28 additions & 4 deletions packages/instrumenter/src/mutators/string-literal-mutator.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,43 @@
import babel, { type NodePath } from '@babel/core';

import { NodeMutator } from './node-mutator.js';
import { MutationOperator } from './mutation-level-options.js';

const { types } = babel;

const operators: MutationOperator = {
FillString: { replacementOperator: types.stringLiteral('Stryker was here!'), mutatorName: 'FillString' },
EmptyString: { replacementOperator: types.stringLiteral(''), mutatorName: 'EmptyString' },
EmptyInterpolation: { replacementOperator: types.templateLiteral([types.templateElement({ raw: '' })], []), mutatorName: 'EmptyInterpolation' },
FillInterpolation: {
replacementOperator: types.templateLiteral([types.templateElement({ raw: 'Stryker was here!' })], []),
mutatorName: 'FillInterpolation',
},
};

export const stringLiteralMutator: NodeMutator = {
name: 'StringLiteral',

*mutate(path) {
*mutate(path, operations: string[] | undefined) {
if (path.isTemplateLiteral()) {
const replacement = path.node.quasis.length === 1 && path.node.quasis[0].value.raw.length === 0 ? 'Stryker was here!' : '';
yield types.templateLiteral([types.templateElement({ raw: replacement })], []);
const stringIsEmpty = path.node.quasis.length === 1 && path.node.quasis[0].value.raw.length === 0;
if (
operations === undefined ||
(stringIsEmpty && operations.includes(operators.FillInterpolation.mutatorName)) ||
(!stringIsEmpty && operations.includes(operators.EmptyInterpolation.mutatorName))
) {
yield stringIsEmpty ? operators.FillInterpolation.replacementOperator : operators.EmptyInterpolation.replacementOperator;
}
}
if (path.isStringLiteral() && isValidParent(path)) {
yield types.stringLiteral(path.node.value.length === 0 ? 'Stryker was here!' : '');
const stringIsEmpty = path.node.value.length === 0;
if (
operations === undefined ||
(stringIsEmpty && operations.includes(operators.FillString.mutatorName)) ||
(!stringIsEmpty && operations.includes(operators.EmptyString.mutatorName))
) {
yield stringIsEmpty ? operators.FillString.replacementOperator : operators.EmptyString.replacementOperator;
}
}
},
};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { expect } from 'chai';

import { expectJSMutation } from '../../helpers/expect-mutation.js';
import { expectJSMutation, expectJSMutationWithLevel } from '../../helpers/expect-mutation.js';
import { stringLiteralMutator as sut } from '../../../src/mutators/string-literal-mutator.js';

describe(sut.name, () => {
Expand Down Expand Up @@ -112,4 +112,30 @@ describe(sut.name, () => {
expectJSMutation(sut, '<Record class="row" />');
});
});

describe('mutation level', () => {
it('should only mutate EmptyString and EmptyInterpolation from all possible mutations', () => {
expectJSMutationWithLevel(
sut,
['EmptyString', 'EmptyInterpolation'],
'const bar = "bar"; const foo = `name: ${level_name}`; const emptyString=""; const emptyInterp=``',
'const bar = ""; const foo = `name: ${level_name}`; const emptyString=""; const emptyInterp=``', // empties string
'const bar = "bar"; const foo = ``; const emptyString=""; const emptyInterp=``', // empties interpolation
);
});
it('should block the mutators', () => {
expectJSMutationWithLevel(sut, [], 'const bar = "bar"; const foo = `name: ${level_name}`; const emptyString=""; const emptyInterp=``');
});
it('should mutate everything', () => {
expectJSMutationWithLevel(
sut,
undefined,
'const bar = "bar"; const foo = `name: ${level_name}`; const emptyString=""; const emptyInterp=``',
'const bar = ""; const foo = `name: ${level_name}`; const emptyString=""; const emptyInterp=``', // empties string literal
'const bar = "bar"; const foo = ``; const emptyString=""; const emptyInterp=``', // empties interpolation
'const bar = "bar"; const foo = `name: ${level_name}`; const emptyString="Stryker was here!"; const emptyInterp=``', // fills string literal
'const bar = "bar"; const foo = `name: ${level_name}`; const emptyString=""; const emptyInterp=`Stryker was here!`', // fills interpolation
);
});
});
});
2 changes: 1 addition & 1 deletion testing-project/stryker.conf.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@
"name": "default",
"ArithmeticOperator": ["+To-", "-To+", "*To/"],
"ArrayDeclaration": ["EmptyArray", "FilledArray", "FilledArrayConstructor"],
"StringLiteral": ["EmptyString", "FillString", "EmptyInterpolation", "FillInterpolation"]
"BooleanLiteral": ["TrueToFalse", "RemoveNegation"]

},
{
"name": "fancy",
Expand Down