3 * Copyright (C) 2009-2023 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.api.batch.sensor.internal;
23 import java.io.IOException;
24 import org.junit.Before;
25 import org.junit.Rule;
26 import org.junit.Test;
27 import org.junit.rules.TemporaryFolder;
28 import org.sonar.api.batch.bootstrap.ProjectDefinition;
29 import org.sonar.api.batch.fs.InputFile;
30 import org.sonar.api.batch.fs.internal.DefaultFileSystem;
31 import org.sonar.api.batch.fs.internal.DefaultInputFile;
32 import org.sonar.api.batch.fs.internal.DefaultInputModule;
33 import org.sonar.api.batch.fs.internal.DefaultTextPointer;
34 import org.sonar.api.batch.fs.internal.TestInputFileBuilder;
35 import org.sonar.api.batch.rule.ActiveRules;
36 import org.sonar.api.batch.rule.Severity;
37 import org.sonar.api.batch.rule.internal.ActiveRulesBuilder;
38 import org.sonar.api.batch.rule.internal.NewActiveRule;
39 import org.sonar.api.batch.sensor.cache.ReadCache;
40 import org.sonar.api.batch.sensor.cache.WriteCache;
41 import org.sonar.api.batch.sensor.error.AnalysisError;
42 import org.sonar.api.batch.sensor.error.NewAnalysisError;
43 import org.sonar.api.batch.sensor.highlighting.TypeOfText;
44 import org.sonar.api.batch.sensor.issue.NewExternalIssue;
45 import org.sonar.api.batch.sensor.issue.NewIssue;
46 import org.sonar.api.batch.sensor.symbol.NewSymbolTable;
47 import org.sonar.api.config.internal.MapSettings;
48 import org.sonar.api.measures.CoreMetrics;
49 import org.sonar.api.rule.RuleKey;
50 import org.sonar.api.rules.RuleType;
52 import static org.assertj.core.api.Assertions.assertThat;
53 import static org.assertj.core.api.Assertions.assertThatThrownBy;
54 import static org.assertj.core.api.Assertions.tuple;
55 import static org.assertj.core.data.MapEntry.entry;
56 import static org.mockito.Mockito.mock;
58 public class SensorContextTesterTest {
61 public TemporaryFolder temp = new TemporaryFolder();
63 private SensorContextTester tester;
67 public void prepare() throws Exception {
68 baseDir = temp.newFolder();
69 tester = SensorContextTester.create(baseDir);
73 public void testSettings() {
74 MapSettings settings = new MapSettings();
75 settings.setProperty("foo", "bar");
76 tester.setSettings(settings);
77 assertThat(tester.config().get("foo")).contains("bar");
81 public void test_canSkipUnchangedFiles() {
82 assertThat(tester.canSkipUnchangedFiles()).isFalse();
83 tester.setCanSkipUnchangedFiles(true);
84 assertThat(tester.canSkipUnchangedFiles()).isTrue();
88 public void testPluginCache() {
89 assertThat(tester.nextCache()).isNull();
90 assertThat(tester.previousCache()).isNull();
91 assertThat(tester.isCacheEnabled()).isFalse();
93 ReadCache readCache = mock(ReadCache.class);
94 WriteCache writeCache = mock(WriteCache.class);
96 tester.setPreviousCache(readCache);
97 tester.setNextCache(writeCache);
98 tester.setCacheEnabled(true);
100 assertThat(tester.nextCache()).isEqualTo(writeCache);
101 assertThat(tester.previousCache()).isEqualTo(readCache);
102 assertThat(tester.isCacheEnabled()).isTrue();
106 public void testActiveRules() {
107 NewActiveRule activeRule = new NewActiveRule.Builder()
108 .setRuleKey(RuleKey.of("foo", "bar"))
110 ActiveRules activeRules = new ActiveRulesBuilder().addRule(activeRule).build();
111 tester.setActiveRules(activeRules);
112 assertThat(tester.activeRules().findAll()).hasSize(1);
116 public void testFs() throws Exception {
117 DefaultFileSystem fs = new DefaultFileSystem(temp.newFolder());
118 tester.setFileSystem(fs);
119 assertThat(tester.fileSystem().baseDir()).isNotEqualTo(baseDir);
123 public void testIssues() {
124 assertThat(tester.allIssues()).isEmpty();
125 NewIssue newIssue = tester.newIssue();
127 .at(newIssue.newLocation().on(new TestInputFileBuilder("foo", "src/Foo.java").build()))
128 .forRule(RuleKey.of("repo", "rule"))
130 newIssue = tester.newIssue();
132 .at(newIssue.newLocation().on(new TestInputFileBuilder("foo", "src/Foo.java").build()))
133 .forRule(RuleKey.of("repo", "rule"))
135 assertThat(tester.allIssues()).hasSize(2);
139 public void testExternalIssues() {
140 assertThat(tester.allExternalIssues()).isEmpty();
141 NewExternalIssue newExternalIssue = tester.newExternalIssue();
143 .at(newExternalIssue.newLocation().message("message").on(new TestInputFileBuilder("foo", "src/Foo.java").build()))
144 .forRule(RuleKey.of("repo", "rule"))
146 .severity(Severity.BLOCKER)
148 newExternalIssue = tester.newExternalIssue();
150 .at(newExternalIssue.newLocation().message("message").on(new TestInputFileBuilder("foo", "src/Foo.java").build()))
152 .severity(Severity.BLOCKER)
153 .forRule(RuleKey.of("repo", "rule"))
155 assertThat(tester.allExternalIssues()).hasSize(2);
159 public void testAnalysisErrors() {
160 assertThat(tester.allAnalysisErrors()).isEmpty();
161 NewAnalysisError newAnalysisError = tester.newAnalysisError();
163 InputFile file = new TestInputFileBuilder("foo", "src/Foo.java").build();
164 newAnalysisError.onFile(file)
166 .at(new DefaultTextPointer(5, 2))
169 assertThat(tester.allAnalysisErrors()).hasSize(1);
170 AnalysisError analysisError = tester.allAnalysisErrors().iterator().next();
172 assertThat(analysisError.inputFile()).isEqualTo(file);
173 assertThat(analysisError.message()).isEqualTo("error");
174 assertThat(analysisError.location()).isEqualTo(new DefaultTextPointer(5, 2));
179 public void testMeasures() throws IOException {
180 assertThat(tester.measures("foo:src/Foo.java")).isEmpty();
181 assertThat(tester.measure("foo:src/Foo.java", "ncloc")).isNull();
182 tester.<Integer>newMeasure()
183 .on(new TestInputFileBuilder("foo", "src/Foo.java").build())
184 .forMetric(CoreMetrics.NCLOC)
187 assertThat(tester.measures("foo:src/Foo.java")).hasSize(1);
188 assertThat(tester.measure("foo:src/Foo.java", "ncloc")).isNotNull();
189 tester.<Integer>newMeasure()
190 .on(new TestInputFileBuilder("foo", "src/Foo.java").build())
191 .forMetric(CoreMetrics.LINES)
194 assertThat(tester.measures("foo:src/Foo.java")).hasSize(2);
195 assertThat(tester.measure("foo:src/Foo.java", "ncloc")).isNotNull();
196 assertThat(tester.measure("foo:src/Foo.java", "lines")).isNotNull();
197 tester.<Integer>newMeasure()
198 .on(new DefaultInputModule(ProjectDefinition.create().setKey("foo").setBaseDir(temp.newFolder()).setWorkDir(temp.newFolder())))
199 .forMetric(CoreMetrics.DIRECTORIES)
202 assertThat(tester.measures("foo")).hasSize(1);
203 assertThat(tester.measure("foo", "directories")).isNotNull();
206 @Test(expected = IllegalStateException.class)
207 public void duplicateMeasures() {
208 tester.<Integer>newMeasure()
209 .on(new TestInputFileBuilder("foo", "src/Foo.java").build())
210 .forMetric(CoreMetrics.NCLOC)
213 tester.<Integer>newMeasure()
214 .on(new TestInputFileBuilder("foo", "src/Foo.java").build())
215 .forMetric(CoreMetrics.NCLOC)
221 public void testHighlighting() {
222 assertThat(tester.highlightingTypeAt("foo:src/Foo.java", 1, 3)).isEmpty();
223 tester.newHighlighting()
224 .onFile(new TestInputFileBuilder("foo", "src/Foo.java").initMetadata("annot dsf fds foo bar").build())
225 .highlight(1, 0, 1, 5, TypeOfText.ANNOTATION)
226 .highlight(1, 8, 1, 10, TypeOfText.CONSTANT)
227 .highlight(1, 9, 1, 10, TypeOfText.COMMENT)
229 assertThat(tester.highlightingTypeAt("foo:src/Foo.java", 1, 3)).containsExactly(TypeOfText.ANNOTATION);
230 assertThat(tester.highlightingTypeAt("foo:src/Foo.java", 1, 9)).containsExactly(TypeOfText.CONSTANT, TypeOfText.COMMENT);
233 @Test(expected = UnsupportedOperationException.class)
234 public void duplicateHighlighting() {
235 tester.newHighlighting()
236 .onFile(new TestInputFileBuilder("foo", "src/Foo.java").initMetadata("annot dsf fds foo bar").build())
237 .highlight(1, 0, 1, 5, TypeOfText.ANNOTATION)
239 tester.newHighlighting()
240 .onFile(new TestInputFileBuilder("foo", "src/Foo.java").initMetadata("annot dsf fds foo bar").build())
241 .highlight(1, 0, 1, 5, TypeOfText.ANNOTATION)
246 public void testSymbolReferences() {
247 assertThat(tester.referencesForSymbolAt("foo:src/Foo.java", 1, 0)).isNull();
249 NewSymbolTable symbolTable = tester.newSymbolTable()
250 .onFile(new TestInputFileBuilder("foo", "src/Foo.java").initMetadata("annot dsf fds foo bar").build());
252 .newSymbol(1, 8, 1, 10);
255 .newSymbol(1, 1, 1, 5)
256 .newReference(1, 10, 1, 13);
260 assertThat(tester.referencesForSymbolAt("foo:src/Foo.java", 1, 0)).isNull();
261 assertThat(tester.referencesForSymbolAt("foo:src/Foo.java", 1, 8)).isEmpty();
262 assertThat(tester.referencesForSymbolAt("foo:src/Foo.java", 1, 3))
263 .extracting("start.line", "start.lineOffset", "end.line", "end.lineOffset")
264 .containsExactly(tuple(1, 10, 1, 13));
267 @Test(expected = UnsupportedOperationException.class)
268 public void duplicateSymbolReferences() {
269 NewSymbolTable symbolTable = tester.newSymbolTable()
270 .onFile(new TestInputFileBuilder("foo", "src/Foo.java").initMetadata("annot dsf fds foo bar").build());
272 .newSymbol(1, 8, 1, 10);
276 symbolTable = tester.newSymbolTable()
277 .onFile(new TestInputFileBuilder("foo", "src/Foo.java").initMetadata("annot dsf fds foo bar").build());
279 .newSymbol(1, 8, 1, 10);
285 public void testCoverageAtLineZero() {
286 assertThat(tester.lineHits("foo:src/Foo.java", 1)).isNull();
287 assertThat(tester.lineHits("foo:src/Foo.java", 4)).isNull();
289 assertThatThrownBy(() -> tester.newCoverage()
290 .onFile(new TestInputFileBuilder("foo", "src/Foo.java").initMetadata("annot dsf fds foo bar").build())
292 .isInstanceOf(IllegalStateException.class);
296 public void testCoverageAtLineOutOfRange() {
297 assertThat(tester.lineHits("foo:src/Foo.java", 1)).isNull();
298 assertThat(tester.lineHits("foo:src/Foo.java", 4)).isNull();
300 assertThatThrownBy(() -> tester.newCoverage()
301 .onFile(new TestInputFileBuilder("foo", "src/Foo.java").initMetadata("annot dsf fds foo bar").build())
303 .isInstanceOf(IllegalStateException.class);
307 public void testLineHits() {
308 assertThat(tester.lineHits("foo:src/Foo.java", 1)).isNull();
309 assertThat(tester.lineHits("foo:src/Foo.java", 4)).isNull();
311 .onFile(new TestInputFileBuilder("foo", "src/Foo.java").initMetadata("annot dsf fds foo bar\nasdas").build())
315 assertThat(tester.lineHits("foo:src/Foo.java", 1)).isEqualTo(2);
316 assertThat(tester.lineHits("foo:src/Foo.java", 2)).isEqualTo(3);
319 public void multipleCoverage() {
321 .onFile(new TestInputFileBuilder("foo", "src/Foo.java").initMetadata("annot dsf fds foo bar\nasdas").build())
326 .onFile(new TestInputFileBuilder("foo", "src/Foo.java").initMetadata("annot dsf fds foo bar\nasdas").build())
330 assertThat(tester.lineHits("foo:src/Foo.java", 1)).isEqualTo(4);
331 assertThat(tester.conditions("foo:src/Foo.java", 3)).isEqualTo(4);
332 assertThat(tester.coveredConditions("foo:src/Foo.java", 3)).isEqualTo(3);
336 public void testConditions() {
337 assertThat(tester.conditions("foo:src/Foo.java", 1)).isNull();
338 assertThat(tester.coveredConditions("foo:src/Foo.java", 1)).isNull();
340 .onFile(new TestInputFileBuilder("foo", "src/Foo.java")
341 .initMetadata("annot dsf fds foo bar\nasd\nasdas\nasdfas")
345 assertThat(tester.conditions("foo:src/Foo.java", 1)).isEqualTo(4);
346 assertThat(tester.coveredConditions("foo:src/Foo.java", 1)).isEqualTo(2);
350 public void testCpdTokens() {
351 assertThat(tester.cpdTokens("foo:src/Foo.java")).isNull();
352 DefaultInputFile inputFile = new TestInputFileBuilder("foo", "src/Foo.java")
353 .initMetadata("public class Foo {\n\n}")
355 tester.newCpdTokens()
357 .addToken(inputFile.newRange(0, 6), "public")
358 .addToken(inputFile.newRange(7, 12), "class")
359 .addToken(inputFile.newRange(13, 16), "$IDENTIFIER")
360 .addToken(inputFile.newRange(17, 18), "{")
361 .addToken(inputFile.newRange(3, 0, 3, 1), "}")
363 assertThat(tester.cpdTokens("foo:src/Foo.java")).extracting("value", "startLine", "startUnit", "endUnit")
365 tuple("publicclass$IDENTIFIER{", 1, 1, 4),
366 tuple("}", 3, 5, 5));
369 @Test(expected = UnsupportedOperationException.class)
370 public void duplicateCpdTokens() {
371 DefaultInputFile inputFile = new TestInputFileBuilder("foo", "src/Foo.java")
372 .initMetadata("public class Foo {\n\n}")
374 tester.newCpdTokens()
376 .addToken(inputFile.newRange(0, 6), "public")
379 tester.newCpdTokens()
381 .addToken(inputFile.newRange(0, 6), "public")
386 public void testCancellation() {
387 assertThat(tester.isCancelled()).isFalse();
388 tester.setCancelled(true);
389 assertThat(tester.isCancelled()).isTrue();
393 public void testContextProperties() {
394 assertThat(tester.getContextProperties()).isEmpty();
396 tester.addContextProperty("foo", "bar");
397 assertThat(tester.getContextProperties()).containsOnly(entry("foo", "bar"));