From dc5c058484a1ec8436e4c7cbfd31614ba4d911b8 Mon Sep 17 00:00:00 2001 From: Ulli Hafner Date: Mon, 23 Sep 2024 10:04:03 +0200 Subject: [PATCH] Fix ErrorProne warnings. - Add english locale to format strings. - Regenerate equals --- .../hm/hafner/grading/AggregatedScore.java | 48 +++++--------- .../hafner/grading/AnalysisConfiguration.java | 6 +- .../hm/hafner/grading/AnalysisMarkdown.java | 8 +-- .../edu/hm/hafner/grading/AnalysisScore.java | 2 +- .../edu/hm/hafner/grading/CommentBuilder.java | 54 +++++++++++++-- .../edu/hm/hafner/grading/Configuration.java | 32 +++------ .../hafner/grading/CoverageConfiguration.java | 20 +++--- .../edu/hm/hafner/grading/CoverageScore.java | 2 +- .../FileSystemCoverageReportFactory.java | 2 +- .../grading/MutationCoverageMarkdown.java | 4 +- .../edu/hm/hafner/grading/ReportFinder.java | 10 +-- .../java/edu/hm/hafner/grading/Score.java | 66 ++++++++++++++----- .../edu/hm/hafner/grading/ScoreMarkdown.java | 46 ++++++++++++- .../edu/hm/hafner/grading/TestMarkdown.java | 17 +++-- .../java/edu/hm/hafner/grading/TestScore.java | 6 +- .../hm/hafner/grading/ToolConfiguration.java | 33 ++++------ .../grading/AutoGradingRunnerITest.java | 3 +- .../hm/hafner/grading/CoverageScoreTest.java | 3 +- .../hm/hafner/grading/ReportFinderTest.java | 10 +-- .../edu/hm/hafner/grading/TestScoreTest.java | 3 +- 20 files changed, 225 insertions(+), 150 deletions(-) diff --git a/src/main/java/edu/hm/hafner/grading/AggregatedScore.java b/src/main/java/edu/hm/hafner/grading/AggregatedScore.java index b04944bf..9e285af6 100644 --- a/src/main/java/edu/hm/hafner/grading/AggregatedScore.java +++ b/src/main/java/edu/hm/hafner/grading/AggregatedScore.java @@ -6,6 +6,7 @@ import java.util.Collection; import java.util.HashMap; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.NoSuchElementException; import java.util.Objects; @@ -23,6 +24,7 @@ import edu.hm.hafner.grading.CoverageScore.CoverageScoreBuilder; import edu.hm.hafner.grading.TestScore.TestScoreBuilder; import edu.hm.hafner.util.FilteredLog; +import edu.hm.hafner.util.Generated; /** * Stores the scores of an autograding run. Persists the configuration and the scores for each metric. @@ -343,7 +345,8 @@ public List getAnalysisScores() { return List.copyOf(analysisScores); } - @Override @SuppressWarnings("PMD.NPathComplexity") + @Override + @Generated public boolean equals(final Object o) { if (this == o) { return true; @@ -351,45 +354,26 @@ public boolean equals(final Object o) { if (o == null || getClass() != o.getClass()) { return false; } - - AggregatedScore that = (AggregatedScore) o; - - if (!Objects.equals(log, that.log)) { - return false; - } - if (!testScores.equals(that.testScores)) { - return false; - } - if (!coverageScores.equals(that.coverageScores)) { - return false; - } - if (!analysisScores.equals(that.analysisScores)) { - return false; - } - if (!Objects.equals(testConfigurations, that.testConfigurations)) { - return false; - } - if (!Objects.equals(coverageConfigurations, that.coverageConfigurations)) { - return false; - } - return Objects.equals(analysisConfigurations, that.analysisConfigurations); + var that = (AggregatedScore) o; + return Objects.equals(log, that.log) + && Objects.equals(testScores, that.testScores) + && Objects.equals(coverageScores, that.coverageScores) + && Objects.equals(analysisScores, that.analysisScores) + && Objects.equals(testConfigurations, that.testConfigurations) + && Objects.equals(coverageConfigurations, that.coverageConfigurations) + && Objects.equals(analysisConfigurations, that.analysisConfigurations); } @Override + @Generated public int hashCode() { - int result = log != null ? log.hashCode() : 0; - result = 31 * result + testScores.hashCode(); - result = 31 * result + coverageScores.hashCode(); - result = 31 * result + analysisScores.hashCode(); - result = 31 * result + (testConfigurations != null ? testConfigurations.hashCode() : 0); - result = 31 * result + (coverageConfigurations != null ? coverageConfigurations.hashCode() : 0); - result = 31 * result + (analysisConfigurations != null ? analysisConfigurations.hashCode() : 0); - return result; + return Objects.hash(log, testScores, coverageScores, analysisScores, testConfigurations, coverageConfigurations, + analysisConfigurations); } @Override public String toString() { - return String.format("Score: %d / %d", getAchievedScore(), getMaxScore()); + return String.format(Locale.ENGLISH, "Score: %d / %d", getAchievedScore(), getMaxScore()); } /** diff --git a/src/main/java/edu/hm/hafner/grading/AnalysisConfiguration.java b/src/main/java/edu/hm/hafner/grading/AnalysisConfiguration.java index 4a213f74..ffd915b4 100644 --- a/src/main/java/edu/hm/hafner/grading/AnalysisConfiguration.java +++ b/src/main/java/edu/hm/hafner/grading/AnalysisConfiguration.java @@ -6,6 +6,8 @@ import com.fasterxml.jackson.annotation.JsonIgnore; +import edu.hm.hafner.util.Generated; + /** * Configuration to grade static analysis results. The configuration specifies the impact of the static analysis results * on the score. This class is intended to be deserialized from JSON, there is no public constructor available. @@ -72,6 +74,7 @@ public int getLowImpact() { } @Override + @Generated public boolean equals(final Object o) { if (this == o) { return true; @@ -82,7 +85,7 @@ public boolean equals(final Object o) { if (!super.equals(o)) { return false; } - AnalysisConfiguration that = (AnalysisConfiguration) o; + var that = (AnalysisConfiguration) o; return errorImpact == that.errorImpact && highImpact == that.highImpact && normalImpact == that.normalImpact @@ -90,6 +93,7 @@ public boolean equals(final Object o) { } @Override + @Generated public int hashCode() { return Objects.hash(super.hashCode(), errorImpact, highImpact, normalImpact, lowImpact); } diff --git a/src/main/java/edu/hm/hafner/grading/AnalysisMarkdown.java b/src/main/java/edu/hm/hafner/grading/AnalysisMarkdown.java index 5d01f112..4afcbfad 100644 --- a/src/main/java/edu/hm/hafner/grading/AnalysisMarkdown.java +++ b/src/main/java/edu/hm/hafner/grading/AnalysisMarkdown.java @@ -90,7 +90,7 @@ protected String extractSeverities(final AnalysisScore score) { return "No warnings"; } else { - return String.format("%d warning%s (%d error%s, %d high, %d normal, %d low)", + return format("%d warning%s (%d error%s, %d high, %d normal, %d low)", score.getTotalSize(), AnalysisScore.plural(score.getTotalSize()), score.getErrorSize(), AnalysisScore.plural(score.getErrorSize()), score.getHighSeveritySize(), @@ -114,7 +114,7 @@ protected String createSummary(final AnalysisScore score) { } private String getIconAndName(final AnalysisScore analysisScore) { - return " %s   %s".formatted(extractParserIcon(analysisScore), analysisScore.getName()) + return format(" %s   %s", extractParserIcon(analysisScore), analysisScore.getName()) + createScoreTitle(analysisScore); } @@ -124,8 +124,8 @@ private String extractParserIcon(final AnalysisScore analysisScore) { return getIcon(analysisScore); } else { - return "\"%s\"" - .formatted(descriptor.getIconUrl(), analysisScore.getName(), ICON_SIZE, ICON_SIZE); + return format("\"%s\"", + descriptor.getIconUrl(), analysisScore.getName(), ICON_SIZE, ICON_SIZE); } } } diff --git a/src/main/java/edu/hm/hafner/grading/AnalysisScore.java b/src/main/java/edu/hm/hafner/grading/AnalysisScore.java index eef680c5..84141f4c 100644 --- a/src/main/java/edu/hm/hafner/grading/AnalysisScore.java +++ b/src/main/java/edu/hm/hafner/grading/AnalysisScore.java @@ -122,7 +122,7 @@ protected String createSummary() { return "No warnings"; } else { - return String.format("%d warning%s (%d error%s, %d high, %d normal, %d low)", + return format("%d warning%s (%d error%s, %d high, %d normal, %d low)", getTotalSize(), plural(getTotalSize()), getErrorSize(), plural(getErrorSize()), getHighSeveritySize(), getNormalSeveritySize(), getLowSeveritySize()); diff --git a/src/main/java/edu/hm/hafner/grading/CommentBuilder.java b/src/main/java/edu/hm/hafner/grading/CommentBuilder.java index c496209e..6efc0d23 100644 --- a/src/main/java/edu/hm/hafner/grading/CommentBuilder.java +++ b/src/main/java/edu/hm/hafner/grading/CommentBuilder.java @@ -5,12 +5,15 @@ import java.util.Arrays; import java.util.Collection; import java.util.List; +import java.util.Locale; import java.util.Map.Entry; import java.util.Set; import java.util.stream.Collectors; import org.apache.commons.lang3.StringUtils; +import com.google.errorprone.annotations.FormatMethod; + import edu.hm.hafner.analysis.Issue; import edu.hm.hafner.analysis.registry.ParserRegistry; import edu.hm.hafner.coverage.FileNode; @@ -229,9 +232,9 @@ private String getMissedLinesMessage(final LineRange range) { private String getMissedLinesDescription(final LineRange range) { if (range.getStart() == range.getEnd()) { - return String.format("Line %d is not covered by tests", range.getStart()); + return format("Line %d is not covered by tests", range.getStart()); } - return String.format("Lines %d-%d are not covered by tests", range.getStart(), range.getEnd()); + return format("Lines %d-%d are not covered by tests", range.getStart(), range.getEnd()); } private void createAnnotationsForPartiallyCoveredLines(final AggregatedScore score, @@ -257,9 +260,9 @@ private void createAnnotationForMissedBranches(final FileNode file, private String createBranchMessage(final int line, final int missed) { if (missed == 1) { - return String.format("Line %d is only partially covered, one branch is missing", line); + return format("Line %d is only partially covered, one branch is missing", line); } - return String.format("Line %d is only partially covered, %d branches are missing", line, missed); + return format("Line %d is only partially covered, %d branches are missing", line, missed); } private String createRelativeRepositoryPath(final String fileName, final Set sourcePaths) { @@ -303,9 +306,9 @@ private void createAnnotationForSurvivedMutation(final FileNode file, private String createMutationMessage(final int line, final List survived) { if (survived.size() == 1) { - return String.format("One mutation survived in line %d (%s)", line, formatMutator(survived)); + return format("One mutation survived in line %d (%s)", line, formatMutator(survived)); } - return String.format("%d mutations survived in line %d", survived.size(), line); + return format("%d mutations survived in line %d", survived.size(), line); } private String formatMutator(final List survived) { @@ -314,7 +317,44 @@ private String formatMutator(final List survived) { private String createMutationDetails(final List mutations) { return mutations.stream() - .map(mutation -> String.format("- %s (%s)", mutation.getDescription(), mutation.getMutator())) + .map(mutation -> format("- %s (%s)", mutation.getDescription(), mutation.getMutator())) .collect(Collectors.joining("\n", "Survived mutations:\n", "")); } + + /** + * Returns a formatted string using the specified format string and + * arguments. The English locale is always used to format the string. + * + * @param format + * A format string + * + * @param args + * Arguments referenced by the format specifiers in the format + * string. If there are more arguments than format specifiers, the + * extra arguments are ignored. The number of arguments is + * variable and may be zero. The maximum number of arguments is + * limited by the maximum dimension of a Java array as defined by + * The Java Virtual Machine Specification. + * The behaviour on a + * {@code null} argument depends on the conversion. + * + * @throws java.util.IllegalFormatException + * If a format string contains an illegal syntax, a format + * specifier that is incompatible with the given arguments, + * insufficient arguments given the format string, or other + * illegal conditions. For specification of all possible + * formatting errors, see the Details section of the + * formatter class specification. + * + * @return A formatted string + * + * @see java.util.Formatter + * @since 1.5 + */ + @FormatMethod + protected String format(final String format, final Object... args) { + return String.format(Locale.ENGLISH, format, args); + } } diff --git a/src/main/java/edu/hm/hafner/grading/Configuration.java b/src/main/java/edu/hm/hafner/grading/Configuration.java index da56d609..923f819a 100644 --- a/src/main/java/edu/hm/hafner/grading/Configuration.java +++ b/src/main/java/edu/hm/hafner/grading/Configuration.java @@ -12,6 +12,7 @@ import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.databind.JsonNode; +import edu.hm.hafner.util.Generated; import edu.umd.cs.findbugs.annotations.CheckForNull; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; @@ -130,6 +131,7 @@ private void validateDefaults() { // protected abstract void validate(); @Override + @Generated public boolean equals(final Object o) { if (this == o) { return true; @@ -137,32 +139,18 @@ public boolean equals(final Object o) { if (o == null || getClass() != o.getClass()) { return false; } - - Configuration that = (Configuration) o; - - if (maxScore != that.maxScore) { - return false; - } - if (!Objects.equals(id, that.id)) { - return false; - } - if (!Objects.equals(name, that.name)) { - return false; - } - if (!Objects.equals(icon, that.icon)) { - return false; - } - return Objects.equals(tools, that.tools); + var that = (Configuration) o; + return maxScore == that.maxScore + && Objects.equals(id, that.id) + && Objects.equals(name, that.name) + && Objects.equals(icon, that.icon) + && Objects.equals(tools, that.tools); } @Override + @Generated public int hashCode() { - int result = id != null ? id.hashCode() : 0; - result = 31 * result + (name != null ? name.hashCode() : 0); - result = 31 * result + (icon != null ? icon.hashCode() : 0); - result = 31 * result + maxScore; - result = 31 * result + (tools != null ? tools.hashCode() : 0); - return result; + return Objects.hash(id, name, icon, maxScore, tools); } @Override diff --git a/src/main/java/edu/hm/hafner/grading/CoverageConfiguration.java b/src/main/java/edu/hm/hafner/grading/CoverageConfiguration.java index d337da1b..8c1d9a6d 100644 --- a/src/main/java/edu/hm/hafner/grading/CoverageConfiguration.java +++ b/src/main/java/edu/hm/hafner/grading/CoverageConfiguration.java @@ -2,11 +2,14 @@ import java.io.Serial; import java.util.List; +import java.util.Objects; import org.apache.commons.lang3.StringUtils; import com.fasterxml.jackson.annotation.JsonIgnore; +import edu.hm.hafner.util.Generated; + /** * Configuration to grade code coverage results. The configuration specifies the impact of the coverage results on the * score. This class is intended to be deserialized from JSON, there is no public constructor available. @@ -80,6 +83,7 @@ public boolean isMutationCoverage() { } @Override + @Generated public boolean equals(final Object o) { if (this == o) { return true; @@ -90,20 +94,14 @@ public boolean equals(final Object o) { if (!super.equals(o)) { return false; } - - CoverageConfiguration that = (CoverageConfiguration) o; - - if (coveredPercentageImpact != that.coveredPercentageImpact) { - return false; - } - return missedPercentageImpact == that.missedPercentageImpact; + var that = (CoverageConfiguration) o; + return coveredPercentageImpact == that.coveredPercentageImpact + && missedPercentageImpact == that.missedPercentageImpact; } @Override + @Generated public int hashCode() { - int result = super.hashCode(); - result = 31 * result + coveredPercentageImpact; - result = 31 * result + missedPercentageImpact; - return result; + return Objects.hash(super.hashCode(), coveredPercentageImpact, missedPercentageImpact); } } diff --git a/src/main/java/edu/hm/hafner/grading/CoverageScore.java b/src/main/java/edu/hm/hafner/grading/CoverageScore.java index 091e5d2b..7f7ee779 100644 --- a/src/main/java/edu/hm/hafner/grading/CoverageScore.java +++ b/src/main/java/edu/hm/hafner/grading/CoverageScore.java @@ -157,7 +157,7 @@ public int getMissedPercentage() { @Override protected String createSummary() { - return String.format("%d%% (%d %s)", getCoveredPercentage(), getMissedItems(), getItemName()); + return format("%d%% (%d %s)", getCoveredPercentage(), getMissedItems(), getItemName()); } private String getItemName() { diff --git a/src/main/java/edu/hm/hafner/grading/FileSystemCoverageReportFactory.java b/src/main/java/edu/hm/hafner/grading/FileSystemCoverageReportFactory.java index fdc0961f..b1ff2062 100644 --- a/src/main/java/edu/hm/hafner/grading/FileSystemCoverageReportFactory.java +++ b/src/main/java/edu/hm/hafner/grading/FileSystemCoverageReportFactory.java @@ -30,7 +30,7 @@ public Node create(final ToolConfiguration tool, final FilteredLog log) { var parser = new ParserRegistry().get(StringUtils.upperCase(tool.getId()), ProcessingMode.IGNORE_ERRORS); var nodes = new ArrayList(); - for (Path file : REPORT_FINDER.find(tool, log)) { + for (Path file : REPORT_FINDER.find(log, tool)) { var node = parser.parse(new FileReaderFactory(file).create(), file.toString(), log); log.logInfo("- %s: %s", PATH_UTIL.getRelativePath(file), extractMetric(tool, node)); nodes.add(node); diff --git a/src/main/java/edu/hm/hafner/grading/MutationCoverageMarkdown.java b/src/main/java/edu/hm/hafner/grading/MutationCoverageMarkdown.java index 03a1a0a6..68815cfc 100644 --- a/src/main/java/edu/hm/hafner/grading/MutationCoverageMarkdown.java +++ b/src/main/java/edu/hm/hafner/grading/MutationCoverageMarkdown.java @@ -26,8 +26,8 @@ protected List createScores(final AggregatedScore aggregation) { @Override protected String getIcon(final CoverageScore score) { if (score.getId().equals("pit")) { - return "\"PIT\"" - .formatted(ICON_SIZE, ICON_SIZE); + return format("\"PIT\"", + ICON_SIZE, ICON_SIZE); } else { return super.getIcon(score); diff --git a/src/main/java/edu/hm/hafner/grading/ReportFinder.java b/src/main/java/edu/hm/hafner/grading/ReportFinder.java index 469cf905..a5eadeb6 100644 --- a/src/main/java/edu/hm/hafner/grading/ReportFinder.java +++ b/src/main/java/edu/hm/hafner/grading/ReportFinder.java @@ -25,14 +25,14 @@ class ReportFinder { /** * Finds reports for the specified tool. * - * @param tool - * the tool to find the reports for * @param log * logger + * @param tool + * the tool to find the reports for * * @return the paths */ - List find(final ToolConfiguration tool, final FilteredLog log) { + List find(final FilteredLog log, final ToolConfiguration tool) { var displayName = tool.getDisplayName(); var pattern = tool.getPattern(); @@ -41,7 +41,7 @@ List find(final ToolConfiguration tool, final FilteredLog log) { List find(final FilteredLog log, final String displayName, final String pattern) { log.logInfo("Searching for %s results matching file name pattern %s", displayName, pattern); - List files = find("glob:" + pattern, ".", log); + List files = findGlob("glob:" + pattern, ".", log); if (files.isEmpty()) { log.logError("No matching report files found when using pattern '%s'! " @@ -53,7 +53,7 @@ List find(final FilteredLog log, final String displayName, final String pa } @VisibleForTesting - List find(final String pattern, final String directory, final FilteredLog log) { + List findGlob(final String pattern, final String directory, final FilteredLog log) { try { var visitor = new PathMatcherFileVisitor(pattern); Files.walkFileTree(Paths.get(directory), visitor); diff --git a/src/main/java/edu/hm/hafner/grading/Score.java b/src/main/java/edu/hm/hafner/grading/Score.java index 6d6312c6..c77da627 100644 --- a/src/main/java/edu/hm/hafner/grading/Score.java +++ b/src/main/java/edu/hm/hafner/grading/Score.java @@ -4,8 +4,11 @@ import java.io.Serializable; import java.util.Arrays; import java.util.List; +import java.util.Locale; import java.util.Objects; +import com.google.errorprone.annotations.FormatMethod; + import edu.hm.hafner.util.Ensure; import edu.hm.hafner.util.Generated; @@ -123,7 +126,45 @@ public int getPercentage() { */ protected abstract String createSummary(); + /** + * Returns a formatted string using the specified format string and + * arguments. The English locale is always used to format the string. + * + * @param format + * A format string + * + * @param args + * Arguments referenced by the format specifiers in the format + * string. If there are more arguments than format specifiers, the + * extra arguments are ignored. The number of arguments is + * variable and may be zero. The maximum number of arguments is + * limited by the maximum dimension of a Java array as defined by + * The Java Virtual Machine Specification. + * The behaviour on a + * {@code null} argument depends on the conversion. + * + * @throws java.util.IllegalFormatException + * If a format string contains an illegal syntax, a format + * specifier that is incompatible with the given arguments, + * insufficient arguments given the format string, or other + * illegal conditions. For specification of all possible + * formatting errors, see the Details section of the + * formatter class specification. + * + * @return A formatted string + * + * @see java.util.Formatter + * @since 1.5 + */ + @FormatMethod + protected String format(final String format, final Object... args) { + return String.format(Locale.ENGLISH, format, args); + } + @Override + @Generated public boolean equals(final Object o) { if (this == o) { return true; @@ -131,28 +172,17 @@ public boolean equals(final Object o) { if (o == null || getClass() != o.getClass()) { return false; } - - Score score = (Score) o; - - if (!id.equals(score.id)) { - return false; - } - if (!name.equals(score.name)) { - return false; - } - if (!configuration.equals(score.configuration)) { - return false; - } - return subScores.equals(score.subScores); + var score = (Score) o; + return Objects.equals(id, score.id) + && Objects.equals(name, score.name) + && Objects.equals(configuration, score.configuration) + && Objects.equals(subScores, score.subScores); } @Override + @Generated public int hashCode() { - int result = id.hashCode(); - result = 31 * result + name.hashCode(); - result = 31 * result + configuration.hashCode(); - result = 31 * result + subScores.hashCode(); - return result; + return Objects.hash(id, name, configuration, subScores); } @Override diff --git a/src/main/java/edu/hm/hafner/grading/ScoreMarkdown.java b/src/main/java/edu/hm/hafner/grading/ScoreMarkdown.java index f2f2f5e9..416fffca 100644 --- a/src/main/java/edu/hm/hafner/grading/ScoreMarkdown.java +++ b/src/main/java/edu/hm/hafner/grading/ScoreMarkdown.java @@ -2,11 +2,14 @@ import java.util.Arrays; import java.util.List; +import java.util.Locale; import java.util.function.Function; import java.util.stream.Collectors; import org.apache.commons.lang3.StringUtils; +import com.google.errorprone.annotations.FormatMethod; + import edu.hm.hafner.grading.TruncatedString.TruncatedStringBuilder; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; @@ -60,7 +63,7 @@ public static String getPercentageImage(final String title, final int percentage if (percentage < 0 || percentage > HUNDRED_PERCENT) { throw new IllegalArgumentException("Percentage must be between 0 and 100: " + percentage); } - return String.format(""" + return format(""" %s: %d%% @@ -156,9 +159,9 @@ static String createScoreTitleSuffix(final int maxScore, final int value, final return StringUtils.EMPTY; } if (maxScore == HUNDRED_PERCENT) { - return String.format(" - %d of %d", value, maxScore); // no need to show percentage for a score of 100 + return format(" - %d of %d", value, maxScore); // no need to show percentage for a score of 100 } - return String.format(" - %d of %d (%d%%)", value, maxScore, percentage); + return format(" - %d of %d (%d%%)", value, maxScore, percentage); } protected String getIcon(final S score) { @@ -177,6 +180,43 @@ String formatBoldColumns(final Object... columns) { return format(s -> "**" + s + "**", columns); } + /** + * Returns a formatted string using the specified format string and + * arguments. The English locale is always used to format the string. + * + * @param format + * A format string + * + * @param args + * Arguments referenced by the format specifiers in the format + * string. If there are more arguments than format specifiers, the + * extra arguments are ignored. The number of arguments is + * variable and may be zero. The maximum number of arguments is + * limited by the maximum dimension of a Java array as defined by + * The Java Virtual Machine Specification. + * The behaviour on a + * {@code null} argument depends on the conversion. + * + * @throws java.util.IllegalFormatException + * If a format string contains an illegal syntax, a format + * specifier that is incompatible with the given arguments, + * insufficient arguments given the format string, or other + * illegal conditions. For specification of all possible + * formatting errors, see the Details section of the + * formatter class specification. + * + * @return A formatted string + * + * @see java.util.Formatter + * @since 1.5 + */ + @FormatMethod + protected static String format(final String format, final Object... args) { + return String.format(Locale.ENGLISH, format, args); + } + private String format(final Function textFormatter, final Object... columns) { return Arrays.stream(columns) .map(Object::toString) diff --git a/src/main/java/edu/hm/hafner/grading/TestMarkdown.java b/src/main/java/edu/hm/hafner/grading/TestMarkdown.java index b984d498..449dac14 100644 --- a/src/main/java/edu/hm/hafner/grading/TestMarkdown.java +++ b/src/main/java/edu/hm/hafner/grading/TestMarkdown.java @@ -99,16 +99,16 @@ protected void createSpecificDetails(final AggregatedScore aggregation, } private String renderSkippedTest(final TestCase issue) { - return String.format("- %s#%s%n", issue.getClassName(), issue.getTestName()); + return format("- %s#%s%n", issue.getClassName(), issue.getTestName()); } @SuppressFBWarnings(value = "VA_FORMAT_STRING_USES_NEWLINE", justification = "Output is Unix anyway") private String renderFailure(final TestCase issue) { - return String.format("__%s:%s__", issue.getClassName(), issue.getTestName()) + return format("__%s:%s__", issue.getClassName(), issue.getTestName()) + LINE_BREAK + getMessage(issue) - + String.format(""" + + format("""
Stack Trace @@ -117,8 +117,7 @@ private String renderFailure(final TestCase issue) { ```
- """, - issue.getDescription()) + """, issue.getDescription()) + LINE_BREAK; } @@ -141,16 +140,16 @@ protected String createSummary(final TestScore score) { .append(getTitle(score, 0)); if (score.hasFailures() || score.hasPassedTests() || score.hasSkippedTests()) { summary.append(": ").append( - "%2d %% successful".formatted(Math.round(score.getPassedSize() * 100.0 / score.getTotalSize()))); + format("%2d %% successful", Math.round(score.getPassedSize() * 100.0 / score.getTotalSize()))); var joiner = new StringJoiner(", ", " (", ")"); if (score.hasFailures()) { - joiner.add(":x: %d failed".formatted(score.getFailedSize())); + joiner.add(format(":x: %d failed", score.getFailedSize())); } if (score.hasPassedTests()) { - joiner.add(":heavy_check_mark: %d passed".formatted(score.getPassedSize())); + joiner.add(format(":heavy_check_mark: %d passed", score.getPassedSize())); } if (score.hasSkippedTests()) { - joiner.add(":see_no_evil: %d skipped".formatted(score.getSkippedSize())); + joiner.add(format(":see_no_evil: %d skipped", score.getSkippedSize())); } summary.append(joiner).append(LINE_BREAK); } diff --git a/src/main/java/edu/hm/hafner/grading/TestScore.java b/src/main/java/edu/hm/hafner/grading/TestScore.java index 65a90346..46fc20cb 100644 --- a/src/main/java/edu/hm/hafner/grading/TestScore.java +++ b/src/main/java/edu/hm/hafner/grading/TestScore.java @@ -178,13 +178,13 @@ protected String createSummary() { var summary = new StringBuilder(CAPACITY); if (hasFailures()) { summary.append( - String.format("%d tests failed, %d passed", getFailedSize(), getPassedSize())); + format("%d tests failed, %d passed", getFailedSize(), getPassedSize())); } else { - summary.append(String.format("%d tests passed", getPassedSize())); + summary.append(format("%d tests passed", getPassedSize())); } if (getSkippedSize() > 0) { - summary.append(String.format(", %d skipped", getSkippedSize())); + summary.append(format(", %d skipped", getSkippedSize())); } return summary.toString(); } diff --git a/src/main/java/edu/hm/hafner/grading/ToolConfiguration.java b/src/main/java/edu/hm/hafner/grading/ToolConfiguration.java index 02140f86..77080e9f 100644 --- a/src/main/java/edu/hm/hafner/grading/ToolConfiguration.java +++ b/src/main/java/edu/hm/hafner/grading/ToolConfiguration.java @@ -6,6 +6,8 @@ import org.apache.commons.lang3.StringUtils; +import edu.hm.hafner.util.Generated; + /** * A tool configuration provides an identifier and report pattern for a specific development tool. * @@ -80,6 +82,7 @@ public String getMetric() { } @Override + @Generated public boolean equals(final Object o) { if (this == o) { return true; @@ -87,32 +90,18 @@ public boolean equals(final Object o) { if (o == null || getClass() != o.getClass()) { return false; } - - ToolConfiguration that = (ToolConfiguration) o; - - if (!Objects.equals(id, that.id)) { - return false; - } - if (!Objects.equals(name, that.name)) { - return false; - } - if (!Objects.equals(pattern, that.pattern)) { - return false; - } - if (!Objects.equals(sourcePath, that.sourcePath)) { - return false; - } - return Objects.equals(metric, that.metric); + var that = (ToolConfiguration) o; + return Objects.equals(id, that.id) + && Objects.equals(name, that.name) + && Objects.equals(pattern, that.pattern) + && Objects.equals(sourcePath, that.sourcePath) + && Objects.equals(metric, that.metric); } @Override + @Generated public int hashCode() { - int result = id != null ? id.hashCode() : 0; - result = 31 * result + (name != null ? name.hashCode() : 0); - result = 31 * result + (pattern != null ? pattern.hashCode() : 0); - result = 31 * result + (sourcePath != null ? sourcePath.hashCode() : 0); - result = 31 * result + (metric != null ? metric.hashCode() : 0); - return result; + return Objects.hash(id, name, pattern, sourcePath, metric); } @Override diff --git a/src/test/java/edu/hm/hafner/grading/AutoGradingRunnerITest.java b/src/test/java/edu/hm/hafner/grading/AutoGradingRunnerITest.java index a1a02f14..f887e9b1 100644 --- a/src/test/java/edu/hm/hafner/grading/AutoGradingRunnerITest.java +++ b/src/test/java/edu/hm/hafner/grading/AutoGradingRunnerITest.java @@ -5,6 +5,7 @@ import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; +import java.util.Locale; import org.junit.jupiter.api.Test; import org.junitpioneer.jupiter.SetEnvironmentVariable; @@ -346,7 +347,7 @@ public List getComments() { protected void createComment(final CommentType commentType, final String relativePath, final int lineStart, final int lineEnd, final String message, final String title, final int columnStart, final int columnEnd, final String details, final String markDownDetails) { - comments.add(String.format("[%s] %s:%d-%d: %s (%s)", commentType.name(), relativePath, lineStart, lineEnd, message, title)); + comments.add(String.format(Locale.ENGLISH, "[%s] %s:%d-%d: %s (%s)", commentType.name(), relativePath, lineStart, lineEnd, message, title)); } } } diff --git a/src/test/java/edu/hm/hafner/grading/CoverageScoreTest.java b/src/test/java/edu/hm/hafner/grading/CoverageScoreTest.java index 72c3e274..2f97e039 100644 --- a/src/test/java/edu/hm/hafner/grading/CoverageScoreTest.java +++ b/src/test/java/edu/hm/hafner/grading/CoverageScoreTest.java @@ -1,6 +1,7 @@ package edu.hm.hafner.grading; import java.util.List; +import java.util.Locale; import org.junit.jupiter.api.Test; @@ -131,7 +132,7 @@ private CoverageConfiguration createCoverageConfiguration(final int missedImpact @SuppressFBWarnings("VA_FORMAT_STRING_USES_NEWLINE") private CoverageConfiguration createCoverageConfiguration(final int missedImpact, final int coveredImpact, final int maxScore) { - return CoverageConfiguration.from(String.format(""" + return CoverageConfiguration.from(String.format(Locale.ENGLISH, """ { "coverage": { "tools": [ diff --git a/src/test/java/edu/hm/hafner/grading/ReportFinderTest.java b/src/test/java/edu/hm/hafner/grading/ReportFinderTest.java index 931c13e4..b0fa9cee 100644 --- a/src/test/java/edu/hm/hafner/grading/ReportFinderTest.java +++ b/src/test/java/edu/hm/hafner/grading/ReportFinderTest.java @@ -13,17 +13,17 @@ class ReportFinderTest { void shouldFindTestReports() { var finder = new ReportFinder(); - assertThat(finder.find("glob:**/TEST*.xml", "src/test/resources/", LOG)).hasSize(3); - assertThat(finder.find("glob:src/test/resources/**/*edu*.xml", "src/test/resources/", LOG)).hasSize(2); - assertThat(finder.find("glob:src/**/*.html", "src/test/resources/", LOG)).isEmpty(); + assertThat(finder.findGlob("glob:**/TEST*.xml", "src/test/resources/", LOG)).hasSize(3); + assertThat(finder.findGlob("glob:src/test/resources/**/*edu*.xml", "src/test/resources/", LOG)).hasSize(2); + assertThat(finder.findGlob("glob:src/**/*.html", "src/test/resources/", LOG)).isEmpty(); - assertThat(finder.find("glob:**/*.xml", "src/java/", LOG)).isEmpty(); + assertThat(finder.findGlob("glob:**/*.xml", "src/java/", LOG)).isEmpty(); } @Test void shouldFindSources() { var finder = new ReportFinder(); - assertThat(finder.find("regex:.*FileSystem.*\\.java", "src/main/java/", LOG)).hasSize(3); + assertThat(finder.findGlob("regex:.*FileSystem.*\\.java", "src/main/java/", LOG)).hasSize(3); } } diff --git a/src/test/java/edu/hm/hafner/grading/TestScoreTest.java b/src/test/java/edu/hm/hafner/grading/TestScoreTest.java index 709d3778..886be753 100644 --- a/src/test/java/edu/hm/hafner/grading/TestScoreTest.java +++ b/src/test/java/edu/hm/hafner/grading/TestScoreTest.java @@ -1,6 +1,7 @@ package edu.hm.hafner.grading; import java.util.List; +import java.util.Locale; import org.apache.commons.lang3.StringUtils; import org.junit.jupiter.api.Test; @@ -187,7 +188,7 @@ static ModuleNode createTestReport(final int passed, final int skipped, final in } static ModuleNode createTestReport(final int passed, final int skipped, final int failed, final String prefix) { - var root = new ModuleNode(String.format("%sTests (%d/%d/%d)", prefix, failed, skipped, passed)); + var root = new ModuleNode(String.format(Locale.ENGLISH, "%sTests (%d/%d/%d)", prefix, failed, skipped, passed)); var tests = new ClassNode("Tests"); root.addChild(tests);