/*
* SonarQube
* Copyright (C) 2009-2017 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.scanner.sensor;
import com.google.common.collect.ImmutableMap;
import java.util.Map;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.rules.TemporaryFolder;
import org.mockito.ArgumentCaptor;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.fs.internal.DefaultInputModule;
import org.sonar.api.batch.fs.internal.TestInputFileBuilder;
import org.sonar.api.batch.measure.MetricFinder;
import org.sonar.api.batch.sensor.highlighting.internal.DefaultHighlighting;
import org.sonar.api.batch.sensor.measure.internal.DefaultMeasure;
import org.sonar.api.batch.sensor.symbol.internal.DefaultSymbolTable;
import org.sonar.api.config.MapSettings;
import org.sonar.api.config.Settings;
import org.sonar.api.measures.CoreMetrics;
import org.sonar.api.utils.KeyValueFormat;
import org.sonar.core.metric.ScannerMetrics;
import org.sonar.scanner.cpd.index.SonarCpdBlockIndex;
import org.sonar.scanner.issue.ModuleIssues;
import org.sonar.scanner.protocol.output.ScannerReportWriter;
import org.sonar.scanner.report.ReportPublisher;
import org.sonar.scanner.repository.ContextPropertiesCache;
import org.sonar.scanner.scan.measure.MeasureCache;
import org.sonar.scanner.sensor.coverage.CoverageExclusions;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.data.MapEntry.entry;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
public class DefaultSensorStorageTest {
@Rule
public TemporaryFolder temp = new TemporaryFolder();
@Rule
public ExpectedException thrown = ExpectedException.none();
private DefaultSensorStorage underTest;
private Settings settings;
private ModuleIssues moduleIssues;
private MeasureCache measureCache;
private ContextPropertiesCache contextPropertiesCache = new ContextPropertiesCache();
@Before
public void prepare() throws Exception {
MetricFinder metricFinder = mock(MetricFinder.class);
when(metricFinder.<Integer>findByKey(CoreMetrics.NCLOC_KEY)).thenReturn(CoreMetrics.NCLOC);
when(metricFinder.<String>findByKey(CoreMetrics.FUNCTION_COMPLEXITY_DISTRIBUTION_KEY)).thenReturn(CoreMetrics.FUNCTION_COMPLEXITY_DISTRIBUTION);
settings = new MapSettings();
moduleIssues = mock(ModuleIssues.class);
measureCache = mock(MeasureCache.class);
CoverageExclusions coverageExclusions = mock(CoverageExclusions.class);
when(coverageExclusions.isExcluded(any(InputFile.class))).thenReturn(false);
ReportPublisher reportPublisher = mock(ReportPublisher.class);
when(reportPublisher.getWriter()).thenReturn(new ScannerReportWriter(temp.newFolder()));
underTest = new DefaultSensorStorage(metricFinder,
moduleIssues, settings, coverageExclusions, reportPublisher, measureCache,
mock(SonarCpdBlockIndex.class), contextPropertiesCache, new ScannerMetrics());
}
@Test
public void shouldFailIfUnknownMetric() {
InputFile file = new TestInputFileBuilder("foo", "src/Foo.php").build();
thrown.expect(UnsupportedOperationException.class);
thrown.expectMessage("Unknown metric: lines");
underTest.store(new DefaultMeasure()
.on(file)
.forMetric(CoreMetrics.LINES)
.withValue(10));
}
@Test
public void shouldSaveFileMeasureToSensorContext() {
InputFile file = new TestInputFileBuilder("foo", "src/Foo.php").build();
ArgumentCaptor<DefaultMeasure> argumentCaptor = ArgumentCaptor.forClass(DefaultMeasure.class);
when(measureCache.put(eq(file.key()), eq(CoreMetrics.NCLOC_KEY), argumentCaptor.capture())).thenReturn(null);
underTest.store(new DefaultMeasure()
.on(file)
.forMetric(CoreMetrics.NCLOC)
.withValue(10));
DefaultMeasure m = argumentCaptor.getValue();
assertThat(m.value()).isEqualTo(10);
assertThat(m.metric()).isEqualTo(CoreMetrics.NCLOC);
}
@Test
public void shouldSaveProjectMeasureToSensorContext() {
String projectKey = "myProject";
DefaultInputModule module = new DefaultInputModule(projectKey);
ArgumentCaptor<DefaultMeasure> argumentCaptor = ArgumentCaptor.forClass(DefaultMeasure.class);
when(measureCache.put(eq(module.key()), eq(CoreMetrics.NCLOC_KEY), argumentCaptor.capture())).thenReturn(null);
underTest.store(new DefaultMeasure()
.on(module)
.forMetric(CoreMetrics.NCLOC)
.withValue(10));
DefaultMeasure m = argumentCaptor.getValue();
assertThat(m.value()).isEqualTo(10);
assertThat(m.metric()).isEqualTo(CoreMetrics.NCLOC);
}
@Test(expected = UnsupportedOperationException.class)
public void duplicateHighlighting() throws Exception {
InputFile inputFile = new TestInputFileBuilder("foo", "src/Foo.java")
.setModuleBaseDir(temp.newFolder().toPath()).build();
DefaultHighlighting h = new DefaultHighlighting(null)
.onFile(inputFile);
underTest.store(h);
underTest.store(h);
}
@Test(expected = UnsupportedOperationException.class)
public void duplicateSymbolTable() throws Exception {
InputFile inputFile = new TestInputFileBuilder("foo", "src/Foo.java")
.setModuleBaseDir(temp.newFolder().toPath()).build();
DefaultSymbolTable st = new DefaultSymbolTable(null)
.onFile(inputFile);
underTest.store(st);
underTest.store(st);
}
@Test
public void shouldStoreContextProperty() {
underTest.storeProperty("foo", "bar");
assertThat(contextPropertiesCache.getAll()).containsOnly(entry("foo", "bar"));
}
@Test
public void shouldValidateStrictlyPositiveLine() throws Exception {
InputFile file = new TestInputFileBuilder("module", "testfile").setModuleBaseDir(temp.newFolder().toPath()).build();
Map<Integer, Integer> map = ImmutableMap.of(0, 3);
String data = KeyValueFormat.format(map);
thrown.expect(IllegalStateException.class);
thrown.expectMessage("must be > 0");
underTest.validateCoverageMeasure(data, file);
}
@Test
public void shouldValidateMaxLine() throws Exception {
InputFile file = new TestInputFileBuilder("module", "testfile").setModuleBaseDir(temp.newFolder().toPath()).build();
Map<Integer, Integer> map = ImmutableMap.of(11, 3);
String data = KeyValueFormat.format(map);
thrown.expect(IllegalStateException.class);
underTest.validateCoverageMeasure(data, file);
}
@Test
public void mergeCoverageLineMetrics_should_be_sorted() {
assertThat(DefaultSensorStorage.mergeCoverageLineMetric(CoreMetrics.COVERAGE_LINE_HITS_DATA, "1=1", "1=1")).isEqualTo("1=2");
assertThat(DefaultSensorStorage.mergeCoverageLineMetric(CoreMetrics.COVERAGE_LINE_HITS_DATA, "1=1", "2=1")).isEqualTo("1=1;2=1");
assertThat(DefaultSensorStorage.mergeCoverageLineMetric(CoreMetrics.COVERAGE_LINE_HITS_DATA, "2=1", "1=1")).isEqualTo("1=1;2=1");
assertThat(DefaultSensorStorage.mergeCoverageLineMetric(CoreMetrics.COVERED_CONDITIONS_BY_LINE, "1=1", "1=1")).isEqualTo("1=1");
assertThat(DefaultSensorStorage.mergeCoverageLineMetric(CoreMetrics.COVERED_CONDITIONS_BY_LINE, "1=1", "2=1")).isEqualTo("1=1;2=1");
assertThat(DefaultSensorStorage.mergeCoverageLineMetric(CoreMetrics.COVERED_CONDITIONS_BY_LINE, "2=1", "1=1")).isEqualTo("1=1;2=1");
}
}