]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-11778 Measure 'new lines' doesn't match 'lines' if the file ends with new line
authorDuarte Meneses <duarte.meneses@sonarsource.com>
Wed, 24 Jul 2019 12:39:46 +0000 (07:39 -0500)
committerSonarTech <sonartech@sonarsource.com>
Wed, 24 Jul 2019 18:21:14 +0000 (20:21 +0200)
sonar-plugin-api-impl/src/main/java/org/sonar/api/batch/fs/internal/DefaultInputFile.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/report/ChangedLinesPublisher.java
sonar-scanner-engine/src/test/java/org/sonar/scanner/report/ChangedLinesPublisherTest.java

index 4a48bf9a89680412a3f26e8d4f2e69a08bff2462..0d019a6d29ccb2a0806dbe50462e366845dbfdeb 100644 (file)
@@ -340,7 +340,7 @@ public class DefaultInputFile extends DefaultInputComponent implements InputFile
       "%s is not a valid line offset for %s. File %s has %s character(s) at line %s", pointer.lineOffset(), owner, this, lineLength, pointer.line());
   }
 
-  private int lineLength(int line) {
+  public int lineLength(int line) {
     return originalLineEndOffsets()[line - 1] - originalLineStartOffsets()[line - 1];
   }
 
index 7da793fdf8dc8108eb8219a449874fffb828cec1..981ab3170666bc91a79e26fbf1c073e83295d75d 100644 (file)
@@ -25,18 +25,18 @@ import java.util.Map;
 import java.util.Set;
 import java.util.stream.Collectors;
 import java.util.stream.StreamSupport;
+import org.sonar.api.batch.fs.internal.DefaultInputFile;
+import org.sonar.api.batch.fs.internal.DefaultInputProject;
 import org.sonar.api.batch.scm.ScmProvider;
+import org.sonar.api.impl.utils.ScannerUtils;
 import org.sonar.api.utils.log.Logger;
 import org.sonar.api.utils.log.Loggers;
 import org.sonar.api.utils.log.Profiler;
-import org.sonar.api.batch.fs.internal.DefaultInputFile;
-import org.sonar.api.batch.fs.internal.DefaultInputProject;
 import org.sonar.scanner.protocol.output.ScannerReport;
 import org.sonar.scanner.protocol.output.ScannerReportWriter;
 import org.sonar.scanner.scan.branch.BranchConfiguration;
 import org.sonar.scanner.scan.filesystem.InputComponentStore;
 import org.sonar.scanner.scm.ScmConfiguration;
-import org.sonar.api.impl.utils.ScannerUtils;
 
 public class ChangedLinesPublisher implements ReportPublisherStep {
   private static final Logger LOG = Loggers.get(ChangedLinesPublisher.class);
@@ -88,8 +88,14 @@ public class ChangedLinesPublisher implements ReportPublisherStep {
     }
 
     for (Map.Entry<Path, DefaultInputFile> e : changedFiles.entrySet()) {
+      DefaultInputFile inputFile = e.getValue();
       Set<Integer> changedLines = pathSetMap.getOrDefault(e.getKey(), Collections.emptySet());
 
+      // detect unchanged last empty line
+      if (changedLines.size() + 1 == inputFile.lines() && inputFile.lineLength(inputFile.lines()) == 0) {
+        changedLines.add(inputFile.lines());
+      }
+
       if (changedLines.isEmpty()) {
         LOG.warn("File '{}' was detected as changed but without having changed lines", e.getKey().toAbsolutePath());
       }
index d06e33f611174619ece4e6751b608e1149785835..76d4f2285e75966f2f4ab7d855ed9756bc8fa932 100644 (file)
@@ -30,11 +30,11 @@ import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.TemporaryFolder;
-import org.sonar.api.batch.scm.ScmProvider;
 import org.sonar.api.batch.fs.internal.DefaultInputFile;
 import org.sonar.api.batch.fs.internal.DefaultInputProject;
-import org.sonar.scanner.fs.InputModuleHierarchy;
 import org.sonar.api.batch.fs.internal.TestInputFileBuilder;
+import org.sonar.api.batch.scm.ScmProvider;
+import org.sonar.scanner.fs.InputModuleHierarchy;
 import org.sonar.scanner.protocol.output.ScannerReportReader;
 import org.sonar.scanner.protocol.output.ScannerReportWriter;
 import org.sonar.scanner.scan.branch.BranchConfiguration;
@@ -113,8 +113,8 @@ public class ChangedLinesPublisherTest {
 
   @Test
   public void write_changed_files() {
-    DefaultInputFile fileWithChangedLines = createInputFile("path1");
-    DefaultInputFile fileWithoutChangedLines = createInputFile("path2");
+    DefaultInputFile fileWithChangedLines = createInputFile("path1", "l1\nl2\nl3\n");
+    DefaultInputFile fileWithoutChangedLines = createInputFile("path2", "l1\nl2\nl3\n");
     Set<Path> paths = new HashSet<>(Arrays.asList(BASE_DIR.resolve("path1"), BASE_DIR.resolve("path2")));
     Set<Integer> lines = new HashSet<>(Arrays.asList(1, 10));
     when(provider.branchChangedLines(TARGET_BRANCH, BASE_DIR, paths)).thenReturn(Collections.singletonMap(BASE_DIR.resolve("path1"), lines));
@@ -122,12 +122,43 @@ public class ChangedLinesPublisherTest {
 
     publisher.publish(writer);
 
-    assertPublished(fileWithChangedLines, lines);
+    assertPublished(fileWithChangedLines, new HashSet<>(Arrays.asList(1, 10)));
+    assertPublished(fileWithoutChangedLines, Collections.emptySet());
+  }
+
+  @Test
+  public void write_last_line_as_changed_if_all_other_lines_are_changed_and_last_line_is_empty() {
+    DefaultInputFile fileWithChangedLines = createInputFile("path1", "l1\nl2\nl3\n");
+    DefaultInputFile fileWithoutChangedLines = createInputFile("path2", "l1\nl2\nl3\n");
+    Set<Path> paths = new HashSet<>(Arrays.asList(BASE_DIR.resolve("path1"), BASE_DIR.resolve("path2")));
+    Set<Integer> lines = new HashSet<>(Arrays.asList(1, 2, 3));
+    when(provider.branchChangedLines(TARGET_BRANCH, BASE_DIR, paths)).thenReturn(Collections.singletonMap(BASE_DIR.resolve("path1"), lines));
+    when(inputComponentStore.allChangedFilesToPublish()).thenReturn(Arrays.asList(fileWithChangedLines, fileWithoutChangedLines));
+
+    publisher.publish(writer);
+
+    assertPublished(fileWithChangedLines, new HashSet<>(Arrays.asList(1, 2, 3, 4)));
+    assertPublished(fileWithoutChangedLines, Collections.emptySet());
+  }
+
+  @Test
+  public void dont_write_last_line_as_changed_if_its_not_empty() {
+    DefaultInputFile fileWithChangedLines = createInputFile("path1", "l1\nl2\nl3\nl4");
+    DefaultInputFile fileWithoutChangedLines = createInputFile("path2", "l1\nl2\nl3\nl4");
+    Set<Path> paths = new HashSet<>(Arrays.asList(BASE_DIR.resolve("path1"), BASE_DIR.resolve("path2")));
+    Set<Integer> lines = new HashSet<>(Arrays.asList(1, 2, 3));
+    when(provider.branchChangedLines(TARGET_BRANCH, BASE_DIR, paths)).thenReturn(Collections.singletonMap(BASE_DIR.resolve("path1"), lines));
+    when(inputComponentStore.allChangedFilesToPublish()).thenReturn(Arrays.asList(fileWithChangedLines, fileWithoutChangedLines));
+
+    publisher.publish(writer);
+
+    assertPublished(fileWithChangedLines, new HashSet<>(Arrays.asList(1, 2, 3)));
     assertPublished(fileWithoutChangedLines, Collections.emptySet());
   }
 
-  private DefaultInputFile createInputFile(String path) {
+  private DefaultInputFile createInputFile(String path, String contents) {
     return new TestInputFileBuilder("module", path)
+      .setContents(contents)
       .setProjectBaseDir(BASE_DIR)
       .setModuleBaseDir(BASE_DIR)
       .build();