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(group-mutants): checkers check groups of mutants #3366

Closed

Conversation

danny12321
Copy link
Contributor

@danny12321 danny12321 commented Jan 19, 2022

The checkers (also known as the TypeScript-checker) now receive an array of mutants. The group of mutants can be checked at once which will increase performance in larger projects.

ThierryRietveld and others added 30 commits September 10, 2021 11:14
@danny12321 danny12321 changed the title Group mutants feat(group-mutants): checkers check groups of mutants Jan 19, 2022
Copy link
Member

@nicojs nicojs left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wow, that seems to be about a half years work condensed into 1 PR 😅. Well done!

This is my first round of review comments. I didn't open in VSCode yet, so it was a colorful experience. I will have a closer look in the second round (after fixes are implemented). No time pressure, let's make sure we get it right.

Also: you probably want to merge epic/esm into this branch. Some of the changes will go away as well as the merge conflict.

await expectMetricsJson({
killed: 27,
mutationScore: 57.45,
killed: 25,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why the changes in score of e2e test?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change came from an upstream fetch.

package.json Outdated
"@typescript-eslint/eslint-plugin": "~5.9.1",
"@typescript-eslint/parser": "~5.9.1",
"@typescript-eslint/eslint-plugin": "~5.10.0",
"@typescript-eslint/parser": "~5.10.0",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why these changes here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change also came from an upstream fetch.


import { CheckResult } from './check-result';

export interface Checker {
init(): Promise<void>;

check(mutant: Mutant): Promise<CheckResult>;
check(mutant: MutantTestCoverage[]): Promise<Array<{ mutant: MutantTestCoverage; checkResult: CheckResult }>>;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now that I think about it, maybe a Promise<Record<string, CheckResult>> is better (keys are mutant ids). It would at least save a lot of duplicate data being serialized back to the core process.

if (!this.options.checkers.length) {
const checkResult$ = new Subject<MutantResult>();
checkResult$.complete();
return {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like this early return, but could we maybe implement this in the CheckerFascade class? I want this Executor class to not have to worry about these kinds of details.

mutant,
};
if (!this.options.checkers.length) {
const checkResult$ = new Subject<MutantResult>();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of creating a subject and completing it instantly, we can use empty()


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

export function createGroups(sourceFiles: SourceFiles, mutants: MutantTestCoverage[]): MutantTestCoverage[][] {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This probably deserves a JS doc explaining what we're doing and why.

continue;
}

let ignoreList = [firstSourceFile.fileName, ...firstSourceFile.importedBy];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can be a const. Instead of using ignoreList = [...ignoreList, val, val2] you can use ignoreList.push(val, val2). Also: you probably want to use a Set, because it is much more performant when checking for existence.

let groups: MutantTestCoverage[][] = [];

while (mutantsWithoutGroup.length) {
const firstMutant = mutantsWithoutGroup[0];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: use shift or pop to get a mutant from the list. That way, you also removed it (and don't need to start from 1 later).


function addGroupToList() {
// Can be improved, we know the index in the for loop but can't remove it because we loop over the same array we want te remove from
// A solution can be to store a array with indexes to remove
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably better yes.

if (possibleMutants.length === 1) {
mutantResults[mutantResults.findIndex((mutantResult) => mutantResult.mutant.id === possibleMutants[0].id)].errors.push(error);
} else if (possibleMutants.length > 1) {
possibleMutants.forEach((mutant) => mutantsToTestIndividual.add(mutant));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You probably want to log on debug level here. Useful information for debugging performance issues later.

@nicojs
Copy link
Member

nicojs commented Feb 13, 2022

I'm thinking of the best way to merge this in. Since this is a very big change and it already diverged from the base branch a lot. I mean, we've migrated to ESM in the meantime, literally changing very code file in our repository 😇.

We might be better off abandoning this branch, and instead, create fresh ones from epic/esm. To not make it big I think we should split it in 2 PR's:

  1. Changes in API and core, but without grouping in the TyperScript. So simply don't implement the group method, and do minimal changes to make the old implementation work with the new API.
  2. Add grouping algorithm and type checking to the TypeScript checker.

@danny12321 @ThierryRietveld do you agree with this approach? We've planned some more Stryker days next week Friday and the following Monday, maybe we can discuss it then?

I've also sent you guys invites to become contributors on StrykerJS. That way you can work on the stryker-mutator git remote directly. That will help with collaborating.

@nicojs nicojs added this to the 6.0 milestone Feb 13, 2022
@ThierryRietveld
Copy link
Contributor

Hi Nico, thanks for the invitation to join the Stryker team! @danny12321 and I agree that splitting the PR into two separate PR's is the best option to make it smaller. Next week Friday and Monday we got 'Open Leercentrum', so I don't know if we can get some time to participate in the Stryker days. This week I got some time to start the separation of this PR.

@nicojs
Copy link
Member

nicojs commented Feb 14, 2022

Ok, great. We can at least have a talk via teams. I'll plan a meeting. See you then, have fun in the mean time! 🤗

@nicojs
Copy link
Member

nicojs commented Mar 28, 2022

@ThierryRietveld @danny12321 is this PR still relevant? Or will you create a new one?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants