diff --git a/cxx-sensors/src/main/java/org/sonar/cxx/sensors/functioncomplexity/CxxFunctionComplexitySquidSensor.java b/cxx-sensors/src/main/java/org/sonar/cxx/sensors/functioncomplexity/CxxFunctionComplexitySquidSensor.java index 47ea12a8c8..e783f22e5a 100644 --- a/cxx-sensors/src/main/java/org/sonar/cxx/sensors/functioncomplexity/CxxFunctionComplexitySquidSensor.java +++ b/cxx-sensors/src/main/java/org/sonar/cxx/sensors/functioncomplexity/CxxFunctionComplexitySquidSensor.java @@ -131,8 +131,11 @@ public void publishMeasureForFile(InputFile inputFile, SourceFile squidFile, Sen private void publishComplexFunctionMetricsForFile(InputFile inputFile, SourceFile squidFile, SensorContext context){ FunctionCount c = complexFunctionsPerFile.get(squidFile); - if (c == null) - return; + if (c == null){ + c = new FunctionCount(); + c.countBelowThreshold = 0; + c.countOverThreshold = 0; + } context.newMeasure() .forMetric(FunctionComplexityMetrics.COMPLEX_FUNCTIONS) @@ -143,15 +146,18 @@ private void publishComplexFunctionMetricsForFile(InputFile inputFile, SourceFil context.newMeasure() .forMetric(FunctionComplexityMetrics.PERC_COMPLEX_FUNCTIONS) .on(inputFile) - .withValue(calculatePercentage((int)c.countOverThreshold, (int)c.countBelowThreshold)) + .withValue(calculatePercentual((int)c.countOverThreshold, (int)c.countBelowThreshold)) .save(); } private void publishLocInComplexFunctionMetricsForFile(InputFile inputFile, SourceFile squidFile, SensorContext context){ FunctionCount locCount = locInComplexFunctionsPerFile.get(squidFile); - if (locCount == null) - return; + if (locCount == null){ + locCount = new FunctionCount(); + locCount.countBelowThreshold = 0; + locCount.countOverThreshold = 0; + } context.newMeasure() .forMetric(FunctionComplexityMetrics.LOC_IN_COMPLEX_FUNCTIONS) @@ -162,7 +168,7 @@ private void publishLocInComplexFunctionMetricsForFile(InputFile inputFile, Sour context.newMeasure() .forMetric(FunctionComplexityMetrics.PERC_LOC_IN_COMPLEX_FUNCTIONS) .on(inputFile) - .withValue(calculatePercentage((int)locCount.countOverThreshold, (int)locCount.countBelowThreshold)) + .withValue(calculatePercentual((int)locCount.countOverThreshold, (int)locCount.countBelowThreshold)) .save(); } @@ -182,7 +188,7 @@ private void publishComplexFunctionMetrics(InputModule module, SensorContext con context.newMeasure() .forMetric(FunctionComplexityMetrics.PERC_COMPLEX_FUNCTIONS) .on(module) - .withValue(calculatePercentage(functionsOverThreshold, functionsBelowThreshold)) + .withValue(calculatePercentual(functionsOverThreshold, functionsBelowThreshold)) .save(); } @@ -196,12 +202,16 @@ private void publishLinesOfCodeInComplexFunctionMetrics(InputModule module, Sens context.newMeasure() .forMetric(FunctionComplexityMetrics.PERC_LOC_IN_COMPLEX_FUNCTIONS) .on(module) - .withValue(calculatePercentage(linesOfCodeOverThreshold, linesOfCodeBelowThreshold)) + .withValue(calculatePercentual(linesOfCodeOverThreshold, linesOfCodeBelowThreshold)) .save(); } - private double calculatePercentage(int overThreshold, int belowThreshold){ - return ((float)overThreshold * 100.0) / ((float)overThreshold + (float)belowThreshold); + private double calculatePercentual(int overThreshold, int belowThreshold){ + double total = (double)overThreshold + (double)belowThreshold; + if (total > 0) + return ((float)overThreshold * 100.0) / ((float)overThreshold + (float)belowThreshold); + else + return 0; } } diff --git a/cxx-sensors/src/main/java/org/sonar/cxx/sensors/functionsize/CxxFunctionSizeSquidSensor.java b/cxx-sensors/src/main/java/org/sonar/cxx/sensors/functionsize/CxxFunctionSizeSquidSensor.java index 90a7f6bdb7..58829090cf 100644 --- a/cxx-sensors/src/main/java/org/sonar/cxx/sensors/functionsize/CxxFunctionSizeSquidSensor.java +++ b/cxx-sensors/src/main/java/org/sonar/cxx/sensors/functionsize/CxxFunctionSizeSquidSensor.java @@ -49,15 +49,15 @@ public class CxxFunctionSizeSquidSensor extends SquidAstVisitor impleme public static final String FUNCTION_SIZE_THRESHOLD_KEY = "funcsize.threshold"; - private int functionsBelowThreshold; + private int functionsBelowThreshold = 0; - private int sizeThreshold; + private int sizeThreshold = 0; - private int functionsOverThreshold; + private int functionsOverThreshold = 0; - private int locBelowThreshold; + private int locBelowThreshold = 0; - private int locOverThreshold; + private int locOverThreshold = 0; private Hashtable bigFunctionsPerFile = new Hashtable<>(); @@ -167,13 +167,20 @@ private void publishLocInBigFunctionForProject(InputModule module, SensorContext } private double calculatePercentual(int overThreshold, int belowThreshold){ - return ((float)overThreshold * 100.0) / ((float)overThreshold + (float)belowThreshold); + double total = (double)overThreshold + (double)belowThreshold; + if (total > 0) + return ((float)overThreshold * 100.0) / ((float)overThreshold + (float)belowThreshold); + else + return 0; } private void publishBigFunctionMetrics(InputFile inputFile, SourceFile squidFile, SensorContext context) { FunctionCount c = bigFunctionsPerFile.get(squidFile); - if (c == null) - return; + if (c == null){ + c = new FunctionCount(); + c.countBelowThreshold = 0; + c.countOverThreshold = 0; + } context.newMeasure() .forMetric(FunctionSizeMetrics.BIG_FUNCTIONS) @@ -190,8 +197,11 @@ private void publishBigFunctionMetrics(InputFile inputFile, SourceFile squidFile private void publishLocInBigFunctionMetrics(InputFile inputFile, SourceFile squidFile, SensorContext context) { FunctionCount c = locInBigFunctionsPerFile.get(squidFile); - if (c == null) - return; + if (c == null) { + c = new FunctionCount(); + c.countBelowThreshold = 0; + c.countOverThreshold = 0; + } context.newMeasure() .forMetric(FunctionSizeMetrics.LOC_IN_FUNCTIONS) diff --git a/cxx-sensors/src/test/java/org/sonar/cxx/sensors/functioncomplexity/CxxFunctionComplexitySquidSensorTest.java b/cxx-sensors/src/test/java/org/sonar/cxx/sensors/functioncomplexity/CxxFunctionComplexitySquidSensorTest.java index c3e961d690..b3d27661f8 100644 --- a/cxx-sensors/src/test/java/org/sonar/cxx/sensors/functioncomplexity/CxxFunctionComplexitySquidSensorTest.java +++ b/cxx-sensors/src/test/java/org/sonar/cxx/sensors/functioncomplexity/CxxFunctionComplexitySquidSensorTest.java @@ -84,6 +84,23 @@ private DefaultInputFile getInputFile() throws IOException{ return inputFile; } + private DefaultInputFile getEmptyInputFile() throws IOException{ + File baseDir = TestUtils.loadResource("/org/sonar/cxx/sensors"); + File target = new File(baseDir, "EmptyFile.cc"); + + String content = new String(Files.readAllBytes(target.toPath()), "UTF-8"); + DefaultInputFile inputFile = TestInputFileBuilder.create("ProjectKey", baseDir, target).setContents(content) + .setCharset(Charset.forName("UTF-8")).setLanguage(language.getKey()) + .setType(InputFile.Type.MAIN).build(); + + sensorContext = SensorContextTester.create(baseDir); + sensorContext.fileSystem().add(inputFile); + + when(fileLinesContextFactory.createFor(inputFile)).thenReturn(fileLinesContext); + + return inputFile; + } + public boolean containsAll(Collection c){ return false; } @@ -109,7 +126,20 @@ public void testPublishMeasuresForProject() throws IOException { assertThat(getMeasureValue(sensorContext, sensorContext.module().key(), FunctionComplexityMetrics.LOC_IN_COMPLEX_FUNCTIONS)).isEqualTo(44); assertThat(getMeasureValue(sensorContext, sensorContext.module().key(), FunctionComplexityMetrics.PERC_COMPLEX_FUNCTIONS)).isEqualTo(40.0); assertThat(getMeasureValue(sensorContext, sensorContext.module().key(), FunctionComplexityMetrics.PERC_LOC_IN_COMPLEX_FUNCTIONS)).isEqualTo(80); - } + } + + @Test + public void testPublishMeasuresForEmptyProject() throws IOException { + DefaultInputFile inputFile = getEmptyInputFile(); + + CxxAstScanner.scanSingleFile(inputFile, sensorContext, TestUtils.mockCxxLanguage(), sensor.getVisitor()); + sensor.publishMeasureForProject(sensorContext.module(), sensorContext); + + assertThat(getMeasureValue(sensorContext, sensorContext.module().key(), FunctionComplexityMetrics.COMPLEX_FUNCTIONS)).isEqualTo(0); + assertThat(getMeasureValue(sensorContext, sensorContext.module().key(), FunctionComplexityMetrics.LOC_IN_COMPLEX_FUNCTIONS)).isEqualTo(0); + assertThat(getMeasureValue(sensorContext, sensorContext.module().key(), FunctionComplexityMetrics.PERC_COMPLEX_FUNCTIONS)).isEqualTo(0); + assertThat(getMeasureValue(sensorContext, sensorContext.module().key(), FunctionComplexityMetrics.PERC_LOC_IN_COMPLEX_FUNCTIONS)).isEqualTo(0); + } @Test public void testPublishMeasuresForFile() throws IOException { @@ -123,4 +153,17 @@ public void testPublishMeasuresForFile() throws IOException { assertThat(getMeasureValue(sensorContext, inputFile.key(), FunctionComplexityMetrics.PERC_COMPLEX_FUNCTIONS)).isEqualTo(40.0); assertThat(getMeasureValue(sensorContext, inputFile.key(), FunctionComplexityMetrics.PERC_LOC_IN_COMPLEX_FUNCTIONS)).isEqualTo(80); } + + @Test + public void testPublishMeasuresForEmptyFile() throws IOException { + DefaultInputFile inputFile = getEmptyInputFile(); + + SourceFile squidFile = CxxAstScanner.scanSingleFile(inputFile, sensorContext, TestUtils.mockCxxLanguage(), sensor.getVisitor()); + sensor.publishMeasureForFile(inputFile, squidFile, sensorContext); + + assertThat(getMeasureValue(sensorContext, inputFile.key(), FunctionComplexityMetrics.COMPLEX_FUNCTIONS)).isEqualTo(0); + assertThat(getMeasureValue(sensorContext, inputFile.key(), FunctionComplexityMetrics.LOC_IN_COMPLEX_FUNCTIONS)).isEqualTo(0); + assertThat(getMeasureValue(sensorContext, inputFile.key(), FunctionComplexityMetrics.PERC_COMPLEX_FUNCTIONS)).isEqualTo(0); + assertThat(getMeasureValue(sensorContext, inputFile.key(), FunctionComplexityMetrics.PERC_LOC_IN_COMPLEX_FUNCTIONS)).isEqualTo(0); + } } diff --git a/cxx-sensors/src/test/java/org/sonar/cxx/sensors/functionsize/CxxFunctionSizeSquidSensorTest.java b/cxx-sensors/src/test/java/org/sonar/cxx/sensors/functionsize/CxxFunctionSizeSquidSensorTest.java index b651df4618..7111629f04 100644 --- a/cxx-sensors/src/test/java/org/sonar/cxx/sensors/functionsize/CxxFunctionSizeSquidSensorTest.java +++ b/cxx-sensors/src/test/java/org/sonar/cxx/sensors/functionsize/CxxFunctionSizeSquidSensorTest.java @@ -82,6 +82,23 @@ private DefaultInputFile getInputFile() throws IOException{ return inputFile; } + private DefaultInputFile getEmptyInputFile() throws IOException{ + File baseDir = TestUtils.loadResource("/org/sonar/cxx/sensors"); + File target = new File(baseDir, "EmptyFile.cc"); + + String content = new String(Files.readAllBytes(target.toPath()), "UTF-8"); + DefaultInputFile inputFile = TestInputFileBuilder.create("ProjectKey", baseDir, target).setContents(content) + .setCharset(Charset.forName("UTF-8")).setLanguage(language.getKey()) + .setType(InputFile.Type.MAIN).build(); + + sensorContext = SensorContextTester.create(baseDir); + sensorContext.fileSystem().add(inputFile); + + when(fileLinesContextFactory.createFor(inputFile)).thenReturn(fileLinesContext); + + return inputFile; + } + private T getMeasureValue(SensorContextTester sensorContext, String componentKey, Metric metric){ Collection measures = sensorContext.measures(componentKey); T value = null; @@ -106,6 +123,20 @@ public void testPublishMeasuresForProject() throws IOException { assertThat(getMeasureValue(sensorContext, sensorContext.module().key(), FunctionSizeMetrics.PERC_LOC_IN_BIG_FUNCTIONS)).isEqualTo(80); } + @Test + public void testPublishMeasuresForEmptyProject() throws IOException { + DefaultInputFile inputFile = getEmptyInputFile(); + + CxxAstScanner.scanSingleFile(inputFile, sensorContext, TestUtils.mockCxxLanguage(), sensor.getVisitor()); + sensor.publishMeasureForProject(sensorContext.module(), sensorContext); + + assertThat(getMeasureValue(sensorContext, sensorContext.module().key(), FunctionSizeMetrics.BIG_FUNCTIONS)).isEqualTo(0); + assertThat(getMeasureValue(sensorContext, sensorContext.module().key(), FunctionSizeMetrics.LOC_IN_FUNCTIONS)).isEqualTo(0); + assertThat(getMeasureValue(sensorContext, sensorContext.module().key(), FunctionSizeMetrics.LOC_IN_BIG_FUNCTIONS)).isEqualTo(0); + assertThat(getMeasureValue(sensorContext, sensorContext.module().key(), FunctionSizeMetrics.PERC_BIG_FUNCTIONS)).isEqualTo(0); + assertThat(getMeasureValue(sensorContext, sensorContext.module().key(), FunctionSizeMetrics.PERC_LOC_IN_BIG_FUNCTIONS)).isEqualTo(0); + } + @Test public void testPublishMeasuresForFile() throws IOException { DefaultInputFile inputFile = getInputFile(); @@ -119,4 +150,18 @@ public void testPublishMeasuresForFile() throws IOException { assertThat(getMeasureValue(sensorContext, inputFile.key(), FunctionSizeMetrics.PERC_BIG_FUNCTIONS)).isEqualTo(40.0); assertThat(getMeasureValue(sensorContext, inputFile.key(), FunctionSizeMetrics.PERC_LOC_IN_BIG_FUNCTIONS)).isEqualTo(80); } + + @Test + public void testPublishMeasuresForEmptyFile() throws IOException { + DefaultInputFile inputFile = getEmptyInputFile(); + + SourceFile squidFile = CxxAstScanner.scanSingleFile(inputFile, sensorContext, TestUtils.mockCxxLanguage(), sensor.getVisitor()); + sensor.publishMeasureForFile(inputFile, squidFile, sensorContext); + + assertThat(getMeasureValue(sensorContext, inputFile.key(), FunctionSizeMetrics.BIG_FUNCTIONS)).isEqualTo(0); + assertThat(getMeasureValue(sensorContext, inputFile.key(), FunctionSizeMetrics.LOC_IN_FUNCTIONS)).isEqualTo(0); + assertThat(getMeasureValue(sensorContext, inputFile.key(), FunctionSizeMetrics.LOC_IN_BIG_FUNCTIONS)).isEqualTo(0); + assertThat(getMeasureValue(sensorContext, inputFile.key(), FunctionSizeMetrics.PERC_BIG_FUNCTIONS)).isEqualTo(0); + assertThat(getMeasureValue(sensorContext, inputFile.key(), FunctionSizeMetrics.PERC_LOC_IN_BIG_FUNCTIONS)).isEqualTo(0); + } } diff --git a/cxx-sensors/src/test/resources/org/sonar/cxx/sensors/EmptyFile.cc b/cxx-sensors/src/test/resources/org/sonar/cxx/sensors/EmptyFile.cc new file mode 100644 index 0000000000..8b13789179 --- /dev/null +++ b/cxx-sensors/src/test/resources/org/sonar/cxx/sensors/EmptyFile.cc @@ -0,0 +1 @@ +