From 807817a51667c29694b84a833bfc8ea915378224 Mon Sep 17 00:00:00 2001 From: Ulli Hafner Date: Fri, 15 Dec 2023 17:44:54 +0100 Subject: [PATCH 1/4] Create special markdown when no scores are set. --- .../hm/hafner/grading/AggregatedScore.java | 28 ++-- .../hm/hafner/grading/AnalysisMarkdown.java | 17 --- .../edu/hm/hafner/grading/AnalysisScore.java | 17 +++ .../hafner/grading/CodeCoverageMarkdown.java | 2 +- .../hafner/grading/CoverageConfiguration.java | 15 +- .../hm/hafner/grading/CoverageMarkdown.java | 14 +- .../edu/hm/hafner/grading/CoverageScore.java | 9 ++ .../edu/hm/hafner/grading/GradingReport.java | 53 ++++++- .../grading/MutationCoverageMarkdown.java | 2 +- .../java/edu/hm/hafner/grading/Score.java | 7 + .../edu/hm/hafner/grading/ScoreMarkdown.java | 30 ++-- .../edu/hm/hafner/grading/TestMarkdown.java | 14 -- .../java/edu/hm/hafner/grading/TestScore.java | 16 +++ .../hm/hafner/grading/GradingReportTest.java | 132 +++++++++++++++++- 14 files changed, 272 insertions(+), 84 deletions(-) diff --git a/src/main/java/edu/hm/hafner/grading/AggregatedScore.java b/src/main/java/edu/hm/hafner/grading/AggregatedScore.java index 12456d16..caec793f 100644 --- a/src/main/java/edu/hm/hafner/grading/AggregatedScore.java +++ b/src/main/java/edu/hm/hafner/grading/AggregatedScore.java @@ -183,14 +183,10 @@ public boolean hasMutationCoverage() { private List getMutationCoverageConfigurations() { return coverageConfigurations.stream() - .filter(configuration -> isMutation(configuration.getId(), configuration.getName())) + .filter(CoverageConfiguration::isMutationCoverage) .toList(); } - private boolean isMutation(final String id, final String name) { - return StringUtils.containsAnyIgnoreCase(id + name, CoverageConfiguration.MUTATION_IDS); - } - private List getCodeCoverageConfigurations() { List configurations = new ArrayList<>(coverageConfigurations); configurations.removeAll(getMutationCoverageConfigurations()); @@ -284,7 +280,7 @@ public List getCoverageScores() { */ public List getMutationCoverageScores() { return coverageScores.stream() - .filter(score -> isMutation(score.getId(), score.getName())) + .filter(score -> score.getConfiguration().isMutationCoverage()) .toList(); } @@ -413,8 +409,7 @@ public void gradeAnalysis(final AnalysisReportFactory factory) { analysisScores.add(aggregation); - log.logInfo("=> %s Score: %d of %d", analysisConfiguration.getName(), aggregation.getValue(), - aggregation.getMaxScore()); + logResult(analysisConfiguration, aggregation); } } @@ -448,8 +443,7 @@ public void gradeCoverage(final CoverageReportFactory factory) { coverageScores.add(aggregation); - log.logInfo("=> %s Score: %d of %d", coverageConfiguration.getName(), aggregation.getValue(), - aggregation.getMaxScore()); + logResult(coverageConfiguration, aggregation); } } @@ -483,8 +477,18 @@ public void gradeTests(final TestReportFactory factory) { testScores.add(aggregation); - log.logInfo("=> %s Score: %d of %d", testConfiguration.getName(), aggregation.getValue(), - aggregation.getMaxScore()); + logResult(testConfiguration, aggregation); + } + } + + private void logResult(final Configuration configuration, final Score score) { + if (configuration.getMaxScore() > 0) { + log.logInfo("=> %s Score: %d of %d", + configuration.getName(), score.getValue(), score.getMaxScore()); + } + else { + log.logInfo("=> %s: %s", + configuration.getName(), score.createSummary()); } } diff --git a/src/main/java/edu/hm/hafner/grading/AnalysisMarkdown.java b/src/main/java/edu/hm/hafner/grading/AnalysisMarkdown.java index b6db0289..2b904758 100644 --- a/src/main/java/edu/hm/hafner/grading/AnalysisMarkdown.java +++ b/src/main/java/edu/hm/hafner/grading/AnalysisMarkdown.java @@ -74,21 +74,4 @@ protected void createSpecificDetails(final AggregatedScore aggregation, final Li private int sum(final AggregatedScore score, final Function property) { return score.getAnalysisScores().stream().map(property).reduce(Integer::sum).orElse(0); } - - @Override - protected void createSpecificSummary(final AnalysisScore score, final StringBuilder summary) { - if (score.getReport().isEmpty()) { - summary.append("No warnings found"); - } - else { - summary.append(String.format("%d warning%s found (%d error%s, %d high, %d normal, %d low)", - score.getTotalSize(), plural(score.getTotalSize()), - score.getErrorSize(), plural(score.getErrorSize()), - score.getHighSeveritySize(), score.getNormalSeveritySize(), score.getLowSeveritySize())); - } - } - - private String plural(final int score) { - return score > 1 ? "s" : ""; - } } diff --git a/src/main/java/edu/hm/hafner/grading/AnalysisScore.java b/src/main/java/edu/hm/hafner/grading/AnalysisScore.java index 40ad166a..3318cd93 100644 --- a/src/main/java/edu/hm/hafner/grading/AnalysisScore.java +++ b/src/main/java/edu/hm/hafner/grading/AnalysisScore.java @@ -112,6 +112,23 @@ public int getTotalSize() { return getErrorSize() + getHighSeveritySize() + getNormalSeveritySize() + getLowSeveritySize(); } + @Override + protected String createSummary() { + if (getReport().isEmpty()) { + return "No warnings found"; + } + else { + return String.format("%d warning%s found (%d error%s, %d high, %d normal, %d low)", + getTotalSize(), plural(getTotalSize()), + getErrorSize(), plural(getErrorSize()), + getHighSeveritySize(), getNormalSeveritySize(), getLowSeveritySize()); + } + } + + private String plural(final int score) { + return score > 1 ? "s" : ""; + } + @Override @Generated public boolean equals(final Object o) { if (this == o) { diff --git a/src/main/java/edu/hm/hafner/grading/CodeCoverageMarkdown.java b/src/main/java/edu/hm/hafner/grading/CodeCoverageMarkdown.java index 9b77f28b..34c9dfb4 100644 --- a/src/main/java/edu/hm/hafner/grading/CodeCoverageMarkdown.java +++ b/src/main/java/edu/hm/hafner/grading/CodeCoverageMarkdown.java @@ -15,7 +15,7 @@ public class CodeCoverageMarkdown extends CoverageMarkdown { * Creates a new Markdown renderer for code coverage results. */ public CodeCoverageMarkdown() { - super(TYPE, "footprints", "Covered %", "Missed %", "coverage achieved"); + super(TYPE, "footprints", "Covered %", "Missed %"); } @Override diff --git a/src/main/java/edu/hm/hafner/grading/CoverageConfiguration.java b/src/main/java/edu/hm/hafner/grading/CoverageConfiguration.java index 1d26111a..1bac3606 100644 --- a/src/main/java/edu/hm/hafner/grading/CoverageConfiguration.java +++ b/src/main/java/edu/hm/hafner/grading/CoverageConfiguration.java @@ -18,7 +18,7 @@ public final class CoverageConfiguration extends Configuration { @Serial private static final long serialVersionUID = 3L; private static final String COVERAGE_ID = "coverage"; - static final String[] MUTATION_IDS = {"pitest", "mutation", "pit"}; + private static final String[] MUTATION_IDS = {"pitest", "mutation", "pit"}; /** * Converts the specified JSON object to a list of {@link CoverageConfiguration} instances. @@ -55,7 +55,8 @@ protected String getDefaultName() { return "Code Coverage"; } - @Override @JsonIgnore + @Override + @JsonIgnore public boolean isPositive() { return coveredPercentageImpact >= 0 && missedPercentageImpact >= 0; } @@ -68,6 +69,16 @@ public int getMissedPercentageImpact() { return missedPercentageImpact; } + /** + * Determines whether the specified ID or name are related to mutation coverage or to code coverage. + * + * @return {@code true} if this configuration is for mutation coverage, {@code false} if this configuration is for + * code coverage + */ + public boolean isMutationCoverage() { + return StringUtils.containsAnyIgnoreCase(getId() + getName(), CoverageConfiguration.MUTATION_IDS); + } + @Override public boolean equals(final Object o) { if (this == o) { diff --git a/src/main/java/edu/hm/hafner/grading/CoverageMarkdown.java b/src/main/java/edu/hm/hafner/grading/CoverageMarkdown.java index bc01898b..b5bd7576 100644 --- a/src/main/java/edu/hm/hafner/grading/CoverageMarkdown.java +++ b/src/main/java/edu/hm/hafner/grading/CoverageMarkdown.java @@ -13,15 +13,12 @@ abstract class CoverageMarkdown extends ScoreMarkdown { private final String coveredText; private final String missedText; - private final String summaryText; - CoverageMarkdown(final String type, final String icon, final String coveredText, final String missedText, - final String summaryText) { + CoverageMarkdown(final String type, final String icon, final String coveredText, final String missedText) { super(type, icon); this.coveredText = coveredText; this.missedText = missedText; - this.summaryText = summaryText; } @Override @@ -60,13 +57,4 @@ protected void createSpecificDetails(final AggregatedScore aggregation, final Li .addNewline(); } } - - @Override - protected void createSpecificSummary(final CoverageScore score, final StringBuilder summary) { - summary.append(String.format("%d%% %s", score.getCoveredPercentage(), getPlainText(summaryText))); - } - - private String getPlainText(final String label) { - return label.replace("%", ""); - } } diff --git a/src/main/java/edu/hm/hafner/grading/CoverageScore.java b/src/main/java/edu/hm/hafner/grading/CoverageScore.java index b953e464..a9c9aace 100644 --- a/src/main/java/edu/hm/hafner/grading/CoverageScore.java +++ b/src/main/java/edu/hm/hafner/grading/CoverageScore.java @@ -110,6 +110,15 @@ public int getMissedPercentage() { return 100 - coveredPercentage; } + @Override + protected String createSummary() { + return String.format("%d%% %s", getCoveredPercentage(), getItemName()); + } + + private String getItemName() { + return getConfiguration().isMutationCoverage() ? "mutations killed" : "coverage achieved"; + } + @Override @Generated public boolean equals(final Object o) { diff --git a/src/main/java/edu/hm/hafner/grading/GradingReport.java b/src/main/java/edu/hm/hafner/grading/GradingReport.java index 49429b8f..d65772c7 100644 --- a/src/main/java/edu/hm/hafner/grading/GradingReport.java +++ b/src/main/java/edu/hm/hafner/grading/GradingReport.java @@ -43,6 +43,18 @@ public String getTextSummary(final AggregatedScore score, final String title) { return createTotal(score, title); } + /** + * Creates a summary of the grading results in Markdown. + * + * @param score + * the aggregated score + * + * @return Markdown text + */ + public String getMarkdownSummary(final AggregatedScore score) { + return getMarkdownSummary(score, DEFAULT_TITLE); + } + /** * Creates a summary of the grading results in Markdown. * @@ -54,11 +66,21 @@ public String getTextSummary(final AggregatedScore score, final String title) { * @return Markdown text */ public String getMarkdownSummary(final AggregatedScore score, final String title) { - var summary = new StringBuilder(); + var summary = getSubScoreDetails(score); - summary.append(createMarkdownTotal(score, title, 3)); - summary.append("\n\n"); + return createMarkdownTotal(score, title, 3) + "\n\n" + summary; + } + /** + * Returns a short summary for all sub scores that are part of the aggregation in Markdown. + * + * @param score + * the aggregated score + * + * @return Markdown text + */ + public StringBuilder getSubScoreDetails(final AggregatedScore score) { + var summary = new StringBuilder(); if (score.hasTests()) { summary.append(TEST_MARKDOWN.createSummary(score)); } @@ -71,8 +93,7 @@ public String getMarkdownSummary(final AggregatedScore score, final String title if (score.hasAnalysis()) { summary.append(ANALYSIS_MARKDOWN.createSummary(score)); } - - return summary.toString(); + return summary; } /** @@ -84,7 +105,21 @@ public String getMarkdownSummary(final AggregatedScore score, final String title * @return Markdown text */ public String getMarkdownDetails(final AggregatedScore score) { - return createMarkdownTotal(score, DEFAULT_TITLE, 1) + return getMarkdownDetails(score, DEFAULT_TITLE); + } + + /** + * Creates a detailed description of the grading results in Markdown. + * + * @param score + * the aggregated score + * @param title + * the title of the details + * + * @return Markdown text + */ + public String getMarkdownDetails(final AggregatedScore score, final String title) { + return createMarkdownTotal(score, title, 1) + "\n\n" + TEST_MARKDOWN.createDetails(score) + ANALYSIS_MARKDOWN.createDetails(score) @@ -93,10 +128,16 @@ public String getMarkdownDetails(final AggregatedScore score) { } private String createMarkdownTotal(final AggregatedScore score, final String title, final int size) { + if (score.getMaxScore() == 0) { + return "#".repeat(size) + " :sunny: " + title; + } return "#".repeat(size) + " :mortar_board: " + createTotal(score, title); } private String createTotal(final AggregatedScore score, final String title) { + if (score.getMaxScore() == 0) { + return String.format("%s", title); + } return String.format("%s - %s of %s", title, score.getAchievedScore(), score.getMaxScore()); } diff --git a/src/main/java/edu/hm/hafner/grading/MutationCoverageMarkdown.java b/src/main/java/edu/hm/hafner/grading/MutationCoverageMarkdown.java index 08143608..fa7ddd59 100644 --- a/src/main/java/edu/hm/hafner/grading/MutationCoverageMarkdown.java +++ b/src/main/java/edu/hm/hafner/grading/MutationCoverageMarkdown.java @@ -15,7 +15,7 @@ public class MutationCoverageMarkdown extends CoverageMarkdown { * Creates a new Markdown renderer for code coverage results. */ public MutationCoverageMarkdown() { - super(TYPE, "microscope", "Killed %", "Survived %", "mutations killed"); + super(TYPE, "microscope", "Killed %", "Survived %"); } @Override diff --git a/src/main/java/edu/hm/hafner/grading/Score.java b/src/main/java/edu/hm/hafner/grading/Score.java index de3bc61b..d639f05a 100644 --- a/src/main/java/edu/hm/hafner/grading/Score.java +++ b/src/main/java/edu/hm/hafner/grading/Score.java @@ -93,6 +93,13 @@ else if (getImpact() > 0) { return getMaxScore(); } + /** + * Renders a short summary text of the specific score. + * + * @return the summary text + */ + protected abstract String createSummary(); + @Override public boolean equals(final Object o) { if (this == o) { diff --git a/src/main/java/edu/hm/hafner/grading/ScoreMarkdown.java b/src/main/java/edu/hm/hafner/grading/ScoreMarkdown.java index 5e8023d3..943b27e3 100644 --- a/src/main/java/edu/hm/hafner/grading/ScoreMarkdown.java +++ b/src/main/java/edu/hm/hafner/grading/ScoreMarkdown.java @@ -86,23 +86,15 @@ public String createSummary(final AggregatedScore aggregation) { var summary = new StringBuilder(MESSAGE_INITIAL_CAPACITY); for (S score : scores) { - summary.append("-").append(getTitle(score, 0)).append(": "); - createSpecificSummary(score, summary); - summary.append(LINE_BREAK); + summary.append("-") + .append(getTitle(score, 0)) + .append(": ") + .append(score.createSummary()) + .append(LINE_BREAK); } return summary.toString(); } - /** - * Renders the score summary of the specific score in Markdown. - * - * @param score - * the score to render the summary for - * @param summary - * the summary Markdown - */ - protected abstract void createSpecificSummary(S score, StringBuilder summary); - /** * Creates the scores to render. * @@ -114,8 +106,16 @@ public String createSummary(final AggregatedScore aggregation) { protected abstract List createScores(AggregatedScore aggregation); protected String getTitle(final S score, final int size) { - return "#".repeat(size) + String.format(" :%s: %s - %d of %d", - getIcon(score), score.getName(), score.getValue(), score.getMaxScore()); + return "#".repeat(size) + + String.format(" :%s: %s", getIcon(score), score.getName()) + + createScoreTitle(score); + } + + private String createScoreTitle(final S score) { + if (score.getMaxScore() > 0) { + return String.format(" - %d of %d", score.getValue(), score.getMaxScore()); + } + return StringUtils.EMPTY; } private String getIcon(final S score) { diff --git a/src/main/java/edu/hm/hafner/grading/TestMarkdown.java b/src/main/java/edu/hm/hafner/grading/TestMarkdown.java index caf059b2..8d3af633 100644 --- a/src/main/java/edu/hm/hafner/grading/TestMarkdown.java +++ b/src/main/java/edu/hm/hafner/grading/TestMarkdown.java @@ -116,20 +116,6 @@ private String getMessage(final TestCase issue) { return issue.getMessage() + LINE_BREAK; } - @Override - protected void createSpecificSummary(final TestScore score, final StringBuilder summary) { - if (score.hasFailures()) { - summary.append( - String.format("%d tests failed, %d passed", score.getFailedSize(), score.getPassedSize())); - } - else { - summary.append(String.format("%d tests passed", score.getPassedSize())); - } - if (score.getSkippedSize() > 0) { - summary.append(String.format(", %d skipped", score.getSkippedSize())); - } - } - private int sum(final AggregatedScore score, final Function property) { return score.getTestScores().stream().map(property).reduce(Integer::sum).orElse(0); } diff --git a/src/main/java/edu/hm/hafner/grading/TestScore.java b/src/main/java/edu/hm/hafner/grading/TestScore.java index 628fd9ec..0447989f 100644 --- a/src/main/java/edu/hm/hafner/grading/TestScore.java +++ b/src/main/java/edu/hm/hafner/grading/TestScore.java @@ -148,6 +148,22 @@ private List filterTests(final TestResult result) { .filter(testCase -> testCase.getResult() == result).collect(Collectors.toList()); } + @Override + protected String createSummary() { + var summary = new StringBuilder(); + if (hasFailures()) { + summary.append( + String.format("%d tests failed, %d passed", getFailedSize(), getPassedSize())); + } + else { + summary.append(String.format("%d tests passed", getPassedSize())); + } + if (getSkippedSize() > 0) { + summary.append(String.format(", %d skipped", getSkippedSize())); + } + return summary.toString(); + } + @Override @Generated public boolean equals(final Object o) { if (this == o) { diff --git a/src/test/java/edu/hm/hafner/grading/GradingReportTest.java b/src/test/java/edu/hm/hafner/grading/GradingReportTest.java index 9d19ad97..e279af85 100644 --- a/src/test/java/edu/hm/hafner/grading/GradingReportTest.java +++ b/src/test/java/edu/hm/hafner/grading/GradingReportTest.java @@ -4,6 +4,9 @@ import org.junit.jupiter.api.Test; +import edu.hm.hafner.util.FilteredLog; + +import static edu.hm.hafner.grading.assertions.Assertions.assertThat; import static org.assertj.core.api.Assertions.*; /** @@ -12,20 +15,88 @@ * @author Ullrich Hafner */ class GradingReportTest { + private static final String NO_SCORE_CONFIGURATION = """ + { + "tests": [{ + "name": "JUnit", + "tools": [ + { + "name": "Integrationstests", + "id": "itest" + }, + { + "name": "Modultests", + "id": "mtest" + } + ] + }], + "analysis": [ + { + "name": "Style", + "id": "style", + "tools": [ + { + "name": "Checkstyle", + "id": "checkstyle" + } + ] + }, + { + "name": "Bugs", + "id": "bugs", + "icon": "bug", + "tools": [ + { + "name": "SpotBugs", + "id": "spotbugs" + } + ] + } + ], + "coverage": [ + { + "name": "JaCoCo", + "tools": [ + { + "id": "jacoco", + "name": "Line Coverage", + "metric": "line" + }, + { + "id": "jacoco", + "name": "Branch Coverage", + "metric": "branch" + } + ] + }, + { + "name": "PIT", + "tools" : [ + { + "name": "Mutation Coverage", + "id": "pit", + "metric": "mutation" + } + ] + } + ] + } + """; + @Test void shouldCreateEmptyResults() { var results = new GradingReport(); var score = new AggregatedScore(); assertThat(results.getTextSummary(score)).isEqualTo( - "Autograding score - 0 of 0"); + "Autograding score"); assertThat(results.getMarkdownDetails(score)).contains( - "Autograding score - 0 of 0", + "Autograding score", "Unit Tests Score: not enabled", "Coverage Score: not enabled", "Static Analysis Warnings Score: not enabled"); assertThat(results.getMarkdownSummary(score, "Summary")) - .contains("Summary - 0 of 0"); + .contains("Summary"); } @Test @@ -86,4 +157,59 @@ void shouldCreateAnalysisResults() { "|SpotBugs|4|3|2|1|10|-120", "Bugs - 0 of 100"); } + + @Test + void shouldSkipScores() { + var results = new GradingReport(); + + var logger = new FilteredLog("Tests"); + var aggregation = new AggregatedScore(NO_SCORE_CONFIGURATION, logger); + + aggregation.gradeAnalysis((tool, log) -> AnalysisMarkdownTest.createTwoReports(tool)); + assertThat(logger.getInfoMessages()).contains( + "Processing 2 static analysis configuration(s)", + "=> Style: 10 warnings found (1 error, 2 high, 3 normal, 4 low)", + "=> Bugs: 10 warnings found (4 errors, 3 high, 2 normal, 1 low)"); + + aggregation.gradeTests((tool, log) -> TestMarkdownTest.createTwoReports(tool)); + assertThat(logger.getInfoMessages()).contains( + "Processing 1 test configuration(s)", + "=> JUnit: 14 tests failed, 5 passed, 3 skipped"); + + aggregation.gradeCoverage((tool, log) -> CoverageMarkdownTest.createTwoReports(tool)); + assertThat(String.join("\n", logger.getInfoMessages())).contains( + "Processing 2 coverage configuration(s)", + "=> JaCoCo: 70% coverage achieved", + "=> PIT: 60% mutations killed" + ); + + assertThat(aggregation.getMetrics()).containsOnly( + entry("tests", 22), + entry("branch", 60), + entry("line", 80), + entry("mutation", 60), + entry("style", 10), + entry("bugs", 10), + entry("checkstyle", 10), + entry("spotbugs", 10)); + + assertThat(results.getMarkdownSummary(aggregation, "Summary")).contains( + "### :sunny: Summary", + "- :vertical_traffic_light: JUnit: 14 tests failed, 5 passed, 3 skipped", + "- :footprints: JaCoCo: 70% coverage achieved", + "- :microscope: PIT: 60% mutations killed", + "- :warning: Style: 10 warnings found (1 error, 2 high, 3 normal, 4 low)", + "- :bug: Bugs: 10 warnings found (4 errors, 3 high, 2 normal, 1 low)"); + assertThat(results.getTextSummary(aggregation)).isEqualTo( + "Autograding score"); + assertThat(results.getTextSummary(aggregation, "Quality Guardian")).isEqualTo( + "Quality Guardian"); + assertThat(results.getMarkdownDetails(aggregation)).contains( + "# :sunny: Autograding score", + "JUnit", + "JaCoCo", + "PIT", + "Style", + "Bugs"); + } } From 2a82c155a58bf8917eaf6d2dde5f503613a2cf93 Mon Sep 17 00:00:00 2001 From: Ulli Hafner Date: Fri, 15 Dec 2023 18:15:30 +0100 Subject: [PATCH 2/4] Remove impact from tables. --- .../hm/hafner/grading/AggregatedScore.java | 2 +- .../hm/hafner/grading/AnalysisMarkdown.java | 35 +++++++------ .../hm/hafner/grading/CoverageMarkdown.java | 30 ++++++----- .../java/edu/hm/hafner/grading/Score.java | 10 ++++ .../edu/hm/hafner/grading/ScoreMarkdown.java | 2 +- .../edu/hm/hafner/grading/TestMarkdown.java | 35 +++++++------ .../hm/hafner/grading/TruncatedString.java | 18 +++++++ .../hafner/grading/AnalysisMarkdownTest.java | 36 +++++++++++++ .../hafner/grading/CoverageMarkdownTest.java | 52 ++++++++++++++++--- .../hm/hafner/grading/GradingReportTest.java | 2 +- .../hm/hafner/grading/TestMarkdownTest.java | 41 +++++++++++++++ 11 files changed, 210 insertions(+), 53 deletions(-) diff --git a/src/main/java/edu/hm/hafner/grading/AggregatedScore.java b/src/main/java/edu/hm/hafner/grading/AggregatedScore.java index caec793f..87f0ee06 100644 --- a/src/main/java/edu/hm/hafner/grading/AggregatedScore.java +++ b/src/main/java/edu/hm/hafner/grading/AggregatedScore.java @@ -482,7 +482,7 @@ public void gradeTests(final TestReportFactory factory) { } private void logResult(final Configuration configuration, final Score score) { - if (configuration.getMaxScore() > 0) { + if (score.hasMaxScore()) { log.logInfo("=> %s Score: %d of %d", configuration.getName(), score.getValue(), score.getMaxScore()); } diff --git a/src/main/java/edu/hm/hafner/grading/AnalysisMarkdown.java b/src/main/java/edu/hm/hafner/grading/AnalysisMarkdown.java index 2b904758..c238f6d0 100644 --- a/src/main/java/edu/hm/hafner/grading/AnalysisMarkdown.java +++ b/src/main/java/edu/hm/hafner/grading/AnalysisMarkdown.java @@ -32,10 +32,11 @@ protected void createSpecificDetails(final AggregatedScore aggregation, final Li for (AnalysisScore score : scores) { details.addText(getTitle(score, 2)) .addNewline() - .addText(formatColumns("Name", "Errors", "Warning High", "Warning Normal", "Warning Low", - "Total", "Impact")) + .addText(formatColumns("Name", "Errors", "Warning High", "Warning Normal", "Warning Low", "Total")) + .addTextIf(formatColumns("Impact"), score.hasMaxScore()) .addNewline() - .addText(formatColumns(":-:", ":-:", ":-:", ":-:", ":-:", ":-:", ":-:")) + .addText(formatColumns(":-:", ":-:", ":-:", ":-:", ":-:", ":-:")) + .addTextIf(formatColumns(":-:"), score.hasMaxScore()) .addNewline(); score.getSubScores().forEach(subScore -> details @@ -44,8 +45,8 @@ protected void createSpecificDetails(final AggregatedScore aggregation, final Li String.valueOf(subScore.getHighSeveritySize()), String.valueOf(subScore.getNormalSeveritySize()), String.valueOf(subScore.getLowSeveritySize()), - String.valueOf(subScore.getTotalSize()), - String.valueOf(subScore.getImpact()))) + String.valueOf(subScore.getTotalSize()))) + .addTextIf(formatColumns(String.valueOf(subScore.getImpact())), score.hasMaxScore()) .addNewline()); if (score.getSubScores().size() > 1) { @@ -54,20 +55,22 @@ protected void createSpecificDetails(final AggregatedScore aggregation, final Li sum(aggregation, AnalysisScore::getHighSeveritySize), sum(aggregation, AnalysisScore::getNormalSeveritySize), sum(aggregation, AnalysisScore::getLowSeveritySize), - sum(aggregation, AnalysisScore::getTotalSize), - sum(aggregation, AnalysisScore::getImpact))) + sum(aggregation, AnalysisScore::getTotalSize))) + .addTextIf(formatBoldColumns(sum(aggregation, AnalysisScore::getImpact)), score.hasMaxScore()) .addNewline(); } - var configuration = score.getConfiguration(); - details.addText(formatColumns(IMPACT)) - .addText(formatItalicColumns( - renderImpact(configuration.getErrorImpact()), - renderImpact(configuration.getHighImpact()), - renderImpact(configuration.getNormalImpact()), - renderImpact(configuration.getLowImpact()))) - .addText(formatColumns(TOTAL, LEDGER)) - .addNewline(); + if (score.hasMaxScore()) { + var configuration = score.getConfiguration(); + details.addText(formatColumns(IMPACT)) + .addText(formatItalicColumns( + renderImpact(configuration.getErrorImpact()), + renderImpact(configuration.getHighImpact()), + renderImpact(configuration.getNormalImpact()), + renderImpact(configuration.getLowImpact()))) + .addText(formatColumns(TOTAL, LEDGER)) + .addNewline(); + } } } diff --git a/src/main/java/edu/hm/hafner/grading/CoverageMarkdown.java b/src/main/java/edu/hm/hafner/grading/CoverageMarkdown.java index b5bd7576..5441064c 100644 --- a/src/main/java/edu/hm/hafner/grading/CoverageMarkdown.java +++ b/src/main/java/edu/hm/hafner/grading/CoverageMarkdown.java @@ -27,34 +27,38 @@ protected void createSpecificDetails(final AggregatedScore aggregation, final Li for (CoverageScore score : scores) { details.addText(getTitle(score, 2)) .addNewline() - .addText(formatColumns("Name", coveredText, missedText, "Impact")) + .addText(formatColumns("Name", coveredText, missedText)) + .addTextIf(formatColumns("Impact"), score.hasMaxScore()) .addNewline() - .addText(formatColumns(":-:", ":-:", ":-:", ":-:")) + .addText(formatColumns(":-:", ":-:", ":-:")) + .addTextIf(formatColumns(":-:"), score.hasMaxScore()) .addNewline(); score.getSubScores().forEach(subScore -> details .addText(formatColumns( subScore.getName(), String.valueOf(subScore.getCoveredPercentage()), - String.valueOf(subScore.getMissedPercentage()), - String.valueOf(subScore.getImpact()))) + String.valueOf(subScore.getMissedPercentage()))) + .addTextIf(formatColumns(String.valueOf(subScore.getImpact())), score.hasMaxScore()) .addNewline()); if (score.getSubScores().size() > 1) { details.addText(formatBoldColumns("Total Ø", score.getCoveredPercentage(), - score.getMissedPercentage(), - score.getImpact())) + score.getMissedPercentage())) + .addTextIf(formatBoldColumns(score.getImpact()), score.hasMaxScore()) .addNewline(); } - var configuration = score.getConfiguration(); - details.addText(formatColumns(IMPACT)) - .addText(formatItalicColumns( - renderImpact(configuration.getCoveredPercentageImpact()), - renderImpact(configuration.getMissedPercentageImpact()))) - .addText(formatColumns(LEDGER)) - .addNewline(); + if (score.hasMaxScore()) { + var configuration = score.getConfiguration(); + details.addText(formatColumns(IMPACT)) + .addText(formatItalicColumns( + renderImpact(configuration.getCoveredPercentageImpact()), + renderImpact(configuration.getMissedPercentageImpact()))) + .addText(formatColumns(LEDGER)) + .addNewline(); + } } } } diff --git a/src/main/java/edu/hm/hafner/grading/Score.java b/src/main/java/edu/hm/hafner/grading/Score.java index d639f05a..cb4b4ef3 100644 --- a/src/main/java/edu/hm/hafner/grading/Score.java +++ b/src/main/java/edu/hm/hafner/grading/Score.java @@ -73,6 +73,16 @@ public int getMaxScore() { return configuration.getMaxScore(); } + /** + * Returns whether this score has a maximum score defined. If not, then the results will only be logged but not + * counted. + * + * @return {@code true} if this score has a maximum score set, {@code false} otherwise + */ + public boolean hasMaxScore() { + return getMaxScore() > 0; + } + /** * Evaluates the score value. The value is in the interval [0, {@link #getMaxScore()}]. If the configuration * property {@link Configuration#isPositive()} is set, then the score will increase by the impact. Otherwise, diff --git a/src/main/java/edu/hm/hafner/grading/ScoreMarkdown.java b/src/main/java/edu/hm/hafner/grading/ScoreMarkdown.java index 943b27e3..22b18393 100644 --- a/src/main/java/edu/hm/hafner/grading/ScoreMarkdown.java +++ b/src/main/java/edu/hm/hafner/grading/ScoreMarkdown.java @@ -112,7 +112,7 @@ protected String getTitle(final S score, final int size) { } private String createScoreTitle(final S score) { - if (score.getMaxScore() > 0) { + if (score.hasMaxScore()) { return String.format(" - %d of %d", score.getValue(), score.getMaxScore()); } return StringUtils.EMPTY; diff --git a/src/main/java/edu/hm/hafner/grading/TestMarkdown.java b/src/main/java/edu/hm/hafner/grading/TestMarkdown.java index 8d3af633..95f37324 100644 --- a/src/main/java/edu/hm/hafner/grading/TestMarkdown.java +++ b/src/main/java/edu/hm/hafner/grading/TestMarkdown.java @@ -35,9 +35,11 @@ protected void createSpecificDetails(final AggregatedScore aggregation, for (TestScore score : scores) { details.addText(getTitle(score, 2)) .addNewline() - .addText(formatColumns("Name", "Passed", "Skipped", "Failed", "Total", "Impact")) + .addText(formatColumns("Name", "Passed", "Skipped", "Failed", "Total")) + .addTextIf(formatColumns("Impact"), score.hasMaxScore()) .addNewline() - .addText(formatColumns(":-:", ":-:", ":-:", ":-:", ":-:", ":-:")) + .addText(formatColumns(":-:", ":-:", ":-:", ":-:", ":-:")) + .addTextIf(formatColumns(":-:"), score.hasMaxScore()) .addNewline(); score.getSubScores().forEach(subScore -> details @@ -46,8 +48,8 @@ protected void createSpecificDetails(final AggregatedScore aggregation, String.valueOf(subScore.getPassedSize()), String.valueOf(subScore.getSkippedSize()), String.valueOf(subScore.getFailedSize()), - String.valueOf(subScore.getTotalSize()), - String.valueOf(subScore.getImpact()))) + String.valueOf(subScore.getTotalSize()))) + .addTextIf(formatColumns(String.valueOf(subScore.getImpact())), score.hasMaxScore()) .addNewline()); if (score.getSubScores().size() > 1) { @@ -55,22 +57,25 @@ protected void createSpecificDetails(final AggregatedScore aggregation, sum(aggregation, TestScore::getPassedSize), sum(aggregation, TestScore::getSkippedSize), sum(aggregation, TestScore::getFailedSize), - sum(aggregation, TestScore::getTotalSize), - sum(aggregation, TestScore::getImpact))) + sum(aggregation, TestScore::getTotalSize))) + .addTextIf(formatBoldColumns(sum(aggregation, TestScore::getImpact)), score.hasMaxScore()) .addNewline(); } var configuration = score.getConfiguration(); - details.addText(formatColumns(IMPACT)) - .addText(formatItalicColumns( - renderImpact(configuration.getPassedImpact()), - renderImpact(configuration.getSkippedImpact()), - renderImpact(configuration.getFailureImpact()))) - .addText(formatColumns(TOTAL, LEDGER)) - .addNewline(); + if (score.hasMaxScore()) { + details.addText(formatColumns(IMPACT)) + .addText(formatItalicColumns( + renderImpact(configuration.getPassedImpact()), + renderImpact(configuration.getSkippedImpact()), + renderImpact(configuration.getFailureImpact()))) + .addText(formatColumns(TOTAL, LEDGER)) + .addNewline(); + } if (score.hasSkippedTests()) { - details.addText("### Skipped Test Cases\n"); + details.addText("### Skipped Test Cases") + .addNewline(); score.getSkippedTests().stream() .map(this::renderSkippedTest) .forEach(details::addText); @@ -78,7 +83,7 @@ protected void createSpecificDetails(final AggregatedScore aggregation, } if (score.hasFailures()) { - details.addText("### Failures\n"); + details.addText("### Failures").addNewline(); score.getFailures().stream() .map(this::renderFailure) .forEach(details::addText); diff --git a/src/main/java/edu/hm/hafner/grading/TruncatedString.java b/src/main/java/edu/hm/hafner/grading/TruncatedString.java index 26d8b651..b9f77f67 100644 --- a/src/main/java/edu/hm/hafner/grading/TruncatedString.java +++ b/src/main/java/edu/hm/hafner/grading/TruncatedString.java @@ -139,6 +139,24 @@ public TruncatedStringBuilder addText(final String text) { return this; } + /** + * Adds a chunk of text to the builder, if the specified guard is {@code true}. + * + * @param text + * the chunk of text to append to this builder + * @param guard + * determines if the text should be added + * + * @return this builder + */ + @CanIgnoreReturnValue + public TruncatedStringBuilder addTextIf(final String text, final boolean guard) { + if (guard) { + this.chunks.add(text); + } + return this; + } + /** * Adds a newline to the builder. * diff --git a/src/test/java/edu/hm/hafner/grading/AnalysisMarkdownTest.java b/src/test/java/edu/hm/hafner/grading/AnalysisMarkdownTest.java index 10ed759e..ad48709c 100644 --- a/src/test/java/edu/hm/hafner/grading/AnalysisMarkdownTest.java +++ b/src/test/java/edu/hm/hafner/grading/AnalysisMarkdownTest.java @@ -133,6 +133,42 @@ void shouldShowScoreWithTwoSubResults() { "**Total**|**5**|**5**|**5**|**5**|**20**|**-50**"); } + @Test + void shouldShowNoImpactsWithTwoSubResults() { + var score = new AggregatedScore(""" + { + "analysis": [{ + "tools": [ + { + "id": "checkstyle", + "name": "CheckStyle", + "pattern": "target/checkstyle.xml" + }, + { + "id": "spotbugs", + "name": "SpotBugs", + "pattern": "target/spotbugsXml.xml" + } + ], + "name": "CheckStyle" + }] + } + """, LOG); + score.gradeAnalysis((tool, log) -> createTwoReports(tool)); + + var analysisMarkdown = new AnalysisMarkdown(); + + assertThat(analysisMarkdown.createSummary(score)) + .startsWith("- :warning: CheckStyle: 20 warnings found (5 errors, 5 high, 5 normal, 5 low)"); + assertThat(analysisMarkdown.createDetails(score)) + .contains("CheckStyle", + "|CheckStyle|1|2|3|4|10", + "|SpotBugs|4|3|2|1|10", + "**Total**|**5**|**5**|**5**|**5**|**20**") + .doesNotContain(IMPACT_CONFIGURATION) + .doesNotContain("Impact"); + } + private static Report createSampleReport() { return createReportWith("CheckStyle 1", Severity.ERROR, diff --git a/src/test/java/edu/hm/hafner/grading/CoverageMarkdownTest.java b/src/test/java/edu/hm/hafner/grading/CoverageMarkdownTest.java index a279f404..e65040ee 100644 --- a/src/test/java/edu/hm/hafner/grading/CoverageMarkdownTest.java +++ b/src/test/java/edu/hm/hafner/grading/CoverageMarkdownTest.java @@ -151,6 +151,46 @@ void shouldShowScoreWithTwoSubResults() { "Mutation Coverage Score: not enabled"); } + @Test + void shouldShowNoImpactsWithTwoSubResults() { + var score = new AggregatedScore(""" + { + "coverage": { + "tools": [ + { + "id": "jacoco", + "name": "Line Coverage", + "metric": "line", + "pattern": "target/jacoco.xml" + }, + { + "id": "jacoco", + "name": "Branch Coverage", + "metric": "branch", + "pattern": "target/jacoco.xml" + } + ] + } + } + """, LOG); + + score.gradeCoverage((tool, log) -> createTwoReports(tool)); + + var codeCoverageMarkdown = new CodeCoverageMarkdown(); + + assertThat(codeCoverageMarkdown.createDetails(score)) + .contains("Code Coverage", + "|Line Coverage|80|20", + "|Branch Coverage|60|40", + "|**Total Ø**|**70**|**30**") + .doesNotContain(IMPACT_CONFIGURATION) + .doesNotContain("Impact"); + assertThat(codeCoverageMarkdown.createSummary(score)).startsWith( + "- :footprints: Code Coverage: 70% coverage achieved"); + assertThat(new MutationCoverageMarkdown().createDetails(score)).contains( + "Mutation Coverage Score: not enabled"); + } + @Test void shouldShowScoreWithTwoResults() { var score = new AggregatedScore(""" @@ -199,18 +239,18 @@ void shouldShowScoreWithTwoResults() { var codeCoverageMarkdown = new CodeCoverageMarkdown(); assertThat(codeCoverageMarkdown.createDetails(score)).contains( - "JaCoCo - 40 of 100", - "|Line Coverage|80|20|60", - "|Branch Coverage|60|40|20", - "|**Total Ø**|**70**|**30**|**40**", - IMPACT_CONFIGURATION) + "JaCoCo - 40 of 100", + "|Line Coverage|80|20|60", + "|Branch Coverage|60|40|20", + "|**Total Ø**|**70**|**30**|**40**", + IMPACT_CONFIGURATION) .doesNotContain("Mutation Coverage", "PIT"); assertThat(codeCoverageMarkdown.createSummary(score)).startsWith( "- :footprints: JaCoCo - 40 of 100: 70% coverage achieved"); var mutationCoverageMarkdown = new MutationCoverageMarkdown(); assertThat(mutationCoverageMarkdown.createDetails(score)).contains( - "PIT - 20 of 100", IMPACT_CONFIGURATION) + "PIT - 20 of 100", IMPACT_CONFIGURATION) .doesNotContain("JaCoCo", "Line Coverage", "Branch Coverage", "Total"); assertThat(mutationCoverageMarkdown.createSummary(score)).contains( "- :microscope: PIT - 20 of 100: 60% mutations killed"); diff --git a/src/test/java/edu/hm/hafner/grading/GradingReportTest.java b/src/test/java/edu/hm/hafner/grading/GradingReportTest.java index e279af85..e1254a82 100644 --- a/src/test/java/edu/hm/hafner/grading/GradingReportTest.java +++ b/src/test/java/edu/hm/hafner/grading/GradingReportTest.java @@ -206,7 +206,7 @@ void shouldSkipScores() { "Quality Guardian"); assertThat(results.getMarkdownDetails(aggregation)).contains( "# :sunny: Autograding score", - "JUnit", + "JUnict", "JaCoCo", "PIT", "Style", diff --git a/src/test/java/edu/hm/hafner/grading/TestMarkdownTest.java b/src/test/java/edu/hm/hafner/grading/TestMarkdownTest.java index 9ad29d74..58e35344 100644 --- a/src/test/java/edu/hm/hafner/grading/TestMarkdownTest.java +++ b/src/test/java/edu/hm/hafner/grading/TestMarkdownTest.java @@ -138,6 +138,47 @@ void shouldShowScoreWithTwoSubResults() { "14 tests failed, 5 passed, 3 skipped"); } + @Test + void shouldShowNoImpactsWithTwoSubResults() { + var score = new AggregatedScore(""" + { + "tests": [{ + "tools": [ + { + "id": "itest", + "name": "Integrationstests", + "pattern": "target/i-junit.xml" + }, + { + "id": "mtest", + "name": "Modultests", + "pattern": "target/u-junit.xml" + } + ], + "name": "JUnit" + }] + } + """, LOG); + score.gradeTests((tool, log) -> createTwoReports(tool)); + + var testMarkdown = new TestMarkdown(); + + assertThat(testMarkdown.createDetails(score)) + .contains("JUnit", + "|Integrationstests|5|3|4|12", + "|Modultests|0|0|10|10", + "**Total**|**5**|**3**|**14**|**22**", + "### Skipped Test Cases", + "- test-class-skipped-0#test-skipped-0", + "- test-class-skipped-1#test-skipped-1", + "- test-class-skipped-2#test-skipped-2") + .doesNotContain(IMPACT_CONFIGURATION) + .doesNotContain("Impact"); + assertThat(testMarkdown.createSummary(score)) + .contains("JUnit", + "14 tests failed, 5 passed, 3 skipped"); + } + static Node createTwoReports(final ToolConfiguration tool) { if (tool.getId().equals("itest")) { return TestScoreTest.createTestReport(5, 3, 4); From d4467821ee277770f663cd11ed1cfb9e2748cb92 Mon Sep 17 00:00:00 2001 From: Ulli Hafner Date: Fri, 15 Dec 2023 18:31:27 +0100 Subject: [PATCH 3/4] Fix test. --- .../java/edu/hm/hafner/grading/GradingReportTest.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/test/java/edu/hm/hafner/grading/GradingReportTest.java b/src/test/java/edu/hm/hafner/grading/GradingReportTest.java index e1254a82..ec03e573 100644 --- a/src/test/java/edu/hm/hafner/grading/GradingReportTest.java +++ b/src/test/java/edu/hm/hafner/grading/GradingReportTest.java @@ -202,11 +202,11 @@ void shouldSkipScores() { "- :bug: Bugs: 10 warnings found (4 errors, 3 high, 2 normal, 1 low)"); assertThat(results.getTextSummary(aggregation)).isEqualTo( "Autograding score"); - assertThat(results.getTextSummary(aggregation, "Quality Guardian")).isEqualTo( - "Quality Guardian"); - assertThat(results.getMarkdownDetails(aggregation)).contains( - "# :sunny: Autograding score", - "JUnict", + assertThat(results.getTextSummary(aggregation, "Quality Summary")).isEqualTo( + "Quality Summary"); + assertThat(results.getMarkdownDetails(aggregation, "Quality Summary")).contains( + "# :sunny: Quality Summary", + "JUni t", "JaCoCo", "PIT", "Style", From 207b111c58e52093ea7627e50e5a16b1f98c6837 Mon Sep 17 00:00:00 2001 From: Ulli Hafner Date: Fri, 15 Dec 2023 18:32:44 +0100 Subject: [PATCH 4/4] Fix test again. --- src/main/java/edu/hm/hafner/grading/AutoGradingRunner.java | 2 +- src/test/java/edu/hm/hafner/grading/GradingReportTest.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/edu/hm/hafner/grading/AutoGradingRunner.java b/src/main/java/edu/hm/hafner/grading/AutoGradingRunner.java index b4e60ebb..b2460e4a 100644 --- a/src/main/java/edu/hm/hafner/grading/AutoGradingRunner.java +++ b/src/main/java/edu/hm/hafner/grading/AutoGradingRunner.java @@ -45,7 +45,7 @@ public AutoGradingRunner() { * @return the grading score */ public AggregatedScore run() { - var log = new FilteredLog("Autograding Action Errors:"); + var log = new FilteredLog("Errors:"); var logHandler = new LogHandler(outputStream, log); diff --git a/src/test/java/edu/hm/hafner/grading/GradingReportTest.java b/src/test/java/edu/hm/hafner/grading/GradingReportTest.java index ec03e573..51e717ec 100644 --- a/src/test/java/edu/hm/hafner/grading/GradingReportTest.java +++ b/src/test/java/edu/hm/hafner/grading/GradingReportTest.java @@ -206,7 +206,7 @@ void shouldSkipScores() { "Quality Summary"); assertThat(results.getMarkdownDetails(aggregation, "Quality Summary")).contains( "# :sunny: Quality Summary", - "JUni t", + "JUnit", "JaCoCo", "PIT", "Style",