From 6bd060c1f24eb9a7be2678cad9e45e7ad273a3a3 Mon Sep 17 00:00:00 2001 From: Rafal Magda Date: Sun, 21 May 2023 17:47:14 +0200 Subject: [PATCH 1/2] (#194) Fix numbers decimal separator --- .../scoverage/ScoverageFunctionalTest.java | 6 +-- .../org/scoverage/CoverageChecker.groovy | 20 ++++------ .../org/scoverage/CoverageCheckerTest.groovy | 38 ++++++++++--------- 3 files changed, 30 insertions(+), 34 deletions(-) diff --git a/src/functionalTest/java/org/scoverage/ScoverageFunctionalTest.java b/src/functionalTest/java/org/scoverage/ScoverageFunctionalTest.java index bfc1c09..fdac1cf 100644 --- a/src/functionalTest/java/org/scoverage/ScoverageFunctionalTest.java +++ b/src/functionalTest/java/org/scoverage/ScoverageFunctionalTest.java @@ -11,8 +11,6 @@ import java.io.File; import java.io.IOException; -import java.text.NumberFormat; -import java.text.ParseException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -108,12 +106,12 @@ protected File resolve(File file, String relativePath) { return file.toPath().resolve(relativePath).toFile(); } - private Double coverage(File reportDir, CoverageType coverageType) throws IOException, SAXException, ParseException { + private Double coverage(File reportDir, CoverageType coverageType) throws IOException, SAXException, NumberFormatException { File reportFile = reportDir.toPath().resolve(coverageType.getFileName()).toFile(); Node xml = parser.parse(reportFile); Object attribute = xml.attribute(coverageType.getParamName()); - double rawValue = NumberFormat.getInstance().parse(attribute.toString()).doubleValue(); + double rawValue = Double.parseDouble(attribute.toString()); return coverageType.normalize(rawValue) * 100.0; } diff --git a/src/main/groovy/org/scoverage/CoverageChecker.groovy b/src/main/groovy/org/scoverage/CoverageChecker.groovy index 1af7b4e..d185f82 100644 --- a/src/main/groovy/org/scoverage/CoverageChecker.groovy +++ b/src/main/groovy/org/scoverage/CoverageChecker.groovy @@ -6,7 +6,7 @@ import org.gradle.api.logging.Logger import org.gradle.internal.impldep.com.google.common.annotations.VisibleForTesting import java.text.DecimalFormat -import java.text.NumberFormat +import java.text.DecimalFormatSymbols /** * Handles different types of coverage Scoverage can measure. @@ -56,30 +56,21 @@ class CoverageChecker { } public void checkLineCoverage(File reportDir, CoverageType coverageType, double minimumRate) throws GradleException { - NumberFormat defaultNf = NumberFormat.getInstance(Locale.getDefault()) - checkLineCoverage(reportDir, coverageType, minimumRate, defaultNf) - } - - public void checkLineCoverage(File reportDir, CoverageType coverageType, double minimumRate, NumberFormat nf) throws GradleException { logger.info("Checking coverage. Type: {}. Minimum rate: {}", coverageType, minimumRate) XmlParser parser = new XmlParser() parser.setFeature('http://apache.org/xml/features/disallow-doctype-decl', false) parser.setFeature('http://apache.org/xml/features/nonvalidating/load-external-dtd', false) - DecimalFormat df = new DecimalFormat("#.##") - try { File reportFile = new File(reportDir, coverageType.fileName) Node xml = parser.parse(reportFile) - Double coverageValue = nf.parse(xml.attribute(coverageType.paramName) as String).doubleValue() + Double coverageValue = (xml.attribute(coverageType.paramName) as String).toDouble() Double overallRate = coverageType.normalize(coverageValue) def difference = (minimumRate - overallRate) if (difference > 1e-7) { - String is = df.format(overallRate * 100) - String needed = df.format(minimumRate * 100) - throw new GradleException(errorMsg(is, needed, coverageType)) + throw new GradleException(errorMsg(overallRate, minimumRate, coverageType)) } } catch (FileNotFoundException fnfe) { throw new GradleException(fileNotFoundErrorMsg(coverageType), fnfe) @@ -87,7 +78,10 @@ class CoverageChecker { } @VisibleForTesting - protected static String errorMsg(String actual, String expected, CoverageType type) { + protected static String errorMsg(double overallRate, double minimumRate, CoverageType type) { + DecimalFormat df = new DecimalFormat("#.##", DecimalFormatSymbols.getInstance(Locale.ENGLISH)) + String actual = df.format(overallRate * 100) + String expected = df.format(minimumRate * 100) "Only $actual% of project is covered by tests instead of $expected% (coverageType: $type)" } diff --git a/src/test/groovy/org/scoverage/CoverageCheckerTest.groovy b/src/test/groovy/org/scoverage/CoverageCheckerTest.groovy index 04c695a..844968e 100644 --- a/src/test/groovy/org/scoverage/CoverageCheckerTest.groovy +++ b/src/test/groovy/org/scoverage/CoverageCheckerTest.groovy @@ -10,15 +10,13 @@ import org.junit.rules.TemporaryFolder import org.slf4j.LoggerFactory import java.nio.file.Paths -import java.text.NumberFormat +import static org.junit.Assert.assertEquals import static org.junit.Assert.assertThat import static org.junit.jupiter.api.Assertions.assertThrows class CoverageCheckerTest { - private NumberFormat numberFormat = NumberFormat.getInstance(Locale.US) - private File reportDir = Paths.get(getClass().getClassLoader().getResource("checkTask").toURI()).toFile() private CoverageChecker checker = new CoverageChecker(LoggerFactory.getLogger(CoverageCheckerTest.class)) @@ -31,7 +29,7 @@ class CoverageCheckerTest { @Test void failsWhenReportFileIsNotFound() { assertFailure(CoverageChecker.fileNotFoundErrorMsg(CoverageType.Line), { - checker.checkLineCoverage(tempDir.getRoot(), CoverageType.Line, 0.0, numberFormat) + checker.checkLineCoverage(tempDir.getRoot(), CoverageType.Line, 0.0) }) } @@ -39,60 +37,66 @@ class CoverageCheckerTest { @Test void failsWhenLineRateIsBelowTarget() { - assertFailure(CoverageChecker.errorMsg("66", "100", CoverageType.Line), { - checker.checkLineCoverage(reportDir, CoverageType.Line, 1.0, numberFormat) + assertFailure(CoverageChecker.errorMsg(0.66, 1.0, CoverageType.Line), { + checker.checkLineCoverage(reportDir, CoverageType.Line, 1.0) }) } @Test void doesNotFailWhenLineRateIsAtTarget() { - checker.checkLineCoverage(reportDir, CoverageType.Line, 0.66, numberFormat) + checker.checkLineCoverage(reportDir, CoverageType.Line, 0.66) } @Test void doesNotFailWhenLineRateIsAboveTarget() { - checker.checkLineCoverage(reportDir, CoverageType.Line, 0.6, numberFormat) + checker.checkLineCoverage(reportDir, CoverageType.Line, 0.6) } // Statement coverage @Test void failsWhenStatementRateIsBelowTarget() { - assertFailure(CoverageChecker.errorMsg(numberFormat.format(new Double(33.33)), "100", CoverageType.Statement), { - checker.checkLineCoverage(reportDir, CoverageType.Statement, 1.0, numberFormat) + assertFailure(CoverageChecker.errorMsg(0.3333, 1.0, CoverageType.Statement), { + checker.checkLineCoverage(reportDir, CoverageType.Statement, 1.0) }) } @Test void doesNotFailWhenStatementRateIsAtTarget() { - checker.checkLineCoverage(reportDir, CoverageType.Statement, 0.33, numberFormat) + checker.checkLineCoverage(reportDir, CoverageType.Statement, 0.33) } @Test void doesNotFailWhenStatementRateIsAboveTarget() { - checker.checkLineCoverage(reportDir, CoverageType.Statement, 0.3, numberFormat) + checker.checkLineCoverage(reportDir, CoverageType.Statement, 0.3) } // Branch coverage @Test void failsWhenBranchRateIsBelowTarget() { - assertFailure(CoverageChecker.errorMsg("50", "100", CoverageType.Branch), { - checker.checkLineCoverage(reportDir, CoverageType.Branch, 1.0, numberFormat) + assertFailure(CoverageChecker.errorMsg(0.5, 1.0, CoverageType.Branch), { + checker.checkLineCoverage(reportDir, CoverageType.Branch, 1.0) }) } @Test void doesNotFailWhenBranchRateIsAtTarget() { - checker.checkLineCoverage(reportDir, CoverageType.Branch, 0.5, numberFormat) + checker.checkLineCoverage(reportDir, CoverageType.Branch, 0.5) } @Test void doesNotFailWhenBranchRateIsAboveTarget() { - checker.checkLineCoverage(reportDir, CoverageType.Branch, 0.45, numberFormat) + checker.checkLineCoverage(reportDir, CoverageType.Branch, 0.45) + } + + @Test + void printsErrorMsgInEnglishWithUpTwoDecimalPointsPrecision() { + assertEquals("Only 54.32% of project is covered by tests instead of 90% (coverageType: Branch)", + CoverageChecker.errorMsg(0.54321, 0.9, CoverageType.Branch)) } - private void assertFailure(String message, Executable executable) { + private static void assertFailure(String message, Executable executable) { GradleException e = assertThrows(GradleException.class, executable) assertThat(e, new CauseMatcher(message)) } From 3e386b8cdb645b05fab3e0f1e2f6da1f642c0a18 Mon Sep 17 00:00:00 2001 From: Rafal Magda Date: Sun, 21 May 2023 19:53:47 +0200 Subject: [PATCH 2/2] (#194) Fix numbers decimal separator - Locale.US --- src/main/groovy/org/scoverage/CoverageChecker.groovy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/groovy/org/scoverage/CoverageChecker.groovy b/src/main/groovy/org/scoverage/CoverageChecker.groovy index d185f82..ff240ba 100644 --- a/src/main/groovy/org/scoverage/CoverageChecker.groovy +++ b/src/main/groovy/org/scoverage/CoverageChecker.groovy @@ -79,7 +79,7 @@ class CoverageChecker { @VisibleForTesting protected static String errorMsg(double overallRate, double minimumRate, CoverageType type) { - DecimalFormat df = new DecimalFormat("#.##", DecimalFormatSymbols.getInstance(Locale.ENGLISH)) + DecimalFormat df = new DecimalFormat("#.##", DecimalFormatSymbols.getInstance(Locale.US)) String actual = df.format(overallRate * 100) String expected = df.format(minimumRate * 100) "Only $actual% of project is covered by tests instead of $expected% (coverageType: $type)"