Skip to content

Commit

Permalink
fix(instrumenter): don't break optional chains(#3156)
Browse files Browse the repository at this point in the history
Don't break optional chains when a TypeScript `NonNullExpression` is involved

```diff
- input?.id!.toString();
+ stryMutAct_9fa48("1") ? input.id!.toString() : (stryCov_9fa48("1"), input?.id!.toString());
```

Instead of

```diff
- input?.id!.toString();
+ (stryMutAct_9fa48("1") ? input.id : (stryCov_9fa48("1"), input?.id))!.toString();
// breaks optional chain! 💥🔗
```


Co-authored-by: Nico Jansen <jansennico@gmail.com>
  • Loading branch information
simondel and nicojs authored Sep 30, 2021
1 parent 50deeb4 commit 95e6b69
Show file tree
Hide file tree
Showing 5 changed files with 10 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,8 @@ function isMemberOrCallExpression(path: NodePath) {
return isCallExpression(path) || isMemberExpression(path);
}

function isMemberExpression(path: NodePath): path is NodePath<types.MemberExpression | types.OptionalMemberExpression> {
return path.isMemberExpression() || path.isOptionalMemberExpression();
function isMemberExpression(path: NodePath): path is NodePath<types.MemberExpression | types.OptionalMemberExpression | types.TSNonNullExpression> {
return path.isMemberExpression() || path.isOptionalMemberExpression() || path.isTSNonNullExpression();
}

function isCallExpression(path: NodePath): path is NodePath<types.CallExpression | types.OptionalCallExpression> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ describe('instrumenter integration', () => {
await arrangeAndActAssert('lit-html-sample.ts');
});
it('should be able to instrument optional chains', async () => {
await arrangeAndActAssert('optional-chains.js');
await arrangeAndActAssert('optional-chains.ts');
});
it('should be able to instrument a vue sample', async () => {
await arrangeAndActAssert('vue-sample.vue');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { normalizeWhitespaces } from '@stryker-mutator/util';
import generate from '@babel/generator';

import { expressionMutantPlacer } from '../../../src/mutant-placers/expression-mutant-placer';
import { findNodePath, parseJS } from '../../helpers/syntax-test-helpers';
import { findNodePath, parseJS, parseTS } from '../../helpers/syntax-test-helpers';
import { Mutant } from '../../../src/mutant';
import { createMutant } from '../../helpers/factories';

Expand Down Expand Up @@ -75,10 +75,11 @@ describe('expressionMutantPlacer', () => {
['foo?.bar()', (p) => p.isOptionalMemberExpression() && types.isIdentifier(p.node.property, { name: 'bar' })],
['foo.bar?.baz', (p) => p.isMemberExpression() && types.isIdentifier(p.node.property, { name: 'bar' })],
['foo?.bar.baz', (p) => p.isOptionalMemberExpression() && types.isIdentifier(p.node.property, { name: 'bar' })],
['foo?.bar!.baz', (p) => p.isTSNonNullExpression()],
];
falsePointers.forEach(([js, query]) => {
it(`should not allow placing in \`bar\` of \`${js}\``, () => {
const path = findNodePath(parseJS(js), query);
const path = findNodePath(parseTS(js), query);
expect(expressionMutantPlacer.canPlace(path)).false;
});
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,5 @@ qux()?.map()
const directiveRanges = comments?.map(tryParseTSDirective)

const qux = quux(corge?.cov());

input?.id!.toString();
Original file line number Diff line number Diff line change
Expand Up @@ -66,5 +66,6 @@ function stryMutAct_9fa48(id) {
const baz = stryMutAct_9fa48(\\"0\\") ? foo?.bar?.()?.[1] && 'qux' : (stryCov_9fa48(\\"0\\"), (stryMutAct_9fa48(\\"3\\") ? foo.bar?.()?.[1] : stryMutAct_9fa48(\\"2\\") ? foo?.bar()?.[1] : stryMutAct_9fa48(\\"1\\") ? foo?.bar?.()[1] : (stryCov_9fa48(\\"1\\", \\"2\\", \\"3\\"), foo?.bar?.()?.[1])) ?? (stryMutAct_9fa48(\\"4\\") ? \\"\\" : (stryCov_9fa48(\\"4\\"), 'qux')));
stryMutAct_9fa48(\\"5\\") ? qux().map() : (stryCov_9fa48(\\"5\\"), qux()?.map());
const directiveRanges = stryMutAct_9fa48(\\"6\\") ? comments.map(tryParseTSDirective) : (stryCov_9fa48(\\"6\\"), comments?.map(tryParseTSDirective));
const qux = quux(stryMutAct_9fa48(\\"7\\") ? corge.cov() : (stryCov_9fa48(\\"7\\"), corge?.cov()));"
const qux = quux(stryMutAct_9fa48(\\"7\\") ? corge.cov() : (stryCov_9fa48(\\"7\\"), corge?.cov()));
stryMutAct_9fa48(\\"8\\") ? input.id!.toString() : (stryCov_9fa48(\\"8\\"), input?.id!.toString());"
`;

0 comments on commit 95e6b69

Please sign in to comment.