From 0ab016962a98727c61b9319f01d3c02f9a7adda0 Mon Sep 17 00:00:00 2001 From: Vyom-Yadav Date: Fri, 24 Jun 2022 18:32:21 +0530 Subject: [PATCH] Issue #11665: Create a robust method of surviving mutation suppression --- ...arterRuleSet-AllRulesByCategory.groovy.txt | 4 +- .ci/jsoref-spellchecker/whitelist.words | 4 + .../pitest-ant-suppressions.xml | 47 ++ .../pitest-coding-1-suppressions.xml | 137 ++++++ .../pitest-coding-2-suppressions.xml | 182 ++++++++ ...coding-require-this-check-suppressions.xml | 92 ++++ .../pitest-common-suppressions.xml | 92 ++++ .../pitest-header-suppressions.xml | 19 + .../pitest-imports-suppressions.xml | 47 ++ .../pitest-indentation-suppressions.xml | 227 ++++++++++ .../pitest-javadoc-suppressions.xml | 29 ++ ...itest.sh => pitest-survival-check-html.sh} | 0 .ci/pitest-survival-check-xml.groovy | 409 ++++++++++++++++++ .github/workflows/pitest.yml | 26 +- ...checkstyle_non_main_files_suppressions.xml | 5 +- pom.xml | 30 ++ 16 files changed, 1346 insertions(+), 4 deletions(-) create mode 100644 .ci/pitest-suppressions/pitest-ant-suppressions.xml create mode 100644 .ci/pitest-suppressions/pitest-coding-1-suppressions.xml create mode 100644 .ci/pitest-suppressions/pitest-coding-2-suppressions.xml create mode 100644 .ci/pitest-suppressions/pitest-coding-require-this-check-suppressions.xml create mode 100644 .ci/pitest-suppressions/pitest-common-suppressions.xml create mode 100644 .ci/pitest-suppressions/pitest-header-suppressions.xml create mode 100644 .ci/pitest-suppressions/pitest-imports-suppressions.xml create mode 100644 .ci/pitest-suppressions/pitest-indentation-suppressions.xml create mode 100644 .ci/pitest-suppressions/pitest-javadoc-suppressions.xml rename .ci/{pitest.sh => pitest-survival-check-html.sh} (100%) create mode 100644 .ci/pitest-survival-check-xml.groovy diff --git a/.ci/StarterRuleSet-AllRulesByCategory.groovy.txt b/.ci/StarterRuleSet-AllRulesByCategory.groovy.txt index 196a7aa11b2..563b9a7f50c 100644 --- a/.ci/StarterRuleSet-AllRulesByCategory.groovy.txt +++ b/.ci/StarterRuleSet-AllRulesByCategory.groovy.txt @@ -343,7 +343,9 @@ ruleset { NonFinalSubclassOfSensitiveInterface ObjectFinalize PublicFinalizeMethod - SystemExit + SystemExit { + doNotApplyToFileNames = 'pitest-survival-check-xml.groovy' + } UnsafeArrayDeclaration // rulesets/serialization.xml diff --git a/.ci/jsoref-spellchecker/whitelist.words b/.ci/jsoref-spellchecker/whitelist.words index 519e30cb995..3d29b7febbe 100644 --- a/.ci/jsoref-spellchecker/whitelist.words +++ b/.ci/jsoref-spellchecker/whitelist.words @@ -516,6 +516,7 @@ googlegroups googlesource Gorm govstrangefolder +GPath gpg gradle gradlew @@ -866,6 +867,7 @@ multiplevariabledeclarations Multiset multithreading mutableexception +mutationtest MVC mvn mvnw @@ -1210,6 +1212,8 @@ sivakumar Slawinski slf slist +Slurper +slurpersupport Sms smth snyk diff --git a/.ci/pitest-suppressions/pitest-ant-suppressions.xml b/.ci/pitest-suppressions/pitest-ant-suppressions.xml new file mode 100644 index 00000000000..2987c4da44f --- /dev/null +++ b/.ci/pitest-suppressions/pitest-ant-suppressions.xml @@ -0,0 +1,47 @@ + + + + CheckstyleAntTask.java + com.puppycrawl.tools.checkstyle.ant.CheckstyleAntTask + execute + org.pitest.mutationtest.engine.gregor.mutators.MathMutator + Replaced long subtraction with addition + log("Total execution took " + (endTime - startTime) + TIME_SUFFIX, + + + + CheckstyleAntTask.java + com.puppycrawl.tools.checkstyle.ant.CheckstyleAntTask + processFiles + org.pitest.mutationtest.engine.gregor.mutators.MathMutator + Replaced long subtraction with addition + log("To locate the files took " + (endTime - startTime) + TIME_SUFFIX, + + + + CheckstyleAntTask.java + com.puppycrawl.tools.checkstyle.ant.CheckstyleAntTask + processFiles + org.pitest.mutationtest.engine.gregor.mutators.MathMutator + Replaced long subtraction with addition + log("To process the files took " + (processingEndTime - processingStartTime) + + + + CheckstyleAntTask.java + com.puppycrawl.tools.checkstyle.ant.CheckstyleAntTask$Formatter + createDefaultLogger + org.pitest.mutationtest.engine.gregor.mutators.RemoveConditionalMutator_EQUAL_IF + removed conditional - replaced equality check with true + if (toFile == null || !useFile) { + + + + CheckstyleAntTask.java + com.puppycrawl.tools.checkstyle.ant.CheckstyleAntTask$Formatter + createXmlLogger + org.pitest.mutationtest.engine.gregor.mutators.RemoveConditionalMutator_EQUAL_IF + removed conditional - replaced equality check with true + if (toFile == null || !useFile) { + + diff --git a/.ci/pitest-suppressions/pitest-coding-1-suppressions.xml b/.ci/pitest-suppressions/pitest-coding-1-suppressions.xml new file mode 100644 index 00000000000..714ca4c30ca --- /dev/null +++ b/.ci/pitest-suppressions/pitest-coding-1-suppressions.xml @@ -0,0 +1,137 @@ + + + + UnnecessaryParenthesesCheck.java + com.puppycrawl.tools.checkstyle.checks.coding.UnnecessaryParenthesesCheck + isLambdaSingleParameterSurrounded + org.pitest.mutationtest.engine.gregor.mutators.RemoveConditionalMutator_EQUAL_IF + removed conditional - replaced equality check with true + if (firstChild != null && firstChild.getType() == TokenTypes.LPAREN) { + + + + UnnecessaryParenthesesCheck.java + com.puppycrawl.tools.checkstyle.checks.coding.UnnecessaryParenthesesCheck + leaveToken + org.pitest.mutationtest.engine.gregor.mutators.RemoveConditionalMutator_EQUAL_ELSE + removed conditional - replaced equality check with false + if (type != TokenTypes.ASSIGN + + + + UnnecessaryParenthesesCheck.java + com.puppycrawl.tools.checkstyle.checks.coding.UnnecessaryParenthesesCheck + leaveToken + org.pitest.mutationtest.engine.gregor.mutators.RemoveConditionalMutator_EQUAL_IF + removed conditional - replaced equality check with true + || parent.getType() != TokenTypes.ANNOTATION_MEMBER_VALUE_PAIR) { + + + + UnnecessaryParenthesesCheck.java + com.puppycrawl.tools.checkstyle.checks.coding.UnnecessaryParenthesesCheck + visitToken + org.pitest.mutationtest.engine.gregor.mutators.RemoveConditionalMutator_EQUAL_IF + removed conditional - replaced equality check with true + else if (type != TokenTypes.ASSIGN + + + + UnnecessaryParenthesesCheck.java + com.puppycrawl.tools.checkstyle.checks.coding.UnnecessaryParenthesesCheck + visitToken + org.pitest.mutationtest.engine.gregor.mutators.RemoveConditionalMutator_EQUAL_IF + removed conditional - replaced equality check with true + if (type == TokenTypes.LAMBDA && isLambdaSingleParameterSurrounded(ast)) { + + + + VariableDeclarationUsageDistanceCheck.java + com.puppycrawl.tools.checkstyle.checks.coding.VariableDeclarationUsageDistanceCheck + calculateDistanceInSingleScope + org.pitest.mutationtest.engine.gregor.mutators.RemoveConditionalMutator_EQUAL_IF + removed conditional - replaced equality check with true + && currentAst.getType() != TokenTypes.RCURLY) { + + + + VariableDeclarationUsageDistanceCheck.java + com.puppycrawl.tools.checkstyle.checks.coding.VariableDeclarationUsageDistanceCheck + calculateDistanceInSingleScope + org.pitest.mutationtest.engine.gregor.mutators.RemoveConditionalMutator_EQUAL_ELSE + removed conditional - replaced equality check with false + if (!firstUsageFound) { + + + + VariableDeclarationUsageDistanceCheck.java + com.puppycrawl.tools.checkstyle.checks.coding.VariableDeclarationUsageDistanceCheck + getFirstNodeInsideForWhileDoWhileBlocks + org.pitest.mutationtest.engine.gregor.mutators.RemoveConditionalMutator_EQUAL_ELSE + removed conditional - replaced equality check with false + if (currentNodeType == TokenTypes.SLIST) { + + + + VariableDeclarationUsageDistanceCheck.java + com.puppycrawl.tools.checkstyle.checks.coding.VariableDeclarationUsageDistanceCheck + getFirstNodeInsideIfBlock + org.pitest.mutationtest.engine.gregor.mutators.RemoveConditionalMutator_EQUAL_ELSE + removed conditional - replaced equality check with false + else if (isChild(currentNode, variable)) { + + + + VariableDeclarationUsageDistanceCheck.java + com.puppycrawl.tools.checkstyle.checks.coding.VariableDeclarationUsageDistanceCheck + getFirstNodeInsideIfBlock + org.pitest.mutationtest.engine.gregor.mutators.RemoveConditionalMutator_EQUAL_ELSE + removed conditional - replaced equality check with false + if (currentNode.getType() == TokenTypes.LITERAL_IF) { + + + + VariableDeclarationUsageDistanceCheck.java + com.puppycrawl.tools.checkstyle.checks.coding.VariableDeclarationUsageDistanceCheck + getFirstNodeInsideTryCatchFinallyBlocks + org.pitest.mutationtest.engine.gregor.mutators.RemoveConditionalMutator_EQUAL_IF + removed conditional - replaced equality check with true + && currentNode.getType() == TokenTypes.LITERAL_CATCH) { + + + + VariableDeclarationUsageDistanceCheck.java + com.puppycrawl.tools.checkstyle.checks.coding.VariableDeclarationUsageDistanceCheck + isChild + org.pitest.mutationtest.engine.gregor.mutators.RemoveConditionalMutator_EQUAL_IF + removed conditional - replaced equality check with true + if (curNode.getType() == ast.getType() && curNode.getText().equals(ast.getText())) { + + + + VariableDeclarationUsageDistanceCheck.java + com.puppycrawl.tools.checkstyle.checks.coding.VariableDeclarationUsageDistanceCheck + isInitializationSequence + org.pitest.mutationtest.engine.gregor.mutators.RemoveConditionalMutator_EQUAL_IF + removed conditional - replaced equality check with true + while (result + + + + VariableDeclarationUsageDistanceCheck.java + com.puppycrawl.tools.checkstyle.checks.coding.VariableDeclarationUsageDistanceCheck + isVariableInOperatorExpr + org.pitest.mutationtest.engine.gregor.mutators.RemoveConditionalMutator_EQUAL_IF + removed conditional - replaced equality check with true + if (!isVarInOperatorDeclaration && operator.getType() == TokenTypes.LITERAL_IF) { + + + + VariableDeclarationUsageDistanceCheck.java + com.puppycrawl.tools.checkstyle.checks.coding.VariableDeclarationUsageDistanceCheck + searchVariableUsageExpressions + org.pitest.mutationtest.engine.gregor.mutators.RemoveConditionalMutator_EQUAL_IF + removed conditional - replaced equality check with true + && currentStatementAst.getType() != TokenTypes.RCURLY) { + + diff --git a/.ci/pitest-suppressions/pitest-coding-2-suppressions.xml b/.ci/pitest-suppressions/pitest-coding-2-suppressions.xml new file mode 100644 index 00000000000..4aea1e54125 --- /dev/null +++ b/.ci/pitest-suppressions/pitest-coding-2-suppressions.xml @@ -0,0 +1,182 @@ + + + + FinalLocalVariableCheck.java + com.puppycrawl.tools.checkstyle.checks.coding.FinalLocalVariableCheck + findLastChildWhichContainsSpecifiedToken + org.pitest.mutationtest.engine.gregor.mutators.RemoveConditionalMutator_EQUAL_IF + removed conditional - replaced equality check with true + if (astIterator.getType() == childType + + + + FinalLocalVariableCheck.java + com.puppycrawl.tools.checkstyle.checks.coding.FinalLocalVariableCheck + isCaseTokenWithAnotherCaseFollowing + org.pitest.mutationtest.engine.gregor.mutators.RemoveConditionalMutator_EQUAL_IF + removed conditional - replaced equality check with true + result = findLastChildWhichContainsSpecifiedToken( + + + + FinalLocalVariableCheck.java + com.puppycrawl.tools.checkstyle.checks.coding.FinalLocalVariableCheck + isIfTokenWithAnElseFollowing + org.pitest.mutationtest.engine.gregor.mutators.RemoveConditionalMutator_EQUAL_IF + removed conditional - replaced equality check with true + return ast.getType() == TokenTypes.LITERAL_IF + + + + FinalLocalVariableCheck.java + com.puppycrawl.tools.checkstyle.checks.coding.FinalLocalVariableCheck + isInTheSameLoop + org.pitest.mutationtest.engine.gregor.mutators.RemoveConditionalMutator_EQUAL_IF + removed conditional - replaced equality check with true + return loop1 != null && loop1 == loop2; + + + + FinalLocalVariableCheck.java + com.puppycrawl.tools.checkstyle.checks.coding.FinalLocalVariableCheck + updateUninitializedVariables + org.pitest.mutationtest.engine.gregor.mutators.RemoveConditionalMutator_EQUAL_IF + removed conditional - replaced equality check with true + && isSameVariables(storedVariable, variable) + + + + FinalLocalVariableCheck.java + com.puppycrawl.tools.checkstyle.checks.coding.FinalLocalVariableCheck + visitToken + org.pitest.mutationtest.engine.gregor.mutators.RemoveConditionalMutator_EQUAL_IF + removed conditional - replaced equality check with true + == ast.getParent()) { + + + + FinalLocalVariableCheck.java + com.puppycrawl.tools.checkstyle.checks.coding.FinalLocalVariableCheck + visitToken + org.pitest.mutationtest.engine.gregor.mutators.RemoveConditionalMutator_EQUAL_IF + removed conditional - replaced equality check with true + if (ast.getParent().getType() == TokenTypes.SWITCH_RULE + + + + HiddenFieldCheck.java + com.puppycrawl.tools.checkstyle.checks.coding.HiddenFieldCheck + isIgnoredParamOfAbstractMethod + org.pitest.mutationtest.engine.gregor.mutators.RemoveConditionalMutator_EQUAL_IF + removed conditional - replaced equality check with true + && ast.getType() == TokenTypes.PARAMETER_DEF) { + + + + HiddenFieldCheck.java + com.puppycrawl.tools.checkstyle.checks.coding.HiddenFieldCheck + isIgnoredParamOfAbstractMethod + org.pitest.mutationtest.engine.gregor.mutators.RemoveConditionalMutator_EQUAL_IF + removed conditional - replaced equality check with true + if (method.getType() == TokenTypes.METHOD_DEF) { + + + + HiddenFieldCheck.java + com.puppycrawl.tools.checkstyle.checks.coding.HiddenFieldCheck + isIgnoredSetterParam + org.pitest.mutationtest.engine.gregor.mutators.RemoveConditionalMutator_EQUAL_IF + removed conditional - replaced equality check with true + && methodAST.getType() == TokenTypes.METHOD_DEF + + + + HiddenFieldCheck.java + com.puppycrawl.tools.checkstyle.checks.coding.HiddenFieldCheck + isIgnoredSetterParam + org.pitest.mutationtest.engine.gregor.mutators.RemoveConditionalMutator_EQUAL_IF + removed conditional - replaced equality check with true + if (ignoreSetter && ast.getType() == TokenTypes.PARAMETER_DEF) { + + + + HiddenFieldCheck.java + com.puppycrawl.tools.checkstyle.checks.coding.HiddenFieldCheck + processLambda + org.pitest.mutationtest.engine.gregor.mutators.RemoveConditionalMutator_EQUAL_IF + removed conditional - replaced equality check with true + && firstChild.getType() == TokenTypes.IDENT) { + + + + HiddenFieldCheck.java + com.puppycrawl.tools.checkstyle.checks.coding.HiddenFieldCheck + visitOtherTokens + org.pitest.mutationtest.engine.gregor.mutators.RemoveConditionalMutator_EQUAL_ELSE + removed conditional - replaced equality check with false + if (type == TokenTypes.CLASS_DEF + + + + HiddenFieldCheck.java + com.puppycrawl.tools.checkstyle.checks.coding.HiddenFieldCheck + visitOtherTokens + org.pitest.mutationtest.engine.gregor.mutators.RemoveConditionalMutator_EQUAL_IF + removed conditional - replaced equality check with true + if (type == TokenTypes.CLASS_DEF + + + + IllegalInstantiationCheck.java + com.puppycrawl.tools.checkstyle.checks.coding.IllegalInstantiationCheck + isStandardClass + org.pitest.mutationtest.engine.gregor.mutators.RemoveConditionalMutator_EQUAL_IF + removed conditional - replaced equality check with true + && illegal.startsWith(JAVA_LANG)) { + + + + OneStatementPerLineCheck.java + com.puppycrawl.tools.checkstyle.checks.coding.OneStatementPerLineCheck + checkIfSemicolonIsInDifferentLineThanPrevious + org.pitest.mutationtest.engine.gregor.mutators.RemoveConditionalMutator_EQUAL_ELSE + removed conditional - replaced equality check with false + && currentStatement.getPreviousSibling().getType() == TokenTypes.RESOURCES; + + + + OneStatementPerLineCheck.java + com.puppycrawl.tools.checkstyle.checks.coding.OneStatementPerLineCheck + checkIfSemicolonIsInDifferentLineThanPrevious + org.pitest.mutationtest.engine.gregor.mutators.RemoveConditionalMutator_EQUAL_ELSE + removed conditional - replaced equality check with false + currentStatement.getPreviousSibling() != null + + + + OneStatementPerLineCheck.java + com.puppycrawl.tools.checkstyle.checks.coding.OneStatementPerLineCheck + checkIfSemicolonIsInDifferentLineThanPrevious + org.pitest.mutationtest.engine.gregor.mutators.RemoveConditionalMutator_EQUAL_IF + removed conditional - replaced equality check with true + if (!hasResourcesPrevSibling && isMultilineStatement(currentStatement)) { + + + + OneStatementPerLineCheck.java + com.puppycrawl.tools.checkstyle.checks.coding.OneStatementPerLineCheck + isMultilineStatement + org.pitest.mutationtest.engine.gregor.mutators.RemoveConditionalMutator_EQUAL_IF + removed conditional - replaced equality check with true + multiline = !TokenUtil.areOnSameLine(prevSibling, ast) + + + + OneStatementPerLineCheck.java + com.puppycrawl.tools.checkstyle.checks.coding.OneStatementPerLineCheck + leaveToken + org.pitest.mutationtest.engine.gregor.mutators.RemoveConditionalMutator_EQUAL_IF + removed conditional - replaced equality check with true + if (countOfSemiInLambda.isEmpty()) { + + diff --git a/.ci/pitest-suppressions/pitest-coding-require-this-check-suppressions.xml b/.ci/pitest-suppressions/pitest-coding-require-this-check-suppressions.xml new file mode 100644 index 00000000000..3bf57197635 --- /dev/null +++ b/.ci/pitest-suppressions/pitest-coding-require-this-check-suppressions.xml @@ -0,0 +1,92 @@ + + + + RequireThisCheck.java + com.puppycrawl.tools.checkstyle.checks.coding.RequireThisCheck + beginTree + org.pitest.mutationtest.engine.gregor.mutators.RemoveConditionalMutator_EQUAL_IF + removed conditional - replaced equality check with true + if (toVisit == null) { + + + + RequireThisCheck.java + com.puppycrawl.tools.checkstyle.checks.coding.RequireThisCheck + canBeReferencedFromStaticContext + org.pitest.mutationtest.engine.gregor.mutators.RemoveConditionalMutator_EQUAL_ELSE + removed conditional - replaced equality check with false + if (definitionToken.getType() == TokenTypes.STATIC_INIT) { + + + + RequireThisCheck.java + com.puppycrawl.tools.checkstyle.checks.coding.RequireThisCheck + canBeReferencedFromStaticContext + org.pitest.mutationtest.engine.gregor.mutators.RemoveConditionalMutator_EQUAL_IF + removed conditional - replaced equality check with true + if (variableDeclarationFrame.getType() == FrameType.CLASS_FRAME) { + + + + RequireThisCheck.java + com.puppycrawl.tools.checkstyle.checks.coding.RequireThisCheck + collectDeclarations + org.pitest.mutationtest.engine.gregor.mutators.RemoveConditionalMutator_EQUAL_IF + removed conditional - replaced equality check with true + && ast.getParent().getType() != TokenTypes.LITERAL_CATCH) { + + + + RequireThisCheck.java + com.puppycrawl.tools.checkstyle.checks.coding.RequireThisCheck + endCollectingDeclarations + org.pitest.mutationtest.engine.gregor.mutators.RemoveConditionalMutator_EQUAL_ELSE + removed conditional - replaced equality check with false + if (isAnonymousClassDef(ast)) { + + + + RequireThisCheck.java + com.puppycrawl.tools.checkstyle.checks.coding.RequireThisCheck + getCodeBlockDefinitionToken + org.pitest.mutationtest.engine.gregor.mutators.RemoveConditionalMutator_EQUAL_IF + removed conditional - replaced equality check with true + && parent.getType() != TokenTypes.CTOR_DEF + + + + RequireThisCheck.java + com.puppycrawl.tools.checkstyle.checks.coding.RequireThisCheck + isAnonymousClassDef + org.pitest.mutationtest.engine.gregor.mutators.RemoveConditionalMutator_EQUAL_IF + removed conditional - replaced equality check with true + && lastChild.getType() == TokenTypes.OBJBLOCK; + + + + RequireThisCheck.java + com.puppycrawl.tools.checkstyle.checks.coding.RequireThisCheck + isAstSimilar + org.pitest.mutationtest.engine.gregor.mutators.RemoveConditionalMutator_EQUAL_IF + removed conditional - replaced equality check with true + return left.getType() == right.getType() && left.getText().equals(right.getText()); + + + + RequireThisCheck.java + com.puppycrawl.tools.checkstyle.checks.coding.RequireThisCheck + isInsideConstructorFrame + org.pitest.mutationtest.engine.gregor.mutators.RemoveConditionalMutator_EQUAL_IF + removed conditional - replaced equality check with true + if (fieldUsageFrame.getType() == FrameType.BLOCK_FRAME) { + + + + RequireThisCheck.java + com.puppycrawl.tools.checkstyle.checks.coding.RequireThisCheck + isOverlappingByLocalVariable + org.pitest.mutationtest.engine.gregor.mutators.RemoveConditionalMutator_EQUAL_IF + removed conditional - replaced equality check with true + if (sibling != null && isAssignToken(parent.getType())) { + + diff --git a/.ci/pitest-suppressions/pitest-common-suppressions.xml b/.ci/pitest-suppressions/pitest-common-suppressions.xml new file mode 100644 index 00000000000..124e956b306 --- /dev/null +++ b/.ci/pitest-suppressions/pitest-common-suppressions.xml @@ -0,0 +1,92 @@ + + + + Checker.java + com.puppycrawl.tools.checkstyle.Checker + processFiles + org.pitest.mutationtest.engine.gregor.mutators.RemoveConditionalMutator_EQUAL_ELSE + removed conditional - replaced equality check with false + if (cacheFile != null && cacheFile.isInCache(fileName, timestamp) + + + + Checker.java + com.puppycrawl.tools.checkstyle.Checker + processFiles + org.pitest.mutationtest.engine.gregor.mutators.RemoveConditionalMutator_EQUAL_IF + removed conditional - replaced equality check with true + if (cacheFile != null && cacheFile.isInCache(fileName, timestamp) + + + + DefaultLogger.java + com.puppycrawl.tools.checkstyle.DefaultLogger + <init> + org.pitest.mutationtest.engine.gregor.mutators.RemoveConditionalMutator_EQUAL_IF + removed conditional - replaced equality check with true + closeError = errorStreamOptions == OutputStreamOptions.CLOSE; + + + + DefaultLogger.java + com.puppycrawl.tools.checkstyle.DefaultLogger + <init> + org.pitest.mutationtest.engine.gregor.mutators.RemoveConditionalMutator_EQUAL_IF + removed conditional - replaced equality check with true + closeInfo = infoStreamOptions == OutputStreamOptions.CLOSE; + + + + DefaultLogger.java + com.puppycrawl.tools.checkstyle.DefaultLogger + addError + org.pitest.mutationtest.engine.gregor.mutators.RemoveConditionalMutator_EQUAL_IF + removed conditional - replaced equality check with true + if (severityLevel != SeverityLevel.IGNORE) { + + + + DefaultLogger.java + com.puppycrawl.tools.checkstyle.DefaultLogger + closeStreams + org.pitest.mutationtest.engine.gregor.mutators.RemoveConditionalMutator_EQUAL_IF + removed conditional - replaced equality check with true + if (closeError) { + + + + DefaultLogger.java + com.puppycrawl.tools.checkstyle.DefaultLogger + closeStreams + org.pitest.mutationtest.engine.gregor.mutators.RemoveConditionalMutator_EQUAL_IF + removed conditional - replaced equality check with true + if (closeInfo) { + + + + PackageObjectFactory.java + com.puppycrawl.tools.checkstyle.PackageObjectFactory + createModule + org.pitest.mutationtest.engine.gregor.mutators.RemoveConditionalMutator_EQUAL_IF + removed conditional - replaced equality check with true + if (!name.contains(PACKAGE_SEPARATOR)) { + + + + PackageObjectFactory.java + com.puppycrawl.tools.checkstyle.PackageObjectFactory + createModule + org.pitest.mutationtest.engine.gregor.mutators.RemoveConditionalMutator_EQUAL_IF + removed conditional - replaced equality check with true + if (instance == null + + + + PackageObjectFactory.java + com.puppycrawl.tools.checkstyle.PackageObjectFactory + createModule + org.pitest.mutationtest.engine.gregor.mutators.RemoveConditionalMutator_EQUAL_IF + removed conditional - replaced equality check with true + if (thirdPartyNameToFullModuleNames == null) { + + diff --git a/.ci/pitest-suppressions/pitest-header-suppressions.xml b/.ci/pitest-suppressions/pitest-header-suppressions.xml new file mode 100644 index 00000000000..af1463a5f84 --- /dev/null +++ b/.ci/pitest-suppressions/pitest-header-suppressions.xml @@ -0,0 +1,19 @@ + + + + RegexpHeaderCheck.java + com.puppycrawl.tools.checkstyle.checks.header.RegexpHeaderCheck + processFiltered + org.pitest.mutationtest.engine.gregor.mutators.RemoveConditionalMutator_EQUAL_ELSE + removed conditional - replaced equality check with false + isMatch = headerLineNo == headerSize + + + RegexpHeaderCheck.java + com.puppycrawl.tools.checkstyle.checks.header.RegexpHeaderCheck + processFiltered + org.pitest.mutationtest.engine.gregor.mutators.RemoveConditionalMutator_EQUAL_IF + removed conditional - replaced equality check with true + || isMatch(line, headerLineNo); + + diff --git a/.ci/pitest-suppressions/pitest-imports-suppressions.xml b/.ci/pitest-suppressions/pitest-imports-suppressions.xml new file mode 100644 index 00000000000..9789588e9d0 --- /dev/null +++ b/.ci/pitest-suppressions/pitest-imports-suppressions.xml @@ -0,0 +1,47 @@ + + + + ImportControlLoader.java + com.puppycrawl.tools.checkstyle.checks.imports.ImportControlLoader + startElement + org.pitest.mutationtest.engine.gregor.mutators.RemoveConditionalMutator_EQUAL_ELSE + removed conditional - replaced equality check with false + else if (ALLOW_ELEMENT_NAME.equals(qName) || "disallow".equals(qName)) { + + + + ImportControlLoader.java + com.puppycrawl.tools.checkstyle.checks.imports.ImportControlLoader + startElement + org.pitest.mutationtest.engine.gregor.mutators.RemoveConditionalMutator_EQUAL_IF + removed conditional - replaced equality check with true + else if (ALLOW_ELEMENT_NAME.equals(qName) || "disallow".equals(qName)) { + + + + PkgImportControl.java + com.puppycrawl.tools.checkstyle.checks.imports.PkgImportControl + <init> + org.pitest.mutationtest.engine.gregor.mutators.RemoveConditionalMutator_EQUAL_ELSE + removed conditional - replaced equality check with false + if (regex || parent.regex) { + + + + PkgImportControl.java + com.puppycrawl.tools.checkstyle.checks.imports.PkgImportControl + <init> + org.pitest.mutationtest.engine.gregor.mutators.RemoveConditionalMutator_EQUAL_IF + removed conditional - replaced equality check with true + if (regex || parent.regex) { + + + + PkgImportControl.java + com.puppycrawl.tools.checkstyle.checks.imports.PkgImportControl + matchesExactly + org.pitest.mutationtest.engine.gregor.mutators.RemoveConditionalMutator_EQUAL_ELSE + removed conditional - replaced equality check with false + if (regex) { + + diff --git a/.ci/pitest-suppressions/pitest-indentation-suppressions.xml b/.ci/pitest-suppressions/pitest-indentation-suppressions.xml new file mode 100644 index 00000000000..08008b53165 --- /dev/null +++ b/.ci/pitest-suppressions/pitest-indentation-suppressions.xml @@ -0,0 +1,227 @@ + + + + AbstractExpressionHandler.java + com.puppycrawl.tools.checkstyle.checks.indentation.AbstractExpressionHandler + findSubtreeAst + org.pitest.mutationtest.engine.gregor.mutators.ConditionalsBoundaryMutator + changed conditional boundary + if (colNum == null || thisLineColumn < colNum) { + + + + AbstractExpressionHandler.java + com.puppycrawl.tools.checkstyle.checks.indentation.AbstractExpressionHandler + getFirstAstNode + org.pitest.mutationtest.engine.gregor.mutators.ConditionalsBoundaryMutator + changed conditional boundary + && curNode.getColumnNo() < realStart.getColumnNo()) { + + + + AbstractExpressionHandler.java + com.puppycrawl.tools.checkstyle.checks.indentation.AbstractExpressionHandler + getFirstToken + org.pitest.mutationtest.engine.gregor.mutators.ConditionalsBoundaryMutator + changed conditional boundary + if (toTest.getColumnNo() < first.getColumnNo()) { + + + + BlockParentHandler.java + com.puppycrawl.tools.checkstyle.checks.indentation.BlockParentHandler + getLineWrappingIndent + org.pitest.mutationtest.engine.gregor.mutators.ReturnValsMutator + replaced return of integer sized value with (x == 0 ? 1 : 0) + return getIndentCheck().getLineWrappingIndentation(); + + + + CommentsIndentationCheck.java + com.puppycrawl.tools.checkstyle.checks.indentation.CommentsIndentationCheck + findPreviousStatement + org.pitest.mutationtest.engine.gregor.mutators.NegateConditionalsMutator + negated conditional + if (root.getFirstChild().getType() == TokenTypes.LITERAL_NEW) { + + + + CommentsIndentationCheck.java + com.puppycrawl.tools.checkstyle.checks.indentation.CommentsIndentationCheck + findPreviousStatement + org.pitest.mutationtest.engine.gregor.mutators.ConditionalsBoundaryMutator + changed conditional boundary + if (root.getLineNo() >= comment.getLineNo()) { + + + + CommentsIndentationCheck.java + com.puppycrawl.tools.checkstyle.checks.indentation.CommentsIndentationCheck + findTokenWhichBeginsTheLine + org.pitest.mutationtest.engine.gregor.mutators.NegateConditionalsMutator + negated conditional + if (isUsingOfObjectReferenceToInvokeMethod(root)) { + + + + CommentsIndentationCheck.java + com.puppycrawl.tools.checkstyle.checks.indentation.CommentsIndentationCheck + getPrevStatementWhenCommentIsUnderCase + org.pitest.mutationtest.engine.gregor.mutators.NegateConditionalsMutator + negated conditional + if (isUsingOfObjectReferenceToInvokeMethod(blockBody)) { + + + + CommentsIndentationCheck.java + com.puppycrawl.tools.checkstyle.checks.indentation.CommentsIndentationCheck + isUsingOfObjectReferenceToInvokeMethod + org.pitest.mutationtest.engine.gregor.mutators.NegateConditionalsMutator + negated conditional + && root.getFirstChild().getFirstChild().getFirstChild().getNextSibling() != null; + + + + CommentsIndentationCheck.java + com.puppycrawl.tools.checkstyle.checks.indentation.CommentsIndentationCheck + isUsingOfObjectReferenceToInvokeMethod + org.pitest.mutationtest.engine.gregor.mutators.ReturnValsMutator + replaced return of integer sized value with (x == 0 ? 1 : 0) + return root.getFirstChild().getFirstChild().getFirstChild() != null + + + + CommentsIndentationCheck.java + com.puppycrawl.tools.checkstyle.checks.indentation.CommentsIndentationCheck + isUsingOfObjectReferenceToInvokeMethod + org.pitest.mutationtest.engine.gregor.mutators.returns.BooleanTrueReturnValsMutator + replaced boolean return with true for com/puppycrawl/tools/checkstyle/checks/indentation/CommentsIndentationCheck::isUsingOfObjectReferenceToInvokeMethod + return root.getFirstChild().getFirstChild().getFirstChild() != null + + + + HandlerFactory.java + com.puppycrawl.tools.checkstyle.checks.indentation.HandlerFactory + <init> + org.pitest.mutationtest.engine.gregor.mutators.VoidMethodCallMutator + removed call to com/puppycrawl/tools/checkstyle/checks/indentation/HandlerFactory::register + register(TokenTypes.INDEX_OP, IndexHandler.class); + + + + HandlerFactory.java + com.puppycrawl.tools.checkstyle.checks.indentation.HandlerFactory + clearCreatedHandlers + org.pitest.mutationtest.engine.gregor.mutators.VoidMethodCallMutator + removed call to java/util/Map::clear + createdHandlers.clear(); + + + + IndentationCheck.java + com.puppycrawl.tools.checkstyle.checks.indentation.IndentationCheck + beginTree + org.pitest.mutationtest.engine.gregor.mutators.VoidMethodCallMutator + removed call to com/puppycrawl/tools/checkstyle/checks/indentation/HandlerFactory::clearCreatedHandlers + handlerFactory.clearCreatedHandlers(); + + + + IndentationCheck.java + com.puppycrawl.tools.checkstyle.checks.indentation.IndentationCheck + beginTree + org.pitest.mutationtest.engine.gregor.mutators.VoidMethodCallMutator + removed call to java/util/Deque::clear + handlers.clear(); + + + + IndentationCheck.java + com.puppycrawl.tools.checkstyle.checks.indentation.IndentationCheck + beginTree + org.pitest.mutationtest.engine.gregor.mutators.VoidMethodCallMutator + removed call to com/puppycrawl/tools/checkstyle/checks/indentation/PrimordialHandler::checkIndentation + primordialHandler.checkIndentation(); + + + + MethodDefHandler.java + com.puppycrawl.tools.checkstyle.checks.indentation.MethodDefHandler + getMethodDefLineStart + org.pitest.mutationtest.engine.gregor.mutators.ConditionalsBoundaryMutator + changed conditional boundary + if (node.getLineNo() < lineStart) { + + + + NewHandler.java + com.puppycrawl.tools.checkstyle.checks.indentation.NewHandler + shouldIncreaseIndent + org.pitest.mutationtest.engine.gregor.mutators.ReturnValsMutator + replaced return of integer sized value with (x == 0 ? 1 : 0) + return false; + + + + NewHandler.java + com.puppycrawl.tools.checkstyle.checks.indentation.NewHandler + shouldIncreaseIndent + org.pitest.mutationtest.engine.gregor.mutators.returns.BooleanTrueReturnValsMutator + replaced boolean return with true for com/puppycrawl/tools/checkstyle/checks/indentation/NewHandler::shouldIncreaseIndent + return false; + + + + SwitchHandler.java + com.puppycrawl.tools.checkstyle.checks.indentation.SwitchHandler + checkIndentation + org.pitest.mutationtest.engine.gregor.mutators.VoidMethodCallMutator + removed call to com/puppycrawl/tools/checkstyle/checks/indentation/SwitchHandler::checkSwitchExpr + checkSwitchExpr(); + + + + SwitchHandler.java + com.puppycrawl.tools.checkstyle.checks.indentation.SwitchHandler + checkSwitchExpr + org.pitest.mutationtest.engine.gregor.mutators.VoidMethodCallMutator + removed call to com/puppycrawl/tools/checkstyle/checks/indentation/SwitchHandler::checkExpressionSubtree + checkExpressionSubtree( + + + + SynchronizedHandler.java + com.puppycrawl.tools.checkstyle.checks.indentation.SynchronizedHandler + checkIndentation + org.pitest.mutationtest.engine.gregor.mutators.VoidMethodCallMutator + removed call to com/puppycrawl/tools/checkstyle/checks/indentation/SynchronizedHandler::checkSynchronizedExpr + checkSynchronizedExpr(); + + + + SynchronizedHandler.java + com.puppycrawl.tools.checkstyle.checks.indentation.SynchronizedHandler + checkIndentation + org.pitest.mutationtest.engine.gregor.mutators.VoidMethodCallMutator + removed call to com/puppycrawl/tools/checkstyle/checks/indentation/SynchronizedHandler::checkWrappingIndentation + checkWrappingIndentation(getMainAst(), + + + + SynchronizedHandler.java + com.puppycrawl.tools.checkstyle.checks.indentation.SynchronizedHandler + checkSynchronizedExpr + org.pitest.mutationtest.engine.gregor.mutators.VoidMethodCallMutator + removed call to com/puppycrawl/tools/checkstyle/checks/indentation/SynchronizedHandler::checkExpressionSubtree + checkExpressionSubtree(syncAst, expected, false, false); + + + + TryHandler.java + com.puppycrawl.tools.checkstyle.checks.indentation.TryHandler + checkIndentation + org.pitest.mutationtest.engine.gregor.mutators.VoidMethodCallMutator + removed call to com/puppycrawl/tools/checkstyle/checks/indentation/TryHandler::checkTryResParen + checkTryResParen(getTryResLparen(), "lparen"); + + diff --git a/.ci/pitest-suppressions/pitest-javadoc-suppressions.xml b/.ci/pitest-suppressions/pitest-javadoc-suppressions.xml new file mode 100644 index 00000000000..819839ecc9c --- /dev/null +++ b/.ci/pitest-suppressions/pitest-javadoc-suppressions.xml @@ -0,0 +1,29 @@ + + + + AbstractJavadocCheck.java + com.puppycrawl.tools.checkstyle.checks.javadoc.AbstractJavadocCheck + processTree + org.pitest.mutationtest.engine.gregor.mutators.VoidMethodCallMutator + removed call to com/puppycrawl/tools/checkstyle/checks/javadoc/AbstractJavadocCheck::beginJavadocTree + beginJavadocTree(root); + + + + AbstractJavadocCheck.java + com.puppycrawl.tools.checkstyle.checks.javadoc.AbstractJavadocCheck + processTree + org.pitest.mutationtest.engine.gregor.mutators.VoidMethodCallMutator + removed call to com/puppycrawl/tools/checkstyle/checks/javadoc/AbstractJavadocCheck::finishJavadocTree + finishJavadocTree(root); + + + + TagParser.java + com.puppycrawl.tools.checkstyle.checks.javadoc.TagParser + getNextCharPos + org.pitest.mutationtest.engine.gregor.mutators.NegateConditionalsMutator + negated conditional + while (column < currentLineLength + + diff --git a/.ci/pitest.sh b/.ci/pitest-survival-check-html.sh similarity index 100% rename from .ci/pitest.sh rename to .ci/pitest-survival-check-html.sh diff --git a/.ci/pitest-survival-check-xml.groovy b/.ci/pitest-survival-check-xml.groovy new file mode 100644 index 00000000000..0ba5123c685 --- /dev/null +++ b/.ci/pitest-survival-check-xml.groovy @@ -0,0 +1,409 @@ +import groovy.io.FileType +import groovy.transform.EqualsAndHashCode +import groovy.transform.Field +import groovy.xml.XmlParser +import groovy.xml.XmlSlurper +import groovy.xml.XmlUtil +import groovy.xml.slurpersupport.GPathResult +import groovy.xml.slurpersupport.NodeChildren + +@Field final static String SEPARATOR = System.getProperty("file.separator") + +final int exitCode +if (args.length == 2) { + exitCode = parseArgumentAndExecute(args[0], args[1]) +} +else { + exitCode = parseArgumentAndExecute(args[0], null) +} +System.exit(exitCode) + +/** + * Parse the command line arguments passed in and execute the branch based on the arguments. + * + * @param argument command line argument + * @return {@code 0} if command executes successfully, {@code 1} otherwise + */ +private int parseArgumentAndExecute(String argument, String flag) { + final Set profiles = getPitestProfiles() + final String usageString = """ + Usage groovy ./.ci/pitest-survival-check-xml.groovy [profile] [-g | --generate-suppression] + To see the full list of supported profiles run + 'groovy ./.ci/pitest-survival-check-xml.groovy --list' + """.stripIndent() + + final int exitCode + if (profiles.contains(argument)) { + if (flag != null && flag != "-g" && flag != "--generate-suppression") { + final String exceptionMessage = "\nUnexpected flag: ${flag}" + usageString + throw new IllegalArgumentException(exceptionMessage) + } + exitCode = checkPitestReport(argument, flag) + + } + else if (argument == "--list") { + println "Supported profiles:" + profiles.each { println it } + exitCode = 0 + } + else { + final String exceptionMessage = "\nUnexpected argument: ${argument}" + usageString + throw new IllegalArgumentException(exceptionMessage) + } + return exitCode +} + +/** + * Parse the pom.xml file to get all the available pitest profiles. + * + * @return A set of all available pitest profiles + */ +private static Set getPitestProfiles() { + final GPathResult mainNode = new XmlSlurper().parse(".${SEPARATOR}pom.xml") + final NodeChildren ids = mainNode.profiles.profile.id as NodeChildren + final Set profiles = new HashSet<>() + ids.each { node -> + final GPathResult id = node as GPathResult + final String idText = id.text() + if (idText.startsWith("pitest-")) { + profiles.add(idText) + } + } + return profiles +} + +/** + * Check the generated pitest report. Parse the surviving and suppressed mutations and compare + * them. + * + * @param profile the pitest profile to execute + * @param flag command line argument flag to determine output format + * @return {@code 0} if pitest report is as expected, {@code 1} otherwise + */ +private static int checkPitestReport(String profile, String flag) { + final XmlParser xmlParser = new XmlParser() + File mutationReportFile = null + final String suppressedMutationFileUri = + ".${SEPARATOR}.ci${SEPARATOR}pitest-suppressions${SEPARATOR}${profile}-suppressions.xml" + + final File pitReports = new File(".${SEPARATOR}target${SEPARATOR}pit-reports") + + if (!pitReports.exists()) { + throw new IllegalStateException( + "Pitest report directory does not exist, generate pitest report first") + } + + pitReports.eachFileRecurse(FileType.FILES) { + if (it.name == 'mutations.xml') { + mutationReportFile = it + } + } + final Node mutationReportNode = xmlParser.parse(mutationReportFile) + final Set survivingMutations = getSurvivingMutations(mutationReportNode) + + final File suppressionFile = new File(suppressedMutationFileUri) + Set suppressedMutations = Collections.emptySet() + if (suppressionFile.exists()) { + final Node suppressedMutationNode = xmlParser.parse(suppressedMutationFileUri) + suppressedMutations = getSuppressedMutations(suppressedMutationNode) + } + return compareMutations(survivingMutations, suppressedMutations, flag) +} + +/** + * Get the surviving mutations. All child nodes of the main {@code mutations} node + * are parsed. + * + * @param mainNode the main {@code mutations} node + * @return A set of surviving mutations + */ +private static Set getSurvivingMutations(Node mainNode) { + + final List children = mainNode.children() + final Set survivingMutations = new TreeSet<>() + + children.each { node -> + final Node mutationNode = node as Node + + final String mutationStatus = mutationNode.attribute("status") + + if (mutationStatus == "SURVIVED" || mutationStatus == "NO_COVERAGE") { + survivingMutations.add(getMutation(mutationNode)) + } + } + return survivingMutations +} + +/** + * Get the suppressed mutations. All child nodes of the main {@code suppressedMutations} node + * are parsed. + * + * @param mainNode the main {@code suppressedMutations} node + * @return A set of suppressed mutations + */ +private static Set getSuppressedMutations(Node mainNode) { + final List children = mainNode.children() + final Set suppressedMutations = new TreeSet<>() + + children.each { node -> + final Node mutationNode = node as Node + suppressedMutations.add(getMutation(mutationNode)) + } + return suppressedMutations +} + +/** + * Construct the {@link Mutation} object from the {@code mutation} XML node. + * The {@code mutations.xml} file is parsed to get the {@code mutationNode}. + * + * @param mutationNode the {@code mutation} XML node + * @return {@link Mutation} object represented by the {@code mutation} XML node + */ +private static Mutation getMutation(Node mutationNode) { + final List childNodes = mutationNode.children() + + String sourceFile = null + String mutatedClass = null + String mutatedMethod = null + String mutator = null + String lineContent = null + String description = null + String mutationClassPackage = null + int lineNumber = 0 + childNodes.each { + final Node childNode = it as Node + final String text = childNode.name() + + final String childNodeText = XmlUtil.escapeXml(childNode.text()) + switch (text) { + case "sourceFile": + sourceFile = childNodeText + break + case "mutatedClass": + mutatedClass = childNodeText + mutationClassPackage = mutatedClass.split("[A-Z]")[0] + break + case "mutatedMethod": + mutatedMethod = childNodeText + break + case "mutator": + mutator = childNodeText + break + case "description": + description = childNodeText + break + case "lineNumber": + lineNumber = Integer.parseInt(childNodeText) + break + case "lineContent": + lineContent = childNodeText + break + } + } + if (lineContent == null) { + final String mutationFileName = mutationClassPackage + sourceFile + final String startingPath = ".${SEPARATOR}src${SEPARATOR}main${SEPARATOR}java${SEPARATOR}" + final String javaExtension = ".java" + final String mutationFilePath = startingPath + mutationFileName + .substring(0, mutationFileName.length() - javaExtension.length()) + .replaceAll("\\.", SEPARATOR) + javaExtension + + final File file = new File(mutationFilePath) + lineContent = XmlUtil.escapeXml(file.readLines().get(lineNumber - 1).trim()) + } + if (lineNumber == 0) { + lineNumber = -1 + } + + final String unstableAttributeValue = mutationNode.attribute("unstable") + final boolean isUnstable = Boolean.parseBoolean(unstableAttributeValue) + + return new Mutation(sourceFile, mutatedClass, mutatedMethod, mutator, description, + lineContent, lineNumber, isUnstable) +} + +/** + * Compare surviving and suppressed mutations. The comparison passes successfully (i.e. returns 0) + * when: + *
    + *
  1. Surviving and suppressed mutations are equal.
  2. + *
  3. There are extra suppressed mutations but they are unstable + * i.e. {@code unstable="true"}.
  4. + *
+ * The comparison fails (i.e. returns 1) when: + *
    + *
  1. Surviving mutations are not present in the suppressed list.
  2. + *
  3. There are mutations in the suppression list that are not there is surviving list.
  4. + *
+ * + * @param survivingMutations A set of surviving mutations + * @param suppressedMutations A set of suppressed mutations + * @param flag command line argument flag to determine output format + * @return {@code 0} if comparison passes successfully + */ +private static int compareMutations(Set survivingMutations, + Set suppressedMutations, + String flag) { + final Set survivingUnsuppressedMutations = + setDifference(survivingMutations, suppressedMutations) + final Set extraSuppressions = + setDifference(suppressedMutations, survivingMutations) + + final int exitCode + if (survivingMutations == suppressedMutations) { + exitCode = 0 + } + else if (survivingUnsuppressedMutations.isEmpty() + && !hasOnlyStableMutations(extraSuppressions)) { + exitCode = 0 + } + else { + if (!survivingUnsuppressedMutations.isEmpty()) { + println "Surviving mutation(s) found:" + survivingUnsuppressedMutations.each { + printMutation(flag, it) + } + } + if (!extraSuppressions.isEmpty() + && extraSuppressions.any { !it.isUnstable() }) { + println "\nUnnecessary suppressed mutation(s) found:" + extraSuppressions.each { + if (!it.isUnstable()) { + printMutation(flag, it) + } + } + } + exitCode = 1 + } + return exitCode +} + +/** + * Whether a set has only stable mutations. + * + * @param mutations A set of mutations + * @return {@code true} if a set has only stable mutations + */ +private static boolean hasOnlyStableMutations(Set mutations) { + return mutations.every { !it.isUnstable() } +} + +/** + * Prints the mutation according to the nature of the flag. + * + * @param flag command line argument flag to determine output format + * @param mutation mutation to print + */ +private static void printMutation(String flag, Mutation mutation) { + if (flag != null) { + println mutation.toXmlString() + } + else { + println mutation + } +} + +/** + * Determine the difference between 2 sets. The result is {@code setOne - setTwo}. + * + * @param setOne The first set in the difference + * @param setTwo The second set in the difference + * @return {@code setOne - setTwo} + */ +private static Set setDifference(final Set setOne, + final Set setTwo) { + final Set result = new HashSet<>(setOne) + result.removeIf(mutation -> setTwo.contains(mutation)) + return result +} + +/** + * A class to represent the XML {@code mutation} node. + */ +@EqualsAndHashCode(excludes = ["lineNumber", "unstable"]) +record Mutation(String sourceFile, String mutatedClass, + String mutatedMethod, String mutator, + String description, String lineContent, int lineNumber, + boolean unstable) + implements Comparable { + + /** + * Mutation nodes present in suppressions file do not have a {@code lineNumber}. + * The {@code lineNumber} is set to {@code -1} for such mutations. + */ + private static final int LINE_NUMBER_NOT_PRESENT_VALUE = -1 + + @Override + String toString() { + String toString = """ + Source File: "${sourceFile()}" + Class: "${mutatedClass()}" + Method: "${mutatedMethod()}" + Line Contents: "${lineContent()}" + Mutator: "${mutator()}" + Description: "${description()}" + """.stripIndent() + if (lineNumber() != LINE_NUMBER_NOT_PRESENT_VALUE) { + toString += 'Line Number: ' + lineNumber() + } + return toString + } + + @Override + int compareTo(Mutation other) { + int i = sourceFile() <=> other.sourceFile() + if (i != 0) { + return i + } + + i = mutatedClass() <=> other.mutatedClass() + if (i != 0) { + return i + } + + i = mutatedMethod() <=> other.mutatedMethod() + if (i != 0) { + return i + } + + i = lineContent() <=> other.lineContent() + if (i != 0) { + return i + } + + i = mutator() <=> other.mutator() + if (i != 0) { + return i + } + + return description() <=> other.description() + } + + /** + * XML format of the mutation. + * + * @return XML format of the mutation + */ + String toXmlString() { + return """ + + ${sourceFile()} + ${mutatedClass()} + ${mutatedMethod()} + ${mutator()} + ${description()} + ${lineContent()} + + """.stripIndent(10) + } + + /** + * Whether the mutation is unstable. + * + * @return {@code true} if the mutation is unstable + */ + boolean isUnstable() { + return unstable + } + +} diff --git a/.github/workflows/pitest.yml b/.github/workflows/pitest.yml index dcda6867fac..b21e78371f5 100644 --- a/.github/workflows/pitest.yml +++ b/.github/workflows/pitest.yml @@ -44,6 +44,23 @@ jobs: runs-on: ubuntu-latest continue-on-error: true steps: + - name: Set up JDK 11 + uses: actions/setup-java@v1 + with: + java-version: 11 + - name: Download Groovy 4.0.3 + uses: sdkman/sdkman-action@master + id: sdkman + with: + candidate: groovy + version: 4.0.3 + - name: Set up Groovy 4.0.3 + run: | + unzip ${{ steps.sdkman.outputs.file }} -d ${{ runner.temp }}; + mv ${{ runner.temp }}/groovy-4.0.3 ${{ runner.temp }}/groovy + GROOVY_HOME=${{ runner.temp }}/groovy + echo "GROOVY_HOME=${{ runner.temp }}/groovy" >> $GITHUB_ENV + echo "$GROOVY_HOME/bin" >> $GITHUB_PATH - name: Setup local maven cache uses: actions/cache@v2 with: @@ -55,9 +72,14 @@ jobs: run: | mvn -e --no-transfer-progress -P"${{ matrix.profile }}" clean test-compile \ org.pitest:pitest-maven:mutationCoverage - - name: ${{ matrix.profile }} + - name: Check ${{ matrix.profile }} with XML report + id: pitest-xml-model + run: | + groovy ./.ci/pitest-survival-check-xml.groovy ${{ matrix.profile }} + - name: Check ${{ matrix.profile }} with HTML report + if: failure() || success() run: | - ./.ci/pitest.sh ${{ matrix.profile }} + ./.ci/pitest-survival-check-html.sh ${{ matrix.profile }} - name: Stage results if: failure() || github.ref == 'refs/heads/master' run: | diff --git a/config/checkstyle_non_main_files_suppressions.xml b/config/checkstyle_non_main_files_suppressions.xml index 1fa3e6ec94b..6f37259dc4d 100644 --- a/config/checkstyle_non_main_files_suppressions.xml +++ b/config/checkstyle_non_main_files_suppressions.xml @@ -76,7 +76,7 @@ + files=".ci[\\/]pitest-survival-check-html.sh"/> @@ -87,6 +87,9 @@ + + + diff --git a/pom.xml b/pom.xml index 5686bf86050..11744cbd16c 100644 --- a/pom.xml +++ b/pom.xml @@ -216,6 +216,7 @@ 11 1.8.1 10 + HTML,XML 50000 4 0.16 @@ -2387,6 +2388,7 @@ ${pitest.plugin.timeout.factor} ${pitest.plugin.timeout.constant} ${pitest.plugin.threads} + ${pitest.plugin.output.formats} @@ -2431,6 +2433,7 @@ ${pitest.plugin.timeout.factor} ${pitest.plugin.timeout.constant} ${pitest.plugin.threads} + ${pitest.plugin.output.formats} @@ -2475,6 +2478,7 @@ ${pitest.plugin.timeout.factor} ${pitest.plugin.timeout.constant} ${pitest.plugin.threads} + ${pitest.plugin.output.formats} @@ -2564,6 +2568,7 @@ ${pitest.plugin.timeout.factor} ${pitest.plugin.timeout.constant} ${pitest.plugin.threads} + ${pitest.plugin.output.formats} @@ -2666,6 +2671,7 @@ ${pitest.plugin.timeout.factor} ${pitest.plugin.timeout.constant} ${pitest.plugin.threads} + ${pitest.plugin.output.formats} @@ -2710,6 +2716,7 @@ ${pitest.plugin.timeout.factor} ${pitest.plugin.timeout.constant} ${pitest.plugin.threads} + ${pitest.plugin.output.formats} @@ -2754,6 +2761,7 @@ ${pitest.plugin.timeout.factor} ${pitest.plugin.timeout.constant} ${pitest.plugin.threads} + ${pitest.plugin.output.formats} @@ -2798,6 +2806,7 @@ ${pitest.plugin.timeout.factor} ${pitest.plugin.timeout.constant} ${pitest.plugin.threads} + ${pitest.plugin.output.formats} @@ -2842,6 +2851,7 @@ ${pitest.plugin.timeout.factor} ${pitest.plugin.timeout.constant} ${pitest.plugin.threads} + ${pitest.plugin.output.formats} @@ -2887,6 +2897,7 @@ ${pitest.plugin.timeout.factor} ${pitest.plugin.timeout.constant} ${pitest.plugin.threads} + ${pitest.plugin.output.formats} @@ -2941,6 +2952,7 @@ ${pitest.plugin.timeout.factor} ${pitest.plugin.timeout.constant} ${pitest.plugin.threads} + ${pitest.plugin.output.formats} @@ -2985,6 +2997,7 @@ ${pitest.plugin.timeout.factor} ${pitest.plugin.timeout.constant} ${pitest.plugin.threads} + ${pitest.plugin.output.formats} @@ -3029,6 +3042,7 @@ ${pitest.plugin.timeout.factor} ${pitest.plugin.timeout.constant} ${pitest.plugin.threads} + ${pitest.plugin.output.formats} @@ -3073,6 +3087,7 @@ ${pitest.plugin.timeout.factor} ${pitest.plugin.timeout.constant} ${pitest.plugin.threads} + ${pitest.plugin.output.formats} @@ -3117,6 +3132,7 @@ ${pitest.plugin.timeout.factor} ${pitest.plugin.timeout.constant} ${pitest.plugin.threads} + ${pitest.plugin.output.formats} @@ -3161,6 +3177,7 @@ ${pitest.plugin.timeout.factor} ${pitest.plugin.timeout.constant} ${pitest.plugin.threads} + ${pitest.plugin.output.formats} @@ -3205,6 +3222,7 @@ ${pitest.plugin.timeout.factor} ${pitest.plugin.timeout.constant} ${pitest.plugin.threads} + ${pitest.plugin.output.formats} @@ -3250,6 +3268,7 @@ ${pitest.plugin.timeout.factor} ${pitest.plugin.timeout.constant} ${pitest.plugin.threads} + ${pitest.plugin.output.formats} @@ -3291,6 +3310,7 @@ ${pitest.plugin.timeout.factor} ${pitest.plugin.timeout.constant} ${pitest.plugin.threads} + ${pitest.plugin.output.formats} @@ -3376,6 +3396,7 @@ ${pitest.plugin.timeout.factor} ${pitest.plugin.timeout.constant} ${pitest.plugin.threads} + ${pitest.plugin.output.formats} @@ -3438,6 +3459,7 @@ ${pitest.plugin.timeout.factor} ${pitest.plugin.timeout.constant} ${pitest.plugin.threads} + ${pitest.plugin.output.formats} @@ -3479,6 +3501,7 @@ ${pitest.plugin.timeout.factor} ${pitest.plugin.timeout.constant} ${pitest.plugin.threads} + ${pitest.plugin.output.formats} @@ -3572,6 +3595,7 @@ ${pitest.plugin.timeout.factor} ${pitest.plugin.timeout.constant} ${pitest.plugin.threads} + ${pitest.plugin.output.formats} @@ -3629,6 +3653,7 @@ ${pitest.plugin.timeout.factor} ${pitest.plugin.timeout.constant} ${pitest.plugin.threads} + ${pitest.plugin.output.formats} @@ -3675,6 +3700,7 @@ ${pitest.plugin.timeout.factor} ${pitest.plugin.timeout.constant} ${pitest.plugin.threads} + ${pitest.plugin.output.formats} @@ -3784,6 +3810,7 @@ ${pitest.plugin.timeout.factor} ${pitest.plugin.timeout.constant} ${pitest.plugin.threads} + ${pitest.plugin.output.formats} @@ -3828,6 +3855,7 @@ ${pitest.plugin.timeout.factor} ${pitest.plugin.timeout.constant} ${pitest.plugin.threads} + ${pitest.plugin.output.formats} @@ -3902,6 +3930,7 @@ ${pitest.plugin.timeout.factor} ${pitest.plugin.timeout.constant} ${pitest.plugin.threads} + ${pitest.plugin.output.formats} @@ -3947,6 +3976,7 @@ ${pitest.plugin.timeout.factor} ${pitest.plugin.timeout.constant} ${pitest.plugin.threads} + ${pitest.plugin.output.formats}