3 * Copyright (C) 2009-2019 SonarSource SA
4 * mailto:info AT sonarsource DOT com
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 3 of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 package org.sonar.ce.task.projectanalysis.source;
22 import com.google.common.collect.Lists;
23 import java.util.List;
24 import java.util.Optional;
25 import org.junit.Before;
26 import org.junit.Rule;
27 import org.junit.Test;
28 import org.sonar.api.utils.internal.JUnitTempFolder;
29 import org.sonar.ce.task.projectanalysis.component.Component;
30 import org.sonar.ce.task.projectanalysis.component.Component.Type;
31 import org.sonar.ce.task.projectanalysis.component.ReportComponent;
32 import org.sonar.ce.task.projectanalysis.source.SourceLinesHashRepositoryImpl.CachedLineHashesComputer;
33 import org.sonar.ce.task.projectanalysis.source.SourceLinesHashRepositoryImpl.LineHashesComputer;
34 import org.sonar.ce.task.projectanalysis.source.SourceLinesHashRepositoryImpl.SignificantCodeLineHashesComputer;
35 import org.sonar.core.hash.LineRange;
36 import org.sonar.core.hash.SourceLineHashesComputer;
37 import org.sonar.db.source.LineHashVersion;
39 import static org.assertj.core.api.Assertions.assertThat;
40 import static org.mockito.Mockito.mock;
41 import static org.mockito.Mockito.times;
42 import static org.mockito.Mockito.verify;
43 import static org.mockito.Mockito.verifyNoMoreInteractions;
44 import static org.mockito.Mockito.verifyZeroInteractions;
45 import static org.mockito.Mockito.when;
47 public class SourceLinesHashRepositoryImplTest {
48 private static final int FILE_REF = 1;
51 public JUnitTempFolder temp = new JUnitTempFolder();
53 public SourceLinesRepositoryRule sourceLinesRepository = new SourceLinesRepositoryRule();
55 private SourceLinesHashCache sourceLinesHashCache;
56 private SignificantCodeRepository significantCodeRepository = mock(SignificantCodeRepository.class);
57 private DbLineHashVersion dbLineHashVersion = mock(DbLineHashVersion.class);
58 private Component file = ReportComponent.builder(Type.FILE, FILE_REF).build();
59 private SourceLinesHashRepositoryImpl underTest;
63 sourceLinesHashCache = new SourceLinesHashCache(temp);
64 underTest = new SourceLinesHashRepositoryImpl(sourceLinesRepository, significantCodeRepository,
65 sourceLinesHashCache, dbLineHashVersion);
66 sourceLinesRepository.addLines(FILE_REF, "line1", "line2", "line3");
70 public void should_return_with_significant_code_if_report_contains_it() {
71 when(significantCodeRepository.getRangesPerLine(file)).thenReturn(Optional.of(new LineRange[0]));
72 assertThat(underTest.getLineHashesVersion(file)).isEqualTo(LineHashVersion.WITH_SIGNIFICANT_CODE.getDbValue());
74 verify(significantCodeRepository).getRangesPerLine(file);
75 verifyNoMoreInteractions(significantCodeRepository);
76 verifyZeroInteractions(dbLineHashVersion);
80 public void should_return_without_significant_code_if_report_does_not_contain_it() {
81 when(significantCodeRepository.getRangesPerLine(file)).thenReturn(Optional.empty());
82 assertThat(underTest.getLineHashesVersion(file)).isEqualTo(LineHashVersion.WITHOUT_SIGNIFICANT_CODE.getDbValue());
84 verify(significantCodeRepository).getRangesPerLine(file);
85 verifyNoMoreInteractions(significantCodeRepository);
86 verifyZeroInteractions(dbLineHashVersion);
90 public void should_create_hash_without_significant_code_if_db_has_no_significant_code() {
91 when(dbLineHashVersion.hasLineHashesWithSignificantCode(file)).thenReturn(false);
92 List<String> lineHashes = underTest.getLineHashesMatchingDBVersion(file);
94 assertLineHashes(lineHashes, "line1", "line2", "line3");
95 verify(dbLineHashVersion).hasLineHashesWithSignificantCode(file);
96 verifyNoMoreInteractions(dbLineHashVersion);
97 verifyZeroInteractions(significantCodeRepository);
101 public void should_create_hash_without_significant_code_if_report_has_no_significant_code() {
102 when(dbLineHashVersion.hasLineHashesWithSignificantCode(file)).thenReturn(true);
103 when(significantCodeRepository.getRangesPerLine(file)).thenReturn(Optional.empty());
105 List<String> lineHashes = underTest.getLineHashesMatchingDBVersion(file);
107 assertLineHashes(lineHashes, "line1", "line2", "line3");
108 verify(dbLineHashVersion).hasLineHashesWithSignificantCode(file);
109 verifyNoMoreInteractions(dbLineHashVersion);
110 verify(significantCodeRepository).getRangesPerLine(file);
111 verifyNoMoreInteractions(significantCodeRepository);
115 public void should_create_hash_with_significant_code() {
116 LineRange[] lineRanges = {new LineRange(0, 1), null, new LineRange(1, 5)};
118 when(dbLineHashVersion.hasLineHashesWithSignificantCode(file)).thenReturn(true);
119 when(significantCodeRepository.getRangesPerLine(file)).thenReturn(Optional.of(lineRanges));
121 List<String> lineHashes = underTest.getLineHashesMatchingDBVersion(file);
123 assertLineHashes(lineHashes, "l", "", "ine3");
124 verify(dbLineHashVersion).hasLineHashesWithSignificantCode(file);
125 verifyNoMoreInteractions(dbLineHashVersion);
126 verify(significantCodeRepository).getRangesPerLine(file);
127 verifyNoMoreInteractions(significantCodeRepository);
131 public void should_return_version_of_line_hashes_with_significant_code_in_the_report() {
132 LineRange[] lineRanges = {new LineRange(0, 1), null, new LineRange(1, 5)};
133 when(significantCodeRepository.getRangesPerLine(file)).thenReturn(Optional.of(lineRanges));
134 assertThat(underTest.getLineHashesVersion(file)).isEqualTo(LineHashVersion.WITH_SIGNIFICANT_CODE.getDbValue());
136 verify(significantCodeRepository).getRangesPerLine(file);
137 verifyNoMoreInteractions(significantCodeRepository);
138 verifyZeroInteractions(dbLineHashVersion);
142 public void should_return_version_of_line_hashes_without_significant_code_in_the_report() {
143 when(significantCodeRepository.getRangesPerLine(file)).thenReturn(Optional.empty());
144 assertThat(underTest.getLineHashesVersion(file)).isEqualTo(LineHashVersion.WITHOUT_SIGNIFICANT_CODE.getDbValue());
146 verify(significantCodeRepository).getRangesPerLine(file);
147 verifyNoMoreInteractions(significantCodeRepository);
148 verifyZeroInteractions(dbLineHashVersion);
152 public void should_persist_with_significant_code_from_cache_if_possible() {
153 List<String> lineHashes = Lists.newArrayList("line1", "line2", "line3");
154 LineRange[] lineRanges = {new LineRange(0, 1), null, new LineRange(1, 5)};
155 sourceLinesHashCache.computeIfAbsent(file, c -> lineHashes);
157 when(dbLineHashVersion.hasLineHashesWithSignificantCode(file)).thenReturn(true);
158 when(significantCodeRepository.getRangesPerLine(file)).thenReturn(Optional.of(lineRanges));
160 LineHashesComputer hashesComputer = underTest.getLineHashesComputerToPersist(file);
162 assertThat(hashesComputer).isInstanceOf(CachedLineHashesComputer.class);
163 assertThat(hashesComputer.getResult()).isEqualTo(lineHashes);
167 public void should_persist_without_significant_code_from_cache_if_possible() {
168 List<String> lineHashes = Lists.newArrayList("line1", "line2", "line3");
169 sourceLinesHashCache.computeIfAbsent(file, c -> lineHashes);
171 when(dbLineHashVersion.hasLineHashesWithSignificantCode(file)).thenReturn(false);
172 when(significantCodeRepository.getRangesPerLine(file)).thenReturn(Optional.empty());
174 LineHashesComputer hashesComputer = underTest.getLineHashesComputerToPersist(file);
176 assertThat(hashesComputer).isInstanceOf(CachedLineHashesComputer.class);
177 assertThat(hashesComputer.getResult()).isEqualTo(lineHashes);
181 public void should_generate_to_persist_if_needed() {
182 List<String> lineHashes = Lists.newArrayList("line1", "line2", "line3");
183 LineRange[] lineRanges = {new LineRange(0, 1), null, new LineRange(1, 5)};
185 sourceLinesHashCache.computeIfAbsent(file, c -> lineHashes);
187 // DB has line hashes without significant code and significant code is available in the report, so we need to generate new line hashes
188 when(dbLineHashVersion.hasLineHashesWithSignificantCode(file)).thenReturn(false);
189 when(significantCodeRepository.getRangesPerLine(file)).thenReturn(Optional.of(lineRanges));
191 LineHashesComputer hashesComputer = underTest.getLineHashesComputerToPersist(file);
193 assertThat(hashesComputer).isInstanceOf(SignificantCodeLineHashesComputer.class);
197 public void SignificantCodeLineHashesComputer_delegates_after_taking_ranges_into_account() {
198 LineRange[] lineRanges = {
206 SourceLineHashesComputer lineHashComputer = mock(SourceLineHashesComputer.class);
207 SignificantCodeLineHashesComputer computer = new SignificantCodeLineHashesComputer(lineHashComputer, lineRanges);
208 computer.addLine("testline");
209 computer.addLine("testline");
210 computer.addLine("testline");
211 computer.addLine("testline");
212 computer.addLine("testline");
213 computer.addLine("testline");
215 verify(lineHashComputer).addLine("t");
216 // there is an extra line at the end which will be ignored since there is no range for it
217 verify(lineHashComputer, times(2)).addLine("");
218 verify(lineHashComputer).addLine("estl");
219 verify(lineHashComputer).addLine("stlin");
220 verify(lineHashComputer).addLine("l");
222 verifyNoMoreInteractions(lineHashComputer);
225 private void assertLineHashes(List<String> actualLines, String... lines) {
226 assertThat(actualLines).hasSize(lines.length);
227 SourceLineHashesComputer computer = new SourceLineHashesComputer();
228 for (String line : lines) {
229 computer.addLine(line);
232 List<String> expectedLines = computer.getLineHashes();
234 for (int i = 0; i < expectedLines.size(); i++) {
235 assertThat(actualLines.get(i))
236 .isEqualTo(expectedLines.get(i))
237 .withFailMessage("Line hash is different for line %d", i);