Skip to content

Issue #13328: Kill mutation ImportOrderCheck #13334

Merged
rnveach merged 1 commit intocheckstyle:masterfrom
Kevin222004:BeginTree3
Aug 2, 2023
Merged

Issue #13328: Kill mutation ImportOrderCheck #13334
rnveach merged 1 commit intocheckstyle:masterfrom
Kevin222004:BeginTree3

Conversation

@Kevin222004
Copy link
Copy Markdown
Contributor

@Kevin222004 Kevin222004 commented Jul 2, 2023

Issue #13328: Kill mutation ImportOrderCheck


Check

https://checkstyle.org/checks/imports/importorder.html#ImportOrder


Mutation

<mutation unstable="false">
<sourceFile>ImportOrderCheck.java</sourceFile>
<mutatedClass>com.puppycrawl.tools.checkstyle.checks.imports.ImportOrderCheck</mutatedClass>
<mutatedMethod>beginTree</mutatedMethod>
<mutator>org.pitest.mutationtest.engine.gregor.mutators.experimental.MemberVariableMutator</mutator>
<description>Removed assignment to member variable lastImportStatic</description>
<lineContent>lastImportStatic = false;</lineContent>
</mutation>


Explaination

begin tree always reset data. for lastImportStatic = false so we need to create two input somehow lastImportStatic become true while the sequentially second file will be come in process and that is easy we only have to set last import of first file as true.

lets start from visitToken
In visit token the parameter isStatic will check wether the current import is static or not.

final boolean isStatic;
if (ast.getType() == TokenTypes.IMPORT) {
ident = FullIdent.createFullIdentBelow(ast);
isStatic = false;
}
else {
ident = FullIdent.createFullIdent(ast.getFirstChild()
.getNextSibling());
isStatic = true;
}

To move further
all the condition

if (option == ImportOrderOption.TOP || option == ImportOrderOption.ABOVE) {
final boolean isStaticAndNotLastImport = isStatic && !lastImportStatic;
doVisitToken(ident, isStatic, isStaticAndNotLastImport, ast);
}
else if (option == ImportOrderOption.BOTTOM || option == ImportOrderOption.UNDER) {
final boolean isLastImportAndNonStatic = lastImportStatic && !isStatic;
doVisitToken(ident, isStatic, isLastImportAndNonStatic, ast);
}
else if (option == ImportOrderOption.INFLOW) {
// "previous" argument is useless here
doVisitToken(ident, isStatic, true, ast);
}

call doVisitToken know our target is to check that output get affected if remove lastimportStatic from beginTree

private void doVisitToken(FullIdent ident, boolean isStatic, boolean previous, DetailAST ast) {

know in doVisitToken only 2 parameter is iportant for us isStatic and previous

final boolean isStaticAndNotLastImport = isStatic && !lastImportStatic;
doVisitToken(ident, isStatic, isStaticAndNotLastImport, ast);

else if (option == ImportOrderOption.BOTTOM || option == ImportOrderOption.UNDER) {
final boolean isLastImportAndNonStatic = lastImportStatic && !isStatic;
doVisitToken(ident, isStatic, isLastImportAndNonStatic, ast);

because they and the reason is they are only one right know which related with lastimportstatic and violation throwing
and in the whole method previous is used only at

else if (groupIdx == lastGroup) {
doVisitTokenInSameGroup(isStatic, previous, name, ast);
}

know this condition is not big deal we can execute that and if we look closure on

private void doVisitTokenInSameGroup(boolean isStatic,
this will execute when which is by default true so that is not issue in that if never execute because in from visittoken condition.

know in else either


needs to be true or in that either
lastImportStatic == isStatic
&& isWrongOrder(name, isStatic);

this is need to be true

case 1
lets see the previous first we know that we need previos true and

if (option == ImportOrderOption.TOP || option == ImportOrderOption.ABOVE) {
final boolean isStaticAndNotLastImport = isStatic && !lastImportStatic;
doVisitToken(ident, isStatic, isStaticAndNotLastImport, ast);
}

lets suppose we set option as above so previous import needs to be nonStatic and current ast need to be static so from here it is for sure that
we want previous as true previous = true know suppose option is set to be true so previous value is comming from visitToken so we need top set isStatic = false and lastimportStatic = true so in previous file lastimportstatic needs to be non static it means false then if it already same then no need to be reset so begin tree is redundant.

know lets suppose option is set to Bottom or under

else if (option == ImportOrderOption.BOTTOM || option == ImportOrderOption.UNDER) {
final boolean isLastImportAndNonStatic = lastImportStatic && !isStatic;
doVisitToken(ident, isStatic, isLastImportAndNonStatic, ast);
}

in this case to set previous true we need to set lastimportstatic = true mean previous file import needs to be static and in current file ast needs to be non static it means isStatic=fasle and isLastImport=true in this case

else if (groupIdx == lastGroup) {
doVisitTokenInSameGroup(isStatic, previous, name, ast);
}
this never will be equal so conditon will never execute

this is alsosimilar if both are static

so no test cases looks possible to clear the state using input


Regression

Report-1 :- https://checkstyle-diff-reports.s3.us-east-2.amazonaws.com/920122e_2023074505/reports/diff/index.html

Report-2 :- https://checkstyle-diff-reports.s3.us-east-2.amazonaws.com/920122e_2023090228/reports/diff/index.html

Diff Regression config: https://gist.githubusercontent.com/Kevin222004/e3a00111b4bb7b8c054483466b88606d/raw/4895c88b1daf686479058c972bad0c27cd0818ef/IOC.xml
Diff Regression projects: https://gist.githubusercontent.com/Kevin222004/9600f179b602d4c971bdb0a050099005/raw/360a95ed7bb60d7a0956e531199d484c4d6f6617/test-projects.properties
Report label: new-Regression-1

@Kevin222004
Copy link
Copy Markdown
Contributor Author

Github, generate report

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Jul 2, 2023

@Kevin222004
Copy link
Copy Markdown
Contributor Author

Github, generate report

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Jul 2, 2023

Copy link
Copy Markdown
Member

@Vyom-Yadav Vyom-Yadav left a comment

Choose a reason for hiding this comment

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

LGTM!

@Vyom-Yadav Vyom-Yadav assigned rdiachenko and unassigned Vyom-Yadav Jul 8, 2023
@Vyom-Yadav
Copy link
Copy Markdown
Member

@Kevin222004 Logic looks correct to me, but to be on the safer side, please generate a report with both changes in this PR and in #13333. You can do it in a separate PR and link it back here.

@Kevin222004
Copy link
Copy Markdown
Contributor Author

Copy link
Copy Markdown
Member

@rdiachenko rdiachenko left a comment

Choose a reason for hiding this comment

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

lgtm

played with this trying multiple inputs and combinations, didn't manage to find a failure case

@rdiachenko rdiachenko assigned romani and unassigned rdiachenko Jul 18, 2023
@romani
Copy link
Copy Markdown
Member

romani commented Jul 20, 2023

This is great example of scary update :).
Right now, yes, maybe we can remove this cleanup.
But it gives opportunity for module to come to wrong state and eventually produce hard to catch unstable violations that will drive crazy our users.

What if we stay on safe side with clean up of all fields in class to default state ? I know we fighting a lot on such pitest in beginTree in other Checks, and before this I was ok, and we able to find coverage.

Proposal: make method resetToDefaultIgnoredByPitest and put there only fields resets we afraid to remove. And we exclude this method from pitest to consider. We do javadoc over it to explain that we damage design a bit in favor of pitest. It doesn't not mean we can easily apply same pattern to other Modules. Allowance to be in such method will be only by very special allowance.

Let's vote, If all agree, we can do this.

Copy link
Copy Markdown
Contributor

@rnveach rnveach left a comment

Choose a reason for hiding this comment

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

As I mentioned in discord, we have a special set of utils to kill mutations like this.

isStatefulFieldClearedDuringBeginTree

public static boolean isStatefulFieldClearedDuringBeginTree(AbstractCheck check,

It looks like visitToken always set the field at .
All that is needed is to have the field change its value using the isStatefulFieldClearedDuringBeginTree.

@rdiachenko
Copy link
Copy Markdown
Member

I'd go with what @rnveach suggests instead of having pitest specific methods in the check's class. It looks clenar and avoids questions like why we have such tool related methods in the mian code. If we do introduce resetToDefaultIgnoredByPitest sort of stuff, it opens opportunities to add similar things for violations from other tools if we can't cover them, which will make main code even more obscure.

@Kevin222004
Copy link
Copy Markdown
Contributor Author

Ok I have updated the pr with the test case suggested at #13334 (review)

Copy link
Copy Markdown
Member

@romani romani left a comment

Choose a reason for hiding this comment

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

Item:

Copy link
Copy Markdown
Member

@romani romani left a comment

Choose a reason for hiding this comment

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

ok to merge

@romani romani assigned rnveach and unassigned romani Jul 29, 2023




Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Why are we adding empty lines to this file?

Copy link
Copy Markdown
Contributor Author

@Kevin222004 Kevin222004 Aug 2, 2023

Choose a reason for hiding this comment

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

To avoid merge Conflicts

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Is the plan to remove them at some point if we can't remove the entire file?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yes, If the entire file is not removed then I will update this and remove it. so at the, it looks clean

But right know in this file 4 mutations are still left which is possible to cover

@rnveach rnveach merged commit 8c3b8fd into checkstyle:master Aug 2, 2023
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.

5 participants