]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-5077 Special case of empty files
authorJulien HENRY <julien.henry@sonarsource.com>
Tue, 20 Jan 2015 11:18:37 +0000 (12:18 +0100)
committerJulien HENRY <julien.henry@sonarsource.com>
Tue, 20 Jan 2015 11:18:37 +0000 (12:18 +0100)
sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/DefaultInputFileValueCoder.java
sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/FileMetadata.java
sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/InputFileBuilder.java
sonar-batch/src/main/java/org/sonar/batch/scm/ScmSensor.java
sonar-batch/src/test/java/org/sonar/batch/mediumtest/scm/ScmMediumTest.java
sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/FileMetadataTest.java
sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/DefaultInputFile.java

index 3ce3c5872c75207714d421fb00b22c7e1343d4f6..7b6b4911191d9b79cd2479dcc99a61f5d3ebdeaf 100644 (file)
@@ -47,6 +47,7 @@ class DefaultInputFileValueCoder implements ValueCoder {
     putUTFOrNull(value, f.hash());
     value.put(f.lines());
     putUTFOrNull(value, f.encoding());
+    value.put(f.isEmpty());
     value.putLongArray(f.originalLineOffsets());
     for (int i = 0; i < f.lines(); i++) {
       value.putByteArray(f.lineHashes()[i]);
@@ -76,6 +77,7 @@ class DefaultInputFileValueCoder implements ValueCoder {
     file.setHash(value.getString());
     file.setLines(value.getInt());
     file.setEncoding(value.getString());
+    file.setEmpty(value.getBoolean());
     file.setOriginalLineOffsets(value.getLongArray());
     byte[][] lineHashes = new byte[file.lines()][];
     for (int i = 0; i < file.lines(); i++) {
index afa4735d77ef6612b98bb4b3043a5f740d073284..d90e026f16b7b2526331b49340738eed7ac33361 100644 (file)
@@ -55,8 +55,8 @@ class FileMetadata {
     long currentOriginalOffset = 0;
     List<Long> originalLineOffsets = new ArrayList<Long>();
     List<Object> lineHashes = new ArrayList<Object>();
-    int lines = 0;
-    char c = (char) -1;
+    int lines = 1;
+    char c = (char) 0;
     try (Reader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), encoding))) {
       MessageDigest globalMd5Digest = DigestUtils.getMd5Digest();
       MessageDigest lineMd5Digest = DigestUtils.getMd5Digest();
@@ -102,11 +102,11 @@ class FileMetadata {
       }
       if (c != (char) -1) {
         // Last line
-        lines++;
         lineHashes.add(blankline ? null : lineMd5Digest.digest());
       }
-      String filehash = Hex.encodeHexString(globalMd5Digest.digest());
-      return new Metadata(lines, filehash, originalLineOffsets, lineHashes.toArray(new byte[0][]));
+      boolean empty = lines == 1 && blankline;
+      String filehash = empty ? null : Hex.encodeHexString(globalMd5Digest.digest());
+      return new Metadata(lines, filehash, originalLineOffsets, lineHashes.toArray(new byte[0][]), empty);
 
     } catch (IOException e) {
       throw new IllegalStateException(String.format("Fail to read file '%s' with encoding '%s'", file.getAbsolutePath(), encoding), e);
@@ -131,10 +131,12 @@ class FileMetadata {
     final String hash;
     final long[] originalLineOffsets;
     final byte[][] lineHashes;
+    final boolean empty;
 
-    private Metadata(int lines, String hash, List<Long> originalLineOffsets, byte[][] lineHashes) {
+    private Metadata(int lines, String hash, List<Long> originalLineOffsets, byte[][] lineHashes, boolean empty) {
       this.lines = lines;
       this.hash = hash;
+      this.empty = empty;
       this.originalLineOffsets = Longs.toArray(originalLineOffsets);
       this.lineHashes = lineHashes;
     }
index 49303a056fd09d058b2d824c2ed5013e7af151b2..b3aba4f61b0472d3e817127aff883290629c0cce 100644 (file)
@@ -112,6 +112,7 @@ class InputFileBuilder {
     inputFile.setHash(metadata.hash);
     inputFile.setOriginalLineOffsets(metadata.originalLineOffsets);
     inputFile.setLineHashes(metadata.lineHashes);
+    inputFile.setEmpty(metadata.empty);
     inputFile.setStatus(statusDetection.status(inputFile.moduleKey(), inputFile.relativePath(), metadata.hash));
     if (analysisMode.isIncremental() && inputFile.status() == InputFile.Status.SAME) {
       return null;
index 56e477ec9c770851fe5aa0768d36efc2e10cadef..00f6839bfdb84cd0e6f469ca92648f30fa9b5618 100644 (file)
@@ -26,6 +26,7 @@ import org.sonar.api.batch.bootstrap.ProjectDefinition;
 import org.sonar.api.batch.fs.FileSystem;
 import org.sonar.api.batch.fs.InputFile;
 import org.sonar.api.batch.fs.InputFile.Status;
+import org.sonar.api.batch.fs.internal.DefaultInputFile;
 import org.sonar.api.batch.sensor.Sensor;
 import org.sonar.api.batch.sensor.SensorContext;
 import org.sonar.api.batch.sensor.SensorDescriptor;
@@ -92,7 +93,7 @@ public final class ScmSensor implements Sensor {
 
     if (f.status() == Status.SAME && fileData != null) {
       if (fileData.needBlame()) {
-        filesToBlame.add(f);
+        addIfNotEmpty(filesToBlame, f);
       } else {
         // Copy previous measures
         String scmAuthorsByLine = fileData.scmAuthorsByLine();
@@ -105,6 +106,12 @@ public final class ScmSensor implements Sensor {
         }
       }
     } else {
+      addIfNotEmpty(filesToBlame, f);
+    }
+  }
+
+  private void addIfNotEmpty(List<InputFile> filesToBlame, InputFile f) {
+    if (!((DefaultInputFile) f).isEmpty()) {
       filesToBlame.add(f);
     }
   }
index 4a6e1a79cef698e307c9017861f98edeb35b82aa..c8456c6c803273d58b938f59dc4fccbe13e5598d 100644 (file)
@@ -94,6 +94,36 @@ public class ScmMediumTest {
       .withValue("1=;2=julien;3=julien;4=julien;5=simon"));
   }
 
+  @Test
+  public void noScmOnEmptyFile() throws IOException {
+
+    File baseDir = prepareProject();
+
+    // Clear file content
+    FileUtils.write(new File(baseDir, "src/sample.xoo"), "");
+
+    TaskResult result = tester.newTask()
+      .properties(ImmutableMap.<String, String>builder()
+        .put("sonar.task", "scan")
+        .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
+        .put("sonar.projectKey", "com.foo.project")
+        .put("sonar.projectName", "Foo Project")
+        .put("sonar.projectVersion", "1.0-SNAPSHOT")
+        .put("sonar.projectDescription", "Description of Foo Project")
+        .put("sonar.sources", "src")
+        .put("sonar.scm.provider", "xoo")
+        .build())
+      .start();
+
+    // lines + qprofile
+    assertThat(result.measures()).hasSize(2);
+
+    assertThat(result.measures()).contains(new DefaultMeasure<Integer>()
+      .forMetric(CoreMetrics.LINES)
+      .onFile(new DefaultInputFile("com.foo.project", "src/sample.xoo"))
+      .withValue(1));
+  }
+
   @Test
   public void failIfMissingFile() throws IOException {
 
index 3b9cec76fdb0c08a89b1b97f348c0536e11f1a4b..e6c73e80fd7f8af2fa1c60e085fe0279e037a8a3 100644 (file)
@@ -46,10 +46,11 @@ public class FileMetadataTest {
     FileUtils.touch(tempFile);
 
     FileMetadata.Metadata metadata = new FileMetadata().read(tempFile, Charsets.UTF_8);
-    assertThat(metadata.lines).isEqualTo(0);
-    assertThat(metadata.hash).isNotEmpty();
+    assertThat(metadata.lines).isEqualTo(1);
+    assertThat(metadata.hash).isNull();
     assertThat(metadata.originalLineOffsets).containsOnly(0);
-    assertThat(metadata.lineHashes).isEmpty();
+    assertThat(metadata.lineHashes[0]).isNull();
+    assertThat(metadata.empty).isTrue();
   }
 
   @Test
@@ -64,6 +65,7 @@ public class FileMetadataTest {
     assertThat(metadata.lineHashes[0]).containsOnly(md5("foo"));
     assertThat(metadata.lineHashes[1]).containsOnly(md5("bar"));
     assertThat(metadata.lineHashes[2]).containsOnly(md5("baz"));
+    assertThat(metadata.empty).isFalse();
   }
 
   @Test
index 391ac575f328ff774ea747b7f48a6b04c016f981..411e3f8389b72c15f20010ca27afe2c6de0e96aa 100644 (file)
@@ -39,8 +39,9 @@ public class DefaultInputFile implements InputFile, Serializable {
   private String hash;
   private int lines;
   private String encoding;
-  long[] originalLineOffsets;
-  byte[][] lineHashes;
+  private long[] originalLineOffsets;
+  private byte[][] lineHashes;
+  private boolean empty;
 
   public DefaultInputFile(String moduleKey, String relativePath) {
     this.moduleKey = moduleKey;
@@ -168,6 +169,15 @@ public class DefaultInputFile implements InputFile, Serializable {
     return this;
   }
 
+  public boolean isEmpty() {
+    return this.empty;
+  }
+
+  public DefaultInputFile setEmpty(boolean empty) {
+    this.empty = empty;
+    return this;
+  }
+
   @Override
   public boolean equals(Object o) {
     if (this == o) {