diff options
author | Simon Brandhof <simon.brandhof@sonarsource.com> | 2017-03-01 15:33:22 +0100 |
---|---|---|
committer | Simon Brandhof <simon.brandhof@sonarsource.com> | 2017-03-01 16:52:54 +0100 |
commit | 72ac5447a32d6537e805374116cbf369f7a65038 (patch) | |
tree | 7f74cc6a6d8ba4b733162f750e449ba7581a010a | |
parent | 187e582f89cc4ba48e7078abe16e8869e69b9e36 (diff) | |
download | sonarqube-72ac5447a32d6537e805374116cbf369f7a65038.tar.gz sonarqube-72ac5447a32d6537e805374116cbf369f7a65038.zip |
SONAR-8835 support NULL in column file_sources.line_hashes
The column can be null on Oracle if source content is empty.
Other databases do not store NULL but empty string.
7 files changed, 49 insertions, 33 deletions
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/filemove/FileMoveDetectionStep.java b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/filemove/FileMoveDetectionStep.java index 182e4232455..df6c144f05f 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/filemove/FileMoveDetectionStep.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/filemove/FileMoveDetectionStep.java @@ -56,6 +56,7 @@ import org.sonar.server.computation.task.projectanalysis.filemove.FileSimilarity import org.sonar.server.computation.task.projectanalysis.source.SourceLinesRepository; import org.sonar.server.computation.task.step.ComputationStep; +import static com.google.common.base.MoreObjects.firstNonNull; import static com.google.common.base.Splitter.on; import static com.google.common.collect.FluentIterable.from; import static java.util.Arrays.asList; @@ -233,7 +234,8 @@ public class FileMoveDetectionStep implements ComputationStep { if (fileSourceDto == null) { return null; } - return new File(dbComponent.getPath(), LINES_HASHES_SPLITTER.splitToList(fileSourceDto.getLineHashes())); + String lineHashes = firstNonNull(fileSourceDto.getLineHashes(), ""); + return new File(dbComponent.getPath(), LINES_HASHES_SPLITTER.splitToList(lineHashes)); } private static void printIfDebug(ScoreMatrix scoreMatrix) { diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/filemove/FileSimilarity.java b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/filemove/FileSimilarity.java index 86743b06906..7f3547b904e 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/filemove/FileSimilarity.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/filemove/FileSimilarity.java @@ -20,8 +20,6 @@ package org.sonar.server.computation.task.projectanalysis.filemove; import java.util.List; -import javax.annotation.CheckForNull; -import javax.annotation.Nullable; import static java.util.Objects.requireNonNull; @@ -31,16 +29,19 @@ public interface FileSimilarity { private final String path; private final List<String> lineHashes; - public File(String path, @Nullable List<String> lineHashes) { + public File(String path, List<String> lineHashes) { this.path = requireNonNull(path, "path can not be null"); - this.lineHashes = lineHashes; + this.lineHashes = requireNonNull(lineHashes, "lineHashes can not be null"); } public String getPath() { return path; } - @CheckForNull + /** + * List of hash of each line. An empty list is returned + * if file content is empty. + */ public List<String> getLineHashes() { return lineHashes; } diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/filemove/FileSimilarityImpl.java b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/filemove/FileSimilarityImpl.java index c34bf8c1564..d059c0ac182 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/filemove/FileSimilarityImpl.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/filemove/FileSimilarityImpl.java @@ -19,8 +19,6 @@ */ package org.sonar.server.computation.task.projectanalysis.filemove; -import java.util.List; - public class FileSimilarityImpl implements FileSimilarity { private final SourceSimilarity sourceSimilarity; @@ -31,15 +29,10 @@ public class FileSimilarityImpl implements FileSimilarity { @Override public int score(File file1, File file2) { - int score = 0; - - // TODO check filenames + // Algorithm could be improved by increasing score + // depending on filename similarity + // Current implementation relies on file content only. - List<String> lineHashes1 = file1.getLineHashes(); - List<String> lineHashes2 = file2.getLineHashes(); - if (lineHashes1 != null && lineHashes2 != null) { - score += sourceSimilarity.score(lineHashes1, lineHashes2); - } - return score; + return sourceSimilarity.score(file1.getLineHashes(), file2.getLineHashes()); } } diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/filemove/SourceSimilarityImpl.java b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/filemove/SourceSimilarityImpl.java index bb9da71e5ef..bdbc91d3b25 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/filemove/SourceSimilarityImpl.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/filemove/SourceSimilarityImpl.java @@ -27,12 +27,15 @@ import static java.lang.Math.min; public class SourceSimilarityImpl implements SourceSimilarity { @Override - public <T extends Object> int score(List<T> left, List<T> right) { + public <T> int score(List<T> left, List<T> right) { + if (left.isEmpty() && right.isEmpty()) { + return 0; + } int distance = levenshteinDistance(left, right); return (int) (100 * (1.0 - ((double) distance) / (max(left.size(), right.size())))); } - <T extends Object> int levenshteinDistance(List<T> left, List<T> right) { + private static <T> int levenshteinDistance(List<T> left, List<T> right) { int len0 = left.size() + 1; int len1 = right.size() + 1; diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/filemove/FileMoveDetectionStepTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/filemove/FileMoveDetectionStepTest.java index 6f67fd94847..68af5bc8837 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/filemove/FileMoveDetectionStepTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/filemove/FileMoveDetectionStepTest.java @@ -23,13 +23,12 @@ import java.io.File; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; import java.util.HashMap; -import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.function.Function; +import javax.annotation.Nullable; import org.apache.commons.io.FileUtils; import org.junit.Before; import org.junit.Rule; @@ -410,6 +409,18 @@ public class FileMoveDetectionStepTest { } @Test + public void execute_detects_no_move_if_two_files_are_empty() { + analysisMetadataHolder.setBaseAnalysis(ANALYSIS); + mockComponents(FILE_1.getKey(), FILE_2.getKey()); + mockContentOfFileInDb(FILE_1.getKey(), null); + mockContentOfFileInDb(FILE_2.getKey(), null); + + underTest.execute(); + + assertThat(movedFilesRepository.getComponentsWithOriginal()).isEmpty(); + } + + @Test public void execute_detects_several_moves() { // testing: // - file1 renamed to file3 @@ -496,17 +507,15 @@ public class FileMoveDetectionStepTest { sourceLinesRepository.addLines(ref, content); } - private void mockContentOfFileInDb(String key, String[] content) { - SourceLinesHashesComputer linesHashesComputer = new SourceLinesHashesComputer(); - Iterator<String> lineIterator = Arrays.asList(content).iterator(); - while (lineIterator.hasNext()) { - String line = lineIterator.next(); - linesHashesComputer.addLine(line); + private void mockContentOfFileInDb(String key, @Nullable String[] content) { + FileSourceDto dto = new FileSourceDto(); + if (content != null) { + SourceLinesHashesComputer linesHashesComputer = new SourceLinesHashesComputer(); + stream(content).forEach(linesHashesComputer::addLine); + dto.setLineHashes(on('\n').join(linesHashesComputer.getLineHashes())); } - when(fileSourceDao.selectSourceByFileUuid(dbSession, componentUuidOf(key))) - .thenReturn(new FileSourceDto() - .setLineHashes(on('\n').join(linesHashesComputer.getLineHashes()))); + when(fileSourceDao.selectSourceByFileUuid(dbSession, componentUuidOf(key))).thenReturn(dto); } private void setFilesInReport(Component... files) { diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/filemove/MatchesByScoreTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/filemove/MatchesByScoreTest.java index cbd96aac878..4007a357a7c 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/filemove/MatchesByScoreTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/filemove/MatchesByScoreTest.java @@ -30,6 +30,8 @@ import java.util.Set; import org.junit.Test; import static com.google.common.collect.ImmutableSet.of; +import static java.util.Collections.emptyList; +import static java.util.Collections.emptySet; import static org.assertj.core.api.Assertions.assertThat; import static org.sonar.server.computation.task.projectanalysis.filemove.FileMoveDetectionStep.MIN_REQUIRED_SCORE; @@ -39,7 +41,7 @@ public class MatchesByScoreTest { @Test public void creates_returns_always_the_same_instance_of_maxScore_is_less_than_min_required_score() { - Set<String> doesNotMatterDbFileKeys = Collections.emptySet(); + Set<String> doesNotMatterDbFileKeys = emptySet(); Map<String, FileSimilarity.File> doesNotMatterReportFiles = Collections.emptyMap(); int[][] doesNotMatterScores = new int[0][0]; @@ -78,6 +80,6 @@ public class MatchesByScoreTest { } private static FileSimilarity.File fileOf(String key) { - return new FileSimilarity.File("path of " + key, null); + return new FileSimilarity.File("path of " + key, emptyList()); } } diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/filemove/SourceSimilarityImplTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/filemove/SourceSimilarityImplTest.java index 1c50bddbdb5..11ae0481655 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/filemove/SourceSimilarityImplTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/filemove/SourceSimilarityImplTest.java @@ -25,6 +25,7 @@ import org.junit.Test; import org.junit.rules.ExpectedException; import static java.util.Arrays.asList; +import static java.util.Collections.emptyList; import static org.assertj.core.api.Assertions.assertThat; public class SourceSimilarityImplTest { @@ -32,7 +33,7 @@ public class SourceSimilarityImplTest { @Rule public ExpectedException expectedException = ExpectedException.none(); - SourceSimilarityImpl underTest = new SourceSimilarityImpl(); + private SourceSimilarityImpl underTest = new SourceSimilarityImpl(); @Test public void zero_if_fully_different() { @@ -53,4 +54,9 @@ public class SourceSimilarityImplTest { assertThat(underTest.score(asList("a"), asList("a", "b", "c"))).isEqualTo(33); assertThat(underTest.score(asList("a", "b", "c"), asList("a"))).isEqualTo(33); } + + @Test + public void two_empty_lists_are_not_considered_as_equal() { + assertThat(underTest.score(emptyList(), emptyList())).isEqualTo(0); + } } |