]> source.dussan.org Git - sonarqube.git/blob
67bce16c807c87e08dd947da1f41c8ab482911ba
[sonarqube.git] /
1 /*
2  * SonarQube
3  * Copyright (C) 2009-2019 SonarSource SA
4  * mailto:info AT sonarsource DOT com
5  *
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.
10  *
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.
15  *
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.
19  */
20 package org.sonar.ce.task.projectanalysis.source;
21
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;
38
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;
46
47 public class SourceLinesHashRepositoryImplTest {
48   private static final int FILE_REF = 1;
49
50   @Rule
51   public JUnitTempFolder temp = new JUnitTempFolder();
52   @Rule
53   public SourceLinesRepositoryRule sourceLinesRepository = new SourceLinesRepositoryRule();
54
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;
60
61   @Before
62   public void setUp() {
63     sourceLinesHashCache = new SourceLinesHashCache(temp);
64     underTest = new SourceLinesHashRepositoryImpl(sourceLinesRepository, significantCodeRepository,
65       sourceLinesHashCache, dbLineHashVersion);
66     sourceLinesRepository.addLines(FILE_REF, "line1", "line2", "line3");
67   }
68
69   @Test
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());
73
74     verify(significantCodeRepository).getRangesPerLine(file);
75     verifyNoMoreInteractions(significantCodeRepository);
76     verifyZeroInteractions(dbLineHashVersion);
77   }
78
79   @Test
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());
83
84     verify(significantCodeRepository).getRangesPerLine(file);
85     verifyNoMoreInteractions(significantCodeRepository);
86     verifyZeroInteractions(dbLineHashVersion);
87   }
88
89   @Test
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);
93
94     assertLineHashes(lineHashes, "line1", "line2", "line3");
95     verify(dbLineHashVersion).hasLineHashesWithSignificantCode(file);
96     verifyNoMoreInteractions(dbLineHashVersion);
97     verifyZeroInteractions(significantCodeRepository);
98   }
99
100   @Test
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());
104
105     List<String> lineHashes = underTest.getLineHashesMatchingDBVersion(file);
106
107     assertLineHashes(lineHashes, "line1", "line2", "line3");
108     verify(dbLineHashVersion).hasLineHashesWithSignificantCode(file);
109     verifyNoMoreInteractions(dbLineHashVersion);
110     verify(significantCodeRepository).getRangesPerLine(file);
111     verifyNoMoreInteractions(significantCodeRepository);
112   }
113
114   @Test
115   public void should_create_hash_with_significant_code() {
116     LineRange[] lineRanges = {new LineRange(0, 1), null, new LineRange(1, 5)};
117
118     when(dbLineHashVersion.hasLineHashesWithSignificantCode(file)).thenReturn(true);
119     when(significantCodeRepository.getRangesPerLine(file)).thenReturn(Optional.of(lineRanges));
120
121     List<String> lineHashes = underTest.getLineHashesMatchingDBVersion(file);
122
123     assertLineHashes(lineHashes, "l", "", "ine3");
124     verify(dbLineHashVersion).hasLineHashesWithSignificantCode(file);
125     verifyNoMoreInteractions(dbLineHashVersion);
126     verify(significantCodeRepository).getRangesPerLine(file);
127     verifyNoMoreInteractions(significantCodeRepository);
128   }
129
130   @Test
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());
135
136     verify(significantCodeRepository).getRangesPerLine(file);
137     verifyNoMoreInteractions(significantCodeRepository);
138     verifyZeroInteractions(dbLineHashVersion);
139   }
140
141   @Test
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());
145
146     verify(significantCodeRepository).getRangesPerLine(file);
147     verifyNoMoreInteractions(significantCodeRepository);
148     verifyZeroInteractions(dbLineHashVersion);
149   }
150
151   @Test
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);
156
157     when(dbLineHashVersion.hasLineHashesWithSignificantCode(file)).thenReturn(true);
158     when(significantCodeRepository.getRangesPerLine(file)).thenReturn(Optional.of(lineRanges));
159
160     LineHashesComputer hashesComputer = underTest.getLineHashesComputerToPersist(file);
161
162     assertThat(hashesComputer).isInstanceOf(CachedLineHashesComputer.class);
163     assertThat(hashesComputer.getResult()).isEqualTo(lineHashes);
164   }
165
166   @Test
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);
170
171     when(dbLineHashVersion.hasLineHashesWithSignificantCode(file)).thenReturn(false);
172     when(significantCodeRepository.getRangesPerLine(file)).thenReturn(Optional.empty());
173
174     LineHashesComputer hashesComputer = underTest.getLineHashesComputerToPersist(file);
175
176     assertThat(hashesComputer).isInstanceOf(CachedLineHashesComputer.class);
177     assertThat(hashesComputer.getResult()).isEqualTo(lineHashes);
178   }
179
180   @Test
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)};
184
185     sourceLinesHashCache.computeIfAbsent(file, c -> lineHashes);
186
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));
190
191     LineHashesComputer hashesComputer = underTest.getLineHashesComputerToPersist(file);
192
193     assertThat(hashesComputer).isInstanceOf(SignificantCodeLineHashesComputer.class);
194   }
195
196   @Test
197   public void SignificantCodeLineHashesComputer_delegates_after_taking_ranges_into_account() {
198     LineRange[] lineRanges = {
199       new LineRange(0, 1),
200       null,
201       new LineRange(1, 5),
202       new LineRange(2, 7),
203       new LineRange(4, 5)
204     };
205
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");
214
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");
221
222     verifyNoMoreInteractions(lineHashComputer);
223   }
224
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);
230     }
231
232     List<String> expectedLines = computer.getLineHashes();
233
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);
238     }
239   }
240 }