From 232698d46de8a87cd274c8f10cadc483cda8cd0d Mon Sep 17 00:00:00 2001 From: Vasile Jureschi Date: Thu, 26 Jan 2023 17:34:14 +0200 Subject: [PATCH 01/16] Adds ignoreMissingReports flag --- README.md | 2 +- pom.xml | 6 +- .../plugins/pitmutation/PitPublisher.java | 588 ++++++++++-------- .../plugins/pitmutation/PitPublisherTest.java | 6 +- 4 files changed, 322 insertions(+), 280 deletions(-) diff --git a/README.md b/README.md index 9f8feec..a90feee 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ Configure report path, e.g. `target/pit-reports/**/mutations.xml` for a Maven bu ## Jenkins Pipeline You can use the following step in pipeline to use this plugin in pipeline: -`pitmutation killRatioMustImprove: false, minimumKillRatio: 50.0, mutationStatsFile: '**/target/pit-reports/**/mutations.xml'` +`pitmutation ignoreMissingReports: false, killRatioMustImprove: false, minimumKillRatio: 50.0, mutationStatsFile: '**/target/pit-reports/**/mutations.xml'` The plugin needs the XML and HTML output from PIT. Also make sure that a clean target is executed before building, otherwise PIT will diff --git a/pom.xml b/pom.xml index 3f245d6..1caebbf 100644 --- a/pom.xml +++ b/pom.xml @@ -9,14 +9,14 @@ pitmutation - 1.0-19-SNAPSHOT + 1.1-4-SNAPSHOT Jenkins PIT Mutation Plugin hpi http://wiki.jenkins-ci.org/display/JENKINS/pitmutation - scm:git:ssh://git@github.com/jenkinsci/pitmutation-plugin.git - scm:git:ssh://git@github.com/jenkinsci/pitmutation-plugin.git + scm:git:git://git@github.com/jenkinsci/pitmutation-plugin.git + scm:git:git://git@github.com/jenkinsci/pitmutation-plugin.git https://github.com/jenkinsci/pitmutation-plugin HEAD diff --git a/src/main/java/org/jenkinsci/plugins/pitmutation/PitPublisher.java b/src/main/java/org/jenkinsci/plugins/pitmutation/PitPublisher.java index 847d961..311e7e6 100644 --- a/src/main/java/org/jenkinsci/plugins/pitmutation/PitPublisher.java +++ b/src/main/java/org/jenkinsci/plugins/pitmutation/PitPublisher.java @@ -4,7 +4,12 @@ import hudson.FilePath; import hudson.Launcher; import hudson.Util; -import hudson.model.*; +import hudson.model.AbstractBuild; +import hudson.model.AbstractProject; +import hudson.model.Action; +import hudson.model.Result; +import hudson.model.Run; +import hudson.model.TaskListener; import hudson.remoting.VirtualChannel; import hudson.tasks.BuildStepDescriptor; import hudson.tasks.BuildStepMonitor; @@ -34,316 +39,353 @@ */ public class PitPublisher extends Recorder implements SimpleBuildStep { - public static final String SINGLE_MODULE_REPORT_FOLDER = "mutation-report-all"; - public static final String MULTI_MODULE_REPORT_FORMAT = "mutation-report-%s"; - - private List buildConditions; - private String mutationStatsFile; - private boolean killRatioMustImprove; - private float minimumKillRatio; - private transient TaskListener listener; - private Run build; - - /** - * Instantiates a new Pit publisher. - * - * @param mutationStatsFile the mutation stats file - * @param minimumKillRatio the minimum kill ratio - * @param killRatioMustImprove the kill ratio must improve - */ - protected PitPublisher(String mutationStatsFile, float minimumKillRatio, boolean killRatioMustImprove) { - this.mutationStatsFile = mutationStatsFile; - this.killRatioMustImprove = killRatioMustImprove; - this.minimumKillRatio = minimumKillRatio; - this.buildConditions = new ArrayList<>(); - this.buildConditions.add(percentageThreshold(minimumKillRatio)); - if (killRatioMustImprove) { - this.buildConditions.add(mustImprove()); + public static final String SINGLE_MODULE_REPORT_FOLDER = "mutation-report-all"; + public static final String MULTI_MODULE_REPORT_FORMAT = "mutation-report-%s"; + + private List buildConditions; + private String mutationStatsFile; + private boolean killRatioMustImprove; + + private boolean ignoreMissingReports = false; + private float minimumKillRatio; + private transient TaskListener listener; + private Run build; + + /** + * Instantiates a new Pit publisher. + * + * @param mutationStatsFile the mutation stats file + * @param minimumKillRatio the minimum kill ratio + * @param killRatioMustImprove the kill ratio must improve + */ + protected PitPublisher(String mutationStatsFile, + float minimumKillRatio, + boolean killRatioMustImprove, + boolean ignoreMissingReports) { + this.mutationStatsFile = mutationStatsFile; + this.killRatioMustImprove = killRatioMustImprove; + this.minimumKillRatio = minimumKillRatio; + this.ignoreMissingReports = ignoreMissingReports; + this.buildConditions = new ArrayList<>(); + this.buildConditions.add(percentageThreshold(minimumKillRatio)); + if (killRatioMustImprove) { + this.buildConditions.add(mustImprove()); + } + } + + /** + * Instantiates a new Pit publisher with Default-Values. + *

+ * {@link #mutationStatsFile} is set to {@code **{@literal /}target/pit-reports/**{@literal /}mutations.xml}, + * {@link #minimumKillRatio} is set to {@code 0.0}, + * {@link #killRatioMustImprove} is set to {@code false}, + */ + @DataBoundConstructor + public PitPublisher() { + this("**/target/pit-reports/**/mutations.xml", 0, false, false); + } + + @DataBoundSetter + public void setMutationStatsFile(final String mutationStatsFile) { + this.mutationStatsFile = mutationStatsFile; + } + + @DataBoundSetter + public void setMinimumKillRatio(final float minimumKillRatio) { + this.minimumKillRatio = minimumKillRatio; + } + + @DataBoundSetter + public void setKillRatioMustImprove(final boolean killRatioMustImprove) { + this.killRatioMustImprove = killRatioMustImprove; + } + + @DataBoundSetter + public void setIgnoreMissingReports(final boolean ignoreMissingReports) { + this.ignoreMissingReports = ignoreMissingReports; + } + + @Override + public void perform(@Nonnull Run build, + @Nonnull FilePath workspace, + @Nonnull Launcher launcher, + @Nonnull TaskListener listener) throws InterruptedException, IOException { + this.listener = listener; + this.build = build; + + Result result = build.getResult(); + if (build instanceof AbstractBuild && result != null && result.isBetterOrEqualTo(Result.UNSTABLE)) { + AbstractBuild abstractBuild = (AbstractBuild) build; + this.listener.getLogger().println("Looking for PIT reports in " + abstractBuild.getModuleRoot().getRemote()); + + final FilePath[] moduleRoots = abstractBuild.getModuleRoots(); + final boolean multipleModuleRoots = moduleRoots != null && moduleRoots.length > 1; + final FilePath moduleRoot = multipleModuleRoots ? abstractBuild.getWorkspace() : abstractBuild.getModuleRoot(); + if (moduleRoot == null) { + this.listener.getLogger().println("Module root was returned as null"); + return; + } + + File f = new File(mutationStatsFile); + if ((!f.exists() || f.isDirectory()) && ignoreMissingReports) { + abstractBuild.setResult(Result.SUCCESS); + } else if (f.exists() || !f.isDirectory()) { + ParseReportCallable fileCallable = new ParseReportCallable(mutationStatsFile); + FilePath[] reports = moduleRoot.act(fileCallable); + publishReports(reports, new FilePath(abstractBuild.getRootDir()), abstractBuild.getModuleRoot().getRemote()); + + //publish latest reports + PitBuildAction action = new PitBuildAction(abstractBuild); + abstractBuild.addAction(action); + abstractBuild.setResult(decideBuildResult(action)); + } + } else { + File f = new File(mutationStatsFile); + if ((!f.exists() || f.isDirectory()) && ignoreMissingReports) { + build.setResult(Result.SUCCESS); + } else if (f.exists() || !f.isDirectory()) { + this.listener.getLogger().println("Looking for PIT reports in " + workspace.getRemote()); + + ParseReportCallable fileCallable = new ParseReportCallable(mutationStatsFile); + FilePath[] reports = workspace.act(fileCallable); + FilePath buildTarget = new FilePath(build.getRootDir()); + if (reports.length == 1) { + copyMutationReports(reports[0], buildTarget, SINGLE_MODULE_REPORT_FOLDER); + } else { + publishReports(reports, buildTarget, workspace.getRemote()); } + PitBuildAction action = new PitBuildAction(build); + build.addAction(action); + build.setResult(decideBuildResult(action)); + } } - - /** - * Instantiates a new Pit publisher with Default-Values. - *

- * {@link #mutationStatsFile} is set to {@code **{@literal /}target/pit-reports/**{@literal /}mutations.xml}, - * {@link #minimumKillRatio} is set to {@code 0.0}, - * {@link #killRatioMustImprove} is set to {@code false}, - */ - @DataBoundConstructor - public PitPublisher() { - this("**/target/pit-reports/**/mutations.xml", 0, false); + } + + /** + * {@inheritDoc} + */ + @Override + public Action getProjectAction(AbstractProject project) { + return new PitProjectAction(project); + } + + /** + * Publish reports. + * + * @param reports the reports + * @param buildTarget the build target + * @param base the base path of the report location + */ + void publishReports(FilePath[] reports, FilePath buildTarget, final String base) { + for (int i = 0; i < reports.length; i++) { + FilePath report = reports[i]; + listener.getLogger().println("Publishing mutation report: " + report.getRemote()); + + final String moduleName; + if (StringUtils.isBlank(base)) { + moduleName = String.valueOf(i == 0 ? null : i); + } else { + String[] partsFromRemoteWithoutBase = report.getRemote().replace(base, "").split("[/\\\\]"); + if (partsFromRemoteWithoutBase.length > 1) { + moduleName = partsFromRemoteWithoutBase[1]; + } else { + moduleName = String.valueOf(i == 0 ? null : i); + } + } + copyMutationReports(reports[i], buildTarget, String.format(MULTI_MODULE_REPORT_FORMAT, moduleName)); } - - @DataBoundSetter - public void setMutationStatsFile(final String mutationStatsFile) { - this.mutationStatsFile = mutationStatsFile; + } + + private void copyMutationReports(FilePath source, FilePath buildTarget, String mutationFilePath) { + final FilePath targetPath = new FilePath(buildTarget, mutationFilePath); + try { + FilePath parent = Optional.ofNullable(source.getParent()).orElseThrow(() -> new IOException()); + parent.copyRecursiveTo(targetPath); + } catch (IOException e) { + Util.displayIOException(e, listener); + e.printStackTrace(listener.fatalError("Unable to copy coverage from " + source + " to " + buildTarget)); + build.setResult(Result.FAILURE); + } catch (InterruptedException e) { + e.printStackTrace(); } - - @DataBoundSetter - public void setMinimumKillRatio(final float minimumKillRatio) { - this.minimumKillRatio = minimumKillRatio; + } + + /** + * Decide build result result. + * + * @param action the action + * @return the worst result from all conditions + */ + public Result decideBuildResult(PitBuildAction action) { + Result result = Result.SUCCESS; + for (Condition condition : buildConditions) { + Result conditionResult = condition.decideResult(action); + result = conditionResult.isWorseThan(result) ? conditionResult : result; } - - @DataBoundSetter - public void setKillRatioMustImprove(final boolean killRatioMustImprove) { - this.killRatioMustImprove = killRatioMustImprove; + return result; + } + + + /** + * Required by plugin config + * + * @return the minimum kill ratio + */ + public float getMinimumKillRatio() { + return minimumKillRatio; + } + + /** + * Required by plugin config + * + * @return the kill ratio must improve + */ + public boolean getKillRatioMustImprove() { + return killRatioMustImprove; + } + + /** + * Required by plugin config + * + * @return the mutation stats file + */ + public String getMutationStatsFile() { + return mutationStatsFile; + } + + public boolean getIgnoreMissingReports() { + return ignoreMissingReports; + } + + Condition percentageThreshold(final float percentage) { + return new PercentageThresholdCondition(percentage); + } + + class PercentageThresholdCondition implements Condition { + private final float percentage; + + PercentageThresholdCondition(float percentage) { + super(); + this.percentage = percentage; } @Override - public void perform(@Nonnull Run build, @Nonnull FilePath workspace, @Nonnull Launcher launcher, @Nonnull TaskListener listener) throws InterruptedException, IOException { - this.listener = listener; - this.build = build; - - Result result = build.getResult(); - if (build instanceof AbstractBuild && result != null && result.isBetterOrEqualTo(Result.UNSTABLE)) { - AbstractBuild abstractBuild = (AbstractBuild) build; - this.listener.getLogger().println("Looking for PIT reports in " + abstractBuild.getModuleRoot().getRemote()); - - final FilePath[] moduleRoots = abstractBuild.getModuleRoots(); - final boolean multipleModuleRoots = moduleRoots != null && moduleRoots.length > 1; - final FilePath moduleRoot = multipleModuleRoots ? abstractBuild.getWorkspace() : abstractBuild.getModuleRoot(); - if (moduleRoot == null) { - this.listener.getLogger().println("Module root was returned as null"); - return; - } - - ParseReportCallable fileCallable = new ParseReportCallable(mutationStatsFile); - FilePath[] reports = moduleRoot.act(fileCallable); - publishReports(reports, new FilePath(abstractBuild.getRootDir()), abstractBuild.getModuleRoot().getRemote()); - - //publish latest reports - PitBuildAction action = new PitBuildAction(abstractBuild); - abstractBuild.addAction(action); - abstractBuild.setResult(decideBuildResult(action)); - } else { - this.listener.getLogger().println("Looking for PIT reports in " + workspace.getRemote()); - - ParseReportCallable fileCallable = new ParseReportCallable(mutationStatsFile); - FilePath[] reports = workspace.act(fileCallable); - FilePath buildTarget = new FilePath(build.getRootDir()); - if (reports.length == 1) { - copyMutationReports(reports[0], buildTarget, SINGLE_MODULE_REPORT_FOLDER); - } else { - publishReports(reports, buildTarget, workspace.getRemote()); - } - PitBuildAction action = new PitBuildAction(build); - build.addAction(action); - build.setResult(decideBuildResult(action)); - } + public Result decideResult(PitBuildAction action) { + MutationStats stats = action.getReport().getMutationStats(); + dologging(stats); + return stats.getKillPercent() >= percentage ? Result.SUCCESS : Result.FAILURE; } - /** - * {@inheritDoc} - */ - @Override - public Action getProjectAction(AbstractProject project) { - return new PitProjectAction(project); + void dologging(MutationStats stats) { + listener + .getLogger() + .println("Kill ratio is " + + stats.getKillPercent() + + "% (" + + stats.getKillCount() + + " " + + stats.getTotalMutations() + + ")"); } + } - /** - * Publish reports. - * - * @param reports the reports - * @param buildTarget the build target - * @param base the base path of the report location - */ - void publishReports(FilePath[] reports, FilePath buildTarget, final String base) { - for (int i = 0; i < reports.length; i++) { - FilePath report = reports[i]; - listener.getLogger().println("Publishing mutation report: " + report.getRemote()); - - final String moduleName; - if (StringUtils.isBlank(base)) { - moduleName = String.valueOf(i == 0 ? null : i); - } else { - String[] partsFromRemoteWithoutBase = report.getRemote().replace(base, "").split("[/\\\\]"); - if (partsFromRemoteWithoutBase.length > 1) { - moduleName = partsFromRemoteWithoutBase[1]; - } else { - moduleName = String.valueOf(i == 0 ? null : i); - } - } - copyMutationReports(reports[i], buildTarget, String.format(MULTI_MODULE_REPORT_FORMAT, moduleName)); - } + class MustImproveCondition implements Condition { + @Override + public Result decideResult(final PitBuildAction action) { + PitBuildAction previousAction = action.getPreviousAction(); + if (previousAction != null) { + MutationStats previousStats = previousAction.getReport().getMutationStats(); + logInfo(action, previousStats); + return action.getReport().getMutationStats().getKillPercent() >= previousStats.getKillPercent() ? + Result.SUCCESS : + Result.UNSTABLE; + } else { + return Result.SUCCESS; + } } - private void copyMutationReports(FilePath source, FilePath buildTarget, String mutationFilePath) { - final FilePath targetPath = new FilePath(buildTarget, mutationFilePath); - try { - FilePath parent = Optional.ofNullable(source.getParent()).orElseThrow(() -> new IOException()); - parent.copyRecursiveTo(targetPath); - } catch (IOException e) { - Util.displayIOException(e, listener); - e.printStackTrace(listener.fatalError("Unable to copy coverage from " + source + " to " + buildTarget)); - build.setResult(Result.FAILURE); - } catch (InterruptedException e) { - e.printStackTrace(); - } + void logInfo(final PitBuildAction action, MutationStats stats) { + listener.getLogger().println("Previous kill ratio was " + stats.getKillPercent() + "%"); + listener + .getLogger() + .println("This kill ration is " + action.getReport().getMutationStats().getKillPercent() + "%"); } + } - /** - * Decide build result result. - * - * @param action the action - * @return the worst result from all conditions - */ - public Result decideBuildResult(PitBuildAction action) { - Result result = Result.SUCCESS; - for (Condition condition : buildConditions) { - Result conditionResult = condition.decideResult(action); - result = conditionResult.isWorseThan(result) ? conditionResult : result; - } - return result; - } + Condition mustImprove() { + return new MustImproveCondition(); + } + @Override + public BuildStepMonitor getRequiredMonitorService() { + return BuildStepMonitor.BUILD; + } - /** - * Required by plugin config - * - * @return the minimum kill ratio - */ - public float getMinimumKillRatio() { - return minimumKillRatio; - } + /** + * The type Descriptor. + */ + @Extension + @Symbol("pitmutation") + public static class DescriptorImpl extends BuildStepDescriptor { /** - * Required by plugin config - * - * @return the kill ratio must improve + * Instantiates a new Descriptor. */ - public boolean getKillRatioMustImprove() { - return killRatioMustImprove; + public DescriptorImpl() { + super(PitPublisher.class); } - /** - * Required by plugin config - * - * @return the mutation stats file - */ - public String getMutationStatsFile() { - return mutationStatsFile; - } - - Condition percentageThreshold(final float percentage) { - return new PercentageThresholdCondition(percentage); - } - - class PercentageThresholdCondition implements Condition { - private final float percentage; - - PercentageThresholdCondition(float percentage) { - super(); - this.percentage = percentage; - } - - @Override - public Result decideResult(PitBuildAction action) { - MutationStats stats = action.getReport().getMutationStats(); - dologging(stats); - return stats.getKillPercent() >= percentage ? Result.SUCCESS : Result.FAILURE; - } - - void dologging(MutationStats stats) { - listener.getLogger().println("Kill ratio is " + stats.getKillPercent() + "% (" + stats.getKillCount() - + " " + stats.getTotalMutations() + ")"); - } - } - - class MustImproveCondition implements Condition { - @Override - public Result decideResult(final PitBuildAction action) { - PitBuildAction previousAction = action.getPreviousAction(); - if (previousAction != null) { - MutationStats previousStats = previousAction.getReport().getMutationStats(); - logInfo(action, previousStats); - return action.getReport().getMutationStats().getKillPercent() >= previousStats.getKillPercent() ? Result.SUCCESS - : Result.UNSTABLE; - } else { - return Result.SUCCESS; - } - } - - void logInfo(final PitBuildAction action, MutationStats stats) { - listener.getLogger().println("Previous kill ratio was " + stats.getKillPercent() + "%"); - listener.getLogger() - .println("This kill ration is " + action.getReport().getMutationStats().getKillPercent() + "%"); - } - } - - Condition mustImprove() { - return new MustImproveCondition(); + @Override + public String getDisplayName() { + return Messages.PitPublisher_DisplayName(); } @Override - public BuildStepMonitor getRequiredMonitorService() { - return BuildStepMonitor.BUILD; + public boolean isApplicable(Class aClass) { + return true; } /** - * The type Descriptor. + * {@inheritDoc} */ - @Extension - @Symbol("pitmutation") - public static class DescriptorImpl extends BuildStepDescriptor { - - /** - * Instantiates a new Descriptor. - */ - public DescriptorImpl() { - super(PitPublisher.class); - } + @Override + public boolean configure(StaplerRequest req, JSONObject formData) throws FormException { + req.bindParameters(this, "pitmutation"); + save(); + return super.configure(req, formData); + } + } - @Override - public String getDisplayName() { - return Messages.PitPublisher_DisplayName(); - } + /** + * The type Parse report callable. + */ + public static class ParseReportCallable implements FilePath.FileCallable { - @Override - public boolean isApplicable(Class aClass) { - return true; - } + private static final long serialVersionUID = 1L; - /** - * {@inheritDoc} - */ - @Override - public boolean configure(StaplerRequest req, JSONObject formData) throws FormException { - req.bindParameters(this, "pitmutation"); - save(); - return super.configure(req, formData); - } - } + private final String reportFilePath; /** - * The type Parse report callable. + * Instantiates a new Parse report callable. + * + * @param reportFilePath the report file path */ - public static class ParseReportCallable implements FilePath.FileCallable { - - private static final long serialVersionUID = 1L; - - private final String reportFilePath; - - /** - * Instantiates a new Parse report callable. - * - * @param reportFilePath the report file path - */ - public ParseReportCallable(String reportFilePath) { - this.reportFilePath = reportFilePath; - } + public ParseReportCallable(String reportFilePath) { + this.reportFilePath = reportFilePath; + } - @Override - public FilePath[] invoke(File f, VirtualChannel channel) throws IOException, InterruptedException { - FilePath[] r = new FilePath(f).list(reportFilePath); - if (r.length < 1) { - throw new IOException("No reports found at location:" + reportFilePath); - } - return r; - } + @Override + public FilePath[] invoke(File f, VirtualChannel channel) throws IOException, InterruptedException { + FilePath[] r = new FilePath(f).list(reportFilePath); + if (r.length < 1) { + throw new IOException("No reports found at location:" + reportFilePath); + } + return r; + } - @Override - public void checkRoles(RoleChecker roleChecker) throws SecurityException { + @Override + public void checkRoles(RoleChecker roleChecker) throws SecurityException { - } } + } } diff --git a/src/test/java/org/jenkinsci/plugins/pitmutation/PitPublisherTest.java b/src/test/java/org/jenkinsci/plugins/pitmutation/PitPublisherTest.java index 2bedfe1..99108be 100644 --- a/src/test/java/org/jenkinsci/plugins/pitmutation/PitPublisherTest.java +++ b/src/test/java/org/jenkinsci/plugins/pitmutation/PitPublisherTest.java @@ -34,8 +34,8 @@ static class PitPublisherTSS extends PitPublisher { boolean infoImproveLogged = false; boolean infoPercentLogged = false; - public PitPublisherTSS(String mutationStatsFile, float minimumKillRatio, boolean killRatioMustImprove) { - super(mutationStatsFile, minimumKillRatio, killRatioMustImprove); + public PitPublisherTSS(String mutationStatsFile, float minimumKillRatio, boolean killRatioMustImprove, boolean ignoreMissingReports) { + super(mutationStatsFile, minimumKillRatio, killRatioMustImprove, ignoreMissingReports); } class MustImproveConditionTSS extends MustImproveCondition { @@ -126,7 +126,7 @@ private void setupPercentKillRatioOK() { } private PitPublisherTSS createPitPublisher(boolean mustImprove) { - return new PitPublisherTSS("**/mutations.xml", MINIMUM_KILL_RATIO, mustImprove); + return new PitPublisherTSS("**/mutations.xml", MINIMUM_KILL_RATIO, mustImprove, false); } private void setupBoilderPlateMocks() { From 38c06200d3515b3bc81041d70cc5b263268829bc Mon Sep 17 00:00:00 2001 From: Vasile Jureschi Date: Fri, 27 Jan 2023 09:20:38 +0200 Subject: [PATCH 02/16] Switched from digester3 Apache to Jackson parser --- pom.xml | 13 + .../plugins/pitmutation/Mutation.java | 254 +++++++++++++-- .../plugins/pitmutation/MutationReport.java | 156 +++++----- .../plugins/pitmutation/Mutations.java | 14 + .../plugins/pitmutation/PitBuildAction.java | 2 +- .../pitmutation/MutationReportTest.java | 14 +- .../MutationReportWithDescriptionTest.java | 82 ++--- .../targets/MutationResultTest.java | 289 +++++++++--------- .../plugins/pitmutation/testmutations-00.xml | 64 +++- .../plugins/pitmutation/testmutations-01.xml | 76 +++-- .../plugins/pitmutation/testmutations-02.xml | 16 +- 11 files changed, 646 insertions(+), 334 deletions(-) create mode 100644 src/main/java/org/jenkinsci/plugins/pitmutation/Mutations.java diff --git a/pom.xml b/pom.xml index 1caebbf..d1a3e54 100644 --- a/pom.xml +++ b/pom.xml @@ -54,6 +54,19 @@ + + + com.fasterxml.jackson.core + jackson-databind + 2.14.1 + + + + com.fasterxml.jackson.dataformat + jackson-dataformat-xml + 2.14.1 + + org.projectlombok lombok diff --git a/src/main/java/org/jenkinsci/plugins/pitmutation/Mutation.java b/src/main/java/org/jenkinsci/plugins/pitmutation/Mutation.java index ff08537..38c2099 100644 --- a/src/main/java/org/jenkinsci/plugins/pitmutation/Mutation.java +++ b/src/main/java/org/jenkinsci/plugins/pitmutation/Mutation.java @@ -1,30 +1,242 @@ package org.jenkinsci.plugins.pitmutation; -import lombok.Data; +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.ArrayList; +import java.util.List; /** + * ` + * * @author edward */ -@Data public class Mutation { - private boolean detected; - private String status; - private String sourceFile; - private String mutatedClass; - private String mutatedMethod; - private int lineNumber; - private String mutator; - private int index; - private String killingTest; - private String methodDescription; - private String description; - private String block; - - public String getMutatorClass() { - int lastDot = mutator.lastIndexOf('.'); - String className = mutator.substring(lastDot + 1); - return className.endsWith("Mutator") - ? className.substring(0, className.length() - 7) - : className; + private boolean detected; + private String status; + @JsonProperty("sourceFile") + private String sourceFile; + private String mutatedClass; + private String mutatedMethod; + private int lineNumber; + private String mutator; + private List indexes = new ArrayList<>(); + private String killingTest; + private String methodDescription; + private String description; + private List blocks = new ArrayList<>(); + + public Mutation() { + } + + public String getMutatorClass() { + int lastDot = mutator.lastIndexOf('.'); + String className = mutator.substring(lastDot + 1); + return className.endsWith("Mutator") ? className.substring(0, className.length() - 7) : className; + } + + public boolean isDetected() { + return this.detected; + } + + public String getStatus() { + return this.status; + } + + public String getSourceFile() { + return this.sourceFile; + } + + public String getMutatedClass() { + return this.mutatedClass; + } + + public String getMutatedMethod() { + return this.mutatedMethod; + } + + public int getLineNumber() { + return this.lineNumber; + } + + public String getMutator() { + return this.mutator; + } + + public List getIndexes() { + return this.indexes; + } + + public String getKillingTest() { + return this.killingTest; + } + + public String getMethodDescription() { + return this.methodDescription; + } + + public String getDescription() { + return this.description; + } + + public List getBlocks() { + return this.blocks; + } + + public void setDetected(boolean detected) { + this.detected = detected; + } + + public void setStatus(String status) { + this.status = status; + } + + public void setSourceFile(String sourceFile) { + this.sourceFile = sourceFile; + } + + public void setMutatedClass(String mutatedClass) { + this.mutatedClass = mutatedClass; + } + + public void setMutatedMethod(String mutatedMethod) { + this.mutatedMethod = mutatedMethod; + } + + public void setLineNumber(int lineNumber) { + this.lineNumber = lineNumber; + } + + public void setMutator(String mutator) { + this.mutator = mutator; + } + + public void setIndexes(List indexes) { + this.indexes = indexes; + } + + public void setKillingTest(String killingTest) { + this.killingTest = killingTest; + } + + public void setMethodDescription(String methodDescription) { + this.methodDescription = methodDescription; + } + + public void setDescription(String description) { + this.description = description; + } + + public void setBlocks(List blocks) { + this.blocks = blocks; + } + + public boolean equals(final Object o) { + if (o == this) {return true;} + if (!(o instanceof Mutation)) {return false;} + final Mutation other = (Mutation) o; + if (!other.canEqual((Object) this)) {return false;} + if (this.isDetected() != other.isDetected()) {return false;} + final Object this$status = this.getStatus(); + final Object other$status = other.getStatus(); + if (this$status == null ? other$status != null : !this$status.equals(other$status)) {return false;} + final Object this$sourceFile = this.getSourceFile(); + final Object other$sourceFile = other.getSourceFile(); + if (this$sourceFile == null ? other$sourceFile != null : !this$sourceFile.equals(other$sourceFile)) {return false;} + final Object this$mutatedClass = this.getMutatedClass(); + final Object other$mutatedClass = other.getMutatedClass(); + if (this$mutatedClass == null ? other$mutatedClass != null : !this$mutatedClass.equals(other$mutatedClass)) { + return false; + } + final Object this$mutatedMethod = this.getMutatedMethod(); + final Object other$mutatedMethod = other.getMutatedMethod(); + if (this$mutatedMethod == null ? other$mutatedMethod != null : !this$mutatedMethod.equals(other$mutatedMethod)) { + return false; + } + if (this.getLineNumber() != other.getLineNumber()) {return false;} + final Object this$mutator = this.getMutator(); + final Object other$mutator = other.getMutator(); + if (this$mutator == null ? other$mutator != null : !this$mutator.equals(other$mutator)) {return false;} + final Object this$indexes = this.getIndexes(); + final Object other$indexes = other.getIndexes(); + if (this$indexes == null ? other$indexes != null : !this$indexes.equals(other$indexes)) {return false;} + final Object this$killingTest = this.getKillingTest(); + final Object other$killingTest = other.getKillingTest(); + if (this$killingTest == null ? other$killingTest != null : !this$killingTest.equals(other$killingTest)) { + return false; } + final Object this$methodDescription = this.getMethodDescription(); + final Object other$methodDescription = other.getMethodDescription(); + if (this$methodDescription == null ? + other$methodDescription != null : + !this$methodDescription.equals(other$methodDescription)) {return false;} + final Object this$description = this.getDescription(); + final Object other$description = other.getDescription(); + if (this$description == null ? other$description != null : !this$description.equals(other$description)) { + return false; + } + final Object this$blocks = this.getBlocks(); + final Object other$blocks = other.getBlocks(); + if (this$blocks == null ? other$blocks != null : !this$blocks.equals(other$blocks)) {return false;} + return true; + } + + protected boolean canEqual(final Object other) { + return other instanceof Mutation; + } + + public int hashCode() { + final int PRIME = 59; + int result = 1; + result = result * PRIME + (this.isDetected() ? 79 : 97); + final Object $status = this.getStatus(); + result = result * PRIME + ($status == null ? 43 : $status.hashCode()); + final Object $sourceFile = this.getSourceFile(); + result = result * PRIME + ($sourceFile == null ? 43 : $sourceFile.hashCode()); + final Object $mutatedClass = this.getMutatedClass(); + result = result * PRIME + ($mutatedClass == null ? 43 : $mutatedClass.hashCode()); + final Object $mutatedMethod = this.getMutatedMethod(); + result = result * PRIME + ($mutatedMethod == null ? 43 : $mutatedMethod.hashCode()); + result = result * PRIME + this.getLineNumber(); + final Object $mutator = this.getMutator(); + result = result * PRIME + ($mutator == null ? 43 : $mutator.hashCode()); + final Object $indexes = this.getIndexes(); + result = result * PRIME + ($indexes == null ? 43 : $indexes.hashCode()); + final Object $killingTest = this.getKillingTest(); + result = result * PRIME + ($killingTest == null ? 43 : $killingTest.hashCode()); + final Object $methodDescription = this.getMethodDescription(); + result = result * PRIME + ($methodDescription == null ? 43 : $methodDescription.hashCode()); + final Object $description = this.getDescription(); + result = result * PRIME + ($description == null ? 43 : $description.hashCode()); + final Object $blocks = this.getBlocks(); + result = result * PRIME + ($blocks == null ? 43 : $blocks.hashCode()); + return result; + } + + public String toString() { + return "Mutation(detected=" + + this.isDetected() + + ", status=" + + this.getStatus() + + ", sourceFile=" + + this.getSourceFile() + + ", mutatedClass=" + + this.getMutatedClass() + + ", mutatedMethod=" + + this.getMutatedMethod() + + ", lineNumber=" + + this.getLineNumber() + + ", mutator=" + + this.getMutator() + + ", indexes=" + + this.getIndexes() + + ", killingTest=" + + this.getKillingTest() + + ", methodDescription=" + + this.getMethodDescription() + + ", description=" + + this.getDescription() + + ", blocks=" + + this.getBlocks() + + ")"; + } } diff --git a/src/main/java/org/jenkinsci/plugins/pitmutation/MutationReport.java b/src/main/java/org/jenkinsci/plugins/pitmutation/MutationReport.java index 7597a1f..3c9671e 100644 --- a/src/main/java/org/jenkinsci/plugins/pitmutation/MutationReport.java +++ b/src/main/java/org/jenkinsci/plugins/pitmutation/MutationReport.java @@ -1,99 +1,85 @@ package org.jenkinsci.plugins.pitmutation; -import org.apache.commons.digester3.Digester; +import com.fasterxml.jackson.dataformat.xml.JacksonXmlModule; +import com.fasterxml.jackson.dataformat.xml.XmlMapper; import org.jenkinsci.plugins.pitmutation.targets.MutationStats; import org.xml.sax.SAXException; import java.io.IOException; import java.io.InputStream; -import java.util.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; /** * @author edward */ public class MutationReport { - private final Map> mutationsByPackage; - private final Map> mutationsByClass; - private int killCount = 0; - - public MutationReport() { - this.mutationsByClass = new HashMap<>(); - this.mutationsByPackage = new HashMap<>(); - } - - public static MutationReport create(InputStream xmlReport) throws IOException, SAXException { - return digestMutations(xmlReport); - } - - private static MutationReport digestMutations(InputStream input) throws IOException, SAXException { - Digester digester = new Digester(); - digester.addObjectCreate("mutations", MutationReport.class); - digester.addObjectCreate("mutations/mutation", Mutation.class); - digester.addSetNext("mutations/mutation", "addMutation", "org.jenkinsci.plugins.pitmutation.Mutation"); - digester.addSetProperties("mutations/mutation"); - digester.addSetNestedProperties("mutations/mutation"); - - MutationReport report = digester.parse(input); - report.mutationsByClass.forEach((className, mutations) -> { - String packageName = packageNameFromClass(className); - List existingPackageMutations = report.mutationsByPackage - .computeIfAbsent(packageName, k -> new ArrayList<>()); - mutations.stream().filter(mutation -> !existingPackageMutations.contains(mutation)) - .forEach(mutation -> report.mutationsByPackage.get(packageName).add(mutation)); - }); - return report; - } - - /** - * Called by digester. - * - * @param mutation {@link Mutation} to add - */ - public void addMutation(Mutation mutation) { - mutationsByClass.computeIfAbsent(mutation.getMutatedClass(), k -> new ArrayList<>()) - .add(mutation); - if (mutation.isDetected()) { - killCount++; - } - mutationsByPackage.computeIfAbsent(packageNameFromClass(mutation.getMutatedClass()), k -> new ArrayList<>()) - .add(mutation); - } - - public Collection getMutationsForPackage(String packageName) { - return mutationsByPackage.computeIfAbsent(packageName, k -> new ArrayList<>()); - } - - public Map> getMutationsByPackage() { - return mutationsByPackage; - } - - public Collection getMutationsForClassName(String className) { - return mutationsByClass.computeIfAbsent(className, k -> new ArrayList<>()); - } - - public MutationStats getMutationStats() { - return new MutationStats() { - @Override - public String getTitle() { - return "Report Stats"; - } - - @Override - public int getUndetected() { - return getTotalMutations() - killCount; - } - - @Override - public int getTotalMutations() { - return mutationsByClass.values().stream().mapToInt(Collection::size).sum(); - } - }; - } - - // TODO: Move somewhere out of this class - static String packageNameFromClass(String fqcn) { - int idx = fqcn.lastIndexOf('.'); - return fqcn.substring(0, idx != -1 ? idx : 0); - } + private final Map> mutationsByPackage; + + private final Map> mutationsByClass; + private int killCount = 0; + + public MutationReport(InputStream xmlReport) throws IOException, SAXException { + this.mutationsByClass = new HashMap<>(); + this.mutationsByPackage = new HashMap<>(); + + + // https://github.com/FasterXML/jackson-dataformat-xml/issues/219 + JacksonXmlModule module = new JacksonXmlModule(); + module.setDefaultUseWrapper(false); + XmlMapper xmlMapper = new XmlMapper(module); + Mutations mutations = xmlMapper.readValue(xmlReport, Mutations.class); + + mutations.getMutation().forEach(mutation -> { + mutationsByClass.computeIfAbsent(mutation.getMutatedClass(), k -> new ArrayList<>()).add(mutation); + if (mutation.isDetected()) { + killCount++; + } + mutationsByPackage + .computeIfAbsent(packageNameFromClass(mutation.getMutatedClass()), k -> new ArrayList<>()) + .add(mutation); + + }); + } + + public Collection getMutationsForPackage(String packageName) { + return mutationsByPackage.computeIfAbsent(packageName, k -> new ArrayList<>()); + } + + public Map> getMutationsByPackage() { + return mutationsByPackage; + } + + public Collection getMutationsForClassName(String className) { + return mutationsByClass.computeIfAbsent(className, k -> new ArrayList<>()); + } + + public MutationStats getMutationStats() { + return new MutationStats() { + @Override + public String getTitle() { + return "Report Stats"; + } + + @Override + public int getUndetected() { + return getTotalMutations() - killCount; + } + + @Override + public int getTotalMutations() { + return mutationsByClass.values().stream().mapToInt(Collection::size).sum(); + } + }; + } + + // TODO: Move somewhere out of this class + static String packageNameFromClass(String fqcn) { + int idx = fqcn.lastIndexOf('.'); + return fqcn.substring(0, idx != -1 ? idx : 0); + } } diff --git a/src/main/java/org/jenkinsci/plugins/pitmutation/Mutations.java b/src/main/java/org/jenkinsci/plugins/pitmutation/Mutations.java new file mode 100644 index 0000000..8bb9655 --- /dev/null +++ b/src/main/java/org/jenkinsci/plugins/pitmutation/Mutations.java @@ -0,0 +1,14 @@ +package org.jenkinsci.plugins.pitmutation; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +@AllArgsConstructor +@Data +@NoArgsConstructor +public class Mutations { + private List mutation; +} diff --git a/src/main/java/org/jenkinsci/plugins/pitmutation/PitBuildAction.java b/src/main/java/org/jenkinsci/plugins/pitmutation/PitBuildAction.java index 998756b..0e33567 100644 --- a/src/main/java/org/jenkinsci/plugins/pitmutation/PitBuildAction.java +++ b/src/main/java/org/jenkinsci/plugins/pitmutation/PitBuildAction.java @@ -94,7 +94,7 @@ private Map readReports() { } else { name = String.valueOf(i); } - reports.put(name, MutationReport.create(files[i].read())); + reports.put(name, new MutationReport(files[i].read())); } } catch (IOException | InterruptedException | SAXException e) { e.printStackTrace(); diff --git a/src/test/java/org/jenkinsci/plugins/pitmutation/MutationReportTest.java b/src/test/java/org/jenkinsci/plugins/pitmutation/MutationReportTest.java index 21129fb..021c03f 100644 --- a/src/test/java/org/jenkinsci/plugins/pitmutation/MutationReportTest.java +++ b/src/test/java/org/jenkinsci/plugins/pitmutation/MutationReportTest.java @@ -27,7 +27,7 @@ public class MutationReportTest { + "getSize\n" + "54\n" + "org.pitest.mutationtest.engine.gregor.mutators.ReturnValsMutator\n" - + "5\n" + + "5\n" + "\n" + "" + "" @@ -36,8 +36,8 @@ public class MutationReportTest { + "getSize" + "57" + "org.pitest.mutationtest.engine.gregor.mutators.ReturnValsMutator" - + "6" - + "3" + + "6" + + "3" + "" + "" + ""; @@ -57,28 +57,28 @@ public void packageNameFinder() { @Test public void countsKills() throws IOException, SAXException { - MutationReport report = MutationReport.create(mutationsXml); + MutationReport report = new MutationReport(mutationsXml); assertThat(report.getMutationStats().getKillCount(), is(5)); assertThat(report.getMutationStats().getTotalMutations(), is(16)); } @Test public void sortsMutationsByClassName() throws IOException, SAXException { - MutationReport report = MutationReport.create(mutationsXml); + MutationReport report = new MutationReport(mutationsXml); Collection mutations = report.getMutationsForClassName("org.jenkinsci.plugins.pitmutation.MutationReport"); assertThat(mutations.size(), is(5)); } @Test public void indexesMutationsByPackage() throws IOException, SAXException { - MutationReport report = MutationReport.create(mutationsXml); + MutationReport report = new MutationReport(mutationsXml); assertThat(report.getMutationsForPackage("org.jenkinsci.plugins.pitmutation"), hasSize(16)); assertThat(report.getMutationsForPackage(""), hasSize(0)); } @Test public void canDigestAMutation() throws IOException, SAXException { - MutationReport report = MutationReport.create(new ByteArrayInputStream(MUTATIONS.getBytes("UTF-8"))); + MutationReport report = new MutationReport(new ByteArrayInputStream(MUTATIONS.getBytes("UTF-8"))); assertThat(report.getMutationStats().getTotalMutations(), is(2)); diff --git a/src/test/java/org/jenkinsci/plugins/pitmutation/MutationReportWithDescriptionTest.java b/src/test/java/org/jenkinsci/plugins/pitmutation/MutationReportWithDescriptionTest.java index 7e00a2b..9b1075a 100644 --- a/src/test/java/org/jenkinsci/plugins/pitmutation/MutationReportWithDescriptionTest.java +++ b/src/test/java/org/jenkinsci/plugins/pitmutation/MutationReportWithDescriptionTest.java @@ -1,55 +1,55 @@ package org.jenkinsci.plugins.pitmutation; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.hasSize; -import static org.hamcrest.Matchers.notNullValue; -import static org.hamcrest.core.Is.is; +import org.junit.Before; +import org.junit.Test; +import org.xml.sax.SAXException; import java.io.IOException; import java.io.InputStream; import java.util.Collection; -import org.junit.Before; -import org.junit.Test; -import org.xml.sax.SAXException; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.hasSize; +import static org.hamcrest.Matchers.notNullValue; +import static org.hamcrest.core.Is.is; /** * @author edward */ public class MutationReportWithDescriptionTest { - private InputStream mutationsXml; - - @Before - public void setUp() { - mutationsXml = getClass().getResourceAsStream("testmutations-02.xml"); - } - - @Test - public void packageNameFinder() { - assertThat(MutationReport.packageNameFromClass("xxx.yyy.zzz.Foo"), is("xxx.yyy.zzz")); - assertThat(MutationReport.packageNameFromClass("Foo"), is("")); - } - - @Test - public void countsKills() throws IOException, SAXException { - MutationReport report = MutationReport.create(mutationsXml); - assertThat(report.getMutationStats().getKillCount(), is(3)); - assertThat(report.getMutationStats().getTotalMutations(), is(4)); - } - - @Test - public void sortsMutationsByClassName() throws IOException, SAXException { - MutationReport report = MutationReport.create(mutationsXml); - Collection mutations = report.getMutationsForClassName("es.rodri.controllers.CompositorController"); - assertThat(mutations.size(), is(4)); - } - - @Test - public void indexesMutationsByPackage() throws IOException, SAXException { - MutationReport report = MutationReport.create(mutationsXml); - assertThat(report.getMutationsForPackage("es.rodri.controllers"), hasSize(4)); - assertThat(report.getMutationsForPackage(""), notNullValue()); - assertThat(report.getMutationsForPackage(""), hasSize(0)); - } + private InputStream mutationsXml; + + @Before + public void setUp() { + mutationsXml = getClass().getResourceAsStream("testmutations-02.xml"); + } + + @Test + public void packageNameFinder() { + assertThat(MutationReport.packageNameFromClass("xxx.yyy.zzz.Foo"), is("xxx.yyy.zzz")); + assertThat(MutationReport.packageNameFromClass("Foo"), is("")); + } + + @Test + public void countsKills() throws IOException, SAXException { + MutationReport report = new MutationReport(mutationsXml); + assertThat(report.getMutationStats().getKillCount(), is(3)); + assertThat(report.getMutationStats().getTotalMutations(), is(4)); + } + + @Test + public void sortsMutationsByClassName() throws IOException, SAXException { + MutationReport report = new MutationReport(mutationsXml); + Collection mutations = report.getMutationsForClassName("es.rodri.controllers.CompositorController"); + assertThat(mutations.size(), is(4)); + } + + @Test + public void indexesMutationsByPackage() throws IOException, SAXException { + MutationReport report = new MutationReport(mutationsXml); + assertThat(report.getMutationsForPackage("es.rodri.controllers"), hasSize(4)); + assertThat(report.getMutationsForPackage(""), notNullValue()); + assertThat(report.getMutationsForPackage(""), hasSize(0)); + } } diff --git a/src/test/java/org/jenkinsci/plugins/pitmutation/targets/MutationResultTest.java b/src/test/java/org/jenkinsci/plugins/pitmutation/targets/MutationResultTest.java index e155de6..0bca4ec 100644 --- a/src/test/java/org/jenkinsci/plugins/pitmutation/targets/MutationResultTest.java +++ b/src/test/java/org/jenkinsci/plugins/pitmutation/targets/MutationResultTest.java @@ -12,7 +12,11 @@ import java.util.Map; import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.*; +import static org.hamcrest.Matchers.hasSize; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.lessThan; +import static org.hamcrest.Matchers.not; +import static org.hamcrest.Matchers.nullValue; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -21,143 +25,148 @@ */ public abstract class MutationResultTest { - private MutationResult projectResult; - private MutationResult moduleResult; - - @Before - public void setUp() throws IOException, SAXException { - MutationReport reportOld = MutationReport.create(MutationReport.class.getResourceAsStream("testmutations-00.xml")); - MutationReport reportNew = MutationReport.create(MutationReport.class.getResourceAsStream("testmutations-01.xml")); - Map reportsNew = new HashMap<>(); - Map reportsOld = new HashMap<>(); - reportsNew.put("test_report", reportNew); - reportsOld.put("test_report", reportOld); - - PitBuildAction buildAction = mock(PitBuildAction.class); - when(buildAction.getReports()).thenReturn(reportsNew); - - PitBuildAction previousBuildAction = mock(PitBuildAction.class); - when(previousBuildAction.getReports()).thenReturn(reportsOld); - when(previousBuildAction.getReport()).thenReturn(new ProjectMutations(previousBuildAction)); - - when(buildAction.getPreviousAction()).thenReturn(previousBuildAction); - - projectResult = new ProjectMutations(buildAction); - moduleResult = projectResult.getChildMap().get("test_report"); - assertThat(moduleResult, not(nullValue())); - assertThat(projectResult.getPreviousResult(), not(nullValue())); - } - - @Test - public void mutationResultStatsDelta() { - MutationStats delta = projectResult.getStatsDelta(); - assertThat(delta.getTotalMutations(), is(3)); - assertThat(delta.getKillCount(), is(-1)); - } - - private MutationResult packageResult() { - return projectResult.getChildResult("test_report").getChildResult("org.jenkinsci.plugins.pitmutation"); - } - - @Test - public void packageResultsStatsDelta() { - MutationStats delta = packageResult().getStatsDelta(); - assertThat(delta.getTotalMutations(), is(3)); - assertThat(delta.getKillCount(), is(-1)); - } - - private MutationResult classResult(String className) { - return packageResult().getChildResult(className); - } - - @Test - public void classResultsStats() { - MutationStats stats = classResult("org.jenkinsci.plugins.pitmutation.Mutation").getMutationStats(); - assertThat(stats.getTotalMutations(), is(3)); - assertThat(stats.getKillCount(), is(1)); - } - - @Test - public void classResultsStatsDelta() { - MutationStats delta = classResult("org.jenkinsci.plugins.pitmutation.Mutation").getStatsDelta(); - assertThat(delta.getTotalMutations(), is(-1)); - assertThat(delta.getKillCount(), is(-2)); - } - - @Test - public void classResultsForNewClass() { - MutationStats stats = classResult("org.jenkinsci.plugins.pitmutation.NewMutatedClass").getMutationStats(); - assertThat(stats.getTotalMutations(), is(1)); - assertThat(stats.getKillCount(), is(0)); - } - - @Test - public void classResultsForNewClassDelta() { - MutationStats stats = classResult("org.jenkinsci.plugins.pitmutation.NewMutatedClass").getStatsDelta(); - assertThat(stats.getTotalMutations(), is(1)); - assertThat(stats.getKillCount(), is(0)); - } - - @Test - public void classResultsOrdered() { - Iterator classes = moduleResult.getChildren().iterator(); - int undetected = classes.next().getMutationStats().getUndetected(); - - while (classes.hasNext()) { - MutationResult result = classes.next(); - assertThat(result.getMutationStats().getUndetected(), lessThan(undetected)); - undetected = result.getMutationStats().getUndetected(); - } - } - - @Test - public void urlTransformPackageName() { - assertThat(moduleResult.getChildMap().get("org.jenkinsci.plugins.pitmutation").getUrl(), - is("org_jenkinsci_plugins_pitmutation")); - } - - @Test - public void urlTransformClassName() { - assertThat(moduleResult.getChildMap().get("org.jenkinsci.plugins.pitmutation") - .getChildMap().get("org.jenkinsci.plugins.pitmutation.PitParser").getUrl(), - is("org_jenkinsci_plugins_pitmutation_PitParser")); - } - - @Test - public void findsMutationsOnPitParserClass() { - MutationResult pitPackage = moduleResult.getChildMap().get("org.jenkinsci.plugins.pitmutation"); - assertThat(pitPackage.getChildren(), hasSize(5)); - MutationResult pitParser = pitPackage.getChildMap().get("org.jenkinsci.plugins.pitmutation.PitParser"); - assertThat(pitParser.getChildren(), hasSize(3)); - } - - @Test - public void collectsMutationStats() { - MutationStats stats = projectResult.getMutationStats(); - assertThat(stats.getTotalMutations(), is(19)); - assertThat(stats.getUndetected(), is(15)); - } - - @Test - public void correctSourceLevels() { - MutationResult pitPackage = moduleResult.getChildMap().get("org.jenkinsci.plugins.pitmutation"); - MutationResult pitParser = pitPackage.getChildMap().get("org.jenkinsci.plugins.pitmutation.PitParser"); - MutationResult lineResult = pitParser.getChildMap().values().iterator().next(); - - assertThat(projectResult.isSourceLevel(), is(false)); - assertThat(moduleResult.isSourceLevel(), is(false)); - assertThat(pitPackage.isSourceLevel(), is(false)); - assertThat(pitParser.isSourceLevel(), is(true)); - assertThat(lineResult.isSourceLevel(), is(false)); - } - - @Test - public void testXmlTransform() { - assertThat(MutationResult.xmlTransform("replace&and"), is("replace&and<and>")); - } - - @Test - public void testUrlTransform() { - assertThat(MutationResult.urlTransform("^*!replace::non+'alphas@}129"), is("___replace__non__alphas__129")); - } + private MutationResult projectResult; + private MutationResult moduleResult; + + @Before + public void setUp() throws IOException, SAXException { + MutationReport reportOld = + new MutationReport(MutationReport.class.getResourceAsStream("testmutations-00.xml")); + MutationReport reportNew = + new MutationReport(MutationReport.class.getResourceAsStream("testmutations-01.xml")); + Map reportsNew = new HashMap<>(); + Map reportsOld = new HashMap<>(); + reportsNew.put("test_report", reportNew); + reportsOld.put("test_report", reportOld); + + PitBuildAction buildAction = mock(PitBuildAction.class); + when(buildAction.getReports()).thenReturn(reportsNew); + + PitBuildAction previousBuildAction = mock(PitBuildAction.class); + when(previousBuildAction.getReports()).thenReturn(reportsOld); + when(previousBuildAction.getReport()).thenReturn(new ProjectMutations(previousBuildAction)); + + when(buildAction.getPreviousAction()).thenReturn(previousBuildAction); + + projectResult = new ProjectMutations(buildAction); + moduleResult = projectResult.getChildMap().get("test_report"); + assertThat(moduleResult, not(nullValue())); + assertThat(projectResult.getPreviousResult(), not(nullValue())); + } + + @Test + public void mutationResultStatsDelta() { + MutationStats delta = projectResult.getStatsDelta(); + assertThat(delta.getTotalMutations(), is(3)); + assertThat(delta.getKillCount(), is(-1)); + } + + private MutationResult packageResult() { + return projectResult.getChildResult("test_report").getChildResult("org.jenkinsci.plugins.pitmutation"); + } + + @Test + public void packageResultsStatsDelta() { + MutationStats delta = packageResult().getStatsDelta(); + assertThat(delta.getTotalMutations(), is(3)); + assertThat(delta.getKillCount(), is(-1)); + } + + private MutationResult classResult(String className) { + return packageResult().getChildResult(className); + } + + @Test + public void classResultsStats() { + MutationStats stats = classResult("org.jenkinsci.plugins.pitmutation.Mutation").getMutationStats(); + assertThat(stats.getTotalMutations(), is(3)); + assertThat(stats.getKillCount(), is(1)); + } + + @Test + public void classResultsStatsDelta() { + MutationStats delta = classResult("org.jenkinsci.plugins.pitmutation.Mutation").getStatsDelta(); + assertThat(delta.getTotalMutations(), is(-1)); + assertThat(delta.getKillCount(), is(-2)); + } + + @Test + public void classResultsForNewClass() { + MutationStats stats = classResult("org.jenkinsci.plugins.pitmutation.NewMutatedClass").getMutationStats(); + assertThat(stats.getTotalMutations(), is(1)); + assertThat(stats.getKillCount(), is(0)); + } + + @Test + public void classResultsForNewClassDelta() { + MutationStats stats = classResult("org.jenkinsci.plugins.pitmutation.NewMutatedClass").getStatsDelta(); + assertThat(stats.getTotalMutations(), is(1)); + assertThat(stats.getKillCount(), is(0)); + } + + @Test + public void classResultsOrdered() { + Iterator classes = moduleResult.getChildren().iterator(); + int undetected = classes.next().getMutationStats().getUndetected(); + + while (classes.hasNext()) { + MutationResult result = classes.next(); + assertThat(result.getMutationStats().getUndetected(), lessThan(undetected)); + undetected = result.getMutationStats().getUndetected(); + } + } + + @Test + public void urlTransformPackageName() { + assertThat(moduleResult.getChildMap().get("org.jenkinsci.plugins.pitmutation").getUrl(), + is("org_jenkinsci_plugins_pitmutation")); + } + + @Test + public void urlTransformClassName() { + assertThat(moduleResult + .getChildMap() + .get("org.jenkinsci.plugins.pitmutation") + .getChildMap() + .get("org.jenkinsci.plugins.pitmutation.PitParser") + .getUrl(), is("org_jenkinsci_plugins_pitmutation_PitParser")); + } + + @Test + public void findsMutationsOnPitParserClass() { + MutationResult pitPackage = moduleResult.getChildMap().get("org.jenkinsci.plugins.pitmutation"); + assertThat(pitPackage.getChildren(), hasSize(5)); + MutationResult pitParser = pitPackage.getChildMap().get("org.jenkinsci.plugins.pitmutation.PitParser"); + assertThat(pitParser.getChildren(), hasSize(3)); + } + + @Test + public void collectsMutationStats() { + MutationStats stats = projectResult.getMutationStats(); + assertThat(stats.getTotalMutations(), is(19)); + assertThat(stats.getUndetected(), is(15)); + } + + @Test + public void correctSourceLevels() { + MutationResult pitPackage = moduleResult.getChildMap().get("org.jenkinsci.plugins.pitmutation"); + MutationResult pitParser = pitPackage.getChildMap().get("org.jenkinsci.plugins.pitmutation.PitParser"); + MutationResult lineResult = pitParser.getChildMap().values().iterator().next(); + + assertThat(projectResult.isSourceLevel(), is(false)); + assertThat(moduleResult.isSourceLevel(), is(false)); + assertThat(pitPackage.isSourceLevel(), is(false)); + assertThat(pitParser.isSourceLevel(), is(true)); + assertThat(lineResult.isSourceLevel(), is(false)); + } + + @Test + public void testXmlTransform() { + assertThat(MutationResult.xmlTransform("replace&and"), is("replace&and<and>")); + } + + @Test + public void testUrlTransform() { + assertThat(MutationResult.urlTransform("^*!replace::non+'alphas@}129"), is("___replace__non__alphas__129")); + } } diff --git a/src/test/resources/org/jenkinsci/plugins/pitmutation/testmutations-00.xml b/src/test/resources/org/jenkinsci/plugins/pitmutation/testmutations-00.xml index 3b5fa68..83f763b 100644 --- a/src/test/resources/org/jenkinsci/plugins/pitmutation/testmutations-00.xml +++ b/src/test/resources/org/jenkinsci/plugins/pitmutation/testmutations-00.xml @@ -6,7 +6,9 @@ <init> 28 org.pitest.mutationtest.engine.gregor.mutators.NonVoidMethodCallMutator - 10 + + 10 + @@ -15,7 +17,9 @@ <init> 23 org.pitest.mutationtest.engine.gregor.mutators.NonVoidMethodCallMutator - 2 + + 2 + @@ -24,7 +28,9 @@ <init> 26 org.pitest.mutationtest.engine.gregor.mutators.NonVoidMethodCallMutator - 7 + + 7 + @@ -34,7 +40,9 @@ equals 15 org.pitest.mutationtest.engine.gregor.mutators.NegateConditionalsMutator - 0 + + 0 + @@ -43,7 +51,9 @@ setStatus 36 org.pitest.mutationtest.engine.gregor.mutators.experimental.MemberVariableMutator - 1 + + 1 + org.jenkinsci.plugins.pitmutation.MutationReportTest.canDigestAMutation(org.jenkinsci.plugins.pitmutation.MutationReportTest) @@ -54,7 +64,9 @@ getSourceFile 40 org.pitest.mutationtest.engine.gregor.mutators.ReturnValsMutator - 5 + + 5 + org.jenkinsci.plugins.pitmutation.MutationReportTest.canDigestAMutation(org.jenkinsci.plugins.pitmutation.MutationReportTest) @@ -65,7 +77,9 @@ getMutator 72 org.pitest.mutationtest.engine.gregor.mutators.ReturnValsMutator - 9 + + 9 + org.jenkinsci.plugins.pitmutation.MutationReportTest.canDigestAMutation(org.jenkinsci.plugins.pitmutation.MutationReportTest) @@ -77,7 +91,9 @@ <init> 18 org.pitest.mutationtest.engine.gregor.mutators.NonVoidMethodCallMutator - 0 + + 0 + @@ -86,7 +102,9 @@ <init> 16 org.pitest.mutationtest.engine.gregor.mutators.experimental.MemberVariableMutator - 0 + + 0 + org.jenkinsci.plugins.pitmutation.PitBuildActionTest.previousReturnsNullIfNoPreviousBuilds(org.jenkinsci.plugins.pitmutation.PitBuildActionTest) @@ -97,7 +115,9 @@ <init> 18 org.pitest.mutationtest.engine.gregor.mutators.experimental.MemberVariableMutator - 2 + + 2 + @@ -106,7 +126,9 @@ <init> 18 org.pitest.mutationtest.engine.gregor.mutators.experimental.MemberVariableMutator - 1 + + 1 + @@ -116,7 +138,9 @@ digestMutations 42 org.pitest.mutationtest.engine.gregor.mutators.experimental.InlineConstantMutator - 2 + + 2 + @@ -125,7 +149,9 @@ digestMutations 39 org.pitest.mutationtest.engine.gregor.mutators.InlineConstantMutator - 1 + + 1 + @@ -134,7 +160,9 @@ digestMutations 38 org.pitest.mutationtest.engine.gregor.mutators.experimental.InlineConstantMutator - 0 + + 0 + @@ -143,7 +171,9 @@ digestMutations 29 org.pitest.mutationtest.engine.gregor.mutators.ConstructorCallMutator - 1 + + 1 + org.jenkinsci.plugins.pitmutation.MutationReportTest.canDigestAMutation(org.jenkinsci.plugins.pitmutation.MutationReportTest) @@ -154,7 +184,9 @@ digestMutations 39 org.pitest.mutationtest.engine.gregor.mutators.experimental.InlineConstantMutator - 1 + + 1 + diff --git a/src/test/resources/org/jenkinsci/plugins/pitmutation/testmutations-01.xml b/src/test/resources/org/jenkinsci/plugins/pitmutation/testmutations-01.xml index c8a1a6a..fa53af5 100644 --- a/src/test/resources/org/jenkinsci/plugins/pitmutation/testmutations-01.xml +++ b/src/test/resources/org/jenkinsci/plugins/pitmutation/testmutations-01.xml @@ -6,7 +6,9 @@ <init> 28 org.pitest.mutationtest.engine.gregor.mutators.NonVoidMethodCallMutator - 10 + + 10 + @@ -15,7 +17,9 @@ <init> 23 org.pitest.mutationtest.engine.gregor.mutators.NonVoidMethodCallMutator - 2 + + 2 + @@ -24,7 +28,9 @@ <init> 26 org.pitest.mutationtest.engine.gregor.mutators.NonVoidMethodCallMutator - 7 + + 7 + @@ -34,7 +40,9 @@ equals 15 org.pitest.mutationtest.engine.gregor.mutators.NegateConditionalsMutator - 0 + + 0 + @@ -43,7 +51,9 @@ setMutatedMethod 60 org.pitest.mutationtest.engine.gregor.mutators.experimental.MemberVariableMutator - 4 + + 4 + @@ -52,7 +62,9 @@ setStatus 36 org.pitest.mutationtest.engine.gregor.mutators.experimental.MemberVariableMutator - 1 + + 1 + org.jenkinsci.plugins.pitmutation.MutationReportTest.canDigestAMutation(org.jenkinsci.plugins.pitmutation.MutationReportTest) @@ -64,7 +76,9 @@ <init> 18 org.pitest.mutationtest.engine.gregor.mutators.NonVoidMethodCallMutator - 0 + + 0 + @@ -73,7 +87,9 @@ <init> 16 org.pitest.mutationtest.engine.gregor.mutators.experimental.MemberVariableMutator - 0 + + 0 + org.jenkinsci.plugins.pitmutation.PitBuildActionTest.previousReturnsNullIfNoPreviousBuilds(org.jenkinsci.plugins.pitmutation.PitBuildActionTest) @@ -84,7 +100,9 @@ <init> 18 org.pitest.mutationtest.engine.gregor.mutators.experimental.MemberVariableMutator - 2 + + 2 + @@ -93,7 +111,9 @@ <init> 17 org.pitest.mutationtest.engine.gregor.mutators.experimental.MemberVariableMutator - 1 + + 1 + @@ -102,7 +122,9 @@ getPreviousAction 29 org.pitest.mutationtest.engine.gregor.mutators.NonVoidMethodCallMutator - 3 + + 3 + org.jenkinsci.plugins.pitmutation.PitBuildActionTest.previousReturnsLastSuccessfulBuild(org.jenkinsci.plugins.pitmutation.PitBuildActionTest) @@ -113,7 +135,9 @@ getBuildHealth 40 org.pitest.mutationtest.engine.gregor.mutators.ConstructorCallMutator - 0 + + 0 + @@ -122,7 +146,9 @@ getPreviousAction 27 org.pitest.mutationtest.engine.gregor.mutators.NonVoidMethodCallMutator - 2 + + 2 + @@ -132,7 +158,9 @@ digestMutations 42 org.pitest.mutationtest.engine.gregor.mutators.experimental.InlineConstantMutator - 2 + + 2 + @@ -141,7 +169,9 @@ digestMutations 39 org.pitest.mutationtest.engine.gregor.mutators.InlineConstantMutator - 1 + + 1 + @@ -150,7 +180,9 @@ digestMutations 38 org.pitest.mutationtest.engine.gregor.mutators.experimental.InlineConstantMutator - 0 + + 0 + @@ -159,7 +191,9 @@ digestMutations 29 org.pitest.mutationtest.engine.gregor.mutators.ConstructorCallMutator - 1 + + 1 + org.jenkinsci.plugins.pitmutation.MutationReportTest.canDigestAMutation(org.jenkinsci.plugins.pitmutation.MutationReportTest) @@ -170,7 +204,9 @@ digestMutations 39 org.pitest.mutationtest.engine.gregor.mutators.experimental.InlineConstantMutator - 1 + + 1 + @@ -180,7 +216,9 @@ digestMutations 45 org.pitest.mutationtest.engine.gregor.mutators.ConstructorCallMutator - 5 + + 5 + org.jenkinsci.plugins.pitmutation.MutationReportTest.countsKills(org.jenkinsci.plugins.pitmutation.MutationReportTest) diff --git a/src/test/resources/org/jenkinsci/plugins/pitmutation/testmutations-02.xml b/src/test/resources/org/jenkinsci/plugins/pitmutation/testmutations-02.xml index 8ecabf7..4c9e217 100644 --- a/src/test/resources/org/jenkinsci/plugins/pitmutation/testmutations-02.xml +++ b/src/test/resources/org/jenkinsci/plugins/pitmutation/testmutations-02.xml @@ -9,7 +9,9 @@ 332 org.pitest.mutationtest.engine.gregor.mutators.NegateConditionalsMutator - 5 + + 5 + negated conditional @@ -22,7 +24,9 @@ 342 org.pitest.mutationtest.engine.gregor.mutators.NegateConditionalsMutator - 47 + + 47 + es.rodri.MSInvoiceDetailTest.testController7(es.rodri.MSInvoiceDetailTest) negated conditional @@ -35,7 +39,9 @@ 344 org.pitest.mutationtest.engine.gregor.mutators.NegateConditionalsMutator - 56 + + 56 + negated conditional @@ -48,7 +54,9 @@ 344 org.pitest.mutationtest.engine.gregor.mutators.NegateConditionalsMutator - 59 + + 59 + negated conditional From 3b30f4682ed3d7677b3d96fcc5eb49d92ff114bd Mon Sep 17 00:00:00 2001 From: Vasile Jureschi Date: Fri, 27 Jan 2023 10:38:25 +0200 Subject: [PATCH 03/16] Adds backward compatibility --- pom.xml | 7 +- .../plugins/pitmutation/Mutation.java | 215 +---------------- .../plugins/pitmutation/MutationReport.java | 2 +- .../pitmutation/MutationReportTest.java | 220 +++++++++++------- 4 files changed, 146 insertions(+), 298 deletions(-) diff --git a/pom.xml b/pom.xml index d1a3e54..629b902 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ pitmutation - 1.1-4-SNAPSHOT + 1.1-5-SNAPSHOT Jenkins PIT Mutation Plugin hpi http://wiki.jenkins-ci.org/display/JENKINS/pitmutation @@ -74,11 +74,6 @@ provided - - org.apache.commons - commons-digester3 - 3.2 - org.jenkins-ci symbol-annotation diff --git a/src/main/java/org/jenkinsci/plugins/pitmutation/Mutation.java b/src/main/java/org/jenkinsci/plugins/pitmutation/Mutation.java index 38c2099..a70c5d3 100644 --- a/src/main/java/org/jenkinsci/plugins/pitmutation/Mutation.java +++ b/src/main/java/org/jenkinsci/plugins/pitmutation/Mutation.java @@ -1,6 +1,6 @@ package org.jenkinsci.plugins.pitmutation; -import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; import java.util.ArrayList; import java.util.List; @@ -10,19 +10,29 @@ * * @author edward */ +@Data public class Mutation { private boolean detected; private String status; - @JsonProperty("sourceFile") private String sourceFile; private String mutatedClass; private String mutatedMethod; private int lineNumber; private String mutator; + /** + * @deprecated from 1 .9 the mutation library generates a list of indexes JENKINS-68990 + */ + @Deprecated(forRemoval = true, since = "1.9") + private Integer index; private List indexes = new ArrayList<>(); private String killingTest; private String methodDescription; private String description; + /** + * @deprecated from 1 .9 the mutation library generates a list of blocks JENKINS-68990 + */ + @Deprecated(forRemoval = true, since = "1.9") + private String block; private List blocks = new ArrayList<>(); public Mutation() { @@ -34,209 +44,8 @@ public String getMutatorClass() { return className.endsWith("Mutator") ? className.substring(0, className.length() - 7) : className; } - public boolean isDetected() { - return this.detected; - } - - public String getStatus() { - return this.status; - } - - public String getSourceFile() { - return this.sourceFile; - } - - public String getMutatedClass() { - return this.mutatedClass; - } - - public String getMutatedMethod() { - return this.mutatedMethod; - } - - public int getLineNumber() { - return this.lineNumber; - } - - public String getMutator() { - return this.mutator; - } - - public List getIndexes() { - return this.indexes; - } - - public String getKillingTest() { - return this.killingTest; - } - - public String getMethodDescription() { - return this.methodDescription; - } - - public String getDescription() { - return this.description; - } - - public List getBlocks() { - return this.blocks; - } - - public void setDetected(boolean detected) { - this.detected = detected; - } - - public void setStatus(String status) { - this.status = status; - } - - public void setSourceFile(String sourceFile) { - this.sourceFile = sourceFile; - } - - public void setMutatedClass(String mutatedClass) { - this.mutatedClass = mutatedClass; - } - - public void setMutatedMethod(String mutatedMethod) { - this.mutatedMethod = mutatedMethod; - } - - public void setLineNumber(int lineNumber) { - this.lineNumber = lineNumber; - } - - public void setMutator(String mutator) { - this.mutator = mutator; - } - - public void setIndexes(List indexes) { - this.indexes = indexes; - } - - public void setKillingTest(String killingTest) { - this.killingTest = killingTest; - } - - public void setMethodDescription(String methodDescription) { - this.methodDescription = methodDescription; - } - - public void setDescription(String description) { - this.description = description; - } - - public void setBlocks(List blocks) { - this.blocks = blocks; - } - - public boolean equals(final Object o) { - if (o == this) {return true;} - if (!(o instanceof Mutation)) {return false;} - final Mutation other = (Mutation) o; - if (!other.canEqual((Object) this)) {return false;} - if (this.isDetected() != other.isDetected()) {return false;} - final Object this$status = this.getStatus(); - final Object other$status = other.getStatus(); - if (this$status == null ? other$status != null : !this$status.equals(other$status)) {return false;} - final Object this$sourceFile = this.getSourceFile(); - final Object other$sourceFile = other.getSourceFile(); - if (this$sourceFile == null ? other$sourceFile != null : !this$sourceFile.equals(other$sourceFile)) {return false;} - final Object this$mutatedClass = this.getMutatedClass(); - final Object other$mutatedClass = other.getMutatedClass(); - if (this$mutatedClass == null ? other$mutatedClass != null : !this$mutatedClass.equals(other$mutatedClass)) { - return false; - } - final Object this$mutatedMethod = this.getMutatedMethod(); - final Object other$mutatedMethod = other.getMutatedMethod(); - if (this$mutatedMethod == null ? other$mutatedMethod != null : !this$mutatedMethod.equals(other$mutatedMethod)) { - return false; - } - if (this.getLineNumber() != other.getLineNumber()) {return false;} - final Object this$mutator = this.getMutator(); - final Object other$mutator = other.getMutator(); - if (this$mutator == null ? other$mutator != null : !this$mutator.equals(other$mutator)) {return false;} - final Object this$indexes = this.getIndexes(); - final Object other$indexes = other.getIndexes(); - if (this$indexes == null ? other$indexes != null : !this$indexes.equals(other$indexes)) {return false;} - final Object this$killingTest = this.getKillingTest(); - final Object other$killingTest = other.getKillingTest(); - if (this$killingTest == null ? other$killingTest != null : !this$killingTest.equals(other$killingTest)) { - return false; - } - final Object this$methodDescription = this.getMethodDescription(); - final Object other$methodDescription = other.getMethodDescription(); - if (this$methodDescription == null ? - other$methodDescription != null : - !this$methodDescription.equals(other$methodDescription)) {return false;} - final Object this$description = this.getDescription(); - final Object other$description = other.getDescription(); - if (this$description == null ? other$description != null : !this$description.equals(other$description)) { - return false; - } - final Object this$blocks = this.getBlocks(); - final Object other$blocks = other.getBlocks(); - if (this$blocks == null ? other$blocks != null : !this$blocks.equals(other$blocks)) {return false;} - return true; - } - protected boolean canEqual(final Object other) { return other instanceof Mutation; } - public int hashCode() { - final int PRIME = 59; - int result = 1; - result = result * PRIME + (this.isDetected() ? 79 : 97); - final Object $status = this.getStatus(); - result = result * PRIME + ($status == null ? 43 : $status.hashCode()); - final Object $sourceFile = this.getSourceFile(); - result = result * PRIME + ($sourceFile == null ? 43 : $sourceFile.hashCode()); - final Object $mutatedClass = this.getMutatedClass(); - result = result * PRIME + ($mutatedClass == null ? 43 : $mutatedClass.hashCode()); - final Object $mutatedMethod = this.getMutatedMethod(); - result = result * PRIME + ($mutatedMethod == null ? 43 : $mutatedMethod.hashCode()); - result = result * PRIME + this.getLineNumber(); - final Object $mutator = this.getMutator(); - result = result * PRIME + ($mutator == null ? 43 : $mutator.hashCode()); - final Object $indexes = this.getIndexes(); - result = result * PRIME + ($indexes == null ? 43 : $indexes.hashCode()); - final Object $killingTest = this.getKillingTest(); - result = result * PRIME + ($killingTest == null ? 43 : $killingTest.hashCode()); - final Object $methodDescription = this.getMethodDescription(); - result = result * PRIME + ($methodDescription == null ? 43 : $methodDescription.hashCode()); - final Object $description = this.getDescription(); - result = result * PRIME + ($description == null ? 43 : $description.hashCode()); - final Object $blocks = this.getBlocks(); - result = result * PRIME + ($blocks == null ? 43 : $blocks.hashCode()); - return result; - } - - public String toString() { - return "Mutation(detected=" - + this.isDetected() - + ", status=" - + this.getStatus() - + ", sourceFile=" - + this.getSourceFile() - + ", mutatedClass=" - + this.getMutatedClass() - + ", mutatedMethod=" - + this.getMutatedMethod() - + ", lineNumber=" - + this.getLineNumber() - + ", mutator=" - + this.getMutator() - + ", indexes=" - + this.getIndexes() - + ", killingTest=" - + this.getKillingTest() - + ", methodDescription=" - + this.getMethodDescription() - + ", description=" - + this.getDescription() - + ", blocks=" - + this.getBlocks() - + ")"; - } } diff --git a/src/main/java/org/jenkinsci/plugins/pitmutation/MutationReport.java b/src/main/java/org/jenkinsci/plugins/pitmutation/MutationReport.java index 3c9671e..8ed6569 100644 --- a/src/main/java/org/jenkinsci/plugins/pitmutation/MutationReport.java +++ b/src/main/java/org/jenkinsci/plugins/pitmutation/MutationReport.java @@ -15,6 +15,7 @@ /** * @author edward + * @author vasile.jureschi */ public class MutationReport { @@ -27,7 +28,6 @@ public MutationReport(InputStream xmlReport) throws IOException, SAXException { this.mutationsByClass = new HashMap<>(); this.mutationsByPackage = new HashMap<>(); - // https://github.com/FasterXML/jackson-dataformat-xml/issues/219 JacksonXmlModule module = new JacksonXmlModule(); module.setDefaultUseWrapper(false); diff --git a/src/test/java/org/jenkinsci/plugins/pitmutation/MutationReportTest.java b/src/test/java/org/jenkinsci/plugins/pitmutation/MutationReportTest.java index 021c03f..6c884a0 100644 --- a/src/test/java/org/jenkinsci/plugins/pitmutation/MutationReportTest.java +++ b/src/test/java/org/jenkinsci/plugins/pitmutation/MutationReportTest.java @@ -19,99 +19,143 @@ */ public class MutationReportTest { - private static final String MUTATIONS = - "" - + "\n" - + "SafeMultipartFile.java\n" - + "com.mediagraft.podsplice.controllers.massupload.SafeMultipartFile\n" - + "getSize\n" - + "54\n" - + "org.pitest.mutationtest.engine.gregor.mutators.ReturnValsMutator\n" - + "5\n" - + "\n" - + "" - + "" - + "SafeMultipartFile.java" - + "com.mediagraft.podsplice.controllers.massupload.SafeMultipartFile" - + "getSize" - + "57" - + "org.pitest.mutationtest.engine.gregor.mutators.ReturnValsMutator" - + "6" - + "3" - + "" - + "" - + ""; - - private InputStream mutationsXml; - - @Before - public void setUp() { - mutationsXml = getClass().getResourceAsStream("testmutations-00.xml"); + private static final String MUTATIONS_OLD = "" + + "\n" + + "SafeMultipartFile.java\n" + + "com.mediagraft.podsplice.controllers.massupload.SafeMultipartFile\n" + + "getSize\n" + + "54\n" + + "org.pitest.mutationtest.engine.gregor.mutators.ReturnValsMutator\n" + + "5\n" + + "\n" + + "" + + "" + + "SafeMultipartFile.java" + + "com.mediagraft.podsplice.controllers.massupload.SafeMultipartFile" + + "getSize" + + "57" + + "org.pitest.mutationtest.engine.gregor.mutators.ReturnValsMutator" + + "6" + + "3" + + "" + + "" + + ""; + + private static final String MUTATIONS = "" + + "\n" + + "SafeMultipartFile.java\n" + + "com.mediagraft.podsplice.controllers.massupload.SafeMultipartFile\n" + + "getSize\n" + + "54\n" + + "org.pitest.mutationtest.engine.gregor.mutators.ReturnValsMutator\n" + + "5\n" + + "\n" + + "" + + "" + + "SafeMultipartFile.java" + + "com.mediagraft.podsplice.controllers.massupload.SafeMultipartFile" + + "getSize" + + "57" + + "org.pitest.mutationtest.engine.gregor.mutators.ReturnValsMutator" + + "6" + + "3" + + "" + + "" + + ""; + + private InputStream mutationsXml; + + @Before + public void setUp() { + mutationsXml = getClass().getResourceAsStream("testmutations-00.xml"); + } + + @Test + public void packageNameFinder() { + assertThat(MutationReport.packageNameFromClass("xxx.yyy.zzz.Foo"), is("xxx.yyy.zzz")); + assertThat(MutationReport.packageNameFromClass("Foo"), is("")); + } + + @Test + public void countsKills() throws IOException, SAXException { + MutationReport report = new MutationReport(mutationsXml); + assertThat(report.getMutationStats().getKillCount(), is(5)); + assertThat(report.getMutationStats().getTotalMutations(), is(16)); + } + + @Test + public void sortsMutationsByClassName() throws IOException, SAXException { + MutationReport report = new MutationReport(mutationsXml); + Collection mutations = + report.getMutationsForClassName("org.jenkinsci.plugins.pitmutation.MutationReport"); + assertThat(mutations.size(), is(5)); + } + + @Test + public void indexesMutationsByPackage() throws IOException, SAXException { + MutationReport report = new MutationReport(mutationsXml); + assertThat(report.getMutationsForPackage("org.jenkinsci.plugins.pitmutation"), hasSize(16)); + assertThat(report.getMutationsForPackage(""), hasSize(0)); + } + + @Test + public void canDigestAMutation() throws IOException, SAXException { + MutationReport report = new MutationReport(new ByteArrayInputStream(MUTATIONS.getBytes("UTF-8"))); + + assertThat(report.getMutationStats().getTotalMutations(), is(2)); + + Iterator mutations = + report.getMutationsForClassName("com.mediagraft.podsplice.controllers.massupload.SafeMultipartFile").iterator(); + + Mutation m1 = mutations.next(); + Mutation m2 = mutations.next(); + + if (m1.getStatus().equals("KILLED")) { + verifyKilled(m1); + verifyNoCoverage(m2); + } else { + verifyKilled(m2); + verifyNoCoverage(m1); } + } - @Test - public void packageNameFinder() { - assertThat(MutationReport.packageNameFromClass("xxx.yyy.zzz.Foo"), is("xxx.yyy.zzz")); - assertThat(MutationReport.packageNameFromClass("Foo"), is("")); - } - - @Test - public void countsKills() throws IOException, SAXException { - MutationReport report = new MutationReport(mutationsXml); - assertThat(report.getMutationStats().getKillCount(), is(5)); - assertThat(report.getMutationStats().getTotalMutations(), is(16)); - } - - @Test - public void sortsMutationsByClassName() throws IOException, SAXException { - MutationReport report = new MutationReport(mutationsXml); - Collection mutations = report.getMutationsForClassName("org.jenkinsci.plugins.pitmutation.MutationReport"); - assertThat(mutations.size(), is(5)); - } - - @Test - public void indexesMutationsByPackage() throws IOException, SAXException { - MutationReport report = new MutationReport(mutationsXml); - assertThat(report.getMutationsForPackage("org.jenkinsci.plugins.pitmutation"), hasSize(16)); - assertThat(report.getMutationsForPackage(""), hasSize(0)); - } - - @Test - public void canDigestAMutation() throws IOException, SAXException { - MutationReport report = new MutationReport(new ByteArrayInputStream(MUTATIONS.getBytes("UTF-8"))); - - assertThat(report.getMutationStats().getTotalMutations(), is(2)); + @Test + public void canDigestAMutationOlderMutations() throws IOException, SAXException { + MutationReport report = new MutationReport(new ByteArrayInputStream(MUTATIONS_OLD.getBytes("UTF-8"))); - Iterator mutations = - report.getMutationsForClassName("com.mediagraft.podsplice.controllers.massupload.SafeMultipartFile").iterator(); + assertThat(report.getMutationStats().getTotalMutations(), is(2)); - Mutation m1 = mutations.next(); - Mutation m2 = mutations.next(); + Iterator mutations = + report.getMutationsForClassName("com.mediagraft.podsplice.controllers.massupload.SafeMultipartFile").iterator(); - if (m1.getStatus().equals("KILLED")) { - verifyKilled(m1); - verifyNoCoverage(m2); - } else { - verifyKilled(m2); - verifyNoCoverage(m1); - } - } - - private void verifyNoCoverage(Mutation m) { - assertThat(m.getLineNumber(), is(54)); - assertThat(m.isDetected(), is(true)); - assertThat(m.getStatus(), is("NO_COVERAGE")); - assertThat(m.getSourceFile(), is("SafeMultipartFile.java")); - assertThat(m.getMutatedClass(), is("com.mediagraft.podsplice.controllers.massupload.SafeMultipartFile")); - assertThat(m.getMutator(), is("org.pitest.mutationtest.engine.gregor.mutators.ReturnValsMutator")); - } + Mutation m1 = mutations.next(); + Mutation m2 = mutations.next(); - private void verifyKilled(Mutation m) { - assertThat(m.getLineNumber(), is(57)); - assertThat(m.isDetected(), is(false)); - assertThat(m.getStatus(), is("KILLED")); - assertThat(m.getSourceFile(), is("SafeMultipartFile.java")); - assertThat(m.getMutatedClass(), is("com.mediagraft.podsplice.controllers.massupload.SafeMultipartFile")); - assertThat(m.getMutator(), is("org.pitest.mutationtest.engine.gregor.mutators.ReturnValsMutator")); + if (m1.getStatus().equals("KILLED")) { + verifyKilled(m1); + verifyNoCoverage(m2); + } else { + verifyKilled(m2); + verifyNoCoverage(m1); } + } + + + private void verifyNoCoverage(Mutation m) { + assertThat(m.getLineNumber(), is(54)); + assertThat(m.isDetected(), is(true)); + assertThat(m.getStatus(), is("NO_COVERAGE")); + assertThat(m.getSourceFile(), is("SafeMultipartFile.java")); + assertThat(m.getMutatedClass(), is("com.mediagraft.podsplice.controllers.massupload.SafeMultipartFile")); + assertThat(m.getMutator(), is("org.pitest.mutationtest.engine.gregor.mutators.ReturnValsMutator")); + } + + private void verifyKilled(Mutation m) { + assertThat(m.getLineNumber(), is(57)); + assertThat(m.isDetected(), is(false)); + assertThat(m.getStatus(), is("KILLED")); + assertThat(m.getSourceFile(), is("SafeMultipartFile.java")); + assertThat(m.getMutatedClass(), is("com.mediagraft.podsplice.controllers.massupload.SafeMultipartFile")); + assertThat(m.getMutator(), is("org.pitest.mutationtest.engine.gregor.mutators.ReturnValsMutator")); + } } From 9a9e7e1fbefd988e1a24ee6a2ef04fbd9b78bc71 Mon Sep 17 00:00:00 2001 From: Vasile Jureschi Date: Fri, 27 Jan 2023 12:00:27 +0200 Subject: [PATCH 04/16] Adds handling of numberOfTestsRun property --- pom.xml | 2 +- .../plugins/pitmutation/Mutation.java | 1 + .../plugins/pitmutation/testmutations-00.xml | 32 +++++++++---------- 3 files changed, 18 insertions(+), 17 deletions(-) diff --git a/pom.xml b/pom.xml index 629b902..52d4f94 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ pitmutation - 1.1-5-SNAPSHOT + 1.1-6-SNAPSHOT Jenkins PIT Mutation Plugin hpi http://wiki.jenkins-ci.org/display/JENKINS/pitmutation diff --git a/src/main/java/org/jenkinsci/plugins/pitmutation/Mutation.java b/src/main/java/org/jenkinsci/plugins/pitmutation/Mutation.java index a70c5d3..ad7c615 100644 --- a/src/main/java/org/jenkinsci/plugins/pitmutation/Mutation.java +++ b/src/main/java/org/jenkinsci/plugins/pitmutation/Mutation.java @@ -17,6 +17,7 @@ public class Mutation { private String sourceFile; private String mutatedClass; private String mutatedMethod; + private int numberOfTestsRun; private int lineNumber; private String mutator; /** diff --git a/src/test/resources/org/jenkinsci/plugins/pitmutation/testmutations-00.xml b/src/test/resources/org/jenkinsci/plugins/pitmutation/testmutations-00.xml index 83f763b..0abaa20 100644 --- a/src/test/resources/org/jenkinsci/plugins/pitmutation/testmutations-00.xml +++ b/src/test/resources/org/jenkinsci/plugins/pitmutation/testmutations-00.xml @@ -1,6 +1,6 @@ - + PitParser.java org.jenkinsci.plugins.pitmutation.PitParser <init> @@ -11,7 +11,7 @@ - + PitParser.java org.jenkinsci.plugins.pitmutation.PitParser <init> @@ -22,7 +22,7 @@ - + PitParser.java org.jenkinsci.plugins.pitmutation.PitParser <init> @@ -34,7 +34,7 @@ - + Mutation.java org.jenkinsci.plugins.pitmutation.Mutation equals @@ -45,7 +45,7 @@ - + Mutation.java org.jenkinsci.plugins.pitmutation.Mutation setStatus @@ -58,7 +58,7 @@ org.jenkinsci.plugins.pitmutation.MutationReportTest.canDigestAMutation(org.jenkinsci.plugins.pitmutation.MutationReportTest) - + Mutation.java org.jenkinsci.plugins.pitmutation.Mutation getSourceFile @@ -71,7 +71,7 @@ org.jenkinsci.plugins.pitmutation.MutationReportTest.canDigestAMutation(org.jenkinsci.plugins.pitmutation.MutationReportTest) - + Mutation.java org.jenkinsci.plugins.pitmutation.Mutation getMutator @@ -85,7 +85,7 @@ - + PitBuildAction.java org.jenkinsci.plugins.pitmutation.PitBuildAction <init> @@ -96,7 +96,7 @@ - + PitBuildAction.java org.jenkinsci.plugins.pitmutation.PitBuildAction <init> @@ -109,7 +109,7 @@ org.jenkinsci.plugins.pitmutation.PitBuildActionTest.previousReturnsNullIfNoPreviousBuilds(org.jenkinsci.plugins.pitmutation.PitBuildActionTest) - + PitBuildAction.java org.jenkinsci.plugins.pitmutation.PitBuildAction <init> @@ -120,7 +120,7 @@ - + PitBuildAction.java org.jenkinsci.plugins.pitmutation.PitBuildAction <init> @@ -132,7 +132,7 @@ - + MutationReport.java org.jenkinsci.plugins.pitmutation.MutationReport digestMutations @@ -143,7 +143,7 @@ - + MutationReport.java org.jenkinsci.plugins.pitmutation.MutationReport digestMutations @@ -154,7 +154,7 @@ - + MutationReport.java org.jenkinsci.plugins.pitmutation.MutationReport digestMutations @@ -165,7 +165,7 @@ - + MutationReport.java org.jenkinsci.plugins.pitmutation.MutationReport digestMutations @@ -178,7 +178,7 @@ org.jenkinsci.plugins.pitmutation.MutationReportTest.canDigestAMutation(org.jenkinsci.plugins.pitmutation.MutationReportTest) - + MutationReport.java org.jenkinsci.plugins.pitmutation.MutationReport digestMutations From f3487d87cdb3cdc391d453fc937a1fc717cbdccc Mon Sep 17 00:00:00 2001 From: Vasile Jureschi Date: Sun, 16 Jul 2023 17:24:15 +0300 Subject: [PATCH 05/16] Adds tests and cleans code --- pom.xml | 39 +- .../plugins/pitmutation/DescriptorImpl.java | 44 ++ .../plugins/pitmutation/FileProcessor.java | 53 +++ .../pitmutation/MustImproveCondition.java | 22 + .../pitmutation/ParseReportCallable.java | 41 ++ .../PercentageThresholdCondition.java | 21 + .../plugins/pitmutation/PitBuildAction.java | 18 +- .../plugins/pitmutation/PitLogger.java | 57 +++ .../plugins/pitmutation/PitProjectAction.java | 6 +- .../plugins/pitmutation/PitPublisher.java | 377 +++++------------ .../plugins/pitmutation/ResultDecider.java | 42 ++ .../pitmutation/portlets/PitColumn.java | 2 +- .../pitmutation/targets/ModuleResult.java | 15 +- .../targets/SingleModuleResult.java | 14 +- .../pitmutation/MustImproveConditionTest.java | 64 +++ .../PercentageThresholdConditionTest.java | 52 +++ .../plugins/pitmutation/PitLoggerTest.java | 83 ++++ .../pitmutation/PitProjectActionTest.java | 126 ++++++ .../plugins/pitmutation/PitPublisherTest.java | 366 +++++++++++------ .../pitmutation/ResultDeciderTest.java | 46 +++ .../pitmutation/testmutations-00-new.xml | 386 ++++++++++++++++++ 21 files changed, 1430 insertions(+), 444 deletions(-) create mode 100644 src/main/java/org/jenkinsci/plugins/pitmutation/DescriptorImpl.java create mode 100644 src/main/java/org/jenkinsci/plugins/pitmutation/FileProcessor.java create mode 100644 src/main/java/org/jenkinsci/plugins/pitmutation/MustImproveCondition.java create mode 100644 src/main/java/org/jenkinsci/plugins/pitmutation/ParseReportCallable.java create mode 100644 src/main/java/org/jenkinsci/plugins/pitmutation/PercentageThresholdCondition.java create mode 100644 src/main/java/org/jenkinsci/plugins/pitmutation/PitLogger.java create mode 100644 src/main/java/org/jenkinsci/plugins/pitmutation/ResultDecider.java create mode 100644 src/test/java/org/jenkinsci/plugins/pitmutation/MustImproveConditionTest.java create mode 100644 src/test/java/org/jenkinsci/plugins/pitmutation/PercentageThresholdConditionTest.java create mode 100644 src/test/java/org/jenkinsci/plugins/pitmutation/PitLoggerTest.java create mode 100644 src/test/java/org/jenkinsci/plugins/pitmutation/PitProjectActionTest.java create mode 100644 src/test/java/org/jenkinsci/plugins/pitmutation/ResultDeciderTest.java create mode 100644 src/test/resources/org/jenkinsci/plugins/pitmutation/testmutations-00-new.xml diff --git a/pom.xml b/pom.xml index 52d4f94..f6acc3d 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ pitmutation - 1.1-6-SNAPSHOT + 2.0.0-SNAPSHOT Jenkins PIT Mutation Plugin hpi http://wiki.jenkins-ci.org/display/JENKINS/pitmutation @@ -23,7 +23,7 @@ UTF-8 - 2.361.4 + 2.414 @@ -89,20 +89,20 @@ org.mockito mockito-core - 5.0.0 + 5.4.0 test - junit - junit - 4.13.2 + org.mockito + mockito-junit-jupiter + 5.4.0 + test + + + org.junit.jupiter + junit-jupiter-engine + 5.9.2 test - - - org.hamcrest - hamcrest-core - - @@ -137,8 +137,8 @@ org.apache.maven.plugins maven-compiler-plugin - 11 - 11 + 17 + 17 @@ -149,7 +149,7 @@ org.apache.maven.plugins maven-javadoc-plugin - 8 + 17 @@ -171,7 +171,14 @@ org.pitest pitest-maven - 1.10.4 + 1.14.2 + + + org.pitest + pitest-junit5-plugin + 1.1.1 + + org.jenkinsci.plugins.pitmutation.* diff --git a/src/main/java/org/jenkinsci/plugins/pitmutation/DescriptorImpl.java b/src/main/java/org/jenkinsci/plugins/pitmutation/DescriptorImpl.java new file mode 100644 index 0000000..e9c415d --- /dev/null +++ b/src/main/java/org/jenkinsci/plugins/pitmutation/DescriptorImpl.java @@ -0,0 +1,44 @@ +package org.jenkinsci.plugins.pitmutation; + +import hudson.Extension; +import hudson.model.AbstractProject; +import hudson.tasks.BuildStepDescriptor; +import hudson.tasks.Publisher; +import net.sf.json.JSONObject; +import org.jenkinsci.Symbol; +import org.kohsuke.stapler.StaplerRequest; + +/** + * The type Descriptor. + */ +@Extension +@Symbol("pitmutation") +public class DescriptorImpl extends BuildStepDescriptor { + + /** + * Instantiates a new Descriptor. + */ + public DescriptorImpl() { + super(PitPublisher.class); + } + + @Override + public String getDisplayName() { + return Messages.PitPublisher_DisplayName(); + } + + @Override + public boolean isApplicable(Class aClass) { + return true; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean configure(StaplerRequest req, JSONObject formData) throws FormException { + req.bindParameters(this, "pitmutation"); + save(); + return super.configure(req, formData); + } +} diff --git a/src/main/java/org/jenkinsci/plugins/pitmutation/FileProcessor.java b/src/main/java/org/jenkinsci/plugins/pitmutation/FileProcessor.java new file mode 100644 index 0000000..219dbd4 --- /dev/null +++ b/src/main/java/org/jenkinsci/plugins/pitmutation/FileProcessor.java @@ -0,0 +1,53 @@ +package org.jenkinsci.plugins.pitmutation; + +import hudson.FilePath; +import org.apache.commons.lang.StringUtils; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import static java.util.Optional.ofNullable; + +public class FileProcessor { + + public static final String SINGLE_MODULE_REPORT_FOLDER = "mutation-report-all"; + public static final String MULTI_MODULE_REPORT_FORMAT = "mutation-report-%s"; + + public void copySingleModuleReport(FilePath source, FilePath buildTarget) throws IOException, InterruptedException { + copyMutationReports(source, buildTarget, SINGLE_MODULE_REPORT_FOLDER); + } + + public void copyMultiModuleReport(FilePath source, FilePath buildTarget, String module) throws IOException, InterruptedException { + copyMutationReports(source, buildTarget, String.format(MULTI_MODULE_REPORT_FORMAT, module)); + } + + private void copyMutationReports(FilePath source, FilePath buildTarget, String mutationFilePath) throws IOException, + InterruptedException { + var targetPath = new FilePath(buildTarget, mutationFilePath); + var parent = ofNullable(source.getParent()).orElseThrow(() -> new IOException("Mutation file not found")); + parent.copyRecursiveTo(targetPath); + } + + public Map getNames(FilePath[] reports, String base) { + Map names = new HashMap<>(); + for (int i = 0; i < reports.length; i++) { + FilePath report = reports[i]; + + final String moduleName; + if (StringUtils.isBlank(base)) { + moduleName = String.valueOf(i == 0 ? null : i); + } else { + String[] partsFromRemoteWithoutBase = report.getRemote().replace(base, "").split("[/\\\\]"); + if (partsFromRemoteWithoutBase.length > 1) { + moduleName = partsFromRemoteWithoutBase[1]; + } else { + moduleName = String.valueOf(i == 0 ? null : i); + } + } + + names.put(report, moduleName); + } + return names; + } +} \ No newline at end of file diff --git a/src/main/java/org/jenkinsci/plugins/pitmutation/MustImproveCondition.java b/src/main/java/org/jenkinsci/plugins/pitmutation/MustImproveCondition.java new file mode 100644 index 0000000..62421cd --- /dev/null +++ b/src/main/java/org/jenkinsci/plugins/pitmutation/MustImproveCondition.java @@ -0,0 +1,22 @@ +package org.jenkinsci.plugins.pitmutation; + +import hudson.model.Result; +import org.jenkinsci.plugins.pitmutation.targets.MutationStats; + +import static hudson.model.Result.SUCCESS; +import static hudson.model.Result.UNSTABLE; + +class MustImproveCondition implements Condition { + @Override + public Result decideResult(final PitBuildAction action) { + PitBuildAction previousAction = action.getPreviousAction(); + if (previousAction != null) { + MutationStats previousStats = previousAction.getReport().getMutationStats(); + return action.getReport().getMutationStats().getKillPercent() >= previousStats.getKillPercent() ? + SUCCESS : + UNSTABLE; + } else { + return SUCCESS; + } + } +} diff --git a/src/main/java/org/jenkinsci/plugins/pitmutation/ParseReportCallable.java b/src/main/java/org/jenkinsci/plugins/pitmutation/ParseReportCallable.java new file mode 100644 index 0000000..2ad9408 --- /dev/null +++ b/src/main/java/org/jenkinsci/plugins/pitmutation/ParseReportCallable.java @@ -0,0 +1,41 @@ +package org.jenkinsci.plugins.pitmutation; + +import hudson.FilePath; +import hudson.remoting.VirtualChannel; +import org.jenkinsci.remoting.RoleChecker; + +import java.io.File; +import java.io.IOException; + +/** + * The type Parse report callable. + */ +public class ParseReportCallable implements FilePath.FileCallable { + + private static final long serialVersionUID = 1L; + + private final String reportFilePath; + + /** + * Instantiates a new Parse report callable. + * + * @param reportFilePath the report file path + */ + public ParseReportCallable(String reportFilePath) { + this.reportFilePath = reportFilePath; + } + + @Override + public FilePath[] invoke(File f, VirtualChannel channel) throws IOException, InterruptedException { + FilePath[] r = new FilePath(f).list(reportFilePath); + if (r.length < 1) { + throw new IOException("No reports found at location:" + reportFilePath); + } + return r; + } + + @Override + public void checkRoles(RoleChecker roleChecker) throws SecurityException { + + } +} diff --git a/src/main/java/org/jenkinsci/plugins/pitmutation/PercentageThresholdCondition.java b/src/main/java/org/jenkinsci/plugins/pitmutation/PercentageThresholdCondition.java new file mode 100644 index 0000000..28c464e --- /dev/null +++ b/src/main/java/org/jenkinsci/plugins/pitmutation/PercentageThresholdCondition.java @@ -0,0 +1,21 @@ +package org.jenkinsci.plugins.pitmutation; + +import hudson.model.Result; +import org.jenkinsci.plugins.pitmutation.targets.MutationStats; + +import static hudson.model.Result.FAILURE; +import static hudson.model.Result.SUCCESS; + +class PercentageThresholdCondition implements Condition { + private final float percentage; + + PercentageThresholdCondition(float percentage) { + super(); + this.percentage = percentage; + } + + @Override + public Result decideResult(PitBuildAction action) { + return action.getReport().getMutationStats().getKillPercent() >= percentage ? SUCCESS : FAILURE; + } +} diff --git a/src/main/java/org/jenkinsci/plugins/pitmutation/PitBuildAction.java b/src/main/java/org/jenkinsci/plugins/pitmutation/PitBuildAction.java index 0e33567..a014f8f 100644 --- a/src/main/java/org/jenkinsci/plugins/pitmutation/PitBuildAction.java +++ b/src/main/java/org/jenkinsci/plugins/pitmutation/PitBuildAction.java @@ -27,6 +27,8 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; +import static hudson.model.Result.FAILURE; + /** * @author edward @@ -45,16 +47,16 @@ public PitBuildAction(Run owner) { } public PitBuildAction getPreviousAction() { - Run b = owner; + Run build = owner; while (true) { - b = b.getPreviousBuild(); - if (b == null) + build = build.getPreviousBuild(); + if (build == null) return null; - if (b.getResult() == Result.FAILURE) + if (build.getResult() == FAILURE) continue; - PitBuildAction r = b.getAction(PitBuildAction.class); - if (r != null) - return r; + PitBuildAction action = build.getAction(PitBuildAction.class); + if (action != null) + return action; } } @@ -121,7 +123,7 @@ static PitBuildAction getPreviousResult(Run start) { if (b == null) { return null; } - assert b.getResult() != Result.FAILURE : "We asked for the previous not failed build"; + assert b.getResult() != FAILURE : "We asked for the previous not failed build"; PitBuildAction r = b.getAction(PitBuildAction.class); if (r != null) { return r; diff --git a/src/main/java/org/jenkinsci/plugins/pitmutation/PitLogger.java b/src/main/java/org/jenkinsci/plugins/pitmutation/PitLogger.java new file mode 100644 index 0000000..91d9069 --- /dev/null +++ b/src/main/java/org/jenkinsci/plugins/pitmutation/PitLogger.java @@ -0,0 +1,57 @@ +package org.jenkinsci.plugins.pitmutation; + +import hudson.FilePath; +import hudson.model.TaskListener; +import org.jenkinsci.plugins.pitmutation.targets.MutationStats; + +/** + * Logging class for various pit information. + * + * @author edward + * @author vasile.jureschi + */ +public class PitLogger { + + PitLogger() { + } + + public void logResults(TaskListener listener, PitBuildAction action ) { + MutationStats mutationStats = action.getReport().getMutationStats(); + float previousKillPercent = action.getPreviousAction().getReport().getMutationStats().getKillPercent(); + logCurrent(mutationStats, listener); + logPrevious(mutationStats.getKillPercent(),previousKillPercent, listener); + } + + public void logMissingReportsIgnored(TaskListener listener) { + listener.getLogger().println("Build successful as no reports generated and build set to ignore missing reports. " + + "If the reports should be present set 'ignoreMissingReports' to false and run the build again to fail the build."); + } + + public void logBuildFailedNoReports(TaskListener listener) { + listener.getLogger().println("Build failed as no reports generated and build set to not ignore missing reports. " + + "If no reports should be generated set 'ignoreMissingReports' to true and run the build again to pass the build."); + } + + private void logCurrent(MutationStats currentStats, TaskListener listener) { + listener + .getLogger() + .printf("Kill ratio is %f \\u0025 (%d %d)%n", + currentStats.getKillPercent(), + currentStats.getKillCount(), + currentStats.getTotalMutations()); + } + + + private void logPrevious(float currentKillPercent, float previousKillPercent, TaskListener listener) { + listener.getLogger().println("Previous kill ratio was " + previousKillPercent + "%"); + listener.getLogger().println("This kill ration is " + currentKillPercent + "%"); + } + + public void logLookingForReports(TaskListener listener, FilePath workspace) { + listener.getLogger().println("Looking for PIT reports in " + workspace.getRemote()); + } + + public void logPublishReport(TaskListener listener, FilePath workspace) { + listener.getLogger().println("Publishing mutation report: " + workspace.getRemote()); + } +} diff --git a/src/main/java/org/jenkinsci/plugins/pitmutation/PitProjectAction.java b/src/main/java/org/jenkinsci/plugins/pitmutation/PitProjectAction.java index 8db7ed7..ce960b8 100644 --- a/src/main/java/org/jenkinsci/plugins/pitmutation/PitProjectAction.java +++ b/src/main/java/org/jenkinsci/plugins/pitmutation/PitProjectAction.java @@ -6,6 +6,8 @@ import java.io.IOException; +import static hudson.model.Result.FAILURE; + /** * @author Ed Kimber */ @@ -24,7 +26,7 @@ public PitProjectAction(AbstractProject project) { */ public PitBuildAction getLastResult() { for (AbstractBuild b = project.getLastSuccessfulBuild(); b != null; b = b.getPreviousNotFailedBuild()) { - if (b.getResult() == Result.FAILURE) + if (b.getResult() == FAILURE) continue; PitBuildAction r = b.getAction(PitBuildAction.class); if (r != null) @@ -44,7 +46,7 @@ public PitBuildAction getLastResult() { */ public Integer getLastResultBuild() { for (AbstractBuild b = project.getLastSuccessfulBuild(); b != null; b = b.getPreviousNotFailedBuild()) { - if (b.getResult() == Result.FAILURE) + if (b.getResult() == FAILURE) continue; PitBuildAction r = b.getAction(PitBuildAction.class); if (r != null) diff --git a/src/main/java/org/jenkinsci/plugins/pitmutation/PitPublisher.java b/src/main/java/org/jenkinsci/plugins/pitmutation/PitPublisher.java index 311e7e6..9543d65 100644 --- a/src/main/java/org/jenkinsci/plugins/pitmutation/PitPublisher.java +++ b/src/main/java/org/jenkinsci/plugins/pitmutation/PitPublisher.java @@ -1,76 +1,73 @@ package org.jenkinsci.plugins.pitmutation; -import hudson.Extension; +import edu.umd.cs.findbugs.annotations.NonNull; +import hudson.EnvVars; import hudson.FilePath; import hudson.Launcher; import hudson.Util; -import hudson.model.AbstractBuild; import hudson.model.AbstractProject; import hudson.model.Action; -import hudson.model.Result; import hudson.model.Run; import hudson.model.TaskListener; -import hudson.remoting.VirtualChannel; -import hudson.tasks.BuildStepDescriptor; import hudson.tasks.BuildStepMonitor; -import hudson.tasks.Publisher; import hudson.tasks.Recorder; import jenkins.tasks.SimpleBuildStep; -import net.sf.json.JSONObject; -import org.apache.commons.lang.StringUtils; -import org.jenkinsci.Symbol; -import org.jenkinsci.plugins.pitmutation.targets.MutationStats; -import org.jenkinsci.remoting.RoleChecker; import org.kohsuke.stapler.DataBoundConstructor; import org.kohsuke.stapler.DataBoundSetter; -import org.kohsuke.stapler.StaplerRequest; import javax.annotation.Nonnull; import java.io.File; import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; +import java.util.Map; + +import static hudson.model.Result.FAILURE; +import static hudson.model.Result.SUCCESS; +import static hudson.tasks.BuildStepMonitor.STEP; /** * The type Pit publisher. * * @author edward + * @author vasile.jureschi */ public class PitPublisher extends Recorder implements SimpleBuildStep { - public static final String SINGLE_MODULE_REPORT_FOLDER = "mutation-report-all"; - public static final String MULTI_MODULE_REPORT_FORMAT = "mutation-report-%s"; - - private List buildConditions; + public static final String GLOB_MUTATIONS_XML = "**/target/pit-reports/**/mutations.xml"; private String mutationStatsFile; private boolean killRatioMustImprove; - - private boolean ignoreMissingReports = false; + /** + * If true and no reports are generated, the missing reports will not cause a build failure. Uses for cases where + * there are test but nothing is mutated them and there are no reports generated. + */ + private boolean ignoreMissingReports; private float minimumKillRatio; - private transient TaskListener listener; - private Run build; + + private FileProcessor fileProcessor; + private ResultDecider resultDecider; + private PitLogger pitLogger; /** - * Instantiates a new Pit publisher. + * Instantiates a new Pit publisher. Only used in tests. * * @param mutationStatsFile the mutation stats file * @param minimumKillRatio the minimum kill ratio * @param killRatioMustImprove the kill ratio must improve + * @param ignoreMissingReports do not fail the build if there are no reports */ - protected PitPublisher(String mutationStatsFile, - float minimumKillRatio, - boolean killRatioMustImprove, - boolean ignoreMissingReports) { + PitPublisher(String mutationStatsFile, + float minimumKillRatio, + boolean killRatioMustImprove, + boolean ignoreMissingReports, + FileProcessor fileProcessor, + ResultDecider resultDecider, + PitLogger pitLogger) { this.mutationStatsFile = mutationStatsFile; this.killRatioMustImprove = killRatioMustImprove; this.minimumKillRatio = minimumKillRatio; this.ignoreMissingReports = ignoreMissingReports; - this.buildConditions = new ArrayList<>(); - this.buildConditions.add(percentageThreshold(minimumKillRatio)); - if (killRatioMustImprove) { - this.buildConditions.add(mustImprove()); - } + this.fileProcessor = fileProcessor; + this.resultDecider = resultDecider; + this.pitLogger = pitLogger; } /** @@ -79,25 +76,22 @@ protected PitPublisher(String mutationStatsFile, * {@link #mutationStatsFile} is set to {@code **{@literal /}target/pit-reports/**{@literal /}mutations.xml}, * {@link #minimumKillRatio} is set to {@code 0.0}, * {@link #killRatioMustImprove} is set to {@code false}, + * {@link #ignoreMissingReports} is set to {@code false}, */ @DataBoundConstructor - public PitPublisher() { - this("**/target/pit-reports/**/mutations.xml", 0, false, false); - } - - @DataBoundSetter - public void setMutationStatsFile(final String mutationStatsFile) { - this.mutationStatsFile = mutationStatsFile; - } - - @DataBoundSetter - public void setMinimumKillRatio(final float minimumKillRatio) { - this.minimumKillRatio = minimumKillRatio; - } - - @DataBoundSetter - public void setKillRatioMustImprove(final boolean killRatioMustImprove) { - this.killRatioMustImprove = killRatioMustImprove; + public PitPublisher(String mutationStatsFile, + float minimumKillRatio, + boolean killRatioMustImprove, + boolean ignoreMissingReports) { + this(mutationStatsFile, + minimumKillRatio, + killRatioMustImprove, + ignoreMissingReports, + new FileProcessor(), + killRatioMustImprove ? + new ResultDecider(new PercentageThresholdCondition(minimumKillRatio)) : + new ResultDecider(new PercentageThresholdCondition(minimumKillRatio), new MustImproveCondition()), + new PitLogger()); } @DataBoundSetter @@ -108,57 +102,63 @@ public void setIgnoreMissingReports(final boolean ignoreMissingReports) { @Override public void perform(@Nonnull Run build, @Nonnull FilePath workspace, + @NonNull EnvVars env, + @Nonnull Launcher launcher, + @Nonnull TaskListener listener) { + try { + process(build, workspace, env, launcher, listener); + } catch (IOException e) { + Util.displayIOException(e, listener); + build.setResult(FAILURE); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + private void process(@Nonnull Run build, + @Nonnull FilePath workspace, + @NonNull EnvVars env, @Nonnull Launcher launcher, @Nonnull TaskListener listener) throws InterruptedException, IOException { - this.listener = listener; - this.build = build; + File statsFile = new File(mutationStatsFile); + if (noReportsAndMissingReportsIgnored(statsFile)) { + pitLogger.logMissingReportsIgnored(listener); + build.setResult(SUCCESS); + return; + } else if (noReportsAndMissingReportsNotIgnored(statsFile)) { + pitLogger.logBuildFailedNoReports(listener); + build.setResult(FAILURE); + return; + } + + pitLogger.logLookingForReports(listener, workspace); + FilePath[] reports = workspace.act(new ParseReportCallable(mutationStatsFile)); + FilePath buildTarget = new FilePath(build.getRootDir()); + if (reports.length == 1) { + fileProcessor.copySingleModuleReport(reports[0], buildTarget); + } else { + for (Map.Entry entry : fileProcessor.getNames(reports, workspace.getRemote()).entrySet()) { + FilePath filePath = entry.getKey(); + String module = entry.getValue(); + pitLogger.logPublishReport(listener, workspace); + fileProcessor.copyMultiModuleReport(filePath, buildTarget, module); + } + } - Result result = build.getResult(); - if (build instanceof AbstractBuild && result != null && result.isBetterOrEqualTo(Result.UNSTABLE)) { - AbstractBuild abstractBuild = (AbstractBuild) build; - this.listener.getLogger().println("Looking for PIT reports in " + abstractBuild.getModuleRoot().getRemote()); - final FilePath[] moduleRoots = abstractBuild.getModuleRoots(); - final boolean multipleModuleRoots = moduleRoots != null && moduleRoots.length > 1; - final FilePath moduleRoot = multipleModuleRoots ? abstractBuild.getWorkspace() : abstractBuild.getModuleRoot(); - if (moduleRoot == null) { - this.listener.getLogger().println("Module root was returned as null"); - return; - } + PitBuildAction action = new PitBuildAction(build); + build.addAction(action); + build.setResult(resultDecider.decideBuildResult(action)); - File f = new File(mutationStatsFile); - if ((!f.exists() || f.isDirectory()) && ignoreMissingReports) { - abstractBuild.setResult(Result.SUCCESS); - } else if (f.exists() || !f.isDirectory()) { - ParseReportCallable fileCallable = new ParseReportCallable(mutationStatsFile); - FilePath[] reports = moduleRoot.act(fileCallable); - publishReports(reports, new FilePath(abstractBuild.getRootDir()), abstractBuild.getModuleRoot().getRemote()); + pitLogger.logResults(listener, action); + } - //publish latest reports - PitBuildAction action = new PitBuildAction(abstractBuild); - abstractBuild.addAction(action); - abstractBuild.setResult(decideBuildResult(action)); - } - } else { - File f = new File(mutationStatsFile); - if ((!f.exists() || f.isDirectory()) && ignoreMissingReports) { - build.setResult(Result.SUCCESS); - } else if (f.exists() || !f.isDirectory()) { - this.listener.getLogger().println("Looking for PIT reports in " + workspace.getRemote()); + private boolean noReportsAndMissingReportsIgnored(File f) { + return (!f.exists() || f.isDirectory()) && ignoreMissingReports; + } - ParseReportCallable fileCallable = new ParseReportCallable(mutationStatsFile); - FilePath[] reports = workspace.act(fileCallable); - FilePath buildTarget = new FilePath(build.getRootDir()); - if (reports.length == 1) { - copyMutationReports(reports[0], buildTarget, SINGLE_MODULE_REPORT_FOLDER); - } else { - publishReports(reports, buildTarget, workspace.getRemote()); - } - PitBuildAction action = new PitBuildAction(build); - build.addAction(action); - build.setResult(decideBuildResult(action)); - } - } + private boolean noReportsAndMissingReportsNotIgnored(File f) { + return (!f.exists() || f.isDirectory()) && !ignoreMissingReports; } /** @@ -169,62 +169,6 @@ public Action getProjectAction(AbstractProject project) { return new PitProjectAction(project); } - /** - * Publish reports. - * - * @param reports the reports - * @param buildTarget the build target - * @param base the base path of the report location - */ - void publishReports(FilePath[] reports, FilePath buildTarget, final String base) { - for (int i = 0; i < reports.length; i++) { - FilePath report = reports[i]; - listener.getLogger().println("Publishing mutation report: " + report.getRemote()); - - final String moduleName; - if (StringUtils.isBlank(base)) { - moduleName = String.valueOf(i == 0 ? null : i); - } else { - String[] partsFromRemoteWithoutBase = report.getRemote().replace(base, "").split("[/\\\\]"); - if (partsFromRemoteWithoutBase.length > 1) { - moduleName = partsFromRemoteWithoutBase[1]; - } else { - moduleName = String.valueOf(i == 0 ? null : i); - } - } - copyMutationReports(reports[i], buildTarget, String.format(MULTI_MODULE_REPORT_FORMAT, moduleName)); - } - } - - private void copyMutationReports(FilePath source, FilePath buildTarget, String mutationFilePath) { - final FilePath targetPath = new FilePath(buildTarget, mutationFilePath); - try { - FilePath parent = Optional.ofNullable(source.getParent()).orElseThrow(() -> new IOException()); - parent.copyRecursiveTo(targetPath); - } catch (IOException e) { - Util.displayIOException(e, listener); - e.printStackTrace(listener.fatalError("Unable to copy coverage from " + source + " to " + buildTarget)); - build.setResult(Result.FAILURE); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - - /** - * Decide build result result. - * - * @param action the action - * @return the worst result from all conditions - */ - public Result decideBuildResult(PitBuildAction action) { - Result result = Result.SUCCESS; - for (Condition condition : buildConditions) { - Result conditionResult = condition.decideResult(action); - result = conditionResult.isWorseThan(result) ? conditionResult : result; - } - return result; - } - /** * Required by plugin config @@ -253,139 +197,18 @@ public String getMutationStatsFile() { return mutationStatsFile; } + /** + * Required by plugin config + * + * @return ignore missing reports flag + */ public boolean getIgnoreMissingReports() { return ignoreMissingReports; } - Condition percentageThreshold(final float percentage) { - return new PercentageThresholdCondition(percentage); - } - - class PercentageThresholdCondition implements Condition { - private final float percentage; - - PercentageThresholdCondition(float percentage) { - super(); - this.percentage = percentage; - } - - @Override - public Result decideResult(PitBuildAction action) { - MutationStats stats = action.getReport().getMutationStats(); - dologging(stats); - return stats.getKillPercent() >= percentage ? Result.SUCCESS : Result.FAILURE; - } - - void dologging(MutationStats stats) { - listener - .getLogger() - .println("Kill ratio is " - + stats.getKillPercent() - + "% (" - + stats.getKillCount() - + " " - + stats.getTotalMutations() - + ")"); - } - } - - class MustImproveCondition implements Condition { - @Override - public Result decideResult(final PitBuildAction action) { - PitBuildAction previousAction = action.getPreviousAction(); - if (previousAction != null) { - MutationStats previousStats = previousAction.getReport().getMutationStats(); - logInfo(action, previousStats); - return action.getReport().getMutationStats().getKillPercent() >= previousStats.getKillPercent() ? - Result.SUCCESS : - Result.UNSTABLE; - } else { - return Result.SUCCESS; - } - } - - void logInfo(final PitBuildAction action, MutationStats stats) { - listener.getLogger().println("Previous kill ratio was " + stats.getKillPercent() + "%"); - listener - .getLogger() - .println("This kill ration is " + action.getReport().getMutationStats().getKillPercent() + "%"); - } - } - - Condition mustImprove() { - return new MustImproveCondition(); - } - @Override public BuildStepMonitor getRequiredMonitorService() { - return BuildStepMonitor.BUILD; - } - - /** - * The type Descriptor. - */ - @Extension - @Symbol("pitmutation") - public static class DescriptorImpl extends BuildStepDescriptor { - - /** - * Instantiates a new Descriptor. - */ - public DescriptorImpl() { - super(PitPublisher.class); - } - - @Override - public String getDisplayName() { - return Messages.PitPublisher_DisplayName(); - } - - @Override - public boolean isApplicable(Class aClass) { - return true; - } - - /** - * {@inheritDoc} - */ - @Override - public boolean configure(StaplerRequest req, JSONObject formData) throws FormException { - req.bindParameters(this, "pitmutation"); - save(); - return super.configure(req, formData); - } + return STEP; } - /** - * The type Parse report callable. - */ - public static class ParseReportCallable implements FilePath.FileCallable { - - private static final long serialVersionUID = 1L; - - private final String reportFilePath; - - /** - * Instantiates a new Parse report callable. - * - * @param reportFilePath the report file path - */ - public ParseReportCallable(String reportFilePath) { - this.reportFilePath = reportFilePath; - } - - @Override - public FilePath[] invoke(File f, VirtualChannel channel) throws IOException, InterruptedException { - FilePath[] r = new FilePath(f).list(reportFilePath); - if (r.length < 1) { - throw new IOException("No reports found at location:" + reportFilePath); - } - return r; - } - - @Override - public void checkRoles(RoleChecker roleChecker) throws SecurityException { - - } - } } diff --git a/src/main/java/org/jenkinsci/plugins/pitmutation/ResultDecider.java b/src/main/java/org/jenkinsci/plugins/pitmutation/ResultDecider.java new file mode 100644 index 0000000..9211d95 --- /dev/null +++ b/src/main/java/org/jenkinsci/plugins/pitmutation/ResultDecider.java @@ -0,0 +1,42 @@ +package org.jenkinsci.plugins.pitmutation; + +import hudson.model.Result; + +import java.util.Collection; +import java.util.List; + +import static hudson.model.Result.SUCCESS; + +/** + * Decides if a build is failed or not based on conditions. + * + * @author edward + * @author vasile.jureschi + */ +public class ResultDecider { + + private final Collection buildConditions; + + protected ResultDecider(PercentageThresholdCondition thresholdCondition) { + buildConditions = List.of(thresholdCondition); + } + + protected ResultDecider(PercentageThresholdCondition thresholdCondition, MustImproveCondition mustImproveCondition) { + buildConditions = List.of(thresholdCondition, mustImproveCondition); + } + + /** + * Decide build result result. + * + * @param action the action + * @return the worst result from all conditions + */ + public Result decideBuildResult(PitBuildAction action) { + Result result = SUCCESS; + for (Condition condition : buildConditions) { + Result conditionResult = condition.decideResult(action); + result = conditionResult.isWorseThan(result) ? conditionResult : result; + } + return result; + } +} diff --git a/src/main/java/org/jenkinsci/plugins/pitmutation/portlets/PitColumn.java b/src/main/java/org/jenkinsci/plugins/pitmutation/portlets/PitColumn.java index 1702a62..ae0d63a 100644 --- a/src/main/java/org/jenkinsci/plugins/pitmutation/portlets/PitColumn.java +++ b/src/main/java/org/jenkinsci/plugins/pitmutation/portlets/PitColumn.java @@ -52,7 +52,7 @@ private Double getLinePercent(final Run lastSuccessfulBuild) { final double doubleValue = percentageFloat.doubleValue(); final int decimalPlaces = 2; - BigDecimal bigDecimal = new BigDecimal(doubleValue); + BigDecimal bigDecimal = BigDecimal.valueOf(doubleValue); // setScale is immutable bigDecimal = bigDecimal.setScale(decimalPlaces, diff --git a/src/main/java/org/jenkinsci/plugins/pitmutation/targets/ModuleResult.java b/src/main/java/org/jenkinsci/plugins/pitmutation/targets/ModuleResult.java index 8326de0..9ea39df 100644 --- a/src/main/java/org/jenkinsci/plugins/pitmutation/targets/ModuleResult.java +++ b/src/main/java/org/jenkinsci/plugins/pitmutation/targets/ModuleResult.java @@ -1,15 +1,14 @@ package org.jenkinsci.plugins.pitmutation.targets; -import static org.jenkinsci.plugins.pitmutation.PitPublisher.MULTI_MODULE_REPORT_FORMAT; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; +import org.jenkinsci.plugins.pitmutation.MutationReport; +import javax.annotation.Nonnull; import java.util.Map; import java.util.Objects; -import javax.annotation.Nonnull; -import org.jenkinsci.plugins.pitmutation.MutationReport; - -import lombok.Getter; -import lombok.extern.slf4j.Slf4j; +import static org.jenkinsci.plugins.pitmutation.FileProcessor.MULTI_MODULE_REPORT_FORMAT; /** * @author edward @@ -17,9 +16,9 @@ @Slf4j public class ModuleResult extends MutationResult { - private MutationReport report; + private final MutationReport report; @Getter - private String name; + private final String name; public ModuleResult(String name, MutationResult parent, MutationReport report) { super(name, parent); diff --git a/src/main/java/org/jenkinsci/plugins/pitmutation/targets/SingleModuleResult.java b/src/main/java/org/jenkinsci/plugins/pitmutation/targets/SingleModuleResult.java index 10992e4..c4cf69f 100644 --- a/src/main/java/org/jenkinsci/plugins/pitmutation/targets/SingleModuleResult.java +++ b/src/main/java/org/jenkinsci/plugins/pitmutation/targets/SingleModuleResult.java @@ -1,16 +1,16 @@ package org.jenkinsci.plugins.pitmutation.targets; +import hudson.model.Run; +import org.jenkinsci.plugins.pitmutation.MutationReport; +import org.jenkinsci.plugins.pitmutation.PitBuildAction; + +import javax.annotation.Nonnull; import java.util.ArrayList; import java.util.Collection; import java.util.Map; import java.util.Objects; -import javax.annotation.Nonnull; -import org.jenkinsci.plugins.pitmutation.MutationReport; -import org.jenkinsci.plugins.pitmutation.PitBuildAction; -import org.jenkinsci.plugins.pitmutation.PitPublisher; - -import hudson.model.Run; +import static org.jenkinsci.plugins.pitmutation.FileProcessor.SINGLE_MODULE_REPORT_FOLDER; public class SingleModuleResult extends MutationResult { @@ -57,7 +57,7 @@ public String getDisplayName() { @Override protected String getMutationReportDirectory() { - return PitPublisher.SINGLE_MODULE_REPORT_FOLDER; + return SINGLE_MODULE_REPORT_FOLDER; } @Override diff --git a/src/test/java/org/jenkinsci/plugins/pitmutation/MustImproveConditionTest.java b/src/test/java/org/jenkinsci/plugins/pitmutation/MustImproveConditionTest.java new file mode 100644 index 0000000..e0e9642 --- /dev/null +++ b/src/test/java/org/jenkinsci/plugins/pitmutation/MustImproveConditionTest.java @@ -0,0 +1,64 @@ +package org.jenkinsci.plugins.pitmutation; + +import hudson.model.Result; +import org.jenkinsci.plugins.pitmutation.targets.MutationResult; +import org.jenkinsci.plugins.pitmutation.targets.MutationStats; +import org.junit.jupiter.api.DynamicTest; +import org.junit.jupiter.api.TestFactory; + +import java.util.stream.Stream; + +import static hudson.model.Result.SUCCESS; +import static hudson.model.Result.UNSTABLE; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.DynamicTest.dynamicTest; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +class MustImproveConditionTest { + + @TestFactory + Stream testFactory() { + return Stream + .of(new TestCase(null, 90f, SUCCESS, "noPreviousAction"), + new TestCase(85f, 90f, SUCCESS, "currentKillPercentGreater"), + new TestCase(85f, 85f, SUCCESS, "currentKillPercentEqual"), + new TestCase(85f, 80f, UNSTABLE, "currentKillPercentLess")) + .map(testCase -> dynamicTest(testCase.name, () -> { + PitBuildAction action = mock(PitBuildAction.class); + PitBuildAction previousAction = mock(PitBuildAction.class); + MutationResult currentReport = mock(MutationResult.class); + MutationResult previousReport = mock(MutationResult.class); + MutationStats currentStats = mock(MutationStats.class); + MutationStats previousStats = mock(MutationStats.class); + + when(action.getReport()).thenReturn(currentReport); + when(currentReport.getMutationStats()).thenReturn(currentStats); + when(currentStats.getKillPercent()).thenReturn(testCase.currentKillPercent); + + if (testCase.previousKillPercent != null) { + when(action.getPreviousAction()).thenReturn(previousAction); + when(previousAction.getReport()).thenReturn(previousReport); + when(previousReport.getMutationStats()).thenReturn(previousStats); + when(previousStats.getKillPercent()).thenReturn(testCase.previousKillPercent); + } + + MustImproveCondition condition = new MustImproveCondition(); + assertEquals(testCase.expectedResult, condition.decideResult(action)); + })); + } + + private static class TestCase { + Float previousKillPercent; + float currentKillPercent; + Result expectedResult; + String name; + + TestCase(Float previousKillPercent, float currentKillPercent, Result expectedResult, String name) { + this.previousKillPercent = previousKillPercent; + this.currentKillPercent = currentKillPercent; + this.expectedResult = expectedResult; + this.name = name; + } + } +} diff --git a/src/test/java/org/jenkinsci/plugins/pitmutation/PercentageThresholdConditionTest.java b/src/test/java/org/jenkinsci/plugins/pitmutation/PercentageThresholdConditionTest.java new file mode 100644 index 0000000..75e911f --- /dev/null +++ b/src/test/java/org/jenkinsci/plugins/pitmutation/PercentageThresholdConditionTest.java @@ -0,0 +1,52 @@ +package org.jenkinsci.plugins.pitmutation; + +import hudson.model.Result; +import org.jenkinsci.plugins.pitmutation.targets.MutationResult; +import org.jenkinsci.plugins.pitmutation.targets.MutationStats; +import org.junit.jupiter.api.DynamicTest; +import org.junit.jupiter.api.TestFactory; + +import java.util.stream.Stream; + +import static hudson.model.Result.FAILURE; +import static hudson.model.Result.SUCCESS; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.DynamicTest.dynamicTest; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +class PercentageThresholdConditionTest { + + @TestFactory + Stream testFactory() { + return Stream + .of(new TestCase(80f, 85f, SUCCESS, "killPercentGreaterThanThreshold"), + new TestCase(85f, 85f, SUCCESS, "killPercentEqualToThreshold"), + new TestCase(90f, 85f, FAILURE, "killPercentLessThanThreshold")) + .map(testCase -> dynamicTest(testCase.name, () -> { + PitBuildAction action = mock(PitBuildAction.class); + MutationResult report = mock(MutationResult.class); + MutationStats stats = mock(MutationStats.class); + when(action.getReport()).thenReturn(report); + when(report.getMutationStats()).thenReturn(stats); + when(stats.getKillPercent()).thenReturn(testCase.killPercent); + + PercentageThresholdCondition condition = new PercentageThresholdCondition(testCase.threshold); + assertEquals(testCase.expectedResult, condition.decideResult(action)); + })); + } + + private static class TestCase { + float threshold; + float killPercent; + Result expectedResult; + String name; + + TestCase(float threshold, float killPercent, Result expectedResult, String name) { + this.threshold = threshold; + this.killPercent = killPercent; + this.expectedResult = expectedResult; + this.name = name; + } + } +} diff --git a/src/test/java/org/jenkinsci/plugins/pitmutation/PitLoggerTest.java b/src/test/java/org/jenkinsci/plugins/pitmutation/PitLoggerTest.java new file mode 100644 index 0000000..d148824 --- /dev/null +++ b/src/test/java/org/jenkinsci/plugins/pitmutation/PitLoggerTest.java @@ -0,0 +1,83 @@ +package org.jenkinsci.plugins.pitmutation; + +import hudson.FilePath; +import hudson.model.TaskListener; +import org.jenkinsci.plugins.pitmutation.targets.MutationResult; +import org.jenkinsci.plugins.pitmutation.targets.MutationStats; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.io.File; +import java.io.PrintStream; + +import static org.mockito.Mockito.anyString; +import static org.mockito.Mockito.atLeastOnce; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) +class PitLoggerTest { + + @Mock + private TaskListener listener; + @Mock + private PitBuildAction action; + @Mock + private MutationResult report; + @Mock + private MutationStats stats; + @Mock + private PrintStream printStream; + + private PitLogger pitLogger; + + @BeforeEach + void setUp() { + pitLogger = new PitLogger(); + + when(listener.getLogger()).thenReturn(printStream); + } + + @Test + void logResults() { + when(action.getReport()).thenReturn(report); + when(action.getPreviousAction()).thenReturn(action); + when(report.getMutationStats()).thenReturn(stats); + when(stats.getKillPercent()).thenReturn(70.0f); + + pitLogger.logResults(listener, action); + + verify(printStream, atLeastOnce()).println(anyString()); + } + + @Test + void logMissingReportsIgnored() { + pitLogger.logMissingReportsIgnored(listener); + verify(printStream).println(anyString()); + } + + @Test + void logBuildFailedNoReports() { + pitLogger.logBuildFailedNoReports(listener); + verify(printStream).println(anyString()); + } + + @Test + void logLookingForReports() { + FilePath workspace = new FilePath(new File("path/to/workspace")); + pitLogger.logLookingForReports(listener, workspace); + + verify(printStream).println(anyString()); + } + + @Test + void logPublishReport() { + FilePath workspace = new FilePath(new File("path/to/workspace")); + pitLogger.logPublishReport(listener, workspace); + + verify(printStream).println(anyString()); + } +} diff --git a/src/test/java/org/jenkinsci/plugins/pitmutation/PitProjectActionTest.java b/src/test/java/org/jenkinsci/plugins/pitmutation/PitProjectActionTest.java new file mode 100644 index 0000000..069c847 --- /dev/null +++ b/src/test/java/org/jenkinsci/plugins/pitmutation/PitProjectActionTest.java @@ -0,0 +1,126 @@ +package org.jenkinsci.plugins.pitmutation; + + +import hudson.model.AbstractBuild; +import hudson.model.AbstractProject; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.kohsuke.stapler.StaplerRequest; +import org.kohsuke.stapler.StaplerResponse; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.io.IOException; + +import static hudson.model.Result.SUCCESS; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.verify; + + +@ExtendWith(MockitoExtension.class) +class PitProjectActionTest { + + @Mock + private AbstractProject project; + @Mock + private AbstractBuild lastSuccessfulBuild; + @Mock + private AbstractBuild previousSuccessfulBuild; + @Mock + private AbstractBuild failedBuild; + @Mock + private PitBuildAction action; + @Mock + private StaplerRequest req; + @Mock + private StaplerResponse rsp; + + private PitProjectAction pitProjectAction; + + @BeforeEach + void setUp() { + pitProjectAction = new PitProjectAction(project); + } + + @Test + void getLastResult_noLastResult() { + doReturn(null).when(project).getLastSuccessfulBuild(); + PitBuildAction lastResult = pitProjectAction.getLastResult(); + assertNull(lastResult); + } + + @Test + void getLastResult_returnsLastResult() { + doReturn(lastSuccessfulBuild).when(project).getLastSuccessfulBuild(); + doReturn(SUCCESS).when(lastSuccessfulBuild).getResult(); + doReturn(action).when(lastSuccessfulBuild).getAction(PitBuildAction.class); + + PitBuildAction lastResult = pitProjectAction.getLastResult(); + assertEquals(action, lastResult); + } + + @Test + void getLastResultBuild_returnsLastBuildNumber() { + doReturn(lastSuccessfulBuild).when(project).getLastSuccessfulBuild(); + doReturn(action).when(lastSuccessfulBuild).getAction(PitBuildAction.class); + doReturn(10).when(lastSuccessfulBuild).getNumber(); + + Integer lastResultBuild = pitProjectAction.getLastResultBuild(); + assertEquals(10, lastResultBuild); + } + + @Test + void getIconFileName_returnsCorrectPath() { + String iconPath = pitProjectAction.getIconFileName(); + assertEquals("/plugin/pitmutation/pitest.png", iconPath); + } + + @Test + void getDisplayName_returnsCorrectName() { + String name = pitProjectAction.getDisplayName(); + assertEquals("PIT Mutation Report", name); + } + + @Test + void getSearchUrl_returnsCorrectUrl() { + String url = pitProjectAction.getSearchUrl(); + assertEquals("pitmutation", url); + } + + @Test + void isFloatingBoxActive_returnsTrue() { + assertTrue(pitProjectAction.isFloatingBoxActive()); + } + + @Test + void doIndex_redirectsCorrectly() throws IOException { + doReturn(lastSuccessfulBuild).when(project).getLastSuccessfulBuild(); + doReturn(action).when(lastSuccessfulBuild).getAction(PitBuildAction.class); + doReturn(10).when(lastSuccessfulBuild).getNumber(); + + pitProjectAction.doIndex(req, rsp); + + verify(rsp).sendRedirect2("../10/pitmutation"); + } + + @Test + void doIndex_buildNumberNull_redirectsCorrectly() throws IOException { + doReturn(null).when(project).getLastSuccessfulBuild(); + pitProjectAction.doIndex(req, rsp); + verify(rsp).sendRedirect2("nodata"); + } + + @Test + void doGraph_CallsDoGraphOnLastResult() throws IOException { + doReturn(lastSuccessfulBuild).when(project).getLastSuccessfulBuild(); + doReturn(action).when(lastSuccessfulBuild).getAction(PitBuildAction.class); + + pitProjectAction.doGraph(req, rsp); + + verify(action).doGraph(req, rsp); + } +} diff --git a/src/test/java/org/jenkinsci/plugins/pitmutation/PitPublisherTest.java b/src/test/java/org/jenkinsci/plugins/pitmutation/PitPublisherTest.java index 99108be..f6d5eaf 100644 --- a/src/test/java/org/jenkinsci/plugins/pitmutation/PitPublisherTest.java +++ b/src/test/java/org/jenkinsci/plugins/pitmutation/PitPublisherTest.java @@ -1,137 +1,253 @@ package org.jenkinsci.plugins.pitmutation; -import hudson.model.Result; +import hudson.EnvVars; +import hudson.FilePath; +import hudson.Launcher; +import hudson.model.AbstractProject; +import hudson.model.Action; +import hudson.model.Project; +import hudson.model.Run; +import hudson.model.TaskListener; import org.jenkinsci.plugins.pitmutation.targets.MutationStats; import org.jenkinsci.plugins.pitmutation.targets.ProjectMutations; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.Mockito; -import org.mockito.MockitoAnnotations; - -import static org.junit.Assert.*; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.io.File; +import java.io.IOException; +import java.util.Map; + +import static hudson.model.Result.FAILURE; +import static hudson.model.Result.SUCCESS; +import static hudson.tasks.BuildStepMonitor.STEP; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; + /** * User: Ed Kimber Date: 17/03/13 Time: 17:55 */ -public class PitPublisherTest { - - private static final float MINIMUM_KILL_RATIO = 0.25f; - - @Mock - private PitBuildAction action; - @Mock - private ProjectMutations report; - @Mock - private MutationStats stats; - - private PitPublisher publisher; - private PitPublisherTSS publisherTSS; - - static class PitPublisherTSS extends PitPublisher { - boolean infoImproveLogged = false; - boolean infoPercentLogged = false; - - public PitPublisherTSS(String mutationStatsFile, float minimumKillRatio, boolean killRatioMustImprove, boolean ignoreMissingReports) { - super(mutationStatsFile, minimumKillRatio, killRatioMustImprove, ignoreMissingReports); - } - - class MustImproveConditionTSS extends MustImproveCondition { - void logInfo(final PitBuildAction action, MutationStats stats) { - infoImproveLogged = true; - } - } - - Condition mustImprove() { - return new MustImproveConditionTSS(); - } - - class PercentageThresholdConditionTSS extends PercentageThresholdCondition { - PercentageThresholdConditionTSS(float percentage) { - super(percentage); - } - - void dologging(MutationStats stats) { - infoPercentLogged = true; - } - } - - Condition percentageThreshold(final float percentage) { - return new PercentageThresholdConditionTSS(percentage); - } - } - - @Before - public void setup() { - MockitoAnnotations.openMocks(this); - } - - @Test - public void testDecideBuildResultFailsIfKillRatioTooLow() { - publisherTSS = createPitPublisher(false); - publisher = publisherTSS; - final float TOO_LOW_RATIO = 0.2f; - setupBoilderPlateMocks(); - Mockito.when(stats.getKillPercent()).thenReturn(TOO_LOW_RATIO); - assertEquals(Result.FAILURE, publisher.decideBuildResult(action)); - assertFalse(publisherTSS.infoImproveLogged); - assertTrue(publisherTSS.infoPercentLogged); - } - - @Test - public void testDecideBuildResultSuccessIfKillRatioSame() { - publisher = createPitPublisher(false); - final float BIGGER_RATIO = MINIMUM_KILL_RATIO + 0.2f; - setupBoilderPlateMocks(); - Mockito.when(stats.getKillPercent()).thenReturn(MINIMUM_KILL_RATIO, BIGGER_RATIO); - assertEquals(Result.SUCCESS, publisher.decideBuildResult(action)); - assertEquals(Result.SUCCESS, publisher.decideBuildResult(action)); - } - - @Test - public void testMustImproveConditionSucceedsWhenPreviousActionIsNull() { - publisher = createPitPublisher(true); - final float BIGGER_RATIO = MINIMUM_KILL_RATIO + 0.2f; - setupBoilderPlateMocks(); - Mockito.when(stats.getKillPercent()).thenReturn(BIGGER_RATIO); - assertEquals(Result.SUCCESS, publisher.decideBuildResult(action)); - } - - @Test - public void testMustImproveConditionFailsWhenWhenPreviousActionKillRatioIsBetter() { - publisher = createPitPublisher(true); - setupBoilderPlateMocks(); - setupPercentKillRatioOK(); - PitBuildAction prevAction = mock(PitBuildAction.class); - ProjectMutations prevReport_ = Mockito.mock(ProjectMutations.class); - MutationStats prevStats_ = Mockito.mock(MutationStats.class); - when(action.getPreviousAction()).thenReturn(prevAction); - when(prevAction.getReport()).thenReturn(prevReport_); - when(prevReport_.getMutationStats()).thenReturn(prevStats_); - when(stats.getKillPercent()).thenReturn(MINIMUM_KILL_RATIO + 0.5f); - when(prevStats_.getKillPercent()).thenReturn(MINIMUM_KILL_RATIO + 0.6f, // previous is better - MINIMUM_KILL_RATIO + 0.5f, // equal - MINIMUM_KILL_RATIO + 0.4f); //previous is worse - - assertEquals(Result.UNSTABLE, publisher.decideBuildResult(action)); //previous is better - assertEquals(Result.SUCCESS, publisher.decideBuildResult(action)); // previous is equal - assertEquals(Result.SUCCESS, publisher.decideBuildResult(action)); //previous is worse - } - - private void setupPercentKillRatioOK() { - final float BIGGER_RATIO = MINIMUM_KILL_RATIO + 0.2f; - when(stats.getKillPercent()).thenReturn(BIGGER_RATIO); - } - - private PitPublisherTSS createPitPublisher(boolean mustImprove) { - return new PitPublisherTSS("**/mutations.xml", MINIMUM_KILL_RATIO, mustImprove, false); - } - - private void setupBoilderPlateMocks() { - Mockito.when(action.getReport()).thenReturn(report); - Mockito.when(report.getMutationStats()).thenReturn(stats); - } - +@ExtendWith(MockitoExtension.class) +class PitPublisherTest { + + private static final float MINIMUM_KILL_RATIO = 0.25f; + + @Mock + private PitBuildAction action; + @Mock + private ProjectMutations report; + @Mock + private MutationStats stats; + @Mock + private PitLogger pitLogger; + + @Mock + private FileProcessor fileProcessor; + + @Mock + private ResultDecider resultDecider; + + @Test + void ignoreMissingReports_ignore_noReports() throws Exception { + FileProcessor fileProcessor = mock(FileProcessor.class); + ResultDecider decider = mock(ResultDecider.class); + PitPublisher publisher = + new PitPublisher("**/mutations.xml", MINIMUM_KILL_RATIO, true, true, fileProcessor, decider, pitLogger); + TaskListener taskListener = mock(TaskListener.class); + Run build = mock(Run.class); + publisher.perform(build, mock(FilePath.class), mock(EnvVars.class), mock(Launcher.class), taskListener); + + verify(build).setResult(SUCCESS); + verify(pitLogger).logMissingReportsIgnored(any()); + } + + @Test + void ignoreMissingReports_doNotIgnore_noReports() throws Exception { + FileProcessor fileProcessor = mock(FileProcessor.class); + ResultDecider decider = mock(ResultDecider.class); + PitPublisher publisher = + new PitPublisher("**/mutations.xml", MINIMUM_KILL_RATIO, true, false, fileProcessor, decider, pitLogger); + TaskListener taskListener = mock(TaskListener.class); + Run build = mock(Run.class); + + + publisher.perform(build, mock(FilePath.class), mock(EnvVars.class), mock(Launcher.class), taskListener); + + verify(build).setResult(FAILURE); + verify(pitLogger).logBuildFailedNoReports(any()); + } + + @Test + void oneReport_ioException() throws Exception { + FileProcessor fileProcessor = mock(FileProcessor.class); + ResultDecider decider = mock(ResultDecider.class); + PitPublisher publisher = new PitPublisher( + "./src/test/resources/org/jenkinsci/plugins/pitmutation/testmutations-00.xml", + MINIMUM_KILL_RATIO, + true, + false, + fileProcessor, + decider, + pitLogger); + TaskListener taskListener = mock(TaskListener.class); + FilePath workspace = mock(FilePath.class); + FilePath[] reports = {mock(FilePath.class)}; + when(workspace.act(any(ParseReportCallable.class))).thenReturn(reports); + doThrow(IOException.class).when(fileProcessor).copySingleModuleReport(any(), any()); + Run build = mock(Run.class); + when(build.getRootDir()).thenReturn(new File("src/test/resources")); + publisher.perform(build, workspace, mock(EnvVars.class), mock(Launcher.class), taskListener); + + verify(build).setResult(FAILURE); + verify(pitLogger, never()).logResults(any(), any()); + } + + @Test + void oneReport() throws Exception { + FileProcessor fileProcessor = mock(FileProcessor.class); + ResultDecider decider = mock(ResultDecider.class); + PitPublisher publisher = new PitPublisher( + "./src/test/resources/org/jenkinsci/plugins/pitmutation/testmutations-00.xml", + MINIMUM_KILL_RATIO, + true, + false, + fileProcessor, + decider, + pitLogger); + TaskListener taskListener = mock(TaskListener.class); + FilePath workspace = mock(FilePath.class); + FilePath[] reports = {mock(FilePath.class)}; + when(workspace.act(any(ParseReportCallable.class))).thenReturn(reports); + doNothing().when(fileProcessor).copySingleModuleReport(any(), any()); + Run build = mock(Run.class); + when(build.getRootDir()).thenReturn(new File("src/test/resources")); + when(decider.decideBuildResult(any())).thenReturn(SUCCESS); + publisher.perform(build, workspace, mock(EnvVars.class), mock(Launcher.class), taskListener); + + verify(build).setResult(SUCCESS); + verify(pitLogger).logResults(any(), any()); + } + + + @Test + void multiModuleReports() throws Exception { + FileProcessor fileProcessor = mock(FileProcessor.class); + ResultDecider decider = mock(ResultDecider.class); + PitPublisher publisher = new PitPublisher( + "./src/test/resources/org/jenkinsci/plugins/pitmutation/testmutations-00.xml", + MINIMUM_KILL_RATIO, + true, + false, + fileProcessor, + decider, + pitLogger); + TaskListener taskListener = mock(TaskListener.class); + FilePath workspace = mock(FilePath.class); + FilePath[] reports = {mock(FilePath.class), mock(FilePath.class)}; + when(workspace.act(any(ParseReportCallable.class))).thenReturn(reports); + when(fileProcessor.getNames(any(), any())).thenReturn(Map.of(mock(FilePath.class), + "1", + mock(FilePath.class), + "2")); + doNothing().when(fileProcessor).copyMultiModuleReport(any(), any(), any()); + Run build = mock(Run.class); + when(build.getRootDir()).thenReturn(new File("src/test/resources")); + when(decider.decideBuildResult(any())).thenReturn(SUCCESS); + publisher.perform(build, workspace, mock(EnvVars.class), mock(Launcher.class), taskListener); + + verify(build).setResult(SUCCESS); + verify(pitLogger).logResults(any(), any()); + } + + + @Test + void multiModuleReports_ioException() throws Exception { + FileProcessor fileProcessor = mock(FileProcessor.class); + ResultDecider decider = mock(ResultDecider.class); + PitPublisher publisher = new PitPublisher( + "./src/test/resources/org/jenkinsci/plugins/pitmutation/testmutations-00.xml", + MINIMUM_KILL_RATIO, + true, + false, + fileProcessor, + decider, + pitLogger); + TaskListener taskListener = mock(TaskListener.class); + FilePath workspace = mock(FilePath.class); + FilePath[] reports = {mock(FilePath.class), mock(FilePath.class)}; + when(workspace.act(any(ParseReportCallable.class))).thenReturn(reports); + when(fileProcessor.getNames(any(), any())).thenReturn(Map.of(mock(FilePath.class), + "1", + mock(FilePath.class), + "2")); + doThrow(IOException.class).when(fileProcessor).copyMultiModuleReport(any(), any(), any()); + Run build = mock(Run.class); + when(build.getRootDir()).thenReturn(new File("src/test/resources")); + publisher.perform(build, workspace, mock(EnvVars.class), mock(Launcher.class), taskListener); + + verify(build).setResult(FAILURE); + verify(pitLogger, never()).logResults(any(), any()); + } + @Test + void getMinimumKillRatio() { + PitPublisher pitPublisher = new PitPublisher("target/pit-reports/mutations.xml", 0.5f, false, false); + assertEquals(0.5f, pitPublisher.getMinimumKillRatio()); + } + + @Test + void getKillRatioMustImprove() { + PitPublisher pitPublisher = new PitPublisher("target/pit-reports/mutations.xml", 0.5f, true, false); + assertTrue(pitPublisher.getKillRatioMustImprove()); + } + + @Test + void getIgnoreMissingReports() { + PitPublisher pitPublisher = new PitPublisher("target/pit-reports/mutations.xml", 0.5f, false, true); + assertTrue(pitPublisher.getIgnoreMissingReports()); + } + + @Test + void setIgnoreMissingReports_true() { + PitPublisher pitPublisher = new PitPublisher("target/pit-reports/mutations.xml", 0.5f, false, false); + pitPublisher.setIgnoreMissingReports(true); + assertTrue(pitPublisher.getIgnoreMissingReports()); + } + + @Test + void setIgnoreMissingReports_false() { + PitPublisher pitPublisher = new PitPublisher("target/pit-reports/mutations.xml", 0.5f, false, true); + pitPublisher.setIgnoreMissingReports(false); + assertFalse(pitPublisher.getIgnoreMissingReports()); + } + + @Test + void getProjectAction() { + PitPublisher pitPublisher = new PitPublisher("target/pit-reports/mutations.xml", 0.5f, false, true); + Action projectAction = pitPublisher.getProjectAction((AbstractProject) mock(Project.class)); + assertNotNull(projectAction); + } + + @Test + void getMutationStatsFile() { + PitPublisher pitPublisher = new PitPublisher("target/pit-reports/mutations.xml", 0.5f, false, true); + assertEquals("target/pit-reports/mutations.xml", pitPublisher.getMutationStatsFile()); + } + + @Test + void getRequiredMonitorService() { + PitPublisher pitPublisher = new PitPublisher("target/pit-reports/mutations.xml", 0.5f, false, true); + assertEquals(STEP, pitPublisher.getRequiredMonitorService()); + } } diff --git a/src/test/java/org/jenkinsci/plugins/pitmutation/ResultDeciderTest.java b/src/test/java/org/jenkinsci/plugins/pitmutation/ResultDeciderTest.java new file mode 100644 index 0000000..64c601f --- /dev/null +++ b/src/test/java/org/jenkinsci/plugins/pitmutation/ResultDeciderTest.java @@ -0,0 +1,46 @@ +package org.jenkinsci.plugins.pitmutation; + +import hudson.model.Result; +import org.junit.jupiter.api.DynamicTest; +import org.junit.jupiter.api.TestFactory; + +import java.util.Arrays; +import java.util.Collection; +import java.util.stream.Stream; + +import static hudson.model.Result.FAILURE; +import static hudson.model.Result.SUCCESS; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +class ResultDeciderTest { + + @TestFactory + Stream testFactory() { + // Create a collection of inputs for the test. + Collection inputs = Arrays.asList(new Object[][] { + {SUCCESS, SUCCESS, SUCCESS}, + {FAILURE, SUCCESS, FAILURE}, + {SUCCESS, FAILURE, FAILURE}, + {FAILURE, FAILURE, FAILURE} + }); + + // Create and return the dynamic tests. + return inputs.stream().map(input -> DynamicTest.dynamicTest( + "Testing with thresholdResult = " + input[0] + ", mustImproveResult = " + input[1], + () -> runTest((Result) input[0], (Result) input[1], (Result) input[2]) + )); + } + + private void runTest(Result thresholdResult, Result mustImproveResult, Result expectedResult) { + PercentageThresholdCondition thresholdCondition = mock(PercentageThresholdCondition.class); + MustImproveCondition mustImproveCondition = mock(MustImproveCondition.class); + PitBuildAction action = mock(PitBuildAction.class); + when(thresholdCondition.decideResult(action)).thenReturn(thresholdResult); + when(mustImproveCondition.decideResult(action)).thenReturn(mustImproveResult); + ResultDecider decider = new ResultDecider(thresholdCondition, mustImproveCondition); + Result result = decider.decideBuildResult(action); + assertEquals(expectedResult, result); + } +} diff --git a/src/test/resources/org/jenkinsci/plugins/pitmutation/testmutations-00-new.xml b/src/test/resources/org/jenkinsci/plugins/pitmutation/testmutations-00-new.xml new file mode 100644 index 0000000..7af0573 --- /dev/null +++ b/src/test/resources/org/jenkinsci/plugins/pitmutation/testmutations-00-new.xml @@ -0,0 +1,386 @@ + + + + RabbitMqMessageListenerServiceImpl.java + com.stayble.badge_log.rabbitmq.impl.RabbitMqMessageListenerServiceImpl + onMessage + (Lcom/stayble/rabbitmq/binding/messages/BadgeLogMessage;)V + 30 + org.pitest.mutationtest.engine.gregor.mutators.VoidMethodCallMutator + + 25 + + + 5 + + + com.stayble.badge_log.rabbitmq.impl.RabbitMqMessageListenerServiceImplTest.[engine:junit-jupiter]/[class:com.stayble.badge_log.rabbitmq.impl.RabbitMqMessageListenerServiceImplTest]/[method:onPasswordResetRequestedMessage()] + + removed call to com/stayble/badge_log/service/BadgeRequestLogService::logBadgeRequest + + + BadgeRequestLogServiceImpl.java + com.stayble.badge_log.service.BadgeRequestLogServiceImpl + getBadgeInfo + (Ljava/lang/String;)Lcom/stayble/badge/service/to/ProductBadgeInfo; + 115 + org.pitest.mutationtest.engine.gregor.mutators.NegateConditionalsMutator + + 5 + + + 1 + + + com.stayble.badge_log.service.BadgeRequestLogServiceTest.[engine:junit-jupiter]/[class:com.stayble.badge_log.service.BadgeRequestLogServiceTest]/[method:getBadgeProductInfo_okEmptyProductId()] + + negated conditional + + + BadgeRequestLogServiceImpl.java + com.stayble.badge_log.service.BadgeRequestLogServiceImpl + getBadgeInfo + (Ljava/lang/String;)Lcom/stayble/badge/service/to/ProductBadgeInfo; + 118 + org.pitest.mutationtest.engine.gregor.mutators.returns.NullReturnValsMutator + + 32 + + + 7 + + + com.stayble.badge_log.service.BadgeRequestLogServiceTest.[engine:junit-jupiter]/[class:com.stayble.badge_log.service.BadgeRequestLogServiceTest]/[method:getBadgeProductInfo_okEmptyProductId()] + + replaced return value with null for + com/stayble/badge_log/service/BadgeRequestLogServiceImpl::getBadgeInfo + + + + BadgeRequestLogServiceImpl.java + com.stayble.badge_log.service.BadgeRequestLogServiceImpl + getBadgeStatus + + (Lcom/stayble/data/entity/Product;Lcom/stayble/data/entity/Retailer;)Lcom/stayble/data/enums/BadgeStatus; + + 86 + org.pitest.mutationtest.engine.gregor.mutators.NegateConditionalsMutator + + 4 + + + 0 + + + com.stayble.badge_log.service.BadgeRequestLogServiceTest.[engine:junit-jupiter]/[class:com.stayble.badge_log.service.BadgeRequestLogServiceTest]/[method:getBadgeStatus_okUpToDate()] + + negated conditional + + + BadgeRequestLogServiceImpl.java + com.stayble.badge_log.service.BadgeRequestLogServiceImpl + getBadgeStatus + + (Lcom/stayble/data/entity/Product;Lcom/stayble/data/entity/Retailer;)Lcom/stayble/data/enums/BadgeStatus; + + 89 + org.pitest.mutationtest.engine.gregor.mutators.NegateConditionalsMutator + + 17 + + + 3 + + + com.stayble.badge_log.service.BadgeRequestLogServiceTest.[engine:junit-jupiter]/[class:com.stayble.badge_log.service.BadgeRequestLogServiceTest]/[method:getBadgeStatus_okUpToDate()] + + negated conditional + + + BadgeRequestLogServiceImpl.java + com.stayble.badge_log.service.BadgeRequestLogServiceImpl + getBadgeStatus + + (Lcom/stayble/data/entity/Product;Lcom/stayble/data/entity/Retailer;)Lcom/stayble/data/enums/BadgeStatus; + + 92 + org.pitest.mutationtest.engine.gregor.mutators.NegateConditionalsMutator + + 30 + + + 6 + + + com.stayble.badge_log.service.BadgeRequestLogServiceTest.[engine:junit-jupiter]/[class:com.stayble.badge_log.service.BadgeRequestLogServiceTest]/[method:getBadgeStatus_okGrace()] + + negated conditional + + + BadgeRequestLogServiceImpl.java + com.stayble.badge_log.service.BadgeRequestLogServiceImpl + getBadgeStatus + + (Lcom/stayble/data/entity/Product;Lcom/stayble/data/entity/Retailer;)Lcom/stayble/data/enums/BadgeStatus; + + 90 + org.pitest.mutationtest.engine.gregor.mutators.returns.NullReturnValsMutator + + 21 + + + 4 + + + com.stayble.badge_log.service.BadgeRequestLogServiceTest.[engine:junit-jupiter]/[class:com.stayble.badge_log.service.BadgeRequestLogServiceTest]/[method:getBadgeStatus_okUpToDate()] + + replaced return value with null for + com/stayble/badge_log/service/BadgeRequestLogServiceImpl::getBadgeStatus + + + + BadgeRequestLogServiceImpl.java + com.stayble.badge_log.service.BadgeRequestLogServiceImpl + getBadgeStatus + + (Lcom/stayble/data/entity/Product;Lcom/stayble/data/entity/Retailer;)Lcom/stayble/data/enums/BadgeStatus; + + 93 + org.pitest.mutationtest.engine.gregor.mutators.returns.NullReturnValsMutator + + 34 + + + 7 + + + com.stayble.badge_log.service.BadgeRequestLogServiceTest.[engine:junit-jupiter]/[class:com.stayble.badge_log.service.BadgeRequestLogServiceTest]/[method:getBadgeStatus_okNotUpToDate()] + + replaced return value with null for + com/stayble/badge_log/service/BadgeRequestLogServiceImpl::getBadgeStatus + + + + BadgeRequestLogServiceImpl.java + com.stayble.badge_log.service.BadgeRequestLogServiceImpl + getBadgeStatus + + (Lcom/stayble/data/entity/Product;Lcom/stayble/data/entity/Retailer;)Lcom/stayble/data/enums/BadgeStatus; + + 95 + org.pitest.mutationtest.engine.gregor.mutators.returns.NullReturnValsMutator + + 39 + + + 8 + + + com.stayble.badge_log.service.BadgeRequestLogServiceTest.[engine:junit-jupiter]/[class:com.stayble.badge_log.service.BadgeRequestLogServiceTest]/[method:getBadgeStatus_okGrace()] + + replaced return value with null for + com/stayble/badge_log/service/BadgeRequestLogServiceImpl::getBadgeStatus + + + + BadgeRequestLogServiceImpl.java + com.stayble.badge_log.service.BadgeRequestLogServiceImpl + getBrandName + (Ljava/lang/String;)Ljava/lang/String; + 101 + org.pitest.mutationtest.engine.gregor.mutators.NegateConditionalsMutator + + 5 + + + 1 + + + com.stayble.badge_log.service.BadgeRequestLogServiceTest.[engine:junit-jupiter]/[class:com.stayble.badge_log.service.BadgeRequestLogServiceTest]/[method:logBadgeRequest_okWithBlankBrand()] + + negated conditional + + + BadgeRequestLogServiceImpl.java + com.stayble.badge_log.service.BadgeRequestLogServiceImpl + getBrandName + (Ljava/lang/String;)Ljava/lang/String; + 101 + org.pitest.mutationtest.engine.gregor.mutators.returns.EmptyObjectReturnValsMutator + + 13 + + + 4 + + + com.stayble.badge_log.service.BadgeRequestLogServiceTest.[engine:junit-jupiter]/[class:com.stayble.badge_log.service.BadgeRequestLogServiceTest]/[method:logBadgeRequest_okWithBlankBrand()] + + replaced return value with "" for + com/stayble/badge_log/service/BadgeRequestLogServiceImpl::getBrandName + + + + BadgeRequestLogServiceImpl.java + com.stayble.badge_log.service.BadgeRequestLogServiceImpl + lambda$getBadgeInfo$2 + (Lcom/stayble/data/entity/Product;)Lcom/stayble/badge/service/to/ProductBadgeInfo; + + 121 + org.pitest.mutationtest.engine.gregor.mutators.returns.NullReturnValsMutator + + 10 + + + 2 + + + com.stayble.badge_log.service.BadgeRequestLogServiceTest.[engine:junit-jupiter]/[class:com.stayble.badge_log.service.BadgeRequestLogServiceTest]/[method:getBadgeProductInfo_okProductBadge()] + + replaced return value with null for + com/stayble/badge_log/service/BadgeRequestLogServiceImpl::lambda$getBadgeInfo$2 + + + + BadgeRequestLogServiceImpl.java + com.stayble.badge_log.service.BadgeRequestLogServiceImpl + lambda$getBadgeInfo$3 + (Ljava/lang/String;)Lcom/stayble/badge/service/to/ProductBadgeInfo; + 122 + org.pitest.mutationtest.engine.gregor.mutators.returns.NullReturnValsMutator + + 25 + + + 6 + + + com.stayble.badge_log.service.BadgeRequestLogServiceTest.[engine:junit-jupiter]/[class:com.stayble.badge_log.service.BadgeRequestLogServiceTest]/[method:getBadgeProductInfo_okNewGtinBadge()] + + replaced return value with null for + com/stayble/badge_log/service/BadgeRequestLogServiceImpl::lambda$getBadgeInfo$3 + + + + BadgeRequestLogServiceImpl.java + com.stayble.badge_log.service.BadgeRequestLogServiceImpl + logBadgeRequest + + (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + + 52 + org.pitest.mutationtest.engine.gregor.mutators.VoidMethodCallMutator + + 22 + + + 3 + + + com.stayble.badge_log.service.BadgeRequestLogServiceTest.[engine:junit-jupiter]/[class:com.stayble.badge_log.service.BadgeRequestLogServiceTest]/[method:logBadgeRequest_okNotExistingLocationExceptionCatch()] + + removed call to java/util/Optional::ifPresentOrElse + + + TomcatLoggingConfiguration.java + com.stayble.badge_log.configuration.TomcatLoggingConfiguration + servletContainer + ()Lorg/springframework/boot/web/servlet/server/ServletWebServerFactory; + 17 + org.pitest.mutationtest.engine.gregor.mutators.VoidMethodCallMutator + + 17 + + + 2 + + + removed call to ch/qos/logback/access/tomcat/LogbackValve::setAsyncSupported + + + TomcatLoggingConfiguration.java + com.stayble.badge_log.configuration.TomcatLoggingConfiguration + servletContainer + ()Lorg/springframework/boot/web/servlet/server/ServletWebServerFactory; + 19 + org.pitest.mutationtest.engine.gregor.mutators.VoidMethodCallMutator + + 22 + + + 3 + + + removed call to ch/qos/logback/access/tomcat/LogbackValve::setFilename + + + TomcatLoggingConfiguration.java + com.stayble.badge_log.configuration.TomcatLoggingConfiguration + servletContainer + ()Lorg/springframework/boot/web/servlet/server/ServletWebServerFactory; + 21 + org.pitest.mutationtest.engine.gregor.mutators.VoidMethodCallMutator + + 32 + + + 4 + + + removed call to + org/springframework/boot/web/embedded/tomcat/TomcatServletWebServerFactory::addContextValves + + + + TomcatLoggingConfiguration.java + com.stayble.badge_log.configuration.TomcatLoggingConfiguration + servletContainer + ()Lorg/springframework/boot/web/servlet/server/ServletWebServerFactory; + 23 + org.pitest.mutationtest.engine.gregor.mutators.returns.NullReturnValsMutator + + 36 + + + 5 + + + replaced return value with null for + com/stayble/badge_log/configuration/TomcatLoggingConfiguration::servletContainer + + + + MethodTimingAspect.java + com.stayble.badge_log.configuration.MethodTimingAspect + measureExecutionTime + (Lorg/aspectj/lang/ProceedingJoinPoint;)Ljava/lang/Object; + 18 + org.pitest.mutationtest.engine.gregor.mutators.MathMutator + + 14 + + + 3 + + + Replaced long subtraction with addition + + + MethodTimingAspect.java + com.stayble.badge_log.configuration.MethodTimingAspect + measureExecutionTime + (Lorg/aspectj/lang/ProceedingJoinPoint;)Ljava/lang/Object; + 21 + org.pitest.mutationtest.engine.gregor.mutators.returns.NullReturnValsMutator + + 19 + + + 3 + + + replaced return value with null for + com/stayble/badge_log/configuration/MethodTimingAspect::measureExecutionTime + + + From e20269e9d3537957c5bbf28f71a9aadd06272880 Mon Sep 17 00:00:00 2001 From: Vasile Jureschi Date: Sun, 16 Jul 2023 18:17:38 +0300 Subject: [PATCH 06/16] Update dependencies --- pom.xml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pom.xml b/pom.xml index f6acc3d..d372f81 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ org.jenkins-ci.plugins plugin - 4.54 + 4.71 @@ -15,8 +15,8 @@ http://wiki.jenkins-ci.org/display/JENKINS/pitmutation - scm:git:git://git@github.com/jenkinsci/pitmutation-plugin.git - scm:git:git://git@github.com/jenkinsci/pitmutation-plugin.git + scm:git:ssh://git@github.com/jenkinsci/pitmutation-plugin.git + scm:git:ssh://git@github.com/jenkinsci/pitmutation-plugin.git https://github.com/jenkinsci/pitmutation-plugin HEAD @@ -70,7 +70,7 @@ org.projectlombok lombok - 1.18.24 + 1.18.28 provided @@ -122,7 +122,7 @@ org.jenkins-ci.tools maven-hpi-plugin - 3.38 + 3.47 org.apache.maven.plugins From 145d4b31406f12ff8def3e6cc14af54cc0184245 Mon Sep 17 00:00:00 2001 From: Vasile Jureschi Date: Mon, 17 Jul 2023 09:47:08 +0300 Subject: [PATCH 07/16] Updates all tests to use Junit5 --- .../pitmutation/MutationReportTest.java | 20 +- .../MutationReportWithDescriptionTest.java | 16 +- .../pitmutation/PitBuildActionTest.java | 13 +- .../plugins/pitmutation/PitPublisherTest.java | 1 - .../portlets/CoverageRangeTest.java | 351 +++++++++--------- .../pitmutation/targets/MutatedClassTest.java | 14 +- .../pitmutation/targets/MutatedLineTest.java | 6 +- .../targets/MutationResultTest.java | 34 +- .../targets/MutationStatsTest.java | 10 +- 9 files changed, 237 insertions(+), 228 deletions(-) diff --git a/src/test/java/org/jenkinsci/plugins/pitmutation/MutationReportTest.java b/src/test/java/org/jenkinsci/plugins/pitmutation/MutationReportTest.java index 6c884a0..d910d57 100644 --- a/src/test/java/org/jenkinsci/plugins/pitmutation/MutationReportTest.java +++ b/src/test/java/org/jenkinsci/plugins/pitmutation/MutationReportTest.java @@ -1,7 +1,7 @@ package org.jenkinsci.plugins.pitmutation; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.xml.sax.SAXException; import java.io.ByteArrayInputStream; @@ -17,7 +17,7 @@ /** * @author edward */ -public class MutationReportTest { +class MutationReportTest { private static final String MUTATIONS_OLD = "" + "\n" @@ -65,26 +65,26 @@ public class MutationReportTest { private InputStream mutationsXml; - @Before + @BeforeEach public void setUp() { mutationsXml = getClass().getResourceAsStream("testmutations-00.xml"); } @Test - public void packageNameFinder() { + void packageNameFinder() { assertThat(MutationReport.packageNameFromClass("xxx.yyy.zzz.Foo"), is("xxx.yyy.zzz")); assertThat(MutationReport.packageNameFromClass("Foo"), is("")); } @Test - public void countsKills() throws IOException, SAXException { + void countsKills() throws IOException, SAXException { MutationReport report = new MutationReport(mutationsXml); assertThat(report.getMutationStats().getKillCount(), is(5)); assertThat(report.getMutationStats().getTotalMutations(), is(16)); } @Test - public void sortsMutationsByClassName() throws IOException, SAXException { + void sortsMutationsByClassName() throws IOException, SAXException { MutationReport report = new MutationReport(mutationsXml); Collection mutations = report.getMutationsForClassName("org.jenkinsci.plugins.pitmutation.MutationReport"); @@ -92,14 +92,14 @@ public void sortsMutationsByClassName() throws IOException, SAXException { } @Test - public void indexesMutationsByPackage() throws IOException, SAXException { + void indexesMutationsByPackage() throws IOException, SAXException { MutationReport report = new MutationReport(mutationsXml); assertThat(report.getMutationsForPackage("org.jenkinsci.plugins.pitmutation"), hasSize(16)); assertThat(report.getMutationsForPackage(""), hasSize(0)); } @Test - public void canDigestAMutation() throws IOException, SAXException { + void canDigestAMutation() throws IOException, SAXException { MutationReport report = new MutationReport(new ByteArrayInputStream(MUTATIONS.getBytes("UTF-8"))); assertThat(report.getMutationStats().getTotalMutations(), is(2)); @@ -120,7 +120,7 @@ public void canDigestAMutation() throws IOException, SAXException { } @Test - public void canDigestAMutationOlderMutations() throws IOException, SAXException { + void canDigestAMutationOlderMutations() throws IOException, SAXException { MutationReport report = new MutationReport(new ByteArrayInputStream(MUTATIONS_OLD.getBytes("UTF-8"))); assertThat(report.getMutationStats().getTotalMutations(), is(2)); diff --git a/src/test/java/org/jenkinsci/plugins/pitmutation/MutationReportWithDescriptionTest.java b/src/test/java/org/jenkinsci/plugins/pitmutation/MutationReportWithDescriptionTest.java index 9b1075a..242e45e 100644 --- a/src/test/java/org/jenkinsci/plugins/pitmutation/MutationReportWithDescriptionTest.java +++ b/src/test/java/org/jenkinsci/plugins/pitmutation/MutationReportWithDescriptionTest.java @@ -1,7 +1,7 @@ package org.jenkinsci.plugins.pitmutation; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.xml.sax.SAXException; import java.io.IOException; @@ -16,37 +16,37 @@ /** * @author edward */ -public class MutationReportWithDescriptionTest { +class MutationReportWithDescriptionTest { private InputStream mutationsXml; - @Before + @BeforeEach public void setUp() { mutationsXml = getClass().getResourceAsStream("testmutations-02.xml"); } @Test - public void packageNameFinder() { + void packageNameFinder() { assertThat(MutationReport.packageNameFromClass("xxx.yyy.zzz.Foo"), is("xxx.yyy.zzz")); assertThat(MutationReport.packageNameFromClass("Foo"), is("")); } @Test - public void countsKills() throws IOException, SAXException { + void countsKills() throws IOException, SAXException { MutationReport report = new MutationReport(mutationsXml); assertThat(report.getMutationStats().getKillCount(), is(3)); assertThat(report.getMutationStats().getTotalMutations(), is(4)); } @Test - public void sortsMutationsByClassName() throws IOException, SAXException { + void sortsMutationsByClassName() throws IOException, SAXException { MutationReport report = new MutationReport(mutationsXml); Collection mutations = report.getMutationsForClassName("es.rodri.controllers.CompositorController"); assertThat(mutations.size(), is(4)); } @Test - public void indexesMutationsByPackage() throws IOException, SAXException { + void indexesMutationsByPackage() throws IOException, SAXException { MutationReport report = new MutationReport(mutationsXml); assertThat(report.getMutationsForPackage("es.rodri.controllers"), hasSize(4)); assertThat(report.getMutationsForPackage(""), notNullValue()); diff --git a/src/test/java/org/jenkinsci/plugins/pitmutation/PitBuildActionTest.java b/src/test/java/org/jenkinsci/plugins/pitmutation/PitBuildActionTest.java index dc855ee..be34ed7 100644 --- a/src/test/java/org/jenkinsci/plugins/pitmutation/PitBuildActionTest.java +++ b/src/test/java/org/jenkinsci/plugins/pitmutation/PitBuildActionTest.java @@ -11,7 +11,8 @@ import java.io.FilenameFilter; import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import hudson.model.AbstractBuild; import hudson.model.Result; @@ -19,13 +20,13 @@ /** * @author edward */ -public class PitBuildActionTest { +class PitBuildActionTest { private PitBuildAction action; private AbstractBuild owner; private AbstractBuild failedBuild; private AbstractBuild successBuild; - @Before + @BeforeEach public void setUp() { failedBuild = mock(AbstractBuild.class); when(failedBuild.getResult()).thenReturn(Result.FAILURE); @@ -43,18 +44,18 @@ public void setUp() { } @Test - public void previousReturnsNullIfNoPreviousBuilds() { + void previousReturnsNullIfNoPreviousBuilds() { assertThat(action.getPreviousAction(), nullValue()); } @Test - public void previousReturnsNullIfAllPreviousBuildsFailed() { + void previousReturnsNullIfAllPreviousBuildsFailed() { when(owner.getPreviousBuild()).thenReturn(failedBuild); assertThat(action.getPreviousAction(), nullValue()); } @Test - public void previousReturnsLastSuccessfulBuild() { + void previousReturnsLastSuccessfulBuild() { PitBuildAction previousSucccessAction = mock(PitBuildAction.class); when(owner.getPreviousBuild()).thenReturn(failedBuild); when(failedBuild.getPreviousBuild()).thenReturn(successBuild); diff --git a/src/test/java/org/jenkinsci/plugins/pitmutation/PitPublisherTest.java b/src/test/java/org/jenkinsci/plugins/pitmutation/PitPublisherTest.java index f6d5eaf..b46516d 100644 --- a/src/test/java/org/jenkinsci/plugins/pitmutation/PitPublisherTest.java +++ b/src/test/java/org/jenkinsci/plugins/pitmutation/PitPublisherTest.java @@ -31,7 +31,6 @@ import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; -import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; diff --git a/src/test/java/org/jenkinsci/plugins/pitmutation/portlets/CoverageRangeTest.java b/src/test/java/org/jenkinsci/plugins/pitmutation/portlets/CoverageRangeTest.java index eab509c..965607e 100644 --- a/src/test/java/org/jenkinsci/plugins/pitmutation/portlets/CoverageRangeTest.java +++ b/src/test/java/org/jenkinsci/plugins/pitmutation/portlets/CoverageRangeTest.java @@ -1,179 +1,188 @@ package org.jenkinsci.plugins.pitmutation.portlets; -import org.junit.Test; +import org.junit.jupiter.api.Test; -import java.awt.*; + +import java.awt.Color; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.is; -import static org.jenkinsci.plugins.pitmutation.portlets.CoverageRange.*; - -public class CoverageRangeTest { - - @Test - public void valueOfLessTHanZeroReturnsAbysmal() { - assertThat(CoverageRange.valueOf(-1D), is(ABYSMAL)); - } - - @Test - public void valueOfZeroReturnsAbysmal() { - assertThat(CoverageRange.valueOf(0D), is(ABYSMAL)); - } - - @Test - public void valueOfTwentyFiveReturnsTragic() { - assertThat(CoverageRange.valueOf(25D), is(TRAGIC)); - } - - @Test - public void valueOfFiftyReturnsPoor() { - assertThat(CoverageRange.valueOf(50D), is(AVERAGE)); - } - - @Test - public void valueOfSeventyFiveReturnsFair() { - assertThat(CoverageRange.valueOf(75D), is(SUFFICIENT)); - } - - @Test - public void valueOfEightyFiveReturnsSufficient() { - assertThat(CoverageRange.valueOf(85D), is(GOOD)); - } - - @Test - public void valueOfNinetyTwoReturnsGood() { - assertThat(CoverageRange.valueOf(92D), is(EXCELLENT)); - } - - @Test - public void valueOfNinetySevenReturnsExcellent() { - assertThat(CoverageRange.valueOf(97D), is(EXCELLENT)); - } - - @Test - public void valueOfOneHundredReturnsPerfect() { - assertThat(CoverageRange.valueOf(100D), is(PERFECT)); - } - - @Test - public void valueOfOneHundredAndOneReturnsPerfect() { - assertThat(CoverageRange.valueOf(101D), is(PERFECT)); - } - - @Test - public void getFillHexStringForAbysmal() { - assertThat(ABYSMAL.getFillHexString(), is("FF0000")); - } - - @Test - public void getFillHexStringForTragic() { - assertThat(TRAGIC.getFillHexString(), is("FF4500")); - } - - @Test - public void getFillHexStringForPoor() { - assertThat(POOR.getFillHexString(), is("FF7F00")); - } - - @Test - public void getFillHexStringForFair() { - assertThat(FAIR.getFillHexString(), is("FFFF00")); - } - - @Test - public void getFillHexStringForSufficient() { - assertThat(SUFFICIENT.getFillHexString(), is("C8FF3F")); - } - - @Test - public void getFillHexStringForGood() { - assertThat(GOOD.getFillHexString(), is("7AFF3F")); - } - - @Test - public void getFillHexStringForExcellent() { - assertThat(EXCELLENT.getFillHexString(), is("00CD00")); - } - - @Test - public void getFillHexStringForPerfect() { - assertThat(PERFECT.getFillHexString(), is("008B00")); - } - - @Test - public void getLineHexStringForAbysmal() { - assertThat(ABYSMAL.getLineHexString(), is("EEEEEE")); - } - - @Test - public void getLineHexStringForTragic() { - assertThat(TRAGIC.getLineHexString(), is("EEEEEE")); - } - - @Test - public void getLineHexStringForPoor() { - assertThat(POOR.getLineHexString(), is("000000")); - } - - @Test - public void getLineHexStringForFair() { - assertThat(FAIR.getLineHexString(), is("000000")); - } - - @Test - public void getLineHexStringForSufficient() { - assertThat(SUFFICIENT.getLineHexString(), is("000000")); - } - - @Test - public void getLineHexStringForGood() { - assertThat(GOOD.getLineHexString(), is("000000")); - } - - @Test - public void getLineHexStringForExcellent() { - assertThat(EXCELLENT.getLineHexString(), is("000000")); - } - - @Test - public void getLineHexStringForPerfect() { - assertThat(PERFECT.getLineHexString(), is("EEEEEE")); - } - - @Test - public void fillColorOfMinusOneReturnsAbysmalFloor() { - assertThat(CoverageRange.fillColorOf(-1D), is(new Color(255, 0, 0))); - } - - @Test - public void fillColorOfThirtyReturnsProportionateBlend() { - assertThat(CoverageRange.fillColorOf(30D), is(new Color(255, 88, 0))); - } - - @Test - public void fillColorOfThirtySevenFiveReturnsProportionateBlend() { - assertThat(CoverageRange.fillColorOf(37.5), is(new Color(255, 117, 0))); - } - - @Test - public void fillColorOfFortyFiveReturnsProportionateBlend() { - assertThat(CoverageRange.fillColorOf(45D), is(new Color(255, 146, 0))); - } - - @Test - public void fillColorOfFiftyFloorFillColor() { - assertThat(CoverageRange.fillColorOf(50D), is(new Color(255, 165, 0))); - } - - @Test - public void fillColorOfOneHundredAndOneReturnsPerfectFloor() { - assertThat(CoverageRange.fillColorOf(101D), is(new Color(0, 139, 0))); - } - - @Test - public void colorAsHexString() { - Color color = new Color(0, 128, 255); - assertThat(CoverageRange.colorAsHexString(color), is("0080FF")); - } +import static org.jenkinsci.plugins.pitmutation.portlets.CoverageRange.ABYSMAL; +import static org.jenkinsci.plugins.pitmutation.portlets.CoverageRange.AVERAGE; +import static org.jenkinsci.plugins.pitmutation.portlets.CoverageRange.EXCELLENT; +import static org.jenkinsci.plugins.pitmutation.portlets.CoverageRange.FAIR; +import static org.jenkinsci.plugins.pitmutation.portlets.CoverageRange.GOOD; +import static org.jenkinsci.plugins.pitmutation.portlets.CoverageRange.PERFECT; +import static org.jenkinsci.plugins.pitmutation.portlets.CoverageRange.POOR; +import static org.jenkinsci.plugins.pitmutation.portlets.CoverageRange.SUFFICIENT; +import static org.jenkinsci.plugins.pitmutation.portlets.CoverageRange.TRAGIC; + +class CoverageRangeTest { + + @Test + void valueOfLessTHanZeroReturnsAbysmal() { + assertThat(CoverageRange.valueOf(-1D), is(ABYSMAL)); + } + + @Test + void valueOfZeroReturnsAbysmal() { + assertThat(CoverageRange.valueOf(0D), is(ABYSMAL)); + } + + @Test + void valueOfTwentyFiveReturnsTragic() { + assertThat(CoverageRange.valueOf(25D), is(TRAGIC)); + } + + @Test + void valueOfFiftyReturnsPoor() { + assertThat(CoverageRange.valueOf(50D), is(AVERAGE)); + } + + @Test + void valueOfSeventyFiveReturnsFair() { + assertThat(CoverageRange.valueOf(75D), is(SUFFICIENT)); + } + + @Test + void valueOfEightyFiveReturnsSufficient() { + assertThat(CoverageRange.valueOf(85D), is(GOOD)); + } + + @Test + void valueOfNinetyTwoReturnsGood() { + assertThat(CoverageRange.valueOf(92D), is(EXCELLENT)); + } + + @Test + void valueOfNinetySevenReturnsExcellent() { + assertThat(CoverageRange.valueOf(97D), is(EXCELLENT)); + } + + @Test + void valueOfOneHundredReturnsPerfect() { + assertThat(CoverageRange.valueOf(100D), is(PERFECT)); + } + + @Test + void valueOfOneHundredAndOneReturnsPerfect() { + assertThat(CoverageRange.valueOf(101D), is(PERFECT)); + } + + @Test + void getFillHexStringForAbysmal() { + assertThat(ABYSMAL.getFillHexString(), is("FF0000")); + } + + @Test + void getFillHexStringForTragic() { + assertThat(TRAGIC.getFillHexString(), is("FF4500")); + } + + @Test + void getFillHexStringForPoor() { + assertThat(POOR.getFillHexString(), is("FF7F00")); + } + + @Test + void getFillHexStringForFair() { + assertThat(FAIR.getFillHexString(), is("FFFF00")); + } + + @Test + void getFillHexStringForSufficient() { + assertThat(SUFFICIENT.getFillHexString(), is("C8FF3F")); + } + + @Test + void getFillHexStringForGood() { + assertThat(GOOD.getFillHexString(), is("7AFF3F")); + } + + @Test + void getFillHexStringForExcellent() { + assertThat(EXCELLENT.getFillHexString(), is("00CD00")); + } + + @Test + void getFillHexStringForPerfect() { + assertThat(PERFECT.getFillHexString(), is("008B00")); + } + + @Test + void getLineHexStringForAbysmal() { + assertThat(ABYSMAL.getLineHexString(), is("EEEEEE")); + } + + @Test + void getLineHexStringForTragic() { + assertThat(TRAGIC.getLineHexString(), is("EEEEEE")); + } + + @Test + void getLineHexStringForPoor() { + assertThat(POOR.getLineHexString(), is("000000")); + } + + @Test + void getLineHexStringForFair() { + assertThat(FAIR.getLineHexString(), is("000000")); + } + + @Test + void getLineHexStringForSufficient() { + assertThat(SUFFICIENT.getLineHexString(), is("000000")); + } + + @Test + void getLineHexStringForGood() { + assertThat(GOOD.getLineHexString(), is("000000")); + } + + @Test + void getLineHexStringForExcellent() { + assertThat(EXCELLENT.getLineHexString(), is("000000")); + } + + @Test + void getLineHexStringForPerfect() { + assertThat(PERFECT.getLineHexString(), is("EEEEEE")); + } + + @Test + void fillColorOfMinusOneReturnsAbysmalFloor() { + assertThat(CoverageRange.fillColorOf(-1D), is(new Color(255, 0, 0))); + } + + @Test + void fillColorOfThirtyReturnsProportionateBlend() { + assertThat(CoverageRange.fillColorOf(30D), is(new Color(255, 88, 0))); + } + + @Test + void fillColorOfThirtySevenFiveReturnsProportionateBlend() { + assertThat(CoverageRange.fillColorOf(37.5), is(new Color(255, 117, 0))); + } + + @Test + void fillColorOfFortyFiveReturnsProportionateBlend() { + assertThat(CoverageRange.fillColorOf(45D), is(new Color(255, 146, 0))); + } + + @Test + void fillColorOfFiftyFloorFillColor() { + assertThat(CoverageRange.fillColorOf(50D), is(new Color(255, 165, 0))); + } + + @Test + void fillColorOfOneHundredAndOneReturnsPerfectFloor() { + assertThat(CoverageRange.fillColorOf(101D), is(new Color(0, 139, 0))); + } + + @Test + void colorAsHexString() { + Color color = new Color(0, 128, 255); + assertThat(CoverageRange.colorAsHexString(color), is("0080FF")); + } } diff --git a/src/test/java/org/jenkinsci/plugins/pitmutation/targets/MutatedClassTest.java b/src/test/java/org/jenkinsci/plugins/pitmutation/targets/MutatedClassTest.java index 81f7eba..dc6eaac 100644 --- a/src/test/java/org/jenkinsci/plugins/pitmutation/targets/MutatedClassTest.java +++ b/src/test/java/org/jenkinsci/plugins/pitmutation/targets/MutatedClassTest.java @@ -1,7 +1,7 @@ package org.jenkinsci.plugins.pitmutation.targets; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.xml.sax.SAXException; import java.io.IOException; @@ -15,27 +15,27 @@ * Date: 19/03/13 * Time: 18:45 */ -public class MutatedClassTest extends MutationResultTest { +class MutatedClassTest extends MutationResultTest { private MutatedClass mutatedClass; - @Before + @BeforeEach public void setUp() throws IOException, SAXException { super.setUp(); mutatedClass = new MutatedClass("TestClass", null, new ArrayList<>()); } @Test - public void isSourceLevelReturnsTrue() { + void isSourceLevelReturnsTrue() { assertThat(mutatedClass.isSourceLevel(), is(true)); } @Test - public void getDisplayNameReturnsName() { + void getDisplayNameReturnsName() { assertThat(mutatedClass.getDisplayName(), is("Class: TestClass")); } @Test - public void lineUrlsAreSet() { + void lineUrlsAreSet() { } } diff --git a/src/test/java/org/jenkinsci/plugins/pitmutation/targets/MutatedLineTest.java b/src/test/java/org/jenkinsci/plugins/pitmutation/targets/MutatedLineTest.java index 4b50b87..10066c6 100644 --- a/src/test/java/org/jenkinsci/plugins/pitmutation/targets/MutatedLineTest.java +++ b/src/test/java/org/jenkinsci/plugins/pitmutation/targets/MutatedLineTest.java @@ -1,7 +1,7 @@ package org.jenkinsci.plugins.pitmutation.targets; import org.jenkinsci.plugins.pitmutation.Mutation; -import org.junit.Test; +import org.junit.jupiter.api.Test; import java.util.Arrays; @@ -14,10 +14,10 @@ /** * @author Ed Kimber */ -public class MutatedLineTest { +class MutatedLineTest { @Test - public void getsMutatorClassNames() { + void getsMutatorClassNames() { Mutation[] mutations = new Mutation[3]; mutations[0] = mock(Mutation.class); diff --git a/src/test/java/org/jenkinsci/plugins/pitmutation/targets/MutationResultTest.java b/src/test/java/org/jenkinsci/plugins/pitmutation/targets/MutationResultTest.java index 0bca4ec..4343414 100644 --- a/src/test/java/org/jenkinsci/plugins/pitmutation/targets/MutationResultTest.java +++ b/src/test/java/org/jenkinsci/plugins/pitmutation/targets/MutationResultTest.java @@ -2,8 +2,8 @@ import org.jenkinsci.plugins.pitmutation.MutationReport; import org.jenkinsci.plugins.pitmutation.PitBuildAction; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.xml.sax.SAXException; import java.io.IOException; @@ -28,7 +28,7 @@ public abstract class MutationResultTest { private MutationResult projectResult; private MutationResult moduleResult; - @Before + @BeforeEach public void setUp() throws IOException, SAXException { MutationReport reportOld = new MutationReport(MutationReport.class.getResourceAsStream("testmutations-00.xml")); @@ -55,7 +55,7 @@ public void setUp() throws IOException, SAXException { } @Test - public void mutationResultStatsDelta() { + void mutationResultStatsDelta() { MutationStats delta = projectResult.getStatsDelta(); assertThat(delta.getTotalMutations(), is(3)); assertThat(delta.getKillCount(), is(-1)); @@ -66,7 +66,7 @@ private MutationResult packageResult() { } @Test - public void packageResultsStatsDelta() { + void packageResultsStatsDelta() { MutationStats delta = packageResult().getStatsDelta(); assertThat(delta.getTotalMutations(), is(3)); assertThat(delta.getKillCount(), is(-1)); @@ -77,35 +77,35 @@ private MutationResult classResult(String className) { } @Test - public void classResultsStats() { + void classResultsStats() { MutationStats stats = classResult("org.jenkinsci.plugins.pitmutation.Mutation").getMutationStats(); assertThat(stats.getTotalMutations(), is(3)); assertThat(stats.getKillCount(), is(1)); } @Test - public void classResultsStatsDelta() { + void classResultsStatsDelta() { MutationStats delta = classResult("org.jenkinsci.plugins.pitmutation.Mutation").getStatsDelta(); assertThat(delta.getTotalMutations(), is(-1)); assertThat(delta.getKillCount(), is(-2)); } @Test - public void classResultsForNewClass() { + void classResultsForNewClass() { MutationStats stats = classResult("org.jenkinsci.plugins.pitmutation.NewMutatedClass").getMutationStats(); assertThat(stats.getTotalMutations(), is(1)); assertThat(stats.getKillCount(), is(0)); } @Test - public void classResultsForNewClassDelta() { + void classResultsForNewClassDelta() { MutationStats stats = classResult("org.jenkinsci.plugins.pitmutation.NewMutatedClass").getStatsDelta(); assertThat(stats.getTotalMutations(), is(1)); assertThat(stats.getKillCount(), is(0)); } @Test - public void classResultsOrdered() { + void classResultsOrdered() { Iterator classes = moduleResult.getChildren().iterator(); int undetected = classes.next().getMutationStats().getUndetected(); @@ -117,13 +117,13 @@ public void classResultsOrdered() { } @Test - public void urlTransformPackageName() { + void urlTransformPackageName() { assertThat(moduleResult.getChildMap().get("org.jenkinsci.plugins.pitmutation").getUrl(), is("org_jenkinsci_plugins_pitmutation")); } @Test - public void urlTransformClassName() { + void urlTransformClassName() { assertThat(moduleResult .getChildMap() .get("org.jenkinsci.plugins.pitmutation") @@ -133,7 +133,7 @@ public void urlTransformClassName() { } @Test - public void findsMutationsOnPitParserClass() { + void findsMutationsOnPitParserClass() { MutationResult pitPackage = moduleResult.getChildMap().get("org.jenkinsci.plugins.pitmutation"); assertThat(pitPackage.getChildren(), hasSize(5)); MutationResult pitParser = pitPackage.getChildMap().get("org.jenkinsci.plugins.pitmutation.PitParser"); @@ -141,14 +141,14 @@ public void findsMutationsOnPitParserClass() { } @Test - public void collectsMutationStats() { + void collectsMutationStats() { MutationStats stats = projectResult.getMutationStats(); assertThat(stats.getTotalMutations(), is(19)); assertThat(stats.getUndetected(), is(15)); } @Test - public void correctSourceLevels() { + void correctSourceLevels() { MutationResult pitPackage = moduleResult.getChildMap().get("org.jenkinsci.plugins.pitmutation"); MutationResult pitParser = pitPackage.getChildMap().get("org.jenkinsci.plugins.pitmutation.PitParser"); MutationResult lineResult = pitParser.getChildMap().values().iterator().next(); @@ -161,12 +161,12 @@ public void correctSourceLevels() { } @Test - public void testXmlTransform() { + void testXmlTransform() { assertThat(MutationResult.xmlTransform("replace&and"), is("replace&and<and>")); } @Test - public void testUrlTransform() { + void testUrlTransform() { assertThat(MutationResult.urlTransform("^*!replace::non+'alphas@}129"), is("___replace__non__alphas__129")); } } diff --git a/src/test/java/org/jenkinsci/plugins/pitmutation/targets/MutationStatsTest.java b/src/test/java/org/jenkinsci/plugins/pitmutation/targets/MutationStatsTest.java index 9ccdb4c..fc4a4fa 100644 --- a/src/test/java/org/jenkinsci/plugins/pitmutation/targets/MutationStatsTest.java +++ b/src/test/java/org/jenkinsci/plugins/pitmutation/targets/MutationStatsTest.java @@ -1,7 +1,7 @@ package org.jenkinsci.plugins.pitmutation.targets; import org.jenkinsci.plugins.pitmutation.Mutation; -import org.junit.Test; +import org.junit.jupiter.api.Test; import java.util.Arrays; @@ -15,10 +15,10 @@ * Date: 17/03/13 * Time: 09:50 */ -public class MutationStatsTest { +class MutationStatsTest { @Test - public void killPercentCorrectlyCalculated() { + void killPercentCorrectlyCalculated() { MutationStats stats = new MutationStats() { @Override @@ -41,7 +41,7 @@ public int getTotalMutations() { } @Test - public void mutationStatsImplTest() { + void mutationStatsImplTest() { MutationStats a = createMutationStatsA(); MutationStats b = createMutationStatsB(); assertThat(a.getTitle(), is("test")); @@ -54,7 +54,7 @@ public void mutationStatsImplTest() { } @Test - public void mutationStatsDelta() { + void mutationStatsDelta() { MutationStats delta = createMutationStatsA().delta(createMutationStatsB()); assertThat(delta.getTotalMutations(), is(0)); From f137cd6f3e8ff665c30bbdfddb5baf1825ce3753 Mon Sep 17 00:00:00 2001 From: Vasile Jureschi Date: Mon, 17 Jul 2023 09:58:22 +0300 Subject: [PATCH 08/16] Add configuration option for ignoring missing reports --- .../jenkinsci/plugins/pitmutation/PitPublisher/config.jelly | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/resources/org/jenkinsci/plugins/pitmutation/PitPublisher/config.jelly b/src/main/resources/org/jenkinsci/plugins/pitmutation/PitPublisher/config.jelly index c3d21e8..d243ebf 100644 --- a/src/main/resources/org/jenkinsci/plugins/pitmutation/PitPublisher/config.jelly +++ b/src/main/resources/org/jenkinsci/plugins/pitmutation/PitPublisher/config.jelly @@ -23,4 +23,9 @@ description="The build will be marked unstable if the kill ratio is lower than the last build."> + + + From 22516679eefbc53d163a7f5398cdd02714b74d85 Mon Sep 17 00:00:00 2001 From: Vasile Jureschi Date: Mon, 17 Jul 2023 15:35:17 +0300 Subject: [PATCH 09/16] Fixes bad checks for missing reports --- pom.xml | 14 ++++-- .../plugins/pitmutation/PitLogger.java | 25 +++++++--- .../plugins/pitmutation/PitPublisher.java | 49 ++++++++++++++----- .../plugins/pitmutation/PitPublisherTest.java | 34 ++++++++++--- 4 files changed, 93 insertions(+), 29 deletions(-) diff --git a/pom.xml b/pom.xml index d372f81..47501bc 100644 --- a/pom.xml +++ b/pom.xml @@ -9,21 +9,21 @@ pitmutation - 2.0.0-SNAPSHOT + 2.0.2 Jenkins PIT Mutation Plugin hpi http://wiki.jenkins-ci.org/display/JENKINS/pitmutation - scm:git:ssh://git@github.com/jenkinsci/pitmutation-plugin.git - scm:git:ssh://git@github.com/jenkinsci/pitmutation-plugin.git + scm:git:git://git@github.com/jenkinsci/pitmutation-plugin.git + scm:git:git://git@github.com/jenkinsci/pitmutation-plugin.git https://github.com/jenkinsci/pitmutation-plugin HEAD UTF-8 - 2.414 + 2.361.4 @@ -37,6 +37,12 @@ Benjamin Sproule benjamin@benjaminsproule.com + + vasilej + Vasile Jureschi + vasile.jureschi@gmail.com + + diff --git a/src/main/java/org/jenkinsci/plugins/pitmutation/PitLogger.java b/src/main/java/org/jenkinsci/plugins/pitmutation/PitLogger.java index 91d9069..9855737 100644 --- a/src/main/java/org/jenkinsci/plugins/pitmutation/PitLogger.java +++ b/src/main/java/org/jenkinsci/plugins/pitmutation/PitLogger.java @@ -15,21 +15,28 @@ public class PitLogger { PitLogger() { } - public void logResults(TaskListener listener, PitBuildAction action ) { + public void logResults(TaskListener listener, PitBuildAction action) { MutationStats mutationStats = action.getReport().getMutationStats(); - float previousKillPercent = action.getPreviousAction().getReport().getMutationStats().getKillPercent(); + PitBuildAction previousAction = action.getPreviousAction(); + if (previousAction != null) { + float previousKillPercent = previousAction.getReport().getMutationStats().getKillPercent(); + logPrevious(mutationStats.getKillPercent(), previousKillPercent, listener); + } logCurrent(mutationStats, listener); - logPrevious(mutationStats.getKillPercent(),previousKillPercent, listener); } public void logMissingReportsIgnored(TaskListener listener) { - listener.getLogger().println("Build successful as no reports generated and build set to ignore missing reports. " - + "If the reports should be present set 'ignoreMissingReports' to false and run the build again to fail the build."); + listener + .getLogger() + .println("Build successful as no reports generated and build set to ignore missing reports. " + + "If the reports should be present set 'ignoreMissingReports' to false and run the build again to fail the build."); } public void logBuildFailedNoReports(TaskListener listener) { - listener.getLogger().println("Build failed as no reports generated and build set to not ignore missing reports. " - + "If no reports should be generated set 'ignoreMissingReports' to true and run the build again to pass the build."); + listener + .getLogger() + .println("Build failed as no reports generated and build set to not ignore missing reports. " + + "If no reports should be generated set 'ignoreMissingReports' to true and run the build again to pass the build."); } private void logCurrent(MutationStats currentStats, TaskListener listener) { @@ -54,4 +61,8 @@ public void logLookingForReports(TaskListener listener, FilePath workspace) { public void logPublishReport(TaskListener listener, FilePath workspace) { listener.getLogger().println("Publishing mutation report: " + workspace.getRemote()); } + + public void log(TaskListener listener, String message) { + listener.getLogger().println(message); + } } diff --git a/src/main/java/org/jenkinsci/plugins/pitmutation/PitPublisher.java b/src/main/java/org/jenkinsci/plugins/pitmutation/PitPublisher.java index 9543d65..572c445 100644 --- a/src/main/java/org/jenkinsci/plugins/pitmutation/PitPublisher.java +++ b/src/main/java/org/jenkinsci/plugins/pitmutation/PitPublisher.java @@ -18,6 +18,7 @@ import javax.annotation.Nonnull; import java.io.File; import java.io.IOException; +import java.util.Arrays; import java.util.Map; import static hudson.model.Result.FAILURE; @@ -116,23 +117,23 @@ public void perform(@Nonnull Run build, } private void process(@Nonnull Run build, - @Nonnull FilePath workspace, - @NonNull EnvVars env, - @Nonnull Launcher launcher, - @Nonnull TaskListener listener) throws InterruptedException, IOException { - File statsFile = new File(mutationStatsFile); - if (noReportsAndMissingReportsIgnored(statsFile)) { + @Nonnull FilePath workspace, + @NonNull EnvVars env, + @Nonnull Launcher launcher, + @Nonnull TaskListener listener) throws InterruptedException, IOException { + FilePath[] reports = workspace.act(new ParseReportCallable(mutationStatsFile)); + + if (noReportsAndMissingReportsIgnored(reports)) { pitLogger.logMissingReportsIgnored(listener); build.setResult(SUCCESS); return; - } else if (noReportsAndMissingReportsNotIgnored(statsFile)) { + } else if (noReportsAndMissingReportsNotIgnored(reports)) { pitLogger.logBuildFailedNoReports(listener); build.setResult(FAILURE); return; } pitLogger.logLookingForReports(listener, workspace); - FilePath[] reports = workspace.act(new ParseReportCallable(mutationStatsFile)); FilePath buildTarget = new FilePath(build.getRootDir()); if (reports.length == 1) { fileProcessor.copySingleModuleReport(reports[0], buildTarget); @@ -153,12 +154,36 @@ private void process(@Nonnull Run build, pitLogger.logResults(listener, action); } - private boolean noReportsAndMissingReportsIgnored(File f) { - return (!f.exists() || f.isDirectory()) && ignoreMissingReports; + private boolean noReportsAndMissingReportsIgnored(FilePath[] reports) { + if (reports == null && ignoreMissingReports) { + return true; + } else if (reports == null ) { + return false; + } + return Arrays.stream(reports).anyMatch(report -> { + try { + return (!report.exists() || report.isDirectory()) && ignoreMissingReports; + } catch (IOException | InterruptedException e) { + e.printStackTrace(); + return false; + } + }); } - private boolean noReportsAndMissingReportsNotIgnored(File f) { - return (!f.exists() || f.isDirectory()) && !ignoreMissingReports; + private boolean noReportsAndMissingReportsNotIgnored(FilePath[] reports) { + if (reports == null && !ignoreMissingReports) { + return false; + } else if (reports == null) { + return true; + } + return Arrays.stream(reports).anyMatch(report -> { + try { + return (!report.exists() || report.isDirectory()) && !ignoreMissingReports; + } catch (IOException | InterruptedException e) { + e.printStackTrace(); + return false; + } + }); } /** diff --git a/src/test/java/org/jenkinsci/plugins/pitmutation/PitPublisherTest.java b/src/test/java/org/jenkinsci/plugins/pitmutation/PitPublisherTest.java index b46516d..fdb74d2 100644 --- a/src/test/java/org/jenkinsci/plugins/pitmutation/PitPublisherTest.java +++ b/src/test/java/org/jenkinsci/plugins/pitmutation/PitPublisherTest.java @@ -80,9 +80,10 @@ void ignoreMissingReports_doNotIgnore_noReports() throws Exception { new PitPublisher("**/mutations.xml", MINIMUM_KILL_RATIO, true, false, fileProcessor, decider, pitLogger); TaskListener taskListener = mock(TaskListener.class); Run build = mock(Run.class); + FilePath workspace = mock(FilePath.class); + when(workspace.act(any(FilePath.FileCallable.class))).thenReturn(new FilePath[]{mock(FilePath.class), mock(FilePath.class)}); - - publisher.perform(build, mock(FilePath.class), mock(EnvVars.class), mock(Launcher.class), taskListener); + publisher.perform(build, workspace, mock(EnvVars.class), mock(Launcher.class), taskListener); verify(build).setResult(FAILURE); verify(pitLogger).logBuildFailedNoReports(any()); @@ -102,7 +103,10 @@ void oneReport_ioException() throws Exception { pitLogger); TaskListener taskListener = mock(TaskListener.class); FilePath workspace = mock(FilePath.class); - FilePath[] reports = {mock(FilePath.class)}; + FilePath report = mock(FilePath.class); + when(report.exists()).thenReturn(true); + when(report.isDirectory()).thenReturn(false); + FilePath[] reports = {report}; when(workspace.act(any(ParseReportCallable.class))).thenReturn(reports); doThrow(IOException.class).when(fileProcessor).copySingleModuleReport(any(), any()); Run build = mock(Run.class); @@ -127,7 +131,10 @@ void oneReport() throws Exception { pitLogger); TaskListener taskListener = mock(TaskListener.class); FilePath workspace = mock(FilePath.class); - FilePath[] reports = {mock(FilePath.class)}; + FilePath report = mock(FilePath.class); + when(report.exists()).thenReturn(true); + when(report.isDirectory()).thenReturn(false); + FilePath[] reports = {report}; when(workspace.act(any(ParseReportCallable.class))).thenReturn(reports); doNothing().when(fileProcessor).copySingleModuleReport(any(), any()); Run build = mock(Run.class); @@ -154,7 +161,14 @@ void multiModuleReports() throws Exception { pitLogger); TaskListener taskListener = mock(TaskListener.class); FilePath workspace = mock(FilePath.class); - FilePath[] reports = {mock(FilePath.class), mock(FilePath.class)}; + FilePath report1 = mock(FilePath.class); + when(report1.exists()).thenReturn(true); + when(report1.isDirectory()).thenReturn(false); + FilePath report2 = mock(FilePath.class); + when(report2.exists()).thenReturn(true); + when(report2.isDirectory()).thenReturn(false); + + FilePath[] reports = {report1, report2}; when(workspace.act(any(ParseReportCallable.class))).thenReturn(reports); when(fileProcessor.getNames(any(), any())).thenReturn(Map.of(mock(FilePath.class), "1", @@ -185,7 +199,15 @@ void multiModuleReports_ioException() throws Exception { pitLogger); TaskListener taskListener = mock(TaskListener.class); FilePath workspace = mock(FilePath.class); - FilePath[] reports = {mock(FilePath.class), mock(FilePath.class)}; + FilePath report1 = mock(FilePath.class); + when(report1.exists()).thenReturn(true); + when(report1.isDirectory()).thenReturn(false); + + FilePath report2 = mock(FilePath.class); + when(report2.exists()).thenReturn(true); + when(report2.isDirectory()).thenReturn(false); + + FilePath[] reports = {report1, report2}; when(workspace.act(any(ParseReportCallable.class))).thenReturn(reports); when(fileProcessor.getNames(any(), any())).thenReturn(Map.of(mock(FilePath.class), "1", From 65387586e338c560a46a4a641c1456ceffcf12db Mon Sep 17 00:00:00 2001 From: Vasile Jureschi Date: Sat, 14 Oct 2023 14:53:19 +0300 Subject: [PATCH 10/16] aider: Added unit tests for `FileProcessor.java`. # Aider chat conversation: USER: tokens ASSISTANT: I'm sorry, but your request is a bit ambiguous. Could you please provide more details? Are you asking about generating tokens for authentication, or are you referring to tokenization in the context of parsing? Which file or part of the application does this relate to? USER: Generate unit tests for `src/main/java/org/jenkinsci/plugins/pitmutation/FileProcessor.java` ASSISTANT: To generate unit tests for `FileProcessor.java`, we need to create a new file `FileProcessorTest.java` in the test directory. This file will contain tests for each public method in `FileProcessor.java`. Here is the structure of the new file: ```java src/test/java/org/jenkinsci/plugins/pitmutation/FileProcessorTest.java <<<<<<< HEAD ======= package org.jenkinsci.plugins.pitmutation; import hudson.FilePath; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import java.io.IOException; import static org.mockito.Mockito.*; public class FileProcessorTest { @Mock private FilePath source; @Mock private FilePath buildTarget; private FileProcessor fileProcessor; @BeforeEach public void setUp() { MockitoAnnotations.openMocks(this); fileProcessor = new FileProcessor(); } @Test public void testCopySingleModuleReport() throws IOException, InterruptedException { fileProcessor.copySingleModuleReport(source, buildTarget); verify(source, times(1)).getParent(); } @Test public void testCopyMultiModuleReport() throws IOException, InterruptedException { String module = "module1"; fileProcessor.copyMultiModuleReport(source, buildTarget, module); verify(source, times(1)).getParent(); } // TODO: Add more tests for other methods in FileProcessor } >>>>>>> updated ``` This is a basic structure for the test class. It includes setup for the tests and two test methods for `copySingleModuleReport` and `copyMultiModuleReport`. You should add more tests for other methods in `FileProcessor`. Please note that this is a basic structure and might need to be adjusted based on the actual behavior of the methods and the requirements of your application. For example, you might need to add more complex scenarios, check for exceptions, or add assertions to check the results of the methods. --- .../pitmutation/FileProcessorTest.java | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 src/test/java/org/jenkinsci/plugins/pitmutation/FileProcessorTest.java diff --git a/src/test/java/org/jenkinsci/plugins/pitmutation/FileProcessorTest.java b/src/test/java/org/jenkinsci/plugins/pitmutation/FileProcessorTest.java new file mode 100644 index 0000000..52ad395 --- /dev/null +++ b/src/test/java/org/jenkinsci/plugins/pitmutation/FileProcessorTest.java @@ -0,0 +1,43 @@ +package org.jenkinsci.plugins.pitmutation; + +import hudson.FilePath; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.io.IOException; + +import static org.mockito.Mockito.*; + +public class FileProcessorTest { + + @Mock + private FilePath source; + + @Mock + private FilePath buildTarget; + + private FileProcessor fileProcessor; + + @BeforeEach + public void setUp() { + MockitoAnnotations.openMocks(this); + fileProcessor = new FileProcessor(); + } + + @Test + public void testCopySingleModuleReport() throws IOException, InterruptedException { + fileProcessor.copySingleModuleReport(source, buildTarget); + verify(source, times(1)).getParent(); + } + + @Test + public void testCopyMultiModuleReport() throws IOException, InterruptedException { + String module = "module1"; + fileProcessor.copyMultiModuleReport(source, buildTarget, module); + verify(source, times(1)).getParent(); + } + + // TODO: Add more tests for other methods in FileProcessor +} From f4ed2d0ec79ec8b203b7bb884597ca5d828d0032 Mon Sep 17 00:00:00 2001 From: Vasile Jureschi Date: Sat, 14 Oct 2023 14:55:10 +0300 Subject: [PATCH 11/16] Refactored test methods to have package-private access. --- .../jenkinsci/plugins/pitmutation/FileProcessorTest.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/test/java/org/jenkinsci/plugins/pitmutation/FileProcessorTest.java b/src/test/java/org/jenkinsci/plugins/pitmutation/FileProcessorTest.java index 52ad395..6b9838a 100644 --- a/src/test/java/org/jenkinsci/plugins/pitmutation/FileProcessorTest.java +++ b/src/test/java/org/jenkinsci/plugins/pitmutation/FileProcessorTest.java @@ -10,7 +10,7 @@ import static org.mockito.Mockito.*; -public class FileProcessorTest { +class FileProcessorTest { @Mock private FilePath source; @@ -27,13 +27,13 @@ public void setUp() { } @Test - public void testCopySingleModuleReport() throws IOException, InterruptedException { + void copySingleModuleReport() throws IOException, InterruptedException { fileProcessor.copySingleModuleReport(source, buildTarget); verify(source, times(1)).getParent(); } @Test - public void testCopyMultiModuleReport() throws IOException, InterruptedException { + void copyMultiModuleReport() throws IOException, InterruptedException { String module = "module1"; fileProcessor.copyMultiModuleReport(source, buildTarget, module); verify(source, times(1)).getParent(); From c322163deeb0ca10e75f435af2b06887c40fb32d Mon Sep 17 00:00:00 2001 From: Vasile Jureschi Date: Sat, 14 Oct 2023 14:55:12 +0300 Subject: [PATCH 12/16] aider: Change test methods in `FileProcessorTest.java` to throw a general `Exception` instead of specific exceptions. # Aider chat conversation: ASSISTANT: Sure, we can modify the test methods in `FileProcessorTest.java` to throw a general `Exception` instead of specific exceptions. Here is the change: ```java src/test/java/org/jenkinsci/plugins/pitmutation/FileProcessorTest.java <<<<<<< HEAD @Test void copySingleModuleReport() throws IOException, InterruptedException { fileProcessor.copySingleModuleReport(source, buildTarget); verify(source, times(1)).getParent(); } @Test void copyMultiModuleReport() throws IOException, InterruptedException { String module = "module1"; fileProcessor.copyMultiModuleReport(source, buildTarget, module); verify(source, times(1)).getParent(); } ======= @Test void copySingleModuleReport() throws Exception { fileProcessor.copySingleModuleReport(source, buildTarget); verify(source, times(1)).getParent(); } @Test void copyMultiModuleReport() throws Exception { String module = "module1"; fileProcessor.copyMultiModuleReport(source, buildTarget, module); verify(source, times(1)).getParent(); } >>>>>>> updated ``` This change replaces `IOException, InterruptedException` with `Exception` in the `throws` clause of the test methods. --- .../org/jenkinsci/plugins/pitmutation/FileProcessorTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/java/org/jenkinsci/plugins/pitmutation/FileProcessorTest.java b/src/test/java/org/jenkinsci/plugins/pitmutation/FileProcessorTest.java index 6b9838a..b946366 100644 --- a/src/test/java/org/jenkinsci/plugins/pitmutation/FileProcessorTest.java +++ b/src/test/java/org/jenkinsci/plugins/pitmutation/FileProcessorTest.java @@ -27,13 +27,13 @@ public void setUp() { } @Test - void copySingleModuleReport() throws IOException, InterruptedException { + void copySingleModuleReport() throws Exception { fileProcessor.copySingleModuleReport(source, buildTarget); verify(source, times(1)).getParent(); } @Test - void copyMultiModuleReport() throws IOException, InterruptedException { + void copyMultiModuleReport() throws Exception { String module = "module1"; fileProcessor.copyMultiModuleReport(source, buildTarget, module); verify(source, times(1)).getParent(); From 79e22a86e27aac2993afc0899abb70300409167d Mon Sep 17 00:00:00 2001 From: Vasile Jureschi Date: Sat, 14 Oct 2023 15:04:46 +0300 Subject: [PATCH 13/16] Add MockitoExtension to FileProcessorTest and remove unused imports and annotations. --- .../org/jenkinsci/plugins/pitmutation/FileProcessorTest.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/test/java/org/jenkinsci/plugins/pitmutation/FileProcessorTest.java b/src/test/java/org/jenkinsci/plugins/pitmutation/FileProcessorTest.java index b946366..4f269d9 100644 --- a/src/test/java/org/jenkinsci/plugins/pitmutation/FileProcessorTest.java +++ b/src/test/java/org/jenkinsci/plugins/pitmutation/FileProcessorTest.java @@ -3,13 +3,16 @@ import hudson.FilePath; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.mockito.junit.jupiter.MockitoExtension; import java.io.IOException; import static org.mockito.Mockito.*; +@ExtendWith(MockitoExtension.class) class FileProcessorTest { @Mock @@ -22,7 +25,6 @@ class FileProcessorTest { @BeforeEach public void setUp() { - MockitoAnnotations.openMocks(this); fileProcessor = new FileProcessor(); } From 493f648be5b71927685e344592bae283d3e6581f Mon Sep 17 00:00:00 2001 From: Vasile Jureschi Date: Sat, 14 Oct 2023 15:04:47 +0300 Subject: [PATCH 14/16] aider: Set up the `source` mock to return itself when `getParent()` is called in `FileProcessorTest`. # Aider chat conversation: ASSISTANT: The error message indicates that the `source.getParent()` call in `FileProcessor` is returning `null`, which leads to an `IOException` being thrown. This is likely because the `source` mock in the test isn't set up to return a value when `getParent()` is called. We need to modify the `FileProcessorTest.java` file to set up the `source` mock to return a value when `getParent()` is called. Here is the change: ```java src/test/java/org/jenkinsci/plugins/pitmutation/FileProcessorTest.java <<<<<<< HEAD @BeforeEach public void setUp() { fileProcessor = new FileProcessor(); } @Test void copySingleModuleReport() throws Exception { fileProcessor.copySingleModuleReport(source, buildTarget); verify(source, times(1)).getParent(); } @Test void copyMultiModuleReport() throws Exception { String module = "module1"; fileProcessor.copyMultiModuleReport(source, buildTarget, module); verify(source, times(1)).getParent(); } ======= @BeforeEach public void setUp() { MockitoAnnotations.openMocks(this); fileProcessor = new FileProcessor(); when(source.getParent()).thenReturn(source); } @Test void copySingleModuleReport() throws Exception { fileProcessor.copySingleModuleReport(source, buildTarget); verify(source, times(1)).getParent(); } @Test void copyMultiModuleReport() throws Exception { String module = "module1"; fileProcessor.copyMultiModuleReport(source, buildTarget, module); verify(source, times(1)).getParent(); } >>>>>>> updated ``` This change adds a line in the `setUp()` method to set up the `source` mock to return itself when `getParent()` is called. This should prevent the `IOException` from being thrown. --- .../org/jenkinsci/plugins/pitmutation/FileProcessorTest.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/test/java/org/jenkinsci/plugins/pitmutation/FileProcessorTest.java b/src/test/java/org/jenkinsci/plugins/pitmutation/FileProcessorTest.java index 4f269d9..dfb1ecc 100644 --- a/src/test/java/org/jenkinsci/plugins/pitmutation/FileProcessorTest.java +++ b/src/test/java/org/jenkinsci/plugins/pitmutation/FileProcessorTest.java @@ -25,7 +25,9 @@ class FileProcessorTest { @BeforeEach public void setUp() { + MockitoAnnotations.openMocks(this); fileProcessor = new FileProcessor(); + when(source.getParent()).thenReturn(source); } @Test From d87a7c33bc0ef94f2d5f8a0254f48b3873682a3c Mon Sep 17 00:00:00 2001 From: Vasile Jureschi Date: Mon, 19 Aug 2024 17:52:30 +0300 Subject: [PATCH 15/16] Ignores aider files --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index f322c19..3fcc4a0 100644 --- a/.gitignore +++ b/.gitignore @@ -127,3 +127,4 @@ work .vscode/ .DS_Store +.aider* From b32bcb87d4fd10a6098c364c2b2f7a5e1f3c4c32 Mon Sep 17 00:00:00 2001 From: Vasile Jureschi Date: Mon, 19 Aug 2024 18:16:43 +0300 Subject: [PATCH 16/16] Reformat to match the original code indent --- .../plugins/pitmutation/DescriptorImpl.java | 46 +- .../plugins/pitmutation/FileProcessor.java | 75 +-- .../pitmutation/MustImproveCondition.java | 22 +- .../plugins/pitmutation/Mutation.java | 66 +-- .../plugins/pitmutation/MutationReport.java | 126 ++--- .../plugins/pitmutation/Mutations.java | 2 +- .../pitmutation/ParseReportCallable.java | 46 +- .../PercentageThresholdCondition.java | 18 +- .../plugins/pitmutation/PitBuildAction.java | 30 +- .../plugins/pitmutation/PitLogger.java | 86 ++-- .../plugins/pitmutation/PitProjectAction.java | 15 +- .../plugins/pitmutation/PitPublisher.java | 386 +++++++-------- .../plugins/pitmutation/ResultDecider.java | 47 +- .../pitmutation/portlets/CoverageRange.java | 14 +- .../pitmutation/portlets/PitColumn.java | 5 +- .../targets/BaseResultFactory.java | 3 +- .../targets/ModuleChildMapBuilder.java | 4 +- .../pitmutation/targets/ModuleResult.java | 9 +- .../pitmutation/targets/MutatedClass.java | 33 +- .../pitmutation/targets/MutatedLine.java | 9 +- .../pitmutation/targets/MutatedPackage.java | 9 +- .../pitmutation/targets/MutationResult.java | 9 +- .../pitmutation/targets/MutationStats.java | 6 +- .../pitmutation/targets/ProjectMutations.java | 6 +- .../targets/SingleModuleResult.java | 6 +- .../pitmutation/MustImproveConditionTest.java | 76 +-- .../pitmutation/MutationReportTest.java | 266 +++++----- .../MutationReportWithDescriptionTest.java | 68 +-- .../PercentageThresholdConditionTest.java | 62 +-- .../plugins/pitmutation/PitLoggerTest.java | 118 ++--- .../pitmutation/PitProjectActionTest.java | 198 ++++---- .../plugins/pitmutation/PitPublisherTest.java | 462 +++++++++--------- .../pitmutation/ResultDeciderTest.java | 53 +- .../portlets/CoverageRangeTest.java | 330 ++++++------- .../targets/MutationResultTest.java | 286 ++++++----- 35 files changed, 1491 insertions(+), 1506 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/pitmutation/DescriptorImpl.java b/src/main/java/org/jenkinsci/plugins/pitmutation/DescriptorImpl.java index e9c415d..e7a6cf2 100644 --- a/src/main/java/org/jenkinsci/plugins/pitmutation/DescriptorImpl.java +++ b/src/main/java/org/jenkinsci/plugins/pitmutation/DescriptorImpl.java @@ -15,30 +15,30 @@ @Symbol("pitmutation") public class DescriptorImpl extends BuildStepDescriptor { - /** - * Instantiates a new Descriptor. - */ - public DescriptorImpl() { - super(PitPublisher.class); - } + /** + * Instantiates a new Descriptor. + */ + public DescriptorImpl() { + super(PitPublisher.class); + } - @Override - public String getDisplayName() { - return Messages.PitPublisher_DisplayName(); - } + @Override + public String getDisplayName() { + return Messages.PitPublisher_DisplayName(); + } - @Override - public boolean isApplicable(Class aClass) { - return true; - } + @Override + public boolean isApplicable(Class aClass) { + return true; + } - /** - * {@inheritDoc} - */ - @Override - public boolean configure(StaplerRequest req, JSONObject formData) throws FormException { - req.bindParameters(this, "pitmutation"); - save(); - return super.configure(req, formData); - } + /** + * {@inheritDoc} + */ + @Override + public boolean configure(StaplerRequest req, JSONObject formData) throws FormException { + req.bindParameters(this, "pitmutation"); + save(); + return super.configure(req, formData); + } } diff --git a/src/main/java/org/jenkinsci/plugins/pitmutation/FileProcessor.java b/src/main/java/org/jenkinsci/plugins/pitmutation/FileProcessor.java index 219dbd4..1f8891c 100644 --- a/src/main/java/org/jenkinsci/plugins/pitmutation/FileProcessor.java +++ b/src/main/java/org/jenkinsci/plugins/pitmutation/FileProcessor.java @@ -11,43 +11,44 @@ public class FileProcessor { - public static final String SINGLE_MODULE_REPORT_FOLDER = "mutation-report-all"; - public static final String MULTI_MODULE_REPORT_FORMAT = "mutation-report-%s"; - - public void copySingleModuleReport(FilePath source, FilePath buildTarget) throws IOException, InterruptedException { - copyMutationReports(source, buildTarget, SINGLE_MODULE_REPORT_FOLDER); - } - - public void copyMultiModuleReport(FilePath source, FilePath buildTarget, String module) throws IOException, InterruptedException { - copyMutationReports(source, buildTarget, String.format(MULTI_MODULE_REPORT_FORMAT, module)); - } - - private void copyMutationReports(FilePath source, FilePath buildTarget, String mutationFilePath) throws IOException, - InterruptedException { - var targetPath = new FilePath(buildTarget, mutationFilePath); - var parent = ofNullable(source.getParent()).orElseThrow(() -> new IOException("Mutation file not found")); - parent.copyRecursiveTo(targetPath); - } - - public Map getNames(FilePath[] reports, String base) { - Map names = new HashMap<>(); - for (int i = 0; i < reports.length; i++) { - FilePath report = reports[i]; - - final String moduleName; - if (StringUtils.isBlank(base)) { - moduleName = String.valueOf(i == 0 ? null : i); - } else { - String[] partsFromRemoteWithoutBase = report.getRemote().replace(base, "").split("[/\\\\]"); - if (partsFromRemoteWithoutBase.length > 1) { - moduleName = partsFromRemoteWithoutBase[1]; - } else { - moduleName = String.valueOf(i == 0 ? null : i); - } - } + public static final String SINGLE_MODULE_REPORT_FOLDER = "mutation-report-all"; + public static final String MULTI_MODULE_REPORT_FORMAT = "mutation-report-%s"; + + public void copySingleModuleReport(FilePath source, FilePath buildTarget) throws IOException, InterruptedException { + copyMutationReports(source, buildTarget, SINGLE_MODULE_REPORT_FOLDER); + } + + public void copyMultiModuleReport(FilePath source, FilePath buildTarget, String module) throws IOException, + InterruptedException { + copyMutationReports(source, buildTarget, String.format(MULTI_MODULE_REPORT_FORMAT, module)); + } + + private void copyMutationReports(FilePath source, FilePath buildTarget, String mutationFilePath) throws IOException, + InterruptedException { + var targetPath = new FilePath(buildTarget, mutationFilePath); + var parent = ofNullable(source.getParent()).orElseThrow(() -> new IOException("Mutation file not found")); + parent.copyRecursiveTo(targetPath); + } - names.put(report, moduleName); + public Map getNames(FilePath[] reports, String base) { + Map names = new HashMap<>(); + for (int i = 0; i < reports.length; i++) { + FilePath report = reports[i]; + + final String moduleName; + if (StringUtils.isBlank(base)) { + moduleName = String.valueOf(i == 0 ? null : i); + } else { + String[] partsFromRemoteWithoutBase = report.getRemote().replace(base, "").split("[/\\\\]"); + if (partsFromRemoteWithoutBase.length > 1) { + moduleName = partsFromRemoteWithoutBase[1]; + } else { + moduleName = String.valueOf(i == 0 ? null : i); + } + } + + names.put(report, moduleName); + } + return names; } - return names; - } } \ No newline at end of file diff --git a/src/main/java/org/jenkinsci/plugins/pitmutation/MustImproveCondition.java b/src/main/java/org/jenkinsci/plugins/pitmutation/MustImproveCondition.java index 62421cd..ec1ac96 100644 --- a/src/main/java/org/jenkinsci/plugins/pitmutation/MustImproveCondition.java +++ b/src/main/java/org/jenkinsci/plugins/pitmutation/MustImproveCondition.java @@ -7,16 +7,16 @@ import static hudson.model.Result.UNSTABLE; class MustImproveCondition implements Condition { - @Override - public Result decideResult(final PitBuildAction action) { - PitBuildAction previousAction = action.getPreviousAction(); - if (previousAction != null) { - MutationStats previousStats = previousAction.getReport().getMutationStats(); - return action.getReport().getMutationStats().getKillPercent() >= previousStats.getKillPercent() ? - SUCCESS : - UNSTABLE; - } else { - return SUCCESS; + @Override + public Result decideResult(final PitBuildAction action) { + PitBuildAction previousAction = action.getPreviousAction(); + if (previousAction != null) { + MutationStats previousStats = previousAction.getReport().getMutationStats(); + return action.getReport().getMutationStats().getKillPercent() >= previousStats.getKillPercent() ? + SUCCESS : + UNSTABLE; + } else { + return SUCCESS; + } } - } } diff --git a/src/main/java/org/jenkinsci/plugins/pitmutation/Mutation.java b/src/main/java/org/jenkinsci/plugins/pitmutation/Mutation.java index ad7c615..7b2443f 100644 --- a/src/main/java/org/jenkinsci/plugins/pitmutation/Mutation.java +++ b/src/main/java/org/jenkinsci/plugins/pitmutation/Mutation.java @@ -12,41 +12,41 @@ */ @Data public class Mutation { - private boolean detected; - private String status; - private String sourceFile; - private String mutatedClass; - private String mutatedMethod; - private int numberOfTestsRun; - private int lineNumber; - private String mutator; - /** - * @deprecated from 1 .9 the mutation library generates a list of indexes JENKINS-68990 - */ - @Deprecated(forRemoval = true, since = "1.9") - private Integer index; - private List indexes = new ArrayList<>(); - private String killingTest; - private String methodDescription; - private String description; - /** - * @deprecated from 1 .9 the mutation library generates a list of blocks JENKINS-68990 - */ - @Deprecated(forRemoval = true, since = "1.9") - private String block; - private List blocks = new ArrayList<>(); + private boolean detected; + private String status; + private String sourceFile; + private String mutatedClass; + private String mutatedMethod; + private int numberOfTestsRun; + private int lineNumber; + private String mutator; + /** + * @deprecated from 1 .9 the mutation library generates a list of indexes JENKINS-68990 + */ + @Deprecated(forRemoval = true, since = "1.9") + private Integer index; + private List indexes = new ArrayList<>(); + private String killingTest; + private String methodDescription; + private String description; + /** + * @deprecated from 1 .9 the mutation library generates a list of blocks JENKINS-68990 + */ + @Deprecated(forRemoval = true, since = "1.9") + private String block; + private List blocks = new ArrayList<>(); - public Mutation() { - } + public Mutation() { + } - public String getMutatorClass() { - int lastDot = mutator.lastIndexOf('.'); - String className = mutator.substring(lastDot + 1); - return className.endsWith("Mutator") ? className.substring(0, className.length() - 7) : className; - } + public String getMutatorClass() { + int lastDot = mutator.lastIndexOf('.'); + String className = mutator.substring(lastDot + 1); + return className.endsWith("Mutator") ? className.substring(0, className.length() - 7) : className; + } - protected boolean canEqual(final Object other) { - return other instanceof Mutation; - } + protected boolean canEqual(final Object other) { + return other instanceof Mutation; + } } diff --git a/src/main/java/org/jenkinsci/plugins/pitmutation/MutationReport.java b/src/main/java/org/jenkinsci/plugins/pitmutation/MutationReport.java index 8ed6569..cf8150d 100644 --- a/src/main/java/org/jenkinsci/plugins/pitmutation/MutationReport.java +++ b/src/main/java/org/jenkinsci/plugins/pitmutation/MutationReport.java @@ -19,67 +19,67 @@ */ public class MutationReport { - private final Map> mutationsByPackage; - - private final Map> mutationsByClass; - private int killCount = 0; - - public MutationReport(InputStream xmlReport) throws IOException, SAXException { - this.mutationsByClass = new HashMap<>(); - this.mutationsByPackage = new HashMap<>(); - - // https://github.com/FasterXML/jackson-dataformat-xml/issues/219 - JacksonXmlModule module = new JacksonXmlModule(); - module.setDefaultUseWrapper(false); - XmlMapper xmlMapper = new XmlMapper(module); - Mutations mutations = xmlMapper.readValue(xmlReport, Mutations.class); - - mutations.getMutation().forEach(mutation -> { - mutationsByClass.computeIfAbsent(mutation.getMutatedClass(), k -> new ArrayList<>()).add(mutation); - if (mutation.isDetected()) { - killCount++; - } - mutationsByPackage - .computeIfAbsent(packageNameFromClass(mutation.getMutatedClass()), k -> new ArrayList<>()) - .add(mutation); - - }); - } - - public Collection getMutationsForPackage(String packageName) { - return mutationsByPackage.computeIfAbsent(packageName, k -> new ArrayList<>()); - } - - public Map> getMutationsByPackage() { - return mutationsByPackage; - } - - public Collection getMutationsForClassName(String className) { - return mutationsByClass.computeIfAbsent(className, k -> new ArrayList<>()); - } - - public MutationStats getMutationStats() { - return new MutationStats() { - @Override - public String getTitle() { - return "Report Stats"; - } - - @Override - public int getUndetected() { - return getTotalMutations() - killCount; - } - - @Override - public int getTotalMutations() { - return mutationsByClass.values().stream().mapToInt(Collection::size).sum(); - } - }; - } - - // TODO: Move somewhere out of this class - static String packageNameFromClass(String fqcn) { - int idx = fqcn.lastIndexOf('.'); - return fqcn.substring(0, idx != -1 ? idx : 0); - } + private final Map> mutationsByPackage; + + private final Map> mutationsByClass; + private int killCount = 0; + + public MutationReport(InputStream xmlReport) throws IOException, SAXException { + this.mutationsByClass = new HashMap<>(); + this.mutationsByPackage = new HashMap<>(); + + // https://github.com/FasterXML/jackson-dataformat-xml/issues/219 + JacksonXmlModule module = new JacksonXmlModule(); + module.setDefaultUseWrapper(false); + XmlMapper xmlMapper = new XmlMapper(module); + Mutations mutations = xmlMapper.readValue(xmlReport, Mutations.class); + + mutations.getMutation().forEach(mutation -> { + mutationsByClass.computeIfAbsent(mutation.getMutatedClass(), k -> new ArrayList<>()).add(mutation); + if (mutation.isDetected()) { + killCount++; + } + mutationsByPackage + .computeIfAbsent(packageNameFromClass(mutation.getMutatedClass()), k -> new ArrayList<>()) + .add(mutation); + + }); + } + + public Collection getMutationsForPackage(String packageName) { + return mutationsByPackage.computeIfAbsent(packageName, k -> new ArrayList<>()); + } + + public Map> getMutationsByPackage() { + return mutationsByPackage; + } + + public Collection getMutationsForClassName(String className) { + return mutationsByClass.computeIfAbsent(className, k -> new ArrayList<>()); + } + + public MutationStats getMutationStats() { + return new MutationStats() { + @Override + public String getTitle() { + return "Report Stats"; + } + + @Override + public int getUndetected() { + return getTotalMutations() - killCount; + } + + @Override + public int getTotalMutations() { + return mutationsByClass.values().stream().mapToInt(Collection::size).sum(); + } + }; + } + + // TODO: Move somewhere out of this class + static String packageNameFromClass(String fqcn) { + int idx = fqcn.lastIndexOf('.'); + return fqcn.substring(0, idx != -1 ? idx : 0); + } } diff --git a/src/main/java/org/jenkinsci/plugins/pitmutation/Mutations.java b/src/main/java/org/jenkinsci/plugins/pitmutation/Mutations.java index 8bb9655..9f49f99 100644 --- a/src/main/java/org/jenkinsci/plugins/pitmutation/Mutations.java +++ b/src/main/java/org/jenkinsci/plugins/pitmutation/Mutations.java @@ -10,5 +10,5 @@ @Data @NoArgsConstructor public class Mutations { - private List mutation; + private List mutation; } diff --git a/src/main/java/org/jenkinsci/plugins/pitmutation/ParseReportCallable.java b/src/main/java/org/jenkinsci/plugins/pitmutation/ParseReportCallable.java index 2ad9408..bfbc7a4 100644 --- a/src/main/java/org/jenkinsci/plugins/pitmutation/ParseReportCallable.java +++ b/src/main/java/org/jenkinsci/plugins/pitmutation/ParseReportCallable.java @@ -12,30 +12,30 @@ */ public class ParseReportCallable implements FilePath.FileCallable { - private static final long serialVersionUID = 1L; - - private final String reportFilePath; - - /** - * Instantiates a new Parse report callable. - * - * @param reportFilePath the report file path - */ - public ParseReportCallable(String reportFilePath) { - this.reportFilePath = reportFilePath; - } - - @Override - public FilePath[] invoke(File f, VirtualChannel channel) throws IOException, InterruptedException { - FilePath[] r = new FilePath(f).list(reportFilePath); - if (r.length < 1) { - throw new IOException("No reports found at location:" + reportFilePath); + private static final long serialVersionUID = 1L; + + private final String reportFilePath; + + /** + * Instantiates a new Parse report callable. + * + * @param reportFilePath the report file path + */ + public ParseReportCallable(String reportFilePath) { + this.reportFilePath = reportFilePath; } - return r; - } - @Override - public void checkRoles(RoleChecker roleChecker) throws SecurityException { + @Override + public FilePath[] invoke(File f, VirtualChannel channel) throws IOException, InterruptedException { + FilePath[] r = new FilePath(f).list(reportFilePath); + if (r.length < 1) { + throw new IOException("No reports found at location:" + reportFilePath); + } + return r; + } - } + @Override + public void checkRoles(RoleChecker roleChecker) throws SecurityException { + + } } diff --git a/src/main/java/org/jenkinsci/plugins/pitmutation/PercentageThresholdCondition.java b/src/main/java/org/jenkinsci/plugins/pitmutation/PercentageThresholdCondition.java index 28c464e..3fd5269 100644 --- a/src/main/java/org/jenkinsci/plugins/pitmutation/PercentageThresholdCondition.java +++ b/src/main/java/org/jenkinsci/plugins/pitmutation/PercentageThresholdCondition.java @@ -7,15 +7,15 @@ import static hudson.model.Result.SUCCESS; class PercentageThresholdCondition implements Condition { - private final float percentage; + private final float percentage; - PercentageThresholdCondition(float percentage) { - super(); - this.percentage = percentage; - } + PercentageThresholdCondition(float percentage) { + super(); + this.percentage = percentage; + } - @Override - public Result decideResult(PitBuildAction action) { - return action.getReport().getMutationStats().getKillPercent() >= percentage ? SUCCESS : FAILURE; - } + @Override + public Result decideResult(PitBuildAction action) { + return action.getReport().getMutationStats().getKillPercent() >= percentage ? SUCCESS : FAILURE; + } } diff --git a/src/main/java/org/jenkinsci/plugins/pitmutation/PitBuildAction.java b/src/main/java/org/jenkinsci/plugins/pitmutation/PitBuildAction.java index a014f8f..91490a9 100644 --- a/src/main/java/org/jenkinsci/plugins/pitmutation/PitBuildAction.java +++ b/src/main/java/org/jenkinsci/plugins/pitmutation/PitBuildAction.java @@ -34,7 +34,8 @@ * @author edward */ @Slf4j -public class PitBuildAction implements HealthReportingAction, StaplerProxy { +public class PitBuildAction implements HealthReportingAction, + StaplerProxy { private static final Pattern MUTATION_REPORT_PATTERN = Pattern.compile(".*mutation-report-([^/\\\\]*).*"); @@ -50,13 +51,10 @@ public PitBuildAction getPreviousAction() { Run build = owner; while (true) { build = build.getPreviousBuild(); - if (build == null) - return null; - if (build.getResult() == FAILURE) - continue; + if (build == null) {return null;} + if (build.getResult() == FAILURE) {continue;} PitBuildAction action = build.getAction(PitBuildAction.class); - if (action != null) - return action; + if (action != null) {return action;} } } @@ -134,7 +132,7 @@ static PitBuildAction getPreviousResult(Run start) { @Override public HealthReport getBuildHealth() { return new HealthReport((int) getReport().getMutationStats().getKillPercent(), - Messages._BuildAction_Description(getReport().getMutationStats().getKillPercent())); + Messages._BuildAction_Description(getReport().getMutationStats().getKillPercent())); } @Override @@ -175,14 +173,14 @@ public void doGraph(StaplerRequest req, StaplerResponse rsp) throws IOException final JFreeChart chart = ChartFactory.createLineChart(null, // chart title - null, // unused - "%", // range axis label - dsb.build(), // data - PlotOrientation.VERTICAL, // orientation - true, // include legend - true, // tooltips - false // urls - );// JFreeChart chart = new MutationChart(this).createChart(); + null, // unused + "%", // range axis label + dsb.build(), // data + PlotOrientation.VERTICAL, // orientation + true, // include legend + true, // tooltips + false // urls + );// JFreeChart chart = new MutationChart(this).createChart(); ChartUtil.generateGraph(req, rsp, chart, 500, 200); } } diff --git a/src/main/java/org/jenkinsci/plugins/pitmutation/PitLogger.java b/src/main/java/org/jenkinsci/plugins/pitmutation/PitLogger.java index 9855737..5ea2380 100644 --- a/src/main/java/org/jenkinsci/plugins/pitmutation/PitLogger.java +++ b/src/main/java/org/jenkinsci/plugins/pitmutation/PitLogger.java @@ -12,57 +12,57 @@ */ public class PitLogger { - PitLogger() { - } + PitLogger() { + } - public void logResults(TaskListener listener, PitBuildAction action) { - MutationStats mutationStats = action.getReport().getMutationStats(); - PitBuildAction previousAction = action.getPreviousAction(); - if (previousAction != null) { - float previousKillPercent = previousAction.getReport().getMutationStats().getKillPercent(); - logPrevious(mutationStats.getKillPercent(), previousKillPercent, listener); + public void logResults(TaskListener listener, PitBuildAction action) { + MutationStats mutationStats = action.getReport().getMutationStats(); + PitBuildAction previousAction = action.getPreviousAction(); + if (previousAction != null) { + float previousKillPercent = previousAction.getReport().getMutationStats().getKillPercent(); + logPrevious(mutationStats.getKillPercent(), previousKillPercent, listener); + } + logCurrent(mutationStats, listener); } - logCurrent(mutationStats, listener); - } - public void logMissingReportsIgnored(TaskListener listener) { - listener - .getLogger() - .println("Build successful as no reports generated and build set to ignore missing reports. " - + "If the reports should be present set 'ignoreMissingReports' to false and run the build again to fail the build."); - } + public void logMissingReportsIgnored(TaskListener listener) { + listener + .getLogger() + .println("Build successful as no reports generated and build set to ignore missing reports. " + + "If the reports should be present set 'ignoreMissingReports' to false and run the build again to fail the build."); + } - public void logBuildFailedNoReports(TaskListener listener) { - listener - .getLogger() - .println("Build failed as no reports generated and build set to not ignore missing reports. " - + "If no reports should be generated set 'ignoreMissingReports' to true and run the build again to pass the build."); - } + public void logBuildFailedNoReports(TaskListener listener) { + listener + .getLogger() + .println("Build failed as no reports generated and build set to not ignore missing reports. " + + "If no reports should be generated set 'ignoreMissingReports' to true and run the build again to pass the build."); + } - private void logCurrent(MutationStats currentStats, TaskListener listener) { - listener - .getLogger() - .printf("Kill ratio is %f \\u0025 (%d %d)%n", - currentStats.getKillPercent(), - currentStats.getKillCount(), - currentStats.getTotalMutations()); - } + private void logCurrent(MutationStats currentStats, TaskListener listener) { + listener + .getLogger() + .printf("Kill ratio is %f \\u0025 (%d %d)%n", + currentStats.getKillPercent(), + currentStats.getKillCount(), + currentStats.getTotalMutations()); + } - private void logPrevious(float currentKillPercent, float previousKillPercent, TaskListener listener) { - listener.getLogger().println("Previous kill ratio was " + previousKillPercent + "%"); - listener.getLogger().println("This kill ration is " + currentKillPercent + "%"); - } + private void logPrevious(float currentKillPercent, float previousKillPercent, TaskListener listener) { + listener.getLogger().println("Previous kill ratio was " + previousKillPercent + "%"); + listener.getLogger().println("This kill ration is " + currentKillPercent + "%"); + } - public void logLookingForReports(TaskListener listener, FilePath workspace) { - listener.getLogger().println("Looking for PIT reports in " + workspace.getRemote()); - } + public void logLookingForReports(TaskListener listener, FilePath workspace) { + listener.getLogger().println("Looking for PIT reports in " + workspace.getRemote()); + } - public void logPublishReport(TaskListener listener, FilePath workspace) { - listener.getLogger().println("Publishing mutation report: " + workspace.getRemote()); - } + public void logPublishReport(TaskListener listener, FilePath workspace) { + listener.getLogger().println("Publishing mutation report: " + workspace.getRemote()); + } - public void log(TaskListener listener, String message) { - listener.getLogger().println(message); - } + public void log(TaskListener listener, String message) { + listener.getLogger().println(message); + } } diff --git a/src/main/java/org/jenkinsci/plugins/pitmutation/PitProjectAction.java b/src/main/java/org/jenkinsci/plugins/pitmutation/PitProjectAction.java index ce960b8..75628b7 100644 --- a/src/main/java/org/jenkinsci/plugins/pitmutation/PitProjectAction.java +++ b/src/main/java/org/jenkinsci/plugins/pitmutation/PitProjectAction.java @@ -26,11 +26,9 @@ public PitProjectAction(AbstractProject project) { */ public PitBuildAction getLastResult() { for (AbstractBuild b = project.getLastSuccessfulBuild(); b != null; b = b.getPreviousNotFailedBuild()) { - if (b.getResult() == FAILURE) - continue; + if (b.getResult() == FAILURE) {continue;} PitBuildAction r = b.getAction(PitBuildAction.class); - if (r != null) - return r; + if (r != null) {return r;} } return null; } @@ -46,11 +44,9 @@ public PitBuildAction getLastResult() { */ public Integer getLastResultBuild() { for (AbstractBuild b = project.getLastSuccessfulBuild(); b != null; b = b.getPreviousNotFailedBuild()) { - if (b.getResult() == FAILURE) - continue; + if (b.getResult() == FAILURE) {continue;} PitBuildAction r = b.getAction(PitBuildAction.class); - if (r != null) - return b.getNumber(); + if (r != null) {return b.getNumber();} } return null; } @@ -89,7 +85,6 @@ public void doIndex(StaplerRequest req, StaplerResponse rsp) throws IOException } public void doGraph(StaplerRequest req, StaplerResponse rsp) throws IOException { - if (getLastResult() != null) - getLastResult().doGraph(req, rsp); + if (getLastResult() != null) {getLastResult().doGraph(req, rsp);} } } diff --git a/src/main/java/org/jenkinsci/plugins/pitmutation/PitPublisher.java b/src/main/java/org/jenkinsci/plugins/pitmutation/PitPublisher.java index 572c445..c6b40d6 100644 --- a/src/main/java/org/jenkinsci/plugins/pitmutation/PitPublisher.java +++ b/src/main/java/org/jenkinsci/plugins/pitmutation/PitPublisher.java @@ -33,207 +33,209 @@ */ public class PitPublisher extends Recorder implements SimpleBuildStep { - public static final String GLOB_MUTATIONS_XML = "**/target/pit-reports/**/mutations.xml"; - private String mutationStatsFile; - private boolean killRatioMustImprove; - /** - * If true and no reports are generated, the missing reports will not cause a build failure. Uses for cases where - * there are test but nothing is mutated them and there are no reports generated. - */ - private boolean ignoreMissingReports; - private float minimumKillRatio; - - private FileProcessor fileProcessor; - private ResultDecider resultDecider; - private PitLogger pitLogger; - - /** - * Instantiates a new Pit publisher. Only used in tests. - * - * @param mutationStatsFile the mutation stats file - * @param minimumKillRatio the minimum kill ratio - * @param killRatioMustImprove the kill ratio must improve - * @param ignoreMissingReports do not fail the build if there are no reports - */ - PitPublisher(String mutationStatsFile, - float minimumKillRatio, - boolean killRatioMustImprove, - boolean ignoreMissingReports, - FileProcessor fileProcessor, - ResultDecider resultDecider, - PitLogger pitLogger) { - this.mutationStatsFile = mutationStatsFile; - this.killRatioMustImprove = killRatioMustImprove; - this.minimumKillRatio = minimumKillRatio; - this.ignoreMissingReports = ignoreMissingReports; - this.fileProcessor = fileProcessor; - this.resultDecider = resultDecider; - this.pitLogger = pitLogger; - } - - /** - * Instantiates a new Pit publisher with Default-Values. - *

- * {@link #mutationStatsFile} is set to {@code **{@literal /}target/pit-reports/**{@literal /}mutations.xml}, - * {@link #minimumKillRatio} is set to {@code 0.0}, - * {@link #killRatioMustImprove} is set to {@code false}, - * {@link #ignoreMissingReports} is set to {@code false}, - */ - @DataBoundConstructor - public PitPublisher(String mutationStatsFile, - float minimumKillRatio, - boolean killRatioMustImprove, - boolean ignoreMissingReports) { - this(mutationStatsFile, - minimumKillRatio, - killRatioMustImprove, - ignoreMissingReports, - new FileProcessor(), - killRatioMustImprove ? - new ResultDecider(new PercentageThresholdCondition(minimumKillRatio)) : - new ResultDecider(new PercentageThresholdCondition(minimumKillRatio), new MustImproveCondition()), - new PitLogger()); - } - - @DataBoundSetter - public void setIgnoreMissingReports(final boolean ignoreMissingReports) { - this.ignoreMissingReports = ignoreMissingReports; - } - - @Override - public void perform(@Nonnull Run build, - @Nonnull FilePath workspace, - @NonNull EnvVars env, - @Nonnull Launcher launcher, - @Nonnull TaskListener listener) { - try { - process(build, workspace, env, launcher, listener); - } catch (IOException e) { - Util.displayIOException(e, listener); - build.setResult(FAILURE); - } catch (InterruptedException e) { - e.printStackTrace(); + public static final String GLOB_MUTATIONS_XML = "**/target/pit-reports/**/mutations.xml"; + private String mutationStatsFile; + private boolean killRatioMustImprove; + /** + * If true and no reports are generated, the missing reports will not cause a build failure. Uses for cases where + * there are test but nothing is mutated them and there are no reports generated. + */ + private boolean ignoreMissingReports; + private float minimumKillRatio; + + private FileProcessor fileProcessor; + private ResultDecider resultDecider; + private PitLogger pitLogger; + + /** + * Instantiates a new Pit publisher. Only used in tests. + * + * @param mutationStatsFile the mutation stats file + * @param minimumKillRatio the minimum kill ratio + * @param killRatioMustImprove the kill ratio must improve + * @param ignoreMissingReports do not fail the build if there are no reports + */ + PitPublisher(String mutationStatsFile, + float minimumKillRatio, + boolean killRatioMustImprove, + boolean ignoreMissingReports, + FileProcessor fileProcessor, + ResultDecider resultDecider, + PitLogger pitLogger) { + this.mutationStatsFile = mutationStatsFile; + this.killRatioMustImprove = killRatioMustImprove; + this.minimumKillRatio = minimumKillRatio; + this.ignoreMissingReports = ignoreMissingReports; + this.fileProcessor = fileProcessor; + this.resultDecider = resultDecider; + this.pitLogger = pitLogger; } - } - - private void process(@Nonnull Run build, - @Nonnull FilePath workspace, - @NonNull EnvVars env, - @Nonnull Launcher launcher, - @Nonnull TaskListener listener) throws InterruptedException, IOException { - FilePath[] reports = workspace.act(new ParseReportCallable(mutationStatsFile)); - - if (noReportsAndMissingReportsIgnored(reports)) { - pitLogger.logMissingReportsIgnored(listener); - build.setResult(SUCCESS); - return; - } else if (noReportsAndMissingReportsNotIgnored(reports)) { - pitLogger.logBuildFailedNoReports(listener); - build.setResult(FAILURE); - return; + + /** + * Instantiates a new Pit publisher with Default-Values. + *

+ * {@link #mutationStatsFile} is set to {@code **{@literal /}target/pit-reports/**{@literal /}mutations.xml}, + * {@link #minimumKillRatio} is set to {@code 0.0}, + * {@link #killRatioMustImprove} is set to {@code false}, + * {@link #ignoreMissingReports} is set to {@code false}, + */ + @DataBoundConstructor + public PitPublisher(String mutationStatsFile, + float minimumKillRatio, + boolean killRatioMustImprove, + boolean ignoreMissingReports) { + this(mutationStatsFile, + minimumKillRatio, + killRatioMustImprove, + ignoreMissingReports, + new FileProcessor(), + killRatioMustImprove ? + new ResultDecider(new PercentageThresholdCondition(minimumKillRatio)) : + new ResultDecider(new PercentageThresholdCondition(minimumKillRatio), new MustImproveCondition()), + new PitLogger()); + } + + @DataBoundSetter + public void setIgnoreMissingReports(final boolean ignoreMissingReports) { + this.ignoreMissingReports = ignoreMissingReports; + } + + @Override + public void perform(@Nonnull Run build, + @Nonnull FilePath workspace, + @NonNull EnvVars env, + @Nonnull Launcher launcher, + @Nonnull TaskListener listener) { + try { + process(build, workspace, env, launcher, listener); + } catch (IOException e) { + Util.displayIOException(e, listener); + build.setResult(FAILURE); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + private void process(@Nonnull Run build, + @Nonnull FilePath workspace, + @NonNull EnvVars env, + @Nonnull Launcher launcher, + @Nonnull TaskListener listener) throws InterruptedException, IOException { + FilePath[] reports = workspace.act(new ParseReportCallable(mutationStatsFile)); + + if (noReportsAndMissingReportsIgnored(reports)) { + pitLogger.logMissingReportsIgnored(listener); + build.setResult(SUCCESS); + return; + } else if (noReportsAndMissingReportsNotIgnored(reports)) { + pitLogger.logBuildFailedNoReports(listener); + build.setResult(FAILURE); + return; + } + + pitLogger.logLookingForReports(listener, workspace); + FilePath buildTarget = new FilePath(build.getRootDir()); + if (reports.length == 1) { + fileProcessor.copySingleModuleReport(reports[0], buildTarget); + } else { + for (Map.Entry entry : fileProcessor + .getNames(reports, workspace.getRemote()) + .entrySet()) { + FilePath filePath = entry.getKey(); + String module = entry.getValue(); + pitLogger.logPublishReport(listener, workspace); + fileProcessor.copyMultiModuleReport(filePath, buildTarget, module); + } + } + + + PitBuildAction action = new PitBuildAction(build); + build.addAction(action); + build.setResult(resultDecider.decideBuildResult(action)); + + pitLogger.logResults(listener, action); + } + + private boolean noReportsAndMissingReportsIgnored(FilePath[] reports) { + if (reports == null && ignoreMissingReports) { + return true; + } else if (reports == null) { + return false; + } + return Arrays.stream(reports).anyMatch(report -> { + try { + return (!report.exists() || report.isDirectory()) && ignoreMissingReports; + } catch (IOException | InterruptedException e) { + e.printStackTrace(); + return false; + } + }); + } + + private boolean noReportsAndMissingReportsNotIgnored(FilePath[] reports) { + if (reports == null && !ignoreMissingReports) { + return false; + } else if (reports == null) { + return true; + } + return Arrays.stream(reports).anyMatch(report -> { + try { + return (!report.exists() || report.isDirectory()) && !ignoreMissingReports; + } catch (IOException | InterruptedException e) { + e.printStackTrace(); + return false; + } + }); } - pitLogger.logLookingForReports(listener, workspace); - FilePath buildTarget = new FilePath(build.getRootDir()); - if (reports.length == 1) { - fileProcessor.copySingleModuleReport(reports[0], buildTarget); - } else { - for (Map.Entry entry : fileProcessor.getNames(reports, workspace.getRemote()).entrySet()) { - FilePath filePath = entry.getKey(); - String module = entry.getValue(); - pitLogger.logPublishReport(listener, workspace); - fileProcessor.copyMultiModuleReport(filePath, buildTarget, module); - } + /** + * {@inheritDoc} + */ + @Override + public Action getProjectAction(AbstractProject project) { + return new PitProjectAction(project); } - PitBuildAction action = new PitBuildAction(build); - build.addAction(action); - build.setResult(resultDecider.decideBuildResult(action)); + /** + * Required by plugin config + * + * @return the minimum kill ratio + */ + public float getMinimumKillRatio() { + return minimumKillRatio; + } + + /** + * Required by plugin config + * + * @return the kill ratio must improve + */ + public boolean getKillRatioMustImprove() { + return killRatioMustImprove; + } - pitLogger.logResults(listener, action); - } + /** + * Required by plugin config + * + * @return the mutation stats file + */ + public String getMutationStatsFile() { + return mutationStatsFile; + } - private boolean noReportsAndMissingReportsIgnored(FilePath[] reports) { - if (reports == null && ignoreMissingReports) { - return true; - } else if (reports == null ) { - return false; + /** + * Required by plugin config + * + * @return ignore missing reports flag + */ + public boolean getIgnoreMissingReports() { + return ignoreMissingReports; } - return Arrays.stream(reports).anyMatch(report -> { - try { - return (!report.exists() || report.isDirectory()) && ignoreMissingReports; - } catch (IOException | InterruptedException e) { - e.printStackTrace(); - return false; - } - }); - } - - private boolean noReportsAndMissingReportsNotIgnored(FilePath[] reports) { - if (reports == null && !ignoreMissingReports) { - return false; - } else if (reports == null) { - return true; + + @Override + public BuildStepMonitor getRequiredMonitorService() { + return STEP; } - return Arrays.stream(reports).anyMatch(report -> { - try { - return (!report.exists() || report.isDirectory()) && !ignoreMissingReports; - } catch (IOException | InterruptedException e) { - e.printStackTrace(); - return false; - } - }); - } - - /** - * {@inheritDoc} - */ - @Override - public Action getProjectAction(AbstractProject project) { - return new PitProjectAction(project); - } - - - /** - * Required by plugin config - * - * @return the minimum kill ratio - */ - public float getMinimumKillRatio() { - return minimumKillRatio; - } - - /** - * Required by plugin config - * - * @return the kill ratio must improve - */ - public boolean getKillRatioMustImprove() { - return killRatioMustImprove; - } - - /** - * Required by plugin config - * - * @return the mutation stats file - */ - public String getMutationStatsFile() { - return mutationStatsFile; - } - - /** - * Required by plugin config - * - * @return ignore missing reports flag - */ - public boolean getIgnoreMissingReports() { - return ignoreMissingReports; - } - - @Override - public BuildStepMonitor getRequiredMonitorService() { - return STEP; - } } diff --git a/src/main/java/org/jenkinsci/plugins/pitmutation/ResultDecider.java b/src/main/java/org/jenkinsci/plugins/pitmutation/ResultDecider.java index 9211d95..6965555 100644 --- a/src/main/java/org/jenkinsci/plugins/pitmutation/ResultDecider.java +++ b/src/main/java/org/jenkinsci/plugins/pitmutation/ResultDecider.java @@ -15,28 +15,29 @@ */ public class ResultDecider { - private final Collection buildConditions; - - protected ResultDecider(PercentageThresholdCondition thresholdCondition) { - buildConditions = List.of(thresholdCondition); - } - - protected ResultDecider(PercentageThresholdCondition thresholdCondition, MustImproveCondition mustImproveCondition) { - buildConditions = List.of(thresholdCondition, mustImproveCondition); - } - - /** - * Decide build result result. - * - * @param action the action - * @return the worst result from all conditions - */ - public Result decideBuildResult(PitBuildAction action) { - Result result = SUCCESS; - for (Condition condition : buildConditions) { - Result conditionResult = condition.decideResult(action); - result = conditionResult.isWorseThan(result) ? conditionResult : result; + private final Collection buildConditions; + + protected ResultDecider(PercentageThresholdCondition thresholdCondition) { + buildConditions = List.of(thresholdCondition); + } + + protected ResultDecider(PercentageThresholdCondition thresholdCondition, + MustImproveCondition mustImproveCondition) { + buildConditions = List.of(thresholdCondition, mustImproveCondition); + } + + /** + * Decide build result result. + * + * @param action the action + * @return the worst result from all conditions + */ + public Result decideBuildResult(PitBuildAction action) { + Result result = SUCCESS; + for (Condition condition : buildConditions) { + Result conditionResult = condition.decideResult(action); + result = conditionResult.isWorseThan(result) ? conditionResult : result; + } + return result; } - return result; - } } diff --git a/src/main/java/org/jenkinsci/plugins/pitmutation/portlets/CoverageRange.java b/src/main/java/org/jenkinsci/plugins/pitmutation/portlets/CoverageRange.java index 9f2ced4..f0d455e 100644 --- a/src/main/java/org/jenkinsci/plugins/pitmutation/portlets/CoverageRange.java +++ b/src/main/java/org/jenkinsci/plugins/pitmutation/portlets/CoverageRange.java @@ -63,14 +63,14 @@ public static Color fillColorOf(final double amount) { return ABYSMAL.fillColor; } - private static Color blendedColor(final Color fillColor0, final Color fillColor1, final double t0, final double t1) { + private static Color blendedColor(final Color fillColor0, + final Color fillColor1, + final double t0, + final double t1) { final double total = t0 + t1; - final int r = (int) ((fillColor0.getRed() * t1 + fillColor1.getRed() - * t0) / total); - final int g = (int) ((fillColor0.getGreen() * t1 + fillColor1 - .getGreen() * t0) / total); - final int b = (int) ((fillColor0.getBlue() * t1 + fillColor1.getBlue() - * t0) / total); + final int r = (int) ((fillColor0.getRed() * t1 + fillColor1.getRed() * t0) / total); + final int g = (int) ((fillColor0.getGreen() * t1 + fillColor1.getGreen() * t0) / total); + final int b = (int) ((fillColor0.getBlue() * t1 + fillColor1.getBlue() * t0) / total); return new Color(r, g, b); } diff --git a/src/main/java/org/jenkinsci/plugins/pitmutation/portlets/PitColumn.java b/src/main/java/org/jenkinsci/plugins/pitmutation/portlets/PitColumn.java index ae0d63a..61a153a 100644 --- a/src/main/java/org/jenkinsci/plugins/pitmutation/portlets/PitColumn.java +++ b/src/main/java/org/jenkinsci/plugins/pitmutation/portlets/PitColumn.java @@ -52,11 +52,10 @@ private Double getLinePercent(final Run lastSuccessfulBuild) { final double doubleValue = percentageFloat.doubleValue(); final int decimalPlaces = 2; - BigDecimal bigDecimal = BigDecimal.valueOf(doubleValue); + BigDecimal bigDecimal = BigDecimal.valueOf(doubleValue); // setScale is immutable - bigDecimal = bigDecimal.setScale(decimalPlaces, - RoundingMode.HALF_UP); + bigDecimal = bigDecimal.setScale(decimalPlaces, RoundingMode.HALF_UP); return bigDecimal.doubleValue(); } diff --git a/src/main/java/org/jenkinsci/plugins/pitmutation/targets/BaseResultFactory.java b/src/main/java/org/jenkinsci/plugins/pitmutation/targets/BaseResultFactory.java index f08ea2d..441038f 100644 --- a/src/main/java/org/jenkinsci/plugins/pitmutation/targets/BaseResultFactory.java +++ b/src/main/java/org/jenkinsci/plugins/pitmutation/targets/BaseResultFactory.java @@ -12,7 +12,6 @@ private BaseResultFactory() { public static MutationResult getBaseMutationResultFrom(PitBuildAction action) { Map reports = action.getReports(); - return reports.size() == 1 ? new SingleModuleResult(action) : - new ProjectMutations(action); + return reports.size() == 1 ? new SingleModuleResult(action) : new ProjectMutations(action); } } diff --git a/src/main/java/org/jenkinsci/plugins/pitmutation/targets/ModuleChildMapBuilder.java b/src/main/java/org/jenkinsci/plugins/pitmutation/targets/ModuleChildMapBuilder.java index 7080516..f5c2f2e 100644 --- a/src/main/java/org/jenkinsci/plugins/pitmutation/targets/ModuleChildMapBuilder.java +++ b/src/main/java/org/jenkinsci/plugins/pitmutation/targets/ModuleChildMapBuilder.java @@ -33,8 +33,6 @@ public Map build() { private String getClassName(Mutation mutation) { String mutatedClassName = mutation.getMutatedClass(); int firstDollar = mutatedClassName.indexOf('$'); - return firstDollar >= 0 - ? mutatedClassName.substring(0, firstDollar) - : mutatedClassName; + return firstDollar >= 0 ? mutatedClassName.substring(0, firstDollar) : mutatedClassName; } } diff --git a/src/main/java/org/jenkinsci/plugins/pitmutation/targets/ModuleResult.java b/src/main/java/org/jenkinsci/plugins/pitmutation/targets/ModuleResult.java index 9ea39df..eb07ae7 100644 --- a/src/main/java/org/jenkinsci/plugins/pitmutation/targets/ModuleResult.java +++ b/src/main/java/org/jenkinsci/plugins/pitmutation/targets/ModuleResult.java @@ -53,13 +53,10 @@ public int compareTo(@Nonnull ModuleResult other) { @Override public boolean equals(Object o) { - if (this == o) - return true; - if (o == null || getClass() != o.getClass()) - return false; + if (this == o) {return true;} + if (o == null || getClass() != o.getClass()) {return false;} ModuleResult that = (ModuleResult) o; - return Objects.equals(report, that.report) && - Objects.equals(name, that.name); + return Objects.equals(report, that.report) && Objects.equals(name, that.name); } @Override diff --git a/src/main/java/org/jenkinsci/plugins/pitmutation/targets/MutatedClass.java b/src/main/java/org/jenkinsci/plugins/pitmutation/targets/MutatedClass.java index a942a50..dcf2a1c 100644 --- a/src/main/java/org/jenkinsci/plugins/pitmutation/targets/MutatedClass.java +++ b/src/main/java/org/jenkinsci/plugins/pitmutation/targets/MutatedClass.java @@ -43,7 +43,8 @@ public MutatedClass(String name, MutationResult parent, Collection mut } private Map createMutatedLines(Collection mutations) { - return mutations.stream() + return mutations + .stream() .collect(groupingBy(Mutation::getLineNumber)) .values() .stream() @@ -58,17 +59,20 @@ public boolean isSourceLevel() { /** * Gets the contents of the coverage report for the file, but removes the header and the stylesheet as this needs to be handled separately in jelly. + * * @return The source of the coverage report to show in the UI */ @Override public String getSourceFileContent() { String fullContents = getFileContents(package_ + File.separator + fileName); - return fullContents.contains(END_HEADER_TAG) ? fullContents.substring(fullContents.indexOf(END_HEADER_TAG) + 5) : - fullContents; + return fullContents.contains(END_HEADER_TAG) ? + fullContents.substring(fullContents.indexOf(END_HEADER_TAG) + 5) : + fullContents; } /** * Gets the contents of the style sheet for the coverage report. + * * @return The source of the coverage report to show in the UI. */ @Override @@ -78,12 +82,10 @@ public String getStyleSheetContent() { private String getFileContents(String path) { String filePath = - getOwner().getRootDir() + File.separator + getMutationReportDirectory() + - File.separator + path; + getOwner().getRootDir() + File.separator + getMutationReportDirectory() + File.separator + path; try { return new TextFile(new File(filePath)).read(); - } - catch (IOException exception) { + } catch (IOException exception) { return "Could not read file: " + filePath + "\n"; } } @@ -110,16 +112,15 @@ public int compareTo(@Nonnull MutatedClass other) { @Override public boolean equals(Object o) { - if (this == o) - return true; - if (o == null || getClass() != o.getClass()) - return false; + if (this == o) {return true;} + if (o == null || getClass() != o.getClass()) {return false;} MutatedClass that = (MutatedClass) o; - return Objects.equals(name, that.name) && - Objects.equals(package_, that.package_) && - Objects.equals(fileName, that.fileName) && - Objects.equals(mutations, that.mutations) && - Objects.equals(mutatedLines, that.mutatedLines); + return Objects.equals(name, that.name) + && Objects.equals(package_, that.package_) + && Objects.equals(fileName, + that.fileName) + && Objects.equals(mutations, that.mutations) + && Objects.equals(mutatedLines, that.mutatedLines); } @Override diff --git a/src/main/java/org/jenkinsci/plugins/pitmutation/targets/MutatedLine.java b/src/main/java/org/jenkinsci/plugins/pitmutation/targets/MutatedLine.java index 8de043d..eaf7821 100644 --- a/src/main/java/org/jenkinsci/plugins/pitmutation/targets/MutatedLine.java +++ b/src/main/java/org/jenkinsci/plugins/pitmutation/targets/MutatedLine.java @@ -68,13 +68,10 @@ public int compareTo(@Nonnull MutatedLine other) { @Override public boolean equals(Object o) { - if (this == o) - return true; - if (o == null || getClass() != o.getClass()) - return false; + if (this == o) {return true;} + if (o == null || getClass() != o.getClass()) {return false;} MutatedLine that = (MutatedLine) o; - return lineNumber == that.lineNumber && - Objects.equals(mutations, that.mutations); + return lineNumber == that.lineNumber && Objects.equals(mutations, that.mutations); } @Override diff --git a/src/main/java/org/jenkinsci/plugins/pitmutation/targets/MutatedPackage.java b/src/main/java/org/jenkinsci/plugins/pitmutation/targets/MutatedPackage.java index 6ed76d5..e9e476c 100644 --- a/src/main/java/org/jenkinsci/plugins/pitmutation/targets/MutatedPackage.java +++ b/src/main/java/org/jenkinsci/plugins/pitmutation/targets/MutatedPackage.java @@ -31,7 +31,8 @@ public String getDisplayName() { @Override public MutationStats getMutationStats() { - return new MutationStatsImpl(getName(), classMutations.values().stream().flatMap(List::stream).collect(toList())); + return new MutationStatsImpl(getName(), + classMutations.values().stream().flatMap(List::stream).collect(toList())); } @Override @@ -53,10 +54,8 @@ public int compareTo(@Nonnull MutatedPackage other) { @Override public boolean equals(Object o) { - if (this == o) - return true; - if (o == null || getClass() != o.getClass()) - return false; + if (this == o) {return true;} + if (o == null || getClass() != o.getClass()) {return false;} MutatedPackage that = (MutatedPackage) o; return Objects.equals(classMutations, that.classMutations); } diff --git a/src/main/java/org/jenkinsci/plugins/pitmutation/targets/MutationResult.java b/src/main/java/org/jenkinsci/plugins/pitmutation/targets/MutationResult.java index 30184b2..46254b4 100644 --- a/src/main/java/org/jenkinsci/plugins/pitmutation/targets/MutationResult.java +++ b/src/main/java/org/jenkinsci/plugins/pitmutation/targets/MutationResult.java @@ -81,10 +81,7 @@ public boolean isCoverageAltered() { } public Collection getChildren() { - return getChildMap().values().stream() - .sorted() - .sorted(Collections.reverseOrder()) - .collect(Collectors.toList()); + return getChildMap().values().stream().sorted().sorted(Collections.reverseOrder()).collect(Collectors.toList()); } public MutationStats getStatsDelta() { @@ -129,9 +126,7 @@ static String urlTransform(String token) { StringBuilder buf = new StringBuilder(token.length()); for (int i = 0; i < token.length(); i++) { final char c = token.charAt(i); - if (('0' <= c && '9' >= c) - || ('A' <= c && 'Z' >= c) - || ('a' <= c && 'z' >= c)) { + if (('0' <= c && '9' >= c) || ('A' <= c && 'Z' >= c) || ('a' <= c && 'z' >= c)) { buf.append(c); } else { buf.append('_'); diff --git a/src/main/java/org/jenkinsci/plugins/pitmutation/targets/MutationStats.java b/src/main/java/org/jenkinsci/plugins/pitmutation/targets/MutationStats.java index f068775..c727797 100644 --- a/src/main/java/org/jenkinsci/plugins/pitmutation/targets/MutationStats.java +++ b/src/main/java/org/jenkinsci/plugins/pitmutation/targets/MutationStats.java @@ -28,7 +28,9 @@ public String getKillPercentFillColor() { return getCoverageColors().getFillHexString(); } - public String getKillPercentTextColor() { return getCoverageColors().getLineHexString();} + public String getKillPercentTextColor() { + return getCoverageColors().getLineHexString(); + } private CoverageRange getCoverageColors() { return CoverageRange.valueOf(getKillPercent()); @@ -36,7 +38,7 @@ private CoverageRange getCoverageColors() { private float round(float ratio) { //TODO NaN mutation test - if (Float.isNaN(ratio) || Float.isInfinite(ratio)) return ratio; + if (Float.isNaN(ratio) || Float.isInfinite(ratio)) {return ratio;} BigDecimal bd = new BigDecimal(ratio); BigDecimal rounded = bd.setScale(3, RoundingMode.HALF_UP); return rounded.floatValue(); diff --git a/src/main/java/org/jenkinsci/plugins/pitmutation/targets/ProjectMutations.java b/src/main/java/org/jenkinsci/plugins/pitmutation/targets/ProjectMutations.java index dc553f5..eec9a02 100644 --- a/src/main/java/org/jenkinsci/plugins/pitmutation/targets/ProjectMutations.java +++ b/src/main/java/org/jenkinsci/plugins/pitmutation/targets/ProjectMutations.java @@ -70,10 +70,8 @@ public int compareTo(@Nonnull ProjectMutations other) { @Override public boolean equals(Object o) { - if (this == o) - return true; - if (o == null || getClass() != o.getClass()) - return false; + if (this == o) {return true;} + if (o == null || getClass() != o.getClass()) {return false;} ProjectMutations that = (ProjectMutations) o; return Objects.equals(action, that.action); } diff --git a/src/main/java/org/jenkinsci/plugins/pitmutation/targets/SingleModuleResult.java b/src/main/java/org/jenkinsci/plugins/pitmutation/targets/SingleModuleResult.java index c4cf69f..eda0c4f 100644 --- a/src/main/java/org/jenkinsci/plugins/pitmutation/targets/SingleModuleResult.java +++ b/src/main/java/org/jenkinsci/plugins/pitmutation/targets/SingleModuleResult.java @@ -77,10 +77,8 @@ public int compareTo(@Nonnull SingleModuleResult other) { @Override public boolean equals(Object o) { - if (this == o) - return true; - if (o == null || getClass() != o.getClass()) - return false; + if (this == o) {return true;} + if (o == null || getClass() != o.getClass()) {return false;} SingleModuleResult that = (SingleModuleResult) o; return Objects.equals(action, that.action); } diff --git a/src/test/java/org/jenkinsci/plugins/pitmutation/MustImproveConditionTest.java b/src/test/java/org/jenkinsci/plugins/pitmutation/MustImproveConditionTest.java index e0e9642..268d757 100644 --- a/src/test/java/org/jenkinsci/plugins/pitmutation/MustImproveConditionTest.java +++ b/src/test/java/org/jenkinsci/plugins/pitmutation/MustImproveConditionTest.java @@ -17,48 +17,48 @@ class MustImproveConditionTest { - @TestFactory - Stream testFactory() { - return Stream - .of(new TestCase(null, 90f, SUCCESS, "noPreviousAction"), - new TestCase(85f, 90f, SUCCESS, "currentKillPercentGreater"), - new TestCase(85f, 85f, SUCCESS, "currentKillPercentEqual"), - new TestCase(85f, 80f, UNSTABLE, "currentKillPercentLess")) - .map(testCase -> dynamicTest(testCase.name, () -> { - PitBuildAction action = mock(PitBuildAction.class); - PitBuildAction previousAction = mock(PitBuildAction.class); - MutationResult currentReport = mock(MutationResult.class); - MutationResult previousReport = mock(MutationResult.class); - MutationStats currentStats = mock(MutationStats.class); - MutationStats previousStats = mock(MutationStats.class); + @TestFactory + Stream testFactory() { + return Stream + .of(new TestCase(null, 90f, SUCCESS, "noPreviousAction"), + new TestCase(85f, 90f, SUCCESS, "currentKillPercentGreater"), + new TestCase(85f, 85f, SUCCESS, "currentKillPercentEqual"), + new TestCase(85f, 80f, UNSTABLE, "currentKillPercentLess")) + .map(testCase -> dynamicTest(testCase.name, () -> { + PitBuildAction action = mock(PitBuildAction.class); + PitBuildAction previousAction = mock(PitBuildAction.class); + MutationResult currentReport = mock(MutationResult.class); + MutationResult previousReport = mock(MutationResult.class); + MutationStats currentStats = mock(MutationStats.class); + MutationStats previousStats = mock(MutationStats.class); - when(action.getReport()).thenReturn(currentReport); - when(currentReport.getMutationStats()).thenReturn(currentStats); - when(currentStats.getKillPercent()).thenReturn(testCase.currentKillPercent); + when(action.getReport()).thenReturn(currentReport); + when(currentReport.getMutationStats()).thenReturn(currentStats); + when(currentStats.getKillPercent()).thenReturn(testCase.currentKillPercent); - if (testCase.previousKillPercent != null) { - when(action.getPreviousAction()).thenReturn(previousAction); - when(previousAction.getReport()).thenReturn(previousReport); - when(previousReport.getMutationStats()).thenReturn(previousStats); - when(previousStats.getKillPercent()).thenReturn(testCase.previousKillPercent); - } + if (testCase.previousKillPercent != null) { + when(action.getPreviousAction()).thenReturn(previousAction); + when(previousAction.getReport()).thenReturn(previousReport); + when(previousReport.getMutationStats()).thenReturn(previousStats); + when(previousStats.getKillPercent()).thenReturn(testCase.previousKillPercent); + } - MustImproveCondition condition = new MustImproveCondition(); - assertEquals(testCase.expectedResult, condition.decideResult(action)); - })); - } + MustImproveCondition condition = new MustImproveCondition(); + assertEquals(testCase.expectedResult, condition.decideResult(action)); + })); + } - private static class TestCase { - Float previousKillPercent; - float currentKillPercent; - Result expectedResult; - String name; + private static class TestCase { + Float previousKillPercent; + float currentKillPercent; + Result expectedResult; + String name; - TestCase(Float previousKillPercent, float currentKillPercent, Result expectedResult, String name) { - this.previousKillPercent = previousKillPercent; - this.currentKillPercent = currentKillPercent; - this.expectedResult = expectedResult; - this.name = name; + TestCase(Float previousKillPercent, float currentKillPercent, Result expectedResult, String name) { + this.previousKillPercent = previousKillPercent; + this.currentKillPercent = currentKillPercent; + this.expectedResult = expectedResult; + this.name = name; + } } - } } diff --git a/src/test/java/org/jenkinsci/plugins/pitmutation/MutationReportTest.java b/src/test/java/org/jenkinsci/plugins/pitmutation/MutationReportTest.java index d910d57..b7c1624 100644 --- a/src/test/java/org/jenkinsci/plugins/pitmutation/MutationReportTest.java +++ b/src/test/java/org/jenkinsci/plugins/pitmutation/MutationReportTest.java @@ -19,143 +19,145 @@ */ class MutationReportTest { - private static final String MUTATIONS_OLD = "" - + "\n" - + "SafeMultipartFile.java\n" - + "com.mediagraft.podsplice.controllers.massupload.SafeMultipartFile\n" - + "getSize\n" - + "54\n" - + "org.pitest.mutationtest.engine.gregor.mutators.ReturnValsMutator\n" - + "5\n" - + "\n" - + "" - + "" - + "SafeMultipartFile.java" - + "com.mediagraft.podsplice.controllers.massupload.SafeMultipartFile" - + "getSize" - + "57" - + "org.pitest.mutationtest.engine.gregor.mutators.ReturnValsMutator" - + "6" - + "3" - + "" - + "" - + ""; - - private static final String MUTATIONS = "" - + "\n" - + "SafeMultipartFile.java\n" - + "com.mediagraft.podsplice.controllers.massupload.SafeMultipartFile\n" - + "getSize\n" - + "54\n" - + "org.pitest.mutationtest.engine.gregor.mutators.ReturnValsMutator\n" - + "5\n" - + "\n" - + "" - + "" - + "SafeMultipartFile.java" - + "com.mediagraft.podsplice.controllers.massupload.SafeMultipartFile" - + "getSize" - + "57" - + "org.pitest.mutationtest.engine.gregor.mutators.ReturnValsMutator" - + "6" - + "3" - + "" - + "" - + ""; - - private InputStream mutationsXml; - - @BeforeEach - public void setUp() { - mutationsXml = getClass().getResourceAsStream("testmutations-00.xml"); - } - - @Test - void packageNameFinder() { - assertThat(MutationReport.packageNameFromClass("xxx.yyy.zzz.Foo"), is("xxx.yyy.zzz")); - assertThat(MutationReport.packageNameFromClass("Foo"), is("")); - } - - @Test - void countsKills() throws IOException, SAXException { - MutationReport report = new MutationReport(mutationsXml); - assertThat(report.getMutationStats().getKillCount(), is(5)); - assertThat(report.getMutationStats().getTotalMutations(), is(16)); - } - - @Test - void sortsMutationsByClassName() throws IOException, SAXException { - MutationReport report = new MutationReport(mutationsXml); - Collection mutations = - report.getMutationsForClassName("org.jenkinsci.plugins.pitmutation.MutationReport"); - assertThat(mutations.size(), is(5)); - } - - @Test - void indexesMutationsByPackage() throws IOException, SAXException { - MutationReport report = new MutationReport(mutationsXml); - assertThat(report.getMutationsForPackage("org.jenkinsci.plugins.pitmutation"), hasSize(16)); - assertThat(report.getMutationsForPackage(""), hasSize(0)); - } - - @Test - void canDigestAMutation() throws IOException, SAXException { - MutationReport report = new MutationReport(new ByteArrayInputStream(MUTATIONS.getBytes("UTF-8"))); - - assertThat(report.getMutationStats().getTotalMutations(), is(2)); - - Iterator mutations = - report.getMutationsForClassName("com.mediagraft.podsplice.controllers.massupload.SafeMultipartFile").iterator(); - - Mutation m1 = mutations.next(); - Mutation m2 = mutations.next(); - - if (m1.getStatus().equals("KILLED")) { - verifyKilled(m1); - verifyNoCoverage(m2); - } else { - verifyKilled(m2); - verifyNoCoverage(m1); + private static final String MUTATIONS_OLD = "" + + "\n" + + "SafeMultipartFile.java\n" + + "com.mediagraft.podsplice.controllers.massupload.SafeMultipartFile\n" + + "getSize\n" + + "54\n" + + "org.pitest.mutationtest.engine.gregor.mutators.ReturnValsMutator\n" + + "5\n" + + "\n" + + "" + + "" + + "SafeMultipartFile.java" + + "com.mediagraft.podsplice.controllers.massupload.SafeMultipartFile" + + "getSize" + + "57" + + "org.pitest.mutationtest.engine.gregor.mutators.ReturnValsMutator" + + "6" + + "3" + + "" + + "" + + ""; + + private static final String MUTATIONS = "" + + "\n" + + "SafeMultipartFile.java\n" + + "com.mediagraft.podsplice.controllers.massupload.SafeMultipartFile\n" + + "getSize\n" + + "54\n" + + "org.pitest.mutationtest.engine.gregor.mutators.ReturnValsMutator\n" + + "5\n" + + "\n" + + "" + + "" + + "SafeMultipartFile.java" + + "com.mediagraft.podsplice.controllers.massupload.SafeMultipartFile" + + "getSize" + + "57" + + "org.pitest.mutationtest.engine.gregor.mutators.ReturnValsMutator" + + "6" + + "3" + + "" + + "" + + ""; + + private InputStream mutationsXml; + + @BeforeEach + public void setUp() { + mutationsXml = getClass().getResourceAsStream("testmutations-00.xml"); } - } - @Test - void canDigestAMutationOlderMutations() throws IOException, SAXException { - MutationReport report = new MutationReport(new ByteArrayInputStream(MUTATIONS_OLD.getBytes("UTF-8"))); + @Test + void packageNameFinder() { + assertThat(MutationReport.packageNameFromClass("xxx.yyy.zzz.Foo"), is("xxx.yyy.zzz")); + assertThat(MutationReport.packageNameFromClass("Foo"), is("")); + } + + @Test + void countsKills() throws IOException, SAXException { + MutationReport report = new MutationReport(mutationsXml); + assertThat(report.getMutationStats().getKillCount(), is(5)); + assertThat(report.getMutationStats().getTotalMutations(), is(16)); + } + + @Test + void sortsMutationsByClassName() throws IOException, SAXException { + MutationReport report = new MutationReport(mutationsXml); + Collection mutations = + report.getMutationsForClassName("org.jenkinsci.plugins.pitmutation.MutationReport"); + assertThat(mutations.size(), is(5)); + } - assertThat(report.getMutationStats().getTotalMutations(), is(2)); + @Test + void indexesMutationsByPackage() throws IOException, SAXException { + MutationReport report = new MutationReport(mutationsXml); + assertThat(report.getMutationsForPackage("org.jenkinsci.plugins.pitmutation"), hasSize(16)); + assertThat(report.getMutationsForPackage(""), hasSize(0)); + } + + @Test + void canDigestAMutation() throws IOException, SAXException { + MutationReport report = new MutationReport(new ByteArrayInputStream(MUTATIONS.getBytes("UTF-8"))); + + assertThat(report.getMutationStats().getTotalMutations(), is(2)); - Iterator mutations = - report.getMutationsForClassName("com.mediagraft.podsplice.controllers.massupload.SafeMultipartFile").iterator(); + Iterator mutations = report + .getMutationsForClassName("com.mediagraft.podsplice.controllers.massupload.SafeMultipartFile") + .iterator(); - Mutation m1 = mutations.next(); - Mutation m2 = mutations.next(); + Mutation m1 = mutations.next(); + Mutation m2 = mutations.next(); + + if (m1.getStatus().equals("KILLED")) { + verifyKilled(m1); + verifyNoCoverage(m2); + } else { + verifyKilled(m2); + verifyNoCoverage(m1); + } + } + + @Test + void canDigestAMutationOlderMutations() throws IOException, SAXException { + MutationReport report = new MutationReport(new ByteArrayInputStream(MUTATIONS_OLD.getBytes("UTF-8"))); + + assertThat(report.getMutationStats().getTotalMutations(), is(2)); + + Iterator mutations = report + .getMutationsForClassName("com.mediagraft.podsplice.controllers.massupload.SafeMultipartFile") + .iterator(); + + Mutation m1 = mutations.next(); + Mutation m2 = mutations.next(); + + if (m1.getStatus().equals("KILLED")) { + verifyKilled(m1); + verifyNoCoverage(m2); + } else { + verifyKilled(m2); + verifyNoCoverage(m1); + } + } + + + private void verifyNoCoverage(Mutation m) { + assertThat(m.getLineNumber(), is(54)); + assertThat(m.isDetected(), is(true)); + assertThat(m.getStatus(), is("NO_COVERAGE")); + assertThat(m.getSourceFile(), is("SafeMultipartFile.java")); + assertThat(m.getMutatedClass(), is("com.mediagraft.podsplice.controllers.massupload.SafeMultipartFile")); + assertThat(m.getMutator(), is("org.pitest.mutationtest.engine.gregor.mutators.ReturnValsMutator")); + } - if (m1.getStatus().equals("KILLED")) { - verifyKilled(m1); - verifyNoCoverage(m2); - } else { - verifyKilled(m2); - verifyNoCoverage(m1); + private void verifyKilled(Mutation m) { + assertThat(m.getLineNumber(), is(57)); + assertThat(m.isDetected(), is(false)); + assertThat(m.getStatus(), is("KILLED")); + assertThat(m.getSourceFile(), is("SafeMultipartFile.java")); + assertThat(m.getMutatedClass(), is("com.mediagraft.podsplice.controllers.massupload.SafeMultipartFile")); + assertThat(m.getMutator(), is("org.pitest.mutationtest.engine.gregor.mutators.ReturnValsMutator")); } - } - - - private void verifyNoCoverage(Mutation m) { - assertThat(m.getLineNumber(), is(54)); - assertThat(m.isDetected(), is(true)); - assertThat(m.getStatus(), is("NO_COVERAGE")); - assertThat(m.getSourceFile(), is("SafeMultipartFile.java")); - assertThat(m.getMutatedClass(), is("com.mediagraft.podsplice.controllers.massupload.SafeMultipartFile")); - assertThat(m.getMutator(), is("org.pitest.mutationtest.engine.gregor.mutators.ReturnValsMutator")); - } - - private void verifyKilled(Mutation m) { - assertThat(m.getLineNumber(), is(57)); - assertThat(m.isDetected(), is(false)); - assertThat(m.getStatus(), is("KILLED")); - assertThat(m.getSourceFile(), is("SafeMultipartFile.java")); - assertThat(m.getMutatedClass(), is("com.mediagraft.podsplice.controllers.massupload.SafeMultipartFile")); - assertThat(m.getMutator(), is("org.pitest.mutationtest.engine.gregor.mutators.ReturnValsMutator")); - } } diff --git a/src/test/java/org/jenkinsci/plugins/pitmutation/MutationReportWithDescriptionTest.java b/src/test/java/org/jenkinsci/plugins/pitmutation/MutationReportWithDescriptionTest.java index 242e45e..991256a 100644 --- a/src/test/java/org/jenkinsci/plugins/pitmutation/MutationReportWithDescriptionTest.java +++ b/src/test/java/org/jenkinsci/plugins/pitmutation/MutationReportWithDescriptionTest.java @@ -18,38 +18,38 @@ */ class MutationReportWithDescriptionTest { - private InputStream mutationsXml; - - @BeforeEach - public void setUp() { - mutationsXml = getClass().getResourceAsStream("testmutations-02.xml"); - } - - @Test - void packageNameFinder() { - assertThat(MutationReport.packageNameFromClass("xxx.yyy.zzz.Foo"), is("xxx.yyy.zzz")); - assertThat(MutationReport.packageNameFromClass("Foo"), is("")); - } - - @Test - void countsKills() throws IOException, SAXException { - MutationReport report = new MutationReport(mutationsXml); - assertThat(report.getMutationStats().getKillCount(), is(3)); - assertThat(report.getMutationStats().getTotalMutations(), is(4)); - } - - @Test - void sortsMutationsByClassName() throws IOException, SAXException { - MutationReport report = new MutationReport(mutationsXml); - Collection mutations = report.getMutationsForClassName("es.rodri.controllers.CompositorController"); - assertThat(mutations.size(), is(4)); - } - - @Test - void indexesMutationsByPackage() throws IOException, SAXException { - MutationReport report = new MutationReport(mutationsXml); - assertThat(report.getMutationsForPackage("es.rodri.controllers"), hasSize(4)); - assertThat(report.getMutationsForPackage(""), notNullValue()); - assertThat(report.getMutationsForPackage(""), hasSize(0)); - } + private InputStream mutationsXml; + + @BeforeEach + public void setUp() { + mutationsXml = getClass().getResourceAsStream("testmutations-02.xml"); + } + + @Test + void packageNameFinder() { + assertThat(MutationReport.packageNameFromClass("xxx.yyy.zzz.Foo"), is("xxx.yyy.zzz")); + assertThat(MutationReport.packageNameFromClass("Foo"), is("")); + } + + @Test + void countsKills() throws IOException, SAXException { + MutationReport report = new MutationReport(mutationsXml); + assertThat(report.getMutationStats().getKillCount(), is(3)); + assertThat(report.getMutationStats().getTotalMutations(), is(4)); + } + + @Test + void sortsMutationsByClassName() throws IOException, SAXException { + MutationReport report = new MutationReport(mutationsXml); + Collection mutations = report.getMutationsForClassName("es.rodri.controllers.CompositorController"); + assertThat(mutations.size(), is(4)); + } + + @Test + void indexesMutationsByPackage() throws IOException, SAXException { + MutationReport report = new MutationReport(mutationsXml); + assertThat(report.getMutationsForPackage("es.rodri.controllers"), hasSize(4)); + assertThat(report.getMutationsForPackage(""), notNullValue()); + assertThat(report.getMutationsForPackage(""), hasSize(0)); + } } diff --git a/src/test/java/org/jenkinsci/plugins/pitmutation/PercentageThresholdConditionTest.java b/src/test/java/org/jenkinsci/plugins/pitmutation/PercentageThresholdConditionTest.java index 75e911f..7627004 100644 --- a/src/test/java/org/jenkinsci/plugins/pitmutation/PercentageThresholdConditionTest.java +++ b/src/test/java/org/jenkinsci/plugins/pitmutation/PercentageThresholdConditionTest.java @@ -17,36 +17,36 @@ class PercentageThresholdConditionTest { - @TestFactory - Stream testFactory() { - return Stream - .of(new TestCase(80f, 85f, SUCCESS, "killPercentGreaterThanThreshold"), - new TestCase(85f, 85f, SUCCESS, "killPercentEqualToThreshold"), - new TestCase(90f, 85f, FAILURE, "killPercentLessThanThreshold")) - .map(testCase -> dynamicTest(testCase.name, () -> { - PitBuildAction action = mock(PitBuildAction.class); - MutationResult report = mock(MutationResult.class); - MutationStats stats = mock(MutationStats.class); - when(action.getReport()).thenReturn(report); - when(report.getMutationStats()).thenReturn(stats); - when(stats.getKillPercent()).thenReturn(testCase.killPercent); - - PercentageThresholdCondition condition = new PercentageThresholdCondition(testCase.threshold); - assertEquals(testCase.expectedResult, condition.decideResult(action)); - })); - } - - private static class TestCase { - float threshold; - float killPercent; - Result expectedResult; - String name; - - TestCase(float threshold, float killPercent, Result expectedResult, String name) { - this.threshold = threshold; - this.killPercent = killPercent; - this.expectedResult = expectedResult; - this.name = name; + @TestFactory + Stream testFactory() { + return Stream + .of(new TestCase(80f, 85f, SUCCESS, "killPercentGreaterThanThreshold"), + new TestCase(85f, 85f, SUCCESS, "killPercentEqualToThreshold"), + new TestCase(90f, 85f, FAILURE, "killPercentLessThanThreshold")) + .map(testCase -> dynamicTest(testCase.name, () -> { + PitBuildAction action = mock(PitBuildAction.class); + MutationResult report = mock(MutationResult.class); + MutationStats stats = mock(MutationStats.class); + when(action.getReport()).thenReturn(report); + when(report.getMutationStats()).thenReturn(stats); + when(stats.getKillPercent()).thenReturn(testCase.killPercent); + + PercentageThresholdCondition condition = new PercentageThresholdCondition(testCase.threshold); + assertEquals(testCase.expectedResult, condition.decideResult(action)); + })); + } + + private static class TestCase { + float threshold; + float killPercent; + Result expectedResult; + String name; + + TestCase(float threshold, float killPercent, Result expectedResult, String name) { + this.threshold = threshold; + this.killPercent = killPercent; + this.expectedResult = expectedResult; + this.name = name; + } } - } } diff --git a/src/test/java/org/jenkinsci/plugins/pitmutation/PitLoggerTest.java b/src/test/java/org/jenkinsci/plugins/pitmutation/PitLoggerTest.java index d148824..888c902 100644 --- a/src/test/java/org/jenkinsci/plugins/pitmutation/PitLoggerTest.java +++ b/src/test/java/org/jenkinsci/plugins/pitmutation/PitLoggerTest.java @@ -21,63 +21,63 @@ @ExtendWith(MockitoExtension.class) class PitLoggerTest { - @Mock - private TaskListener listener; - @Mock - private PitBuildAction action; - @Mock - private MutationResult report; - @Mock - private MutationStats stats; - @Mock - private PrintStream printStream; - - private PitLogger pitLogger; - - @BeforeEach - void setUp() { - pitLogger = new PitLogger(); - - when(listener.getLogger()).thenReturn(printStream); - } - - @Test - void logResults() { - when(action.getReport()).thenReturn(report); - when(action.getPreviousAction()).thenReturn(action); - when(report.getMutationStats()).thenReturn(stats); - when(stats.getKillPercent()).thenReturn(70.0f); - - pitLogger.logResults(listener, action); - - verify(printStream, atLeastOnce()).println(anyString()); - } - - @Test - void logMissingReportsIgnored() { - pitLogger.logMissingReportsIgnored(listener); - verify(printStream).println(anyString()); - } - - @Test - void logBuildFailedNoReports() { - pitLogger.logBuildFailedNoReports(listener); - verify(printStream).println(anyString()); - } - - @Test - void logLookingForReports() { - FilePath workspace = new FilePath(new File("path/to/workspace")); - pitLogger.logLookingForReports(listener, workspace); - - verify(printStream).println(anyString()); - } - - @Test - void logPublishReport() { - FilePath workspace = new FilePath(new File("path/to/workspace")); - pitLogger.logPublishReport(listener, workspace); - - verify(printStream).println(anyString()); - } + @Mock + private TaskListener listener; + @Mock + private PitBuildAction action; + @Mock + private MutationResult report; + @Mock + private MutationStats stats; + @Mock + private PrintStream printStream; + + private PitLogger pitLogger; + + @BeforeEach + void setUp() { + pitLogger = new PitLogger(); + + when(listener.getLogger()).thenReturn(printStream); + } + + @Test + void logResults() { + when(action.getReport()).thenReturn(report); + when(action.getPreviousAction()).thenReturn(action); + when(report.getMutationStats()).thenReturn(stats); + when(stats.getKillPercent()).thenReturn(70.0f); + + pitLogger.logResults(listener, action); + + verify(printStream, atLeastOnce()).println(anyString()); + } + + @Test + void logMissingReportsIgnored() { + pitLogger.logMissingReportsIgnored(listener); + verify(printStream).println(anyString()); + } + + @Test + void logBuildFailedNoReports() { + pitLogger.logBuildFailedNoReports(listener); + verify(printStream).println(anyString()); + } + + @Test + void logLookingForReports() { + FilePath workspace = new FilePath(new File("path/to/workspace")); + pitLogger.logLookingForReports(listener, workspace); + + verify(printStream).println(anyString()); + } + + @Test + void logPublishReport() { + FilePath workspace = new FilePath(new File("path/to/workspace")); + pitLogger.logPublishReport(listener, workspace); + + verify(printStream).println(anyString()); + } } diff --git a/src/test/java/org/jenkinsci/plugins/pitmutation/PitProjectActionTest.java b/src/test/java/org/jenkinsci/plugins/pitmutation/PitProjectActionTest.java index 069c847..2e022fa 100644 --- a/src/test/java/org/jenkinsci/plugins/pitmutation/PitProjectActionTest.java +++ b/src/test/java/org/jenkinsci/plugins/pitmutation/PitProjectActionTest.java @@ -24,103 +24,103 @@ @ExtendWith(MockitoExtension.class) class PitProjectActionTest { - @Mock - private AbstractProject project; - @Mock - private AbstractBuild lastSuccessfulBuild; - @Mock - private AbstractBuild previousSuccessfulBuild; - @Mock - private AbstractBuild failedBuild; - @Mock - private PitBuildAction action; - @Mock - private StaplerRequest req; - @Mock - private StaplerResponse rsp; - - private PitProjectAction pitProjectAction; - - @BeforeEach - void setUp() { - pitProjectAction = new PitProjectAction(project); - } - - @Test - void getLastResult_noLastResult() { - doReturn(null).when(project).getLastSuccessfulBuild(); - PitBuildAction lastResult = pitProjectAction.getLastResult(); - assertNull(lastResult); - } - - @Test - void getLastResult_returnsLastResult() { - doReturn(lastSuccessfulBuild).when(project).getLastSuccessfulBuild(); - doReturn(SUCCESS).when(lastSuccessfulBuild).getResult(); - doReturn(action).when(lastSuccessfulBuild).getAction(PitBuildAction.class); - - PitBuildAction lastResult = pitProjectAction.getLastResult(); - assertEquals(action, lastResult); - } - - @Test - void getLastResultBuild_returnsLastBuildNumber() { - doReturn(lastSuccessfulBuild).when(project).getLastSuccessfulBuild(); - doReturn(action).when(lastSuccessfulBuild).getAction(PitBuildAction.class); - doReturn(10).when(lastSuccessfulBuild).getNumber(); - - Integer lastResultBuild = pitProjectAction.getLastResultBuild(); - assertEquals(10, lastResultBuild); - } - - @Test - void getIconFileName_returnsCorrectPath() { - String iconPath = pitProjectAction.getIconFileName(); - assertEquals("/plugin/pitmutation/pitest.png", iconPath); - } - - @Test - void getDisplayName_returnsCorrectName() { - String name = pitProjectAction.getDisplayName(); - assertEquals("PIT Mutation Report", name); - } - - @Test - void getSearchUrl_returnsCorrectUrl() { - String url = pitProjectAction.getSearchUrl(); - assertEquals("pitmutation", url); - } - - @Test - void isFloatingBoxActive_returnsTrue() { - assertTrue(pitProjectAction.isFloatingBoxActive()); - } - - @Test - void doIndex_redirectsCorrectly() throws IOException { - doReturn(lastSuccessfulBuild).when(project).getLastSuccessfulBuild(); - doReturn(action).when(lastSuccessfulBuild).getAction(PitBuildAction.class); - doReturn(10).when(lastSuccessfulBuild).getNumber(); - - pitProjectAction.doIndex(req, rsp); - - verify(rsp).sendRedirect2("../10/pitmutation"); - } - - @Test - void doIndex_buildNumberNull_redirectsCorrectly() throws IOException { - doReturn(null).when(project).getLastSuccessfulBuild(); - pitProjectAction.doIndex(req, rsp); - verify(rsp).sendRedirect2("nodata"); - } - - @Test - void doGraph_CallsDoGraphOnLastResult() throws IOException { - doReturn(lastSuccessfulBuild).when(project).getLastSuccessfulBuild(); - doReturn(action).when(lastSuccessfulBuild).getAction(PitBuildAction.class); - - pitProjectAction.doGraph(req, rsp); - - verify(action).doGraph(req, rsp); - } + @Mock + private AbstractProject project; + @Mock + private AbstractBuild lastSuccessfulBuild; + @Mock + private AbstractBuild previousSuccessfulBuild; + @Mock + private AbstractBuild failedBuild; + @Mock + private PitBuildAction action; + @Mock + private StaplerRequest req; + @Mock + private StaplerResponse rsp; + + private PitProjectAction pitProjectAction; + + @BeforeEach + void setUp() { + pitProjectAction = new PitProjectAction(project); + } + + @Test + void getLastResult_noLastResult() { + doReturn(null).when(project).getLastSuccessfulBuild(); + PitBuildAction lastResult = pitProjectAction.getLastResult(); + assertNull(lastResult); + } + + @Test + void getLastResult_returnsLastResult() { + doReturn(lastSuccessfulBuild).when(project).getLastSuccessfulBuild(); + doReturn(SUCCESS).when(lastSuccessfulBuild).getResult(); + doReturn(action).when(lastSuccessfulBuild).getAction(PitBuildAction.class); + + PitBuildAction lastResult = pitProjectAction.getLastResult(); + assertEquals(action, lastResult); + } + + @Test + void getLastResultBuild_returnsLastBuildNumber() { + doReturn(lastSuccessfulBuild).when(project).getLastSuccessfulBuild(); + doReturn(action).when(lastSuccessfulBuild).getAction(PitBuildAction.class); + doReturn(10).when(lastSuccessfulBuild).getNumber(); + + Integer lastResultBuild = pitProjectAction.getLastResultBuild(); + assertEquals(10, lastResultBuild); + } + + @Test + void getIconFileName_returnsCorrectPath() { + String iconPath = pitProjectAction.getIconFileName(); + assertEquals("/plugin/pitmutation/pitest.png", iconPath); + } + + @Test + void getDisplayName_returnsCorrectName() { + String name = pitProjectAction.getDisplayName(); + assertEquals("PIT Mutation Report", name); + } + + @Test + void getSearchUrl_returnsCorrectUrl() { + String url = pitProjectAction.getSearchUrl(); + assertEquals("pitmutation", url); + } + + @Test + void isFloatingBoxActive_returnsTrue() { + assertTrue(pitProjectAction.isFloatingBoxActive()); + } + + @Test + void doIndex_redirectsCorrectly() throws IOException { + doReturn(lastSuccessfulBuild).when(project).getLastSuccessfulBuild(); + doReturn(action).when(lastSuccessfulBuild).getAction(PitBuildAction.class); + doReturn(10).when(lastSuccessfulBuild).getNumber(); + + pitProjectAction.doIndex(req, rsp); + + verify(rsp).sendRedirect2("../10/pitmutation"); + } + + @Test + void doIndex_buildNumberNull_redirectsCorrectly() throws IOException { + doReturn(null).when(project).getLastSuccessfulBuild(); + pitProjectAction.doIndex(req, rsp); + verify(rsp).sendRedirect2("nodata"); + } + + @Test + void doGraph_CallsDoGraphOnLastResult() throws IOException { + doReturn(lastSuccessfulBuild).when(project).getLastSuccessfulBuild(); + doReturn(action).when(lastSuccessfulBuild).getAction(PitBuildAction.class); + + pitProjectAction.doGraph(req, rsp); + + verify(action).doGraph(req, rsp); + } } diff --git a/src/test/java/org/jenkinsci/plugins/pitmutation/PitPublisherTest.java b/src/test/java/org/jenkinsci/plugins/pitmutation/PitPublisherTest.java index fdb74d2..97e0083 100644 --- a/src/test/java/org/jenkinsci/plugins/pitmutation/PitPublisherTest.java +++ b/src/test/java/org/jenkinsci/plugins/pitmutation/PitPublisherTest.java @@ -41,234 +41,236 @@ @ExtendWith(MockitoExtension.class) class PitPublisherTest { - private static final float MINIMUM_KILL_RATIO = 0.25f; - - @Mock - private PitBuildAction action; - @Mock - private ProjectMutations report; - @Mock - private MutationStats stats; - @Mock - private PitLogger pitLogger; - - @Mock - private FileProcessor fileProcessor; - - @Mock - private ResultDecider resultDecider; - - @Test - void ignoreMissingReports_ignore_noReports() throws Exception { - FileProcessor fileProcessor = mock(FileProcessor.class); - ResultDecider decider = mock(ResultDecider.class); - PitPublisher publisher = - new PitPublisher("**/mutations.xml", MINIMUM_KILL_RATIO, true, true, fileProcessor, decider, pitLogger); - TaskListener taskListener = mock(TaskListener.class); - Run build = mock(Run.class); - publisher.perform(build, mock(FilePath.class), mock(EnvVars.class), mock(Launcher.class), taskListener); - - verify(build).setResult(SUCCESS); - verify(pitLogger).logMissingReportsIgnored(any()); - } - - @Test - void ignoreMissingReports_doNotIgnore_noReports() throws Exception { - FileProcessor fileProcessor = mock(FileProcessor.class); - ResultDecider decider = mock(ResultDecider.class); - PitPublisher publisher = - new PitPublisher("**/mutations.xml", MINIMUM_KILL_RATIO, true, false, fileProcessor, decider, pitLogger); - TaskListener taskListener = mock(TaskListener.class); - Run build = mock(Run.class); - FilePath workspace = mock(FilePath.class); - when(workspace.act(any(FilePath.FileCallable.class))).thenReturn(new FilePath[]{mock(FilePath.class), mock(FilePath.class)}); - - publisher.perform(build, workspace, mock(EnvVars.class), mock(Launcher.class), taskListener); - - verify(build).setResult(FAILURE); - verify(pitLogger).logBuildFailedNoReports(any()); - } - - @Test - void oneReport_ioException() throws Exception { - FileProcessor fileProcessor = mock(FileProcessor.class); - ResultDecider decider = mock(ResultDecider.class); - PitPublisher publisher = new PitPublisher( - "./src/test/resources/org/jenkinsci/plugins/pitmutation/testmutations-00.xml", - MINIMUM_KILL_RATIO, - true, - false, - fileProcessor, - decider, - pitLogger); - TaskListener taskListener = mock(TaskListener.class); - FilePath workspace = mock(FilePath.class); - FilePath report = mock(FilePath.class); - when(report.exists()).thenReturn(true); - when(report.isDirectory()).thenReturn(false); - FilePath[] reports = {report}; - when(workspace.act(any(ParseReportCallable.class))).thenReturn(reports); - doThrow(IOException.class).when(fileProcessor).copySingleModuleReport(any(), any()); - Run build = mock(Run.class); - when(build.getRootDir()).thenReturn(new File("src/test/resources")); - publisher.perform(build, workspace, mock(EnvVars.class), mock(Launcher.class), taskListener); - - verify(build).setResult(FAILURE); - verify(pitLogger, never()).logResults(any(), any()); - } - - @Test - void oneReport() throws Exception { - FileProcessor fileProcessor = mock(FileProcessor.class); - ResultDecider decider = mock(ResultDecider.class); - PitPublisher publisher = new PitPublisher( - "./src/test/resources/org/jenkinsci/plugins/pitmutation/testmutations-00.xml", - MINIMUM_KILL_RATIO, - true, - false, - fileProcessor, - decider, - pitLogger); - TaskListener taskListener = mock(TaskListener.class); - FilePath workspace = mock(FilePath.class); - FilePath report = mock(FilePath.class); - when(report.exists()).thenReturn(true); - when(report.isDirectory()).thenReturn(false); - FilePath[] reports = {report}; - when(workspace.act(any(ParseReportCallable.class))).thenReturn(reports); - doNothing().when(fileProcessor).copySingleModuleReport(any(), any()); - Run build = mock(Run.class); - when(build.getRootDir()).thenReturn(new File("src/test/resources")); - when(decider.decideBuildResult(any())).thenReturn(SUCCESS); - publisher.perform(build, workspace, mock(EnvVars.class), mock(Launcher.class), taskListener); - - verify(build).setResult(SUCCESS); - verify(pitLogger).logResults(any(), any()); - } - - - @Test - void multiModuleReports() throws Exception { - FileProcessor fileProcessor = mock(FileProcessor.class); - ResultDecider decider = mock(ResultDecider.class); - PitPublisher publisher = new PitPublisher( - "./src/test/resources/org/jenkinsci/plugins/pitmutation/testmutations-00.xml", - MINIMUM_KILL_RATIO, - true, - false, - fileProcessor, - decider, - pitLogger); - TaskListener taskListener = mock(TaskListener.class); - FilePath workspace = mock(FilePath.class); - FilePath report1 = mock(FilePath.class); - when(report1.exists()).thenReturn(true); - when(report1.isDirectory()).thenReturn(false); - FilePath report2 = mock(FilePath.class); - when(report2.exists()).thenReturn(true); - when(report2.isDirectory()).thenReturn(false); - - FilePath[] reports = {report1, report2}; - when(workspace.act(any(ParseReportCallable.class))).thenReturn(reports); - when(fileProcessor.getNames(any(), any())).thenReturn(Map.of(mock(FilePath.class), - "1", - mock(FilePath.class), - "2")); - doNothing().when(fileProcessor).copyMultiModuleReport(any(), any(), any()); - Run build = mock(Run.class); - when(build.getRootDir()).thenReturn(new File("src/test/resources")); - when(decider.decideBuildResult(any())).thenReturn(SUCCESS); - publisher.perform(build, workspace, mock(EnvVars.class), mock(Launcher.class), taskListener); - - verify(build).setResult(SUCCESS); - verify(pitLogger).logResults(any(), any()); - } - - - @Test - void multiModuleReports_ioException() throws Exception { - FileProcessor fileProcessor = mock(FileProcessor.class); - ResultDecider decider = mock(ResultDecider.class); - PitPublisher publisher = new PitPublisher( - "./src/test/resources/org/jenkinsci/plugins/pitmutation/testmutations-00.xml", - MINIMUM_KILL_RATIO, - true, - false, - fileProcessor, - decider, - pitLogger); - TaskListener taskListener = mock(TaskListener.class); - FilePath workspace = mock(FilePath.class); - FilePath report1 = mock(FilePath.class); - when(report1.exists()).thenReturn(true); - when(report1.isDirectory()).thenReturn(false); - - FilePath report2 = mock(FilePath.class); - when(report2.exists()).thenReturn(true); - when(report2.isDirectory()).thenReturn(false); - - FilePath[] reports = {report1, report2}; - when(workspace.act(any(ParseReportCallable.class))).thenReturn(reports); - when(fileProcessor.getNames(any(), any())).thenReturn(Map.of(mock(FilePath.class), - "1", - mock(FilePath.class), - "2")); - doThrow(IOException.class).when(fileProcessor).copyMultiModuleReport(any(), any(), any()); - Run build = mock(Run.class); - when(build.getRootDir()).thenReturn(new File("src/test/resources")); - publisher.perform(build, workspace, mock(EnvVars.class), mock(Launcher.class), taskListener); - - verify(build).setResult(FAILURE); - verify(pitLogger, never()).logResults(any(), any()); - } - @Test - void getMinimumKillRatio() { - PitPublisher pitPublisher = new PitPublisher("target/pit-reports/mutations.xml", 0.5f, false, false); - assertEquals(0.5f, pitPublisher.getMinimumKillRatio()); - } - - @Test - void getKillRatioMustImprove() { - PitPublisher pitPublisher = new PitPublisher("target/pit-reports/mutations.xml", 0.5f, true, false); - assertTrue(pitPublisher.getKillRatioMustImprove()); - } - - @Test - void getIgnoreMissingReports() { - PitPublisher pitPublisher = new PitPublisher("target/pit-reports/mutations.xml", 0.5f, false, true); - assertTrue(pitPublisher.getIgnoreMissingReports()); - } - - @Test - void setIgnoreMissingReports_true() { - PitPublisher pitPublisher = new PitPublisher("target/pit-reports/mutations.xml", 0.5f, false, false); - pitPublisher.setIgnoreMissingReports(true); - assertTrue(pitPublisher.getIgnoreMissingReports()); - } - - @Test - void setIgnoreMissingReports_false() { - PitPublisher pitPublisher = new PitPublisher("target/pit-reports/mutations.xml", 0.5f, false, true); - pitPublisher.setIgnoreMissingReports(false); - assertFalse(pitPublisher.getIgnoreMissingReports()); - } - - @Test - void getProjectAction() { - PitPublisher pitPublisher = new PitPublisher("target/pit-reports/mutations.xml", 0.5f, false, true); - Action projectAction = pitPublisher.getProjectAction((AbstractProject) mock(Project.class)); - assertNotNull(projectAction); - } - - @Test - void getMutationStatsFile() { - PitPublisher pitPublisher = new PitPublisher("target/pit-reports/mutations.xml", 0.5f, false, true); - assertEquals("target/pit-reports/mutations.xml", pitPublisher.getMutationStatsFile()); - } - - @Test - void getRequiredMonitorService() { - PitPublisher pitPublisher = new PitPublisher("target/pit-reports/mutations.xml", 0.5f, false, true); - assertEquals(STEP, pitPublisher.getRequiredMonitorService()); - } + private static final float MINIMUM_KILL_RATIO = 0.25f; + + @Mock + private PitBuildAction action; + @Mock + private ProjectMutations report; + @Mock + private MutationStats stats; + @Mock + private PitLogger pitLogger; + + @Mock + private FileProcessor fileProcessor; + + @Mock + private ResultDecider resultDecider; + + @Test + void ignoreMissingReports_ignore_noReports() throws Exception { + FileProcessor fileProcessor = mock(FileProcessor.class); + ResultDecider decider = mock(ResultDecider.class); + PitPublisher publisher = + new PitPublisher("**/mutations.xml", MINIMUM_KILL_RATIO, true, true, fileProcessor, decider, pitLogger); + TaskListener taskListener = mock(TaskListener.class); + Run build = mock(Run.class); + publisher.perform(build, mock(FilePath.class), mock(EnvVars.class), mock(Launcher.class), taskListener); + + verify(build).setResult(SUCCESS); + verify(pitLogger).logMissingReportsIgnored(any()); + } + + @Test + void ignoreMissingReports_doNotIgnore_noReports() throws Exception { + FileProcessor fileProcessor = mock(FileProcessor.class); + ResultDecider decider = mock(ResultDecider.class); + PitPublisher publisher = + new PitPublisher("**/mutations.xml", MINIMUM_KILL_RATIO, true, false, fileProcessor, decider, pitLogger); + TaskListener taskListener = mock(TaskListener.class); + Run build = mock(Run.class); + FilePath workspace = mock(FilePath.class); + when(workspace.act(any(FilePath.FileCallable.class))).thenReturn(new FilePath[]{mock(FilePath.class), + mock(FilePath.class)}); + + publisher.perform(build, workspace, mock(EnvVars.class), mock(Launcher.class), taskListener); + + verify(build).setResult(FAILURE); + verify(pitLogger).logBuildFailedNoReports(any()); + } + + @Test + void oneReport_ioException() throws Exception { + FileProcessor fileProcessor = mock(FileProcessor.class); + ResultDecider decider = mock(ResultDecider.class); + PitPublisher publisher = new PitPublisher( + "./src/test/resources/org/jenkinsci/plugins/pitmutation/testmutations-00.xml", + MINIMUM_KILL_RATIO, + true, + false, + fileProcessor, + decider, + pitLogger); + TaskListener taskListener = mock(TaskListener.class); + FilePath workspace = mock(FilePath.class); + FilePath report = mock(FilePath.class); + when(report.exists()).thenReturn(true); + when(report.isDirectory()).thenReturn(false); + FilePath[] reports = {report}; + when(workspace.act(any(ParseReportCallable.class))).thenReturn(reports); + doThrow(IOException.class).when(fileProcessor).copySingleModuleReport(any(), any()); + Run build = mock(Run.class); + when(build.getRootDir()).thenReturn(new File("src/test/resources")); + publisher.perform(build, workspace, mock(EnvVars.class), mock(Launcher.class), taskListener); + + verify(build).setResult(FAILURE); + verify(pitLogger, never()).logResults(any(), any()); + } + + @Test + void oneReport() throws Exception { + FileProcessor fileProcessor = mock(FileProcessor.class); + ResultDecider decider = mock(ResultDecider.class); + PitPublisher publisher = new PitPublisher( + "./src/test/resources/org/jenkinsci/plugins/pitmutation/testmutations-00.xml", + MINIMUM_KILL_RATIO, + true, + false, + fileProcessor, + decider, + pitLogger); + TaskListener taskListener = mock(TaskListener.class); + FilePath workspace = mock(FilePath.class); + FilePath report = mock(FilePath.class); + when(report.exists()).thenReturn(true); + when(report.isDirectory()).thenReturn(false); + FilePath[] reports = {report}; + when(workspace.act(any(ParseReportCallable.class))).thenReturn(reports); + doNothing().when(fileProcessor).copySingleModuleReport(any(), any()); + Run build = mock(Run.class); + when(build.getRootDir()).thenReturn(new File("src/test/resources")); + when(decider.decideBuildResult(any())).thenReturn(SUCCESS); + publisher.perform(build, workspace, mock(EnvVars.class), mock(Launcher.class), taskListener); + + verify(build).setResult(SUCCESS); + verify(pitLogger).logResults(any(), any()); + } + + + @Test + void multiModuleReports() throws Exception { + FileProcessor fileProcessor = mock(FileProcessor.class); + ResultDecider decider = mock(ResultDecider.class); + PitPublisher publisher = new PitPublisher( + "./src/test/resources/org/jenkinsci/plugins/pitmutation/testmutations-00.xml", + MINIMUM_KILL_RATIO, + true, + false, + fileProcessor, + decider, + pitLogger); + TaskListener taskListener = mock(TaskListener.class); + FilePath workspace = mock(FilePath.class); + FilePath report1 = mock(FilePath.class); + when(report1.exists()).thenReturn(true); + when(report1.isDirectory()).thenReturn(false); + FilePath report2 = mock(FilePath.class); + when(report2.exists()).thenReturn(true); + when(report2.isDirectory()).thenReturn(false); + + FilePath[] reports = {report1, report2}; + when(workspace.act(any(ParseReportCallable.class))).thenReturn(reports); + when(fileProcessor.getNames(any(), any())).thenReturn(Map.of(mock(FilePath.class), + "1", + mock(FilePath.class), + "2")); + doNothing().when(fileProcessor).copyMultiModuleReport(any(), any(), any()); + Run build = mock(Run.class); + when(build.getRootDir()).thenReturn(new File("src/test/resources")); + when(decider.decideBuildResult(any())).thenReturn(SUCCESS); + publisher.perform(build, workspace, mock(EnvVars.class), mock(Launcher.class), taskListener); + + verify(build).setResult(SUCCESS); + verify(pitLogger).logResults(any(), any()); + } + + + @Test + void multiModuleReports_ioException() throws Exception { + FileProcessor fileProcessor = mock(FileProcessor.class); + ResultDecider decider = mock(ResultDecider.class); + PitPublisher publisher = new PitPublisher( + "./src/test/resources/org/jenkinsci/plugins/pitmutation/testmutations-00.xml", + MINIMUM_KILL_RATIO, + true, + false, + fileProcessor, + decider, + pitLogger); + TaskListener taskListener = mock(TaskListener.class); + FilePath workspace = mock(FilePath.class); + FilePath report1 = mock(FilePath.class); + when(report1.exists()).thenReturn(true); + when(report1.isDirectory()).thenReturn(false); + + FilePath report2 = mock(FilePath.class); + when(report2.exists()).thenReturn(true); + when(report2.isDirectory()).thenReturn(false); + + FilePath[] reports = {report1, report2}; + when(workspace.act(any(ParseReportCallable.class))).thenReturn(reports); + when(fileProcessor.getNames(any(), any())).thenReturn(Map.of(mock(FilePath.class), + "1", + mock(FilePath.class), + "2")); + doThrow(IOException.class).when(fileProcessor).copyMultiModuleReport(any(), any(), any()); + Run build = mock(Run.class); + when(build.getRootDir()).thenReturn(new File("src/test/resources")); + publisher.perform(build, workspace, mock(EnvVars.class), mock(Launcher.class), taskListener); + + verify(build).setResult(FAILURE); + verify(pitLogger, never()).logResults(any(), any()); + } + + @Test + void getMinimumKillRatio() { + PitPublisher pitPublisher = new PitPublisher("target/pit-reports/mutations.xml", 0.5f, false, false); + assertEquals(0.5f, pitPublisher.getMinimumKillRatio()); + } + + @Test + void getKillRatioMustImprove() { + PitPublisher pitPublisher = new PitPublisher("target/pit-reports/mutations.xml", 0.5f, true, false); + assertTrue(pitPublisher.getKillRatioMustImprove()); + } + + @Test + void getIgnoreMissingReports() { + PitPublisher pitPublisher = new PitPublisher("target/pit-reports/mutations.xml", 0.5f, false, true); + assertTrue(pitPublisher.getIgnoreMissingReports()); + } + + @Test + void setIgnoreMissingReports_true() { + PitPublisher pitPublisher = new PitPublisher("target/pit-reports/mutations.xml", 0.5f, false, false); + pitPublisher.setIgnoreMissingReports(true); + assertTrue(pitPublisher.getIgnoreMissingReports()); + } + + @Test + void setIgnoreMissingReports_false() { + PitPublisher pitPublisher = new PitPublisher("target/pit-reports/mutations.xml", 0.5f, false, true); + pitPublisher.setIgnoreMissingReports(false); + assertFalse(pitPublisher.getIgnoreMissingReports()); + } + + @Test + void getProjectAction() { + PitPublisher pitPublisher = new PitPublisher("target/pit-reports/mutations.xml", 0.5f, false, true); + Action projectAction = pitPublisher.getProjectAction((AbstractProject) mock(Project.class)); + assertNotNull(projectAction); + } + + @Test + void getMutationStatsFile() { + PitPublisher pitPublisher = new PitPublisher("target/pit-reports/mutations.xml", 0.5f, false, true); + assertEquals("target/pit-reports/mutations.xml", pitPublisher.getMutationStatsFile()); + } + + @Test + void getRequiredMonitorService() { + PitPublisher pitPublisher = new PitPublisher("target/pit-reports/mutations.xml", 0.5f, false, true); + assertEquals(STEP, pitPublisher.getRequiredMonitorService()); + } } diff --git a/src/test/java/org/jenkinsci/plugins/pitmutation/ResultDeciderTest.java b/src/test/java/org/jenkinsci/plugins/pitmutation/ResultDeciderTest.java index 64c601f..78efd6a 100644 --- a/src/test/java/org/jenkinsci/plugins/pitmutation/ResultDeciderTest.java +++ b/src/test/java/org/jenkinsci/plugins/pitmutation/ResultDeciderTest.java @@ -16,31 +16,34 @@ class ResultDeciderTest { - @TestFactory - Stream testFactory() { - // Create a collection of inputs for the test. - Collection inputs = Arrays.asList(new Object[][] { - {SUCCESS, SUCCESS, SUCCESS}, - {FAILURE, SUCCESS, FAILURE}, - {SUCCESS, FAILURE, FAILURE}, - {FAILURE, FAILURE, FAILURE} - }); + @TestFactory + Stream testFactory() { + // Create a collection of inputs for the test. + Collection inputs = Arrays.asList(new Object[][]{{SUCCESS, SUCCESS, SUCCESS}, + {FAILURE, SUCCESS, FAILURE}, + {SUCCESS, FAILURE, FAILURE}, + {FAILURE, FAILURE, FAILURE}}); - // Create and return the dynamic tests. - return inputs.stream().map(input -> DynamicTest.dynamicTest( - "Testing with thresholdResult = " + input[0] + ", mustImproveResult = " + input[1], - () -> runTest((Result) input[0], (Result) input[1], (Result) input[2]) - )); - } + // Create and return the dynamic tests. + return inputs + .stream() + .map(input -> DynamicTest.dynamicTest("Testing with thresholdResult = " + + input[0] + + ", mustImproveResult = " + + input[1], + () -> runTest((Result) input[0], + (Result) input[1], + (Result) input[2]))); + } - private void runTest(Result thresholdResult, Result mustImproveResult, Result expectedResult) { - PercentageThresholdCondition thresholdCondition = mock(PercentageThresholdCondition.class); - MustImproveCondition mustImproveCondition = mock(MustImproveCondition.class); - PitBuildAction action = mock(PitBuildAction.class); - when(thresholdCondition.decideResult(action)).thenReturn(thresholdResult); - when(mustImproveCondition.decideResult(action)).thenReturn(mustImproveResult); - ResultDecider decider = new ResultDecider(thresholdCondition, mustImproveCondition); - Result result = decider.decideBuildResult(action); - assertEquals(expectedResult, result); - } + private void runTest(Result thresholdResult, Result mustImproveResult, Result expectedResult) { + PercentageThresholdCondition thresholdCondition = mock(PercentageThresholdCondition.class); + MustImproveCondition mustImproveCondition = mock(MustImproveCondition.class); + PitBuildAction action = mock(PitBuildAction.class); + when(thresholdCondition.decideResult(action)).thenReturn(thresholdResult); + when(mustImproveCondition.decideResult(action)).thenReturn(mustImproveResult); + ResultDecider decider = new ResultDecider(thresholdCondition, mustImproveCondition); + Result result = decider.decideBuildResult(action); + assertEquals(expectedResult, result); + } } diff --git a/src/test/java/org/jenkinsci/plugins/pitmutation/portlets/CoverageRangeTest.java b/src/test/java/org/jenkinsci/plugins/pitmutation/portlets/CoverageRangeTest.java index 965607e..2331d31 100644 --- a/src/test/java/org/jenkinsci/plugins/pitmutation/portlets/CoverageRangeTest.java +++ b/src/test/java/org/jenkinsci/plugins/pitmutation/portlets/CoverageRangeTest.java @@ -19,170 +19,170 @@ class CoverageRangeTest { - @Test - void valueOfLessTHanZeroReturnsAbysmal() { - assertThat(CoverageRange.valueOf(-1D), is(ABYSMAL)); - } - - @Test - void valueOfZeroReturnsAbysmal() { - assertThat(CoverageRange.valueOf(0D), is(ABYSMAL)); - } - - @Test - void valueOfTwentyFiveReturnsTragic() { - assertThat(CoverageRange.valueOf(25D), is(TRAGIC)); - } - - @Test - void valueOfFiftyReturnsPoor() { - assertThat(CoverageRange.valueOf(50D), is(AVERAGE)); - } - - @Test - void valueOfSeventyFiveReturnsFair() { - assertThat(CoverageRange.valueOf(75D), is(SUFFICIENT)); - } - - @Test - void valueOfEightyFiveReturnsSufficient() { - assertThat(CoverageRange.valueOf(85D), is(GOOD)); - } - - @Test - void valueOfNinetyTwoReturnsGood() { - assertThat(CoverageRange.valueOf(92D), is(EXCELLENT)); - } - - @Test - void valueOfNinetySevenReturnsExcellent() { - assertThat(CoverageRange.valueOf(97D), is(EXCELLENT)); - } - - @Test - void valueOfOneHundredReturnsPerfect() { - assertThat(CoverageRange.valueOf(100D), is(PERFECT)); - } - - @Test - void valueOfOneHundredAndOneReturnsPerfect() { - assertThat(CoverageRange.valueOf(101D), is(PERFECT)); - } - - @Test - void getFillHexStringForAbysmal() { - assertThat(ABYSMAL.getFillHexString(), is("FF0000")); - } - - @Test - void getFillHexStringForTragic() { - assertThat(TRAGIC.getFillHexString(), is("FF4500")); - } - - @Test - void getFillHexStringForPoor() { - assertThat(POOR.getFillHexString(), is("FF7F00")); - } - - @Test - void getFillHexStringForFair() { - assertThat(FAIR.getFillHexString(), is("FFFF00")); - } - - @Test - void getFillHexStringForSufficient() { - assertThat(SUFFICIENT.getFillHexString(), is("C8FF3F")); - } - - @Test - void getFillHexStringForGood() { - assertThat(GOOD.getFillHexString(), is("7AFF3F")); - } - - @Test - void getFillHexStringForExcellent() { - assertThat(EXCELLENT.getFillHexString(), is("00CD00")); - } - - @Test - void getFillHexStringForPerfect() { - assertThat(PERFECT.getFillHexString(), is("008B00")); - } - - @Test - void getLineHexStringForAbysmal() { - assertThat(ABYSMAL.getLineHexString(), is("EEEEEE")); - } - - @Test - void getLineHexStringForTragic() { - assertThat(TRAGIC.getLineHexString(), is("EEEEEE")); - } - - @Test - void getLineHexStringForPoor() { - assertThat(POOR.getLineHexString(), is("000000")); - } - - @Test - void getLineHexStringForFair() { - assertThat(FAIR.getLineHexString(), is("000000")); - } - - @Test - void getLineHexStringForSufficient() { - assertThat(SUFFICIENT.getLineHexString(), is("000000")); - } - - @Test - void getLineHexStringForGood() { - assertThat(GOOD.getLineHexString(), is("000000")); - } - - @Test - void getLineHexStringForExcellent() { - assertThat(EXCELLENT.getLineHexString(), is("000000")); - } - - @Test - void getLineHexStringForPerfect() { - assertThat(PERFECT.getLineHexString(), is("EEEEEE")); - } - - @Test - void fillColorOfMinusOneReturnsAbysmalFloor() { - assertThat(CoverageRange.fillColorOf(-1D), is(new Color(255, 0, 0))); - } - - @Test - void fillColorOfThirtyReturnsProportionateBlend() { - assertThat(CoverageRange.fillColorOf(30D), is(new Color(255, 88, 0))); - } - - @Test - void fillColorOfThirtySevenFiveReturnsProportionateBlend() { - assertThat(CoverageRange.fillColorOf(37.5), is(new Color(255, 117, 0))); - } - - @Test - void fillColorOfFortyFiveReturnsProportionateBlend() { - assertThat(CoverageRange.fillColorOf(45D), is(new Color(255, 146, 0))); - } - - @Test - void fillColorOfFiftyFloorFillColor() { - assertThat(CoverageRange.fillColorOf(50D), is(new Color(255, 165, 0))); - } - - @Test - void fillColorOfOneHundredAndOneReturnsPerfectFloor() { - assertThat(CoverageRange.fillColorOf(101D), is(new Color(0, 139, 0))); - } - - @Test - void colorAsHexString() { - Color color = new Color(0, 128, 255); - assertThat(CoverageRange.colorAsHexString(color), is("0080FF")); - } + @Test + void valueOfLessTHanZeroReturnsAbysmal() { + assertThat(CoverageRange.valueOf(-1D), is(ABYSMAL)); + } + + @Test + void valueOfZeroReturnsAbysmal() { + assertThat(CoverageRange.valueOf(0D), is(ABYSMAL)); + } + + @Test + void valueOfTwentyFiveReturnsTragic() { + assertThat(CoverageRange.valueOf(25D), is(TRAGIC)); + } + + @Test + void valueOfFiftyReturnsPoor() { + assertThat(CoverageRange.valueOf(50D), is(AVERAGE)); + } + + @Test + void valueOfSeventyFiveReturnsFair() { + assertThat(CoverageRange.valueOf(75D), is(SUFFICIENT)); + } + + @Test + void valueOfEightyFiveReturnsSufficient() { + assertThat(CoverageRange.valueOf(85D), is(GOOD)); + } + + @Test + void valueOfNinetyTwoReturnsGood() { + assertThat(CoverageRange.valueOf(92D), is(EXCELLENT)); + } + + @Test + void valueOfNinetySevenReturnsExcellent() { + assertThat(CoverageRange.valueOf(97D), is(EXCELLENT)); + } + + @Test + void valueOfOneHundredReturnsPerfect() { + assertThat(CoverageRange.valueOf(100D), is(PERFECT)); + } + + @Test + void valueOfOneHundredAndOneReturnsPerfect() { + assertThat(CoverageRange.valueOf(101D), is(PERFECT)); + } + + @Test + void getFillHexStringForAbysmal() { + assertThat(ABYSMAL.getFillHexString(), is("FF0000")); + } + + @Test + void getFillHexStringForTragic() { + assertThat(TRAGIC.getFillHexString(), is("FF4500")); + } + + @Test + void getFillHexStringForPoor() { + assertThat(POOR.getFillHexString(), is("FF7F00")); + } + + @Test + void getFillHexStringForFair() { + assertThat(FAIR.getFillHexString(), is("FFFF00")); + } + + @Test + void getFillHexStringForSufficient() { + assertThat(SUFFICIENT.getFillHexString(), is("C8FF3F")); + } + + @Test + void getFillHexStringForGood() { + assertThat(GOOD.getFillHexString(), is("7AFF3F")); + } + + @Test + void getFillHexStringForExcellent() { + assertThat(EXCELLENT.getFillHexString(), is("00CD00")); + } + + @Test + void getFillHexStringForPerfect() { + assertThat(PERFECT.getFillHexString(), is("008B00")); + } + + @Test + void getLineHexStringForAbysmal() { + assertThat(ABYSMAL.getLineHexString(), is("EEEEEE")); + } + + @Test + void getLineHexStringForTragic() { + assertThat(TRAGIC.getLineHexString(), is("EEEEEE")); + } + + @Test + void getLineHexStringForPoor() { + assertThat(POOR.getLineHexString(), is("000000")); + } + + @Test + void getLineHexStringForFair() { + assertThat(FAIR.getLineHexString(), is("000000")); + } + + @Test + void getLineHexStringForSufficient() { + assertThat(SUFFICIENT.getLineHexString(), is("000000")); + } + + @Test + void getLineHexStringForGood() { + assertThat(GOOD.getLineHexString(), is("000000")); + } + + @Test + void getLineHexStringForExcellent() { + assertThat(EXCELLENT.getLineHexString(), is("000000")); + } + + @Test + void getLineHexStringForPerfect() { + assertThat(PERFECT.getLineHexString(), is("EEEEEE")); + } + + @Test + void fillColorOfMinusOneReturnsAbysmalFloor() { + assertThat(CoverageRange.fillColorOf(-1D), is(new Color(255, 0, 0))); + } + + @Test + void fillColorOfThirtyReturnsProportionateBlend() { + assertThat(CoverageRange.fillColorOf(30D), is(new Color(255, 88, 0))); + } + + @Test + void fillColorOfThirtySevenFiveReturnsProportionateBlend() { + assertThat(CoverageRange.fillColorOf(37.5), is(new Color(255, 117, 0))); + } + + @Test + void fillColorOfFortyFiveReturnsProportionateBlend() { + assertThat(CoverageRange.fillColorOf(45D), is(new Color(255, 146, 0))); + } + + @Test + void fillColorOfFiftyFloorFillColor() { + assertThat(CoverageRange.fillColorOf(50D), is(new Color(255, 165, 0))); + } + + @Test + void fillColorOfOneHundredAndOneReturnsPerfectFloor() { + assertThat(CoverageRange.fillColorOf(101D), is(new Color(0, 139, 0))); + } + + @Test + void colorAsHexString() { + Color color = new Color(0, 128, 255); + assertThat(CoverageRange.colorAsHexString(color), is("0080FF")); + } } diff --git a/src/test/java/org/jenkinsci/plugins/pitmutation/targets/MutationResultTest.java b/src/test/java/org/jenkinsci/plugins/pitmutation/targets/MutationResultTest.java index 4343414..e9b0736 100644 --- a/src/test/java/org/jenkinsci/plugins/pitmutation/targets/MutationResultTest.java +++ b/src/test/java/org/jenkinsci/plugins/pitmutation/targets/MutationResultTest.java @@ -25,148 +25,146 @@ */ public abstract class MutationResultTest { - private MutationResult projectResult; - private MutationResult moduleResult; - - @BeforeEach - public void setUp() throws IOException, SAXException { - MutationReport reportOld = - new MutationReport(MutationReport.class.getResourceAsStream("testmutations-00.xml")); - MutationReport reportNew = - new MutationReport(MutationReport.class.getResourceAsStream("testmutations-01.xml")); - Map reportsNew = new HashMap<>(); - Map reportsOld = new HashMap<>(); - reportsNew.put("test_report", reportNew); - reportsOld.put("test_report", reportOld); - - PitBuildAction buildAction = mock(PitBuildAction.class); - when(buildAction.getReports()).thenReturn(reportsNew); - - PitBuildAction previousBuildAction = mock(PitBuildAction.class); - when(previousBuildAction.getReports()).thenReturn(reportsOld); - when(previousBuildAction.getReport()).thenReturn(new ProjectMutations(previousBuildAction)); - - when(buildAction.getPreviousAction()).thenReturn(previousBuildAction); - - projectResult = new ProjectMutations(buildAction); - moduleResult = projectResult.getChildMap().get("test_report"); - assertThat(moduleResult, not(nullValue())); - assertThat(projectResult.getPreviousResult(), not(nullValue())); - } - - @Test - void mutationResultStatsDelta() { - MutationStats delta = projectResult.getStatsDelta(); - assertThat(delta.getTotalMutations(), is(3)); - assertThat(delta.getKillCount(), is(-1)); - } - - private MutationResult packageResult() { - return projectResult.getChildResult("test_report").getChildResult("org.jenkinsci.plugins.pitmutation"); - } - - @Test - void packageResultsStatsDelta() { - MutationStats delta = packageResult().getStatsDelta(); - assertThat(delta.getTotalMutations(), is(3)); - assertThat(delta.getKillCount(), is(-1)); - } - - private MutationResult classResult(String className) { - return packageResult().getChildResult(className); - } - - @Test - void classResultsStats() { - MutationStats stats = classResult("org.jenkinsci.plugins.pitmutation.Mutation").getMutationStats(); - assertThat(stats.getTotalMutations(), is(3)); - assertThat(stats.getKillCount(), is(1)); - } - - @Test - void classResultsStatsDelta() { - MutationStats delta = classResult("org.jenkinsci.plugins.pitmutation.Mutation").getStatsDelta(); - assertThat(delta.getTotalMutations(), is(-1)); - assertThat(delta.getKillCount(), is(-2)); - } - - @Test - void classResultsForNewClass() { - MutationStats stats = classResult("org.jenkinsci.plugins.pitmutation.NewMutatedClass").getMutationStats(); - assertThat(stats.getTotalMutations(), is(1)); - assertThat(stats.getKillCount(), is(0)); - } - - @Test - void classResultsForNewClassDelta() { - MutationStats stats = classResult("org.jenkinsci.plugins.pitmutation.NewMutatedClass").getStatsDelta(); - assertThat(stats.getTotalMutations(), is(1)); - assertThat(stats.getKillCount(), is(0)); - } - - @Test - void classResultsOrdered() { - Iterator classes = moduleResult.getChildren().iterator(); - int undetected = classes.next().getMutationStats().getUndetected(); - - while (classes.hasNext()) { - MutationResult result = classes.next(); - assertThat(result.getMutationStats().getUndetected(), lessThan(undetected)); - undetected = result.getMutationStats().getUndetected(); - } - } - - @Test - void urlTransformPackageName() { - assertThat(moduleResult.getChildMap().get("org.jenkinsci.plugins.pitmutation").getUrl(), - is("org_jenkinsci_plugins_pitmutation")); - } - - @Test - void urlTransformClassName() { - assertThat(moduleResult - .getChildMap() - .get("org.jenkinsci.plugins.pitmutation") - .getChildMap() - .get("org.jenkinsci.plugins.pitmutation.PitParser") - .getUrl(), is("org_jenkinsci_plugins_pitmutation_PitParser")); - } - - @Test - void findsMutationsOnPitParserClass() { - MutationResult pitPackage = moduleResult.getChildMap().get("org.jenkinsci.plugins.pitmutation"); - assertThat(pitPackage.getChildren(), hasSize(5)); - MutationResult pitParser = pitPackage.getChildMap().get("org.jenkinsci.plugins.pitmutation.PitParser"); - assertThat(pitParser.getChildren(), hasSize(3)); - } - - @Test - void collectsMutationStats() { - MutationStats stats = projectResult.getMutationStats(); - assertThat(stats.getTotalMutations(), is(19)); - assertThat(stats.getUndetected(), is(15)); - } - - @Test - void correctSourceLevels() { - MutationResult pitPackage = moduleResult.getChildMap().get("org.jenkinsci.plugins.pitmutation"); - MutationResult pitParser = pitPackage.getChildMap().get("org.jenkinsci.plugins.pitmutation.PitParser"); - MutationResult lineResult = pitParser.getChildMap().values().iterator().next(); - - assertThat(projectResult.isSourceLevel(), is(false)); - assertThat(moduleResult.isSourceLevel(), is(false)); - assertThat(pitPackage.isSourceLevel(), is(false)); - assertThat(pitParser.isSourceLevel(), is(true)); - assertThat(lineResult.isSourceLevel(), is(false)); - } - - @Test - void testXmlTransform() { - assertThat(MutationResult.xmlTransform("replace&and"), is("replace&and<and>")); - } - - @Test - void testUrlTransform() { - assertThat(MutationResult.urlTransform("^*!replace::non+'alphas@}129"), is("___replace__non__alphas__129")); - } + private MutationResult projectResult; + private MutationResult moduleResult; + + @BeforeEach + public void setUp() throws IOException, SAXException { + MutationReport reportOld = new MutationReport(MutationReport.class.getResourceAsStream("testmutations-00.xml")); + MutationReport reportNew = new MutationReport(MutationReport.class.getResourceAsStream("testmutations-01.xml")); + Map reportsNew = new HashMap<>(); + Map reportsOld = new HashMap<>(); + reportsNew.put("test_report", reportNew); + reportsOld.put("test_report", reportOld); + + PitBuildAction buildAction = mock(PitBuildAction.class); + when(buildAction.getReports()).thenReturn(reportsNew); + + PitBuildAction previousBuildAction = mock(PitBuildAction.class); + when(previousBuildAction.getReports()).thenReturn(reportsOld); + when(previousBuildAction.getReport()).thenReturn(new ProjectMutations(previousBuildAction)); + + when(buildAction.getPreviousAction()).thenReturn(previousBuildAction); + + projectResult = new ProjectMutations(buildAction); + moduleResult = projectResult.getChildMap().get("test_report"); + assertThat(moduleResult, not(nullValue())); + assertThat(projectResult.getPreviousResult(), not(nullValue())); + } + + @Test + void mutationResultStatsDelta() { + MutationStats delta = projectResult.getStatsDelta(); + assertThat(delta.getTotalMutations(), is(3)); + assertThat(delta.getKillCount(), is(-1)); + } + + private MutationResult packageResult() { + return projectResult.getChildResult("test_report").getChildResult("org.jenkinsci.plugins.pitmutation"); + } + + @Test + void packageResultsStatsDelta() { + MutationStats delta = packageResult().getStatsDelta(); + assertThat(delta.getTotalMutations(), is(3)); + assertThat(delta.getKillCount(), is(-1)); + } + + private MutationResult classResult(String className) { + return packageResult().getChildResult(className); + } + + @Test + void classResultsStats() { + MutationStats stats = classResult("org.jenkinsci.plugins.pitmutation.Mutation").getMutationStats(); + assertThat(stats.getTotalMutations(), is(3)); + assertThat(stats.getKillCount(), is(1)); + } + + @Test + void classResultsStatsDelta() { + MutationStats delta = classResult("org.jenkinsci.plugins.pitmutation.Mutation").getStatsDelta(); + assertThat(delta.getTotalMutations(), is(-1)); + assertThat(delta.getKillCount(), is(-2)); + } + + @Test + void classResultsForNewClass() { + MutationStats stats = classResult("org.jenkinsci.plugins.pitmutation.NewMutatedClass").getMutationStats(); + assertThat(stats.getTotalMutations(), is(1)); + assertThat(stats.getKillCount(), is(0)); + } + + @Test + void classResultsForNewClassDelta() { + MutationStats stats = classResult("org.jenkinsci.plugins.pitmutation.NewMutatedClass").getStatsDelta(); + assertThat(stats.getTotalMutations(), is(1)); + assertThat(stats.getKillCount(), is(0)); + } + + @Test + void classResultsOrdered() { + Iterator classes = moduleResult.getChildren().iterator(); + int undetected = classes.next().getMutationStats().getUndetected(); + + while (classes.hasNext()) { + MutationResult result = classes.next(); + assertThat(result.getMutationStats().getUndetected(), lessThan(undetected)); + undetected = result.getMutationStats().getUndetected(); + } + } + + @Test + void urlTransformPackageName() { + assertThat(moduleResult.getChildMap().get("org.jenkinsci.plugins.pitmutation").getUrl(), + is("org_jenkinsci_plugins_pitmutation")); + } + + @Test + void urlTransformClassName() { + assertThat(moduleResult + .getChildMap() + .get("org.jenkinsci.plugins.pitmutation") + .getChildMap() + .get("org.jenkinsci.plugins.pitmutation.PitParser") + .getUrl(), is("org_jenkinsci_plugins_pitmutation_PitParser")); + } + + @Test + void findsMutationsOnPitParserClass() { + MutationResult pitPackage = moduleResult.getChildMap().get("org.jenkinsci.plugins.pitmutation"); + assertThat(pitPackage.getChildren(), hasSize(5)); + MutationResult pitParser = pitPackage.getChildMap().get("org.jenkinsci.plugins.pitmutation.PitParser"); + assertThat(pitParser.getChildren(), hasSize(3)); + } + + @Test + void collectsMutationStats() { + MutationStats stats = projectResult.getMutationStats(); + assertThat(stats.getTotalMutations(), is(19)); + assertThat(stats.getUndetected(), is(15)); + } + + @Test + void correctSourceLevels() { + MutationResult pitPackage = moduleResult.getChildMap().get("org.jenkinsci.plugins.pitmutation"); + MutationResult pitParser = pitPackage.getChildMap().get("org.jenkinsci.plugins.pitmutation.PitParser"); + MutationResult lineResult = pitParser.getChildMap().values().iterator().next(); + + assertThat(projectResult.isSourceLevel(), is(false)); + assertThat(moduleResult.isSourceLevel(), is(false)); + assertThat(pitPackage.isSourceLevel(), is(false)); + assertThat(pitParser.isSourceLevel(), is(true)); + assertThat(lineResult.isSourceLevel(), is(false)); + } + + @Test + void testXmlTransform() { + assertThat(MutationResult.xmlTransform("replace&and"), is("replace&and<and>")); + } + + @Test + void testUrlTransform() { + assertThat(MutationResult.urlTransform("^*!replace::non+'alphas@}129"), is("___replace__non__alphas__129")); + } }