import java.nio.file.LinkOption;
import java.nio.file.Path;
import java.util.ArrayList;
-import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
public class DefaultFileSystem implements FileSystem {
private final Cache cache;
- private final SortedSet<String> languages = new TreeSet<>();
private final Path baseDir;
private Path workDir;
private Charset encoding;
public DefaultFileSystem add(InputFile inputFile) {
cache.add(inputFile);
- String language = inputFile.language();
- if (language != null) {
- languages.add(language);
- }
return this;
}
return this;
}
- /**
- * Adds a language to the list. To be used only for unit tests that need to use {@link #languages()} without
- * using {@link #add(InputFile)}.
- */
- public DefaultFileSystem addLanguages(String language, String... others) {
- languages.add(language);
- Collections.addAll(languages, others);
- return this;
- }
-
@Override
public SortedSet<String> languages() {
doPreloadFiles();
- return languages;
+ return cache.languages();
}
@Override
public void add(InputDir inputDir) {
doAdd(inputDir);
}
+
+ protected abstract SortedSet<String> languages();
}
/**
private final Map<String, InputDir> dirMap = new HashMap<>();
private final SetMultimap<String, InputFile> filesByNameCache = LinkedHashMultimap.create();
private final SetMultimap<String, InputFile> filesByExtensionCache = LinkedHashMultimap.create();
+ private SortedSet<String> languages = new TreeSet<>();
@Override
public Iterable<InputFile> inputFiles() {
@Override
protected void doAdd(InputFile inputFile) {
+ if (inputFile.language() != null) {
+ languages.add(inputFile.language());
+ }
fileMap.put(inputFile.relativePath(), inputFile);
filesByNameCache.put(FilenamePredicate.getFilename(inputFile), inputFile);
filesByExtensionCache.put(FileExtensionPredicate.getExtension(inputFile), inputFile);
protected void doAdd(InputDir inputDir) {
dirMap.put(inputDir.relativePath(), inputDir);
}
+
+ @Override
+ protected SortedSet<String> languages() {
+ return languages;
+ }
}
@Override
*/
package org.sonar.api.batch.fs.internal;
+import java.io.File;
import java.io.StringReader;
import java.nio.charset.Charset;
import java.nio.file.Path;
import java.nio.file.Paths;
import javax.annotation.Nullable;
+import org.sonar.api.batch.bootstrap.ProjectDefinition;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.utils.PathUtils;
inputFile.setPublish(publish);
return inputFile;
}
+
+ public static DefaultInputModule newDefaultInputModule(String moduleKey, File baseDir) {
+ ProjectDefinition definition = ProjectDefinition.create().setKey(moduleKey);
+ definition.setBaseDir(baseDir);
+ return new DefaultInputModule(definition, TestInputFileBuilder.nextBatchId());
+ }
}
*/
SensorDescriptor requireProperties(String... propertyKeys);
+ /**
+ * This sensor should be executed at the project level, instead of per-module.
+ * @since 6.4
+ */
+ SensorDescriptor global();
}
private InputFile.Type type = null;
private String[] ruleRepositories = new String[0];
private String[] properties = new String[0];
+ private boolean global = false;
public String name() {
return name;
return Arrays.asList(properties);
}
+ public boolean isGlobal() {
+ return global;
+ }
+
@Override
public DefaultSensorDescriptor name(String name) {
this.name = name;
return this;
}
+ @Override
+ public SensorDescriptor global() {
+ this.global = true;
+ return this;
+ }
+
}
public void add_languages() {
assertThat(fs.languages()).isEmpty();
- fs.addLanguages("java", "php", "cobol");
- assertThat(fs.languages()).containsOnly("cobol", "java", "php");
+ fs.add(new TestInputFileBuilder("foo", "src/Foo.php").setLanguage("php").build());
+ fs.add(new TestInputFileBuilder("foo", "src/Bar.java").setLanguage("java").build());
+
+ assertThat(fs.languages()).containsOnly("java", "php");
}
@Test
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
+import java.util.Iterator;
import java.util.List;
import java.util.stream.Collectors;
return result;
}
+ public Collection<org.sonar.api.batch.Sensor> selectSensors(@Nullable DefaultInputModule module, boolean global) {
+ List<org.sonar.api.batch.Sensor> result = getFilteredExtensions(org.sonar.api.batch.Sensor.class, module, null);
+
+ Iterator<org.sonar.api.batch.Sensor> iterator = result.iterator();
+ while (iterator.hasNext()) {
+ org.sonar.api.batch.Sensor sensor = iterator.next();
+ if (sensor instanceof SensorWrapper) {
+ if (global != ((SensorWrapper) sensor).isGlobal()) {
+ iterator.remove();
+ }
+ } else if (global) {
+ // only old sensors are not wrapped, and old sensors are never global -> exclude
+ iterator.remove();
+ }
+ }
+
+ return sort(result);
+ }
+
private static Phase.Name evaluatePhase(Object extension) {
Object extensionToEvaluate;
if (extension instanceof SensorWrapper) {
@Override
public void describe(SensorDescriptor descriptor) {
- descriptor.name("CPD Block Indexer");
+ descriptor.name("CPD Block Indexer")
+ .global();
}
@VisibleForTesting
@Override
public void execute(SensorContext context) {
-
for (String language : fs.languages()) {
CpdBlockIndexer blockIndexer = getBlockIndexer(language);
if (!blockIndexer.isLanguageSupported(language)) {
package org.sonar.scanner.phases;
import com.google.common.collect.Lists;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
import org.sonar.api.batch.ScannerSide;
import org.sonar.api.batch.Sensor;
import org.sonar.api.batch.SensorContext;
import org.sonar.api.resources.Project;
import org.sonar.scanner.bootstrap.ScannerExtensionDictionnary;
import org.sonar.scanner.events.EventBus;
-import java.util.Collection;
+import org.sonar.scanner.sensor.SensorStrategy;
@ScannerSide
public class SensorsExecutor {
- private final EventBus eventBus;
- private final DefaultInputModule module;
private final ScannerExtensionDictionnary selector;
+ private final DefaultInputModule module;
+ private final EventBus eventBus;
+ private final SensorStrategy strategy;
+ private final boolean isRoot;
- public SensorsExecutor(ScannerExtensionDictionnary selector, DefaultInputModule module, EventBus eventBus) {
+ public SensorsExecutor(ScannerExtensionDictionnary selector, DefaultInputModule module, EventBus eventBus, SensorStrategy strategy) {
this.selector = selector;
- this.eventBus = eventBus;
this.module = module;
+ this.eventBus = eventBus;
+ this.strategy = strategy;
+ this.isRoot = module.definition().getParent() == null;
}
public void execute(SensorContext context) {
- Collection<Sensor> sensors = selector.select(Sensor.class, module, true, null);
- eventBus.fireEvent(new SensorsPhaseEvent(Lists.newArrayList(sensors), true));
+ Collection<Sensor> perModuleSensors = selector.selectSensors(module, false);
+ Collection<Sensor> globalSensors;
+ if (isRoot) {
+ boolean orig = strategy.isGlobal();
+ strategy.setGlobal(true);
+ globalSensors = selector.selectSensors(module, true);
+ strategy.setGlobal(orig);
+ } else {
+ globalSensors = Collections.emptyList();
+ }
+
+ Collection<Sensor> allSensors = new ArrayList<>(perModuleSensors);
+ allSensors.addAll(globalSensors);
+ eventBus.fireEvent(new SensorsPhaseEvent(Lists.newArrayList(allSensors), true));
+
+ execute(context, perModuleSensors);
+
+ if (isRoot) {
+ boolean orig = strategy.isGlobal();
+ strategy.setGlobal(true);
+ execute(context, globalSensors);
+ strategy.setGlobal(orig);
+ }
+
+ eventBus.fireEvent(new SensorsPhaseEvent(Lists.newArrayList(allSensors), false));
+ }
+ private void execute(SensorContext context, Collection<Sensor> sensors) {
for (Sensor sensor : sensors) {
executeSensor(context, sensor);
}
-
- eventBus.fireEvent(new SensorsPhaseEvent(Lists.newArrayList(sensors), false));
}
private void executeSensor(SensorContext context, Sensor sensor) {
import org.sonar.scanner.scan.report.IssuesReports;
import org.sonar.scanner.sensor.DefaultSensorStorage;
import org.sonar.scanner.sensor.SensorOptimizer;
+import org.sonar.scanner.sensor.SensorStrategy;
import org.sonar.scanner.sensor.coverage.CoverageExclusions;
import org.sonar.scanner.source.HighlightableBuilder;
import org.sonar.scanner.source.SymbolizableBuilder;
IssueFilters.class,
CoverageExclusions.class,
+ SensorStrategy.class,
+
// rules
new RulesProfileProvider(),
CheckFactory.class,
LOG.debug("Start recursive analysis of project modules");
scanRecursively(tree, tree.root());
+
if (analysisMode.isMediumTest()) {
getComponentByType(ScanTaskObservers.class).notifyEndOfScanTask();
}
*/
package org.sonar.scanner.scan.filesystem;
+import com.google.common.base.Preconditions;
import com.google.common.collect.LinkedHashMultimap;
import com.google.common.collect.SetMultimap;
+import com.google.common.collect.Table;
+import com.google.common.collect.TreeBasedTable;
+import java.nio.file.Path;
import java.util.Collection;
+import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
-
+import java.util.SortedSet;
+import java.util.TreeSet;
import javax.annotation.CheckForNull;
-
import org.sonar.api.batch.ScannerSide;
import org.sonar.api.batch.fs.InputComponent;
import org.sonar.api.batch.fs.InputDir;
import org.sonar.api.batch.fs.InputModule;
import org.sonar.api.batch.fs.internal.DefaultInputDir;
import org.sonar.api.batch.fs.internal.DefaultInputFile;
-
-import com.google.common.collect.Table;
-import com.google.common.collect.TreeBasedTable;
+import org.sonar.api.batch.fs.internal.DefaultInputModule;
import org.sonar.api.batch.fs.internal.FileExtensionPredicate;
import org.sonar.api.batch.fs.internal.FilenamePredicate;
+import org.sonar.api.scan.filesystem.PathResolver;
/**
* Store of all files and dirs. This cache is shared amongst all project modules. Inclusion and
@ScannerSide
public class InputComponentStore {
+ private final PathResolver pathResolver;
+ private final SortedSet<String> globalLanguagesCache = new TreeSet<>();
+ private final Map<String, SortedSet<String>> languagesCache = new HashMap<>();
+ private final Map<String, InputFile> globalInputFileCache = new HashMap<>();
private final Table<String, String, InputFile> inputFileCache = TreeBasedTable.create();
+ private final Map<String, InputDir> globalInputDirCache = new HashMap<>();
private final Table<String, String, InputDir> inputDirCache = TreeBasedTable.create();
private final Map<String, InputModule> inputModuleCache = new HashMap<>();
private final Map<String, InputComponent> inputComponents = new HashMap<>();
private final SetMultimap<String, InputFile> filesByExtensionCache = LinkedHashMultimap.create();
private InputModule root;
+ public InputComponentStore(PathResolver pathResolver) {
+ this.pathResolver = pathResolver;
+ }
+
public Collection<InputComponent> all() {
return inputComponents.values();
}
return inputComponents.get(key);
}
- public void setRoot(InputModule root) {
- this.root = root;
- }
-
@CheckForNull
public InputModule root() {
return root;
public InputComponentStore put(InputFile inputFile) {
DefaultInputFile file = (DefaultInputFile) inputFile;
+ addToLanguageCache(file);
inputFileCache.put(file.moduleKey(), inputFile.relativePath(), inputFile);
+ globalInputFileCache.put(getProjectRelativePath(file), inputFile);
inputComponents.put(inputFile.key(), inputFile);
filesByNameCache.put(FilenamePredicate.getFilename(inputFile), inputFile);
filesByExtensionCache.put(FileExtensionPredicate.getExtension(inputFile), inputFile);
return this;
}
+ private void addToLanguageCache(DefaultInputFile inputFile) {
+ String language = inputFile.language();
+ if (language != null) {
+ globalLanguagesCache.add(language);
+ languagesCache.computeIfAbsent(inputFile.moduleKey(), k -> new TreeSet<>()).add(language);
+ }
+ }
+
public InputComponentStore put(InputDir inputDir) {
DefaultInputDir dir = (DefaultInputDir) inputDir;
inputDirCache.put(dir.moduleKey(), inputDir.relativePath(), inputDir);
+ globalInputDirCache.put(getProjectRelativePath(dir), inputDir);
inputComponents.put(inputDir.key(), inputDir);
return this;
}
+ private String getProjectRelativePath(DefaultInputFile file) {
+ return pathResolver.relativePath(getProjectBaseDir(), file.path());
+ }
+
+ private String getProjectRelativePath(DefaultInputDir dir) {
+ return pathResolver.relativePath(getProjectBaseDir(), dir.path());
+ }
+
+ private Path getProjectBaseDir() {
+ return ((DefaultInputModule) root).definition().getBaseDir().toPath();
+ }
+
@CheckForNull
public InputFile getFile(String moduleKey, String relativePath) {
return inputFileCache.get(moduleKey, relativePath);
}
+ @CheckForNull
+ public InputFile getFile(String relativePath) {
+ return globalInputFileCache.get(relativePath);
+ }
+
@CheckForNull
public InputDir getDir(String moduleKey, String relativePath) {
return inputDirCache.get(moduleKey, relativePath);
}
+ @CheckForNull
+ public InputDir getDir(String relativePath) {
+ return globalInputDirCache.get(relativePath);
+ }
+
@CheckForNull
public InputModule getModule(String moduleKey) {
return inputModuleCache.get(moduleKey);
}
- public void put(InputModule inputModule) {
+ public void put(DefaultInputModule inputModule) {
+ Preconditions.checkState(!inputComponents.containsKey(inputModule.key()), "Module '%s' already indexed", inputModule.key());
+ Preconditions.checkState(!inputModuleCache.containsKey(inputModule.key()), "Module '%s' already indexed", inputModule.key());
inputComponents.put(inputModule.key(), inputModule);
inputModuleCache.put(inputModule.key(), inputModule);
+ if (inputModule.definition().getParent() == null) {
+ if (root != null) {
+ throw new IllegalStateException("Root module already indexed: '" + root.key() + "', '" + inputModule.key() + "'");
+ }
+ root = inputModule;
+ }
}
public Iterable<InputFile> getFilesByName(String filename) {
public Iterable<InputFile> getFilesByExtension(String extension) {
return filesByExtensionCache.get(extension);
}
+
+ public SortedSet<String> getLanguages() {
+ return globalLanguagesCache;
+ }
+
+ public SortedSet<String> getLanguages(String moduleKey) {
+ return languagesCache.getOrDefault(moduleKey, Collections.emptySortedSet());
+ }
}
*/
package org.sonar.scanner.scan.filesystem;
+import java.util.SortedSet;
import org.sonar.api.batch.ScannerSide;
import org.sonar.api.batch.fs.InputDir;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.fs.InputModule;
import org.sonar.api.batch.fs.internal.DefaultFileSystem;
+import org.sonar.scanner.sensor.SensorStrategy;
@ScannerSide
public class ModuleInputComponentStore extends DefaultFileSystem.Cache {
private final String moduleKey;
private final InputComponentStore inputComponentStore;
+ private final SensorStrategy strategy;
- public ModuleInputComponentStore(InputModule module, InputComponentStore inputComponentStore) {
+ public ModuleInputComponentStore(InputModule module, InputComponentStore inputComponentStore, SensorStrategy strategy) {
this.moduleKey = module.key();
this.inputComponentStore = inputComponentStore;
+ this.strategy = strategy;
}
@Override
public Iterable<InputFile> inputFiles() {
- return inputComponentStore.filesByModule(moduleKey);
+ if (strategy.isGlobal()) {
+ return inputComponentStore.allFiles();
+ } else {
+ return inputComponentStore.filesByModule(moduleKey);
+ }
}
@Override
public InputFile inputFile(String relativePath) {
- return inputComponentStore.getFile(moduleKey, relativePath);
+ if (strategy.isGlobal()) {
+ return inputComponentStore.getFile(relativePath);
+ } else {
+ return inputComponentStore.getFile(moduleKey, relativePath);
+ }
}
@Override
public InputDir inputDir(String relativePath) {
- return inputComponentStore.getDir(moduleKey, relativePath);
+ if (strategy.isGlobal()) {
+ return inputComponentStore.getDir(relativePath);
+ } else {
+ return inputComponentStore.getDir(moduleKey, relativePath);
+ }
+ }
+
+ @Override
+ public SortedSet<String> languages() {
+ if (strategy.isGlobal()) {
+ return inputComponentStore.getLanguages();
+ } else {
+ return inputComponentStore.getLanguages(moduleKey);
+ }
}
@Override
--- /dev/null
+/*
+ * 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;
+
+/**
+ * A shared, mutable object in the module container.
+ * It's used during the execution of sensors to decide whether
+ * sensors should be executed once for the entire project, or per-module.
+ */
+public class SensorStrategy {
+
+ private boolean global = false;
+
+ public boolean isGlobal() {
+ return global;
+ }
+
+ public void setGlobal(boolean global) {
+ this.global = global;
+ }
+}
return wrappedSensor.getClass().getName();
}
}
+
+ public boolean isGlobal() {
+ return descriptor.isGlobal();
+ }
}
@Override
public void describe(SensorDescriptor descriptor) {
- descriptor.name("Code Colorizer Sensor");
+ descriptor.name("Code Colorizer Sensor")
+ .global();
}
@Override
@Override
public void describe(SensorDescriptor descriptor) {
- descriptor.name("Zero Coverage Sensor");
+ descriptor.name("Zero Coverage Sensor")
+ .global();
}
@Override
import org.sonar.api.batch.SensorContext;
import org.sonar.api.batch.fs.internal.DefaultInputModule;
import org.sonar.api.batch.postjob.PostJobContext;
+import org.sonar.api.batch.sensor.SensorDescriptor;
import org.sonar.api.resources.Project;
import org.sonar.core.platform.ComponentContainer;
-import org.sonar.scanner.bootstrap.ScannerExtensionDictionnary;
-import org.sonar.scanner.bootstrap.ExtensionMatcher;
import org.sonar.scanner.postjob.PostJobOptimizer;
import org.sonar.scanner.sensor.DefaultSensorContext;
import org.sonar.scanner.sensor.SensorOptimizer;
+import org.sonar.scanner.sensor.SensorWrapper;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.assertEquals;
ScannerExtensionDictionnary selector = newSelector(analyze, post, pre);
List extensions = Lists.newArrayList(selector.select(BatchExtension.class, null, true, null));
- assertThat(extensions).hasSize(3);
- assertThat(extensions.get(0)).isEqualTo(pre);
- assertThat(extensions.get(1)).isEqualTo(analyze);
- assertThat(extensions.get(2)).isEqualTo(post);
+ assertThat(extensions).containsExactly(pre, analyze, post);
}
@Test
assertThat(extensions.get(2)).isEqualTo(checker);
}
+ @Test
+ public void querySensors() {
+ BatchExtension pre = new PreSensorSubclass();
+ BatchExtension analyze = new GeneratesSomething("something");
+ BatchExtension post = new PostSensorSubclass();
+
+ FakeSensor fakeSensor = new FakeSensor();
+ FakeNewSensor fakeNewSensor = new FakeNewSensor();
+ FakeNewGlobalSensor fakeNewGlobalSensor = new FakeNewGlobalSensor();
+ ScannerExtensionDictionnary selector = newSelector(fakeSensor, fakeNewSensor, fakeNewGlobalSensor);
+ List extensions = Lists.newArrayList(selector.selectSensors(null, false));
+
+ assertThat(extensions).hasSize(2);
+ assertThat(extensions).contains(fakeSensor);
+ extensions.remove(fakeSensor);
+ assertThat(extensions.get(0)).isInstanceOf(SensorWrapper.class);
+ assertThat(((SensorWrapper) extensions.get(0)).wrappedSensor()).isEqualTo(fakeNewSensor);
+
+ extensions = Lists.newArrayList(selector.selectSensors(null, true));
+
+ assertThat(extensions.get(0)).isInstanceOf(SensorWrapper.class);
+ assertThat(((SensorWrapper) extensions.get(0)).wrappedSensor()).isEqualTo(fakeNewGlobalSensor);
+ }
+
class FakeSensor implements Sensor {
public void analyse(Project project, SensorContext context) {
}
}
+ class FakeNewSensor implements org.sonar.api.batch.sensor.Sensor {
+
+ @Override
+ public void describe(SensorDescriptor descriptor) {
+ }
+
+ @Override
+ public void execute(org.sonar.api.batch.sensor.SensorContext context) {
+ }
+
+ }
+
+ class FakeNewGlobalSensor implements org.sonar.api.batch.sensor.Sensor {
+
+ @Override
+ public void describe(SensorDescriptor descriptor) {
+ descriptor.global();
+ }
+
+ @Override
+ public void execute(org.sonar.api.batch.sensor.SensorContext context) {
+ }
+
+ }
+
class MethodDependentOf implements BatchExtension {
private Object dep;
import org.junit.rules.TemporaryFolder;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.fs.internal.DefaultInputFile;
-import org.sonar.api.batch.fs.internal.DefaultInputModule;
import org.sonar.api.batch.fs.internal.TestInputFileBuilder;
import org.sonar.api.config.MapSettings;
import org.sonar.api.config.Settings;
+import org.sonar.api.scan.filesystem.PathResolver;
import org.sonar.api.utils.log.LogTester;
import org.sonar.api.utils.log.LoggerLevel;
import org.sonar.core.util.CloseableIterator;
publisher = mock(ReportPublisher.class);
when(publisher.getWriter()).thenReturn(new ScannerReportWriter(outputDir));
index = new SonarCpdBlockIndex(publisher, settings);
- componentStore = new InputComponentStore();
+ componentStore = new InputComponentStore(new PathResolver());
executor = new CpdExecutor(settings, index, publisher, componentStore);
reader = new ScannerReportReader(outputDir);
- componentStore.put(new DefaultInputModule("foo"));
+ componentStore.put(TestInputFileBuilder.newDefaultInputModule("foo", baseDir));
batchComponent1 = createComponent("src/Foo.php", 5);
batchComponent2 = createComponent("src/Foo2.php", 5);
*/
package org.sonar.scanner.postjob;
+import java.io.IOException;
import java.util.Arrays;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
import org.sonar.api.batch.AnalysisMode;
import org.sonar.api.batch.fs.internal.TestInputFileBuilder;
import org.sonar.api.batch.postjob.issue.PostJobIssue;
import org.sonar.api.batch.rule.Severity;
-import org.sonar.api.config.Settings;
import org.sonar.api.config.MapSettings;
+import org.sonar.api.config.Settings;
+import org.sonar.api.scan.filesystem.PathResolver;
import org.sonar.scanner.issue.IssueCache;
import org.sonar.scanner.issue.tracking.TrackedIssue;
import org.sonar.scanner.scan.filesystem.InputComponentStore;
public class DefaultPostJobContextTest {
+ @Rule
+ public TemporaryFolder temp = new TemporaryFolder();
+
private IssueCache issueCache;
private InputComponentStore componentStore;
private DefaultPostJobContext context;
@Before
public void prepare() {
issueCache = mock(IssueCache.class);
- componentStore = new InputComponentStore();
+ componentStore = new InputComponentStore(new PathResolver());
settings = new MapSettings();
analysisMode = mock(AnalysisMode.class);
context = new DefaultPostJobContext(settings, issueCache, componentStore, analysisMode);
}
@Test
- public void testIssues() {
+ public void testIssues() throws IOException {
when(analysisMode.isIssues()).thenReturn(true);
assertThat(context.settings()).isSameAs(settings);
assertThat(issue.severity()).isEqualTo(Severity.BLOCKER);
assertThat(issue.inputComponent()).isNull();
- componentStore.put(new TestInputFileBuilder("foo", "src/Foo.php").build());
+ String moduleKey = "foo";
+ componentStore.put(TestInputFileBuilder.newDefaultInputModule("foo", temp.newFolder()));
+
+ componentStore.put(new TestInputFileBuilder(moduleKey, "src/Foo.php").build());
assertThat(issue.inputComponent()).isNotNull();
}
package org.sonar.scanner.report;
import java.io.File;
+import java.io.IOException;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.sonar.api.batch.fs.internal.DefaultInputFile;
-import org.sonar.api.batch.fs.internal.DefaultInputModule;
import org.sonar.api.batch.fs.internal.TestInputFileBuilder;
import org.sonar.api.batch.sensor.measure.internal.DefaultMeasure;
import org.sonar.api.measures.CoreMetrics;
+import org.sonar.api.scan.filesystem.PathResolver;
import org.sonar.core.util.CloseableIterator;
import org.sonar.scanner.protocol.output.ScannerReport.LineCoverage;
import org.sonar.scanner.protocol.output.ScannerReportReader;
private MeasureCache measureCache;
private CoveragePublisher publisher;
- private InputComponentStore componentCache;
private DefaultInputFile inputFile;
@Before
- public void prepare() {
- inputFile = new TestInputFileBuilder("foo", "src/Foo.php").setLines(5).build();
- componentCache = new InputComponentStore();
- componentCache.put(new DefaultInputModule("foo"));
+ public void prepare() throws IOException {
+ String moduleKey = "foo";
+ inputFile = new TestInputFileBuilder(moduleKey, "src/Foo.php").setLines(5).build();
+ InputComponentStore componentCache = new InputComponentStore(new PathResolver());
+ componentCache.put(TestInputFileBuilder.newDefaultInputModule(moduleKey, temp.newFolder()));
componentCache.put(inputFile);
measureCache = mock(MeasureCache.class);
import org.sonar.api.batch.fs.internal.TestInputFileBuilder;
import org.sonar.api.batch.sensor.measure.internal.DefaultMeasure;
import org.sonar.api.measures.CoreMetrics;
+import org.sonar.api.scan.filesystem.PathResolver;
import org.sonar.core.util.CloseableIterator;
import org.sonar.scanner.deprecated.test.TestPlanBuilder;
import org.sonar.scanner.protocol.output.ScannerReport;
private MeasureCache measureCache;
private MeasuresPublisher publisher;
- private InputComponentStore componentCache;
private File outputDir;
private ScannerReportWriter writer;
private DefaultInputFile inputFile;
- private DefaultInputModule InputModule;
+ private DefaultInputModule inputModule;
@Before
public void prepare() throws IOException {
- InputModule = new DefaultInputModule("foo");
- inputFile = new TestInputFileBuilder("foo", "src/Foo.php").setPublish(true).build();
- componentCache = new InputComponentStore();
- componentCache.put(InputModule);
+ String moduleKey = "foo";
+ inputModule = TestInputFileBuilder.newDefaultInputModule(moduleKey, temp.newFolder());
+ inputFile = new TestInputFileBuilder(moduleKey, "src/Foo.php").setPublish(true).build();
+ InputComponentStore componentCache = new InputComponentStore(new PathResolver());
+ componentCache.put(inputModule);
componentCache.put(inputFile);
measureCache = mock(MeasureCache.class);
when(measureCache.byComponentKey(anyString())).thenReturn(Collections.<DefaultMeasure<?>>emptyList());
publisher.publish(writer);
ScannerReportReader reader = new ScannerReportReader(outputDir);
- assertThat(reader.readComponentMeasures(InputModule.batchId())).hasSize(0);
+ assertThat(reader.readComponentMeasures(inputModule.batchId())).hasSize(0);
try (CloseableIterator<ScannerReport.Measure> componentMeasures = reader.readComponentMeasures(inputFile.batchId())) {
assertThat(componentMeasures).hasSize(2);
}
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.sonar.api.batch.fs.internal.DefaultInputFile;
-import org.sonar.api.batch.fs.internal.DefaultInputModule;
import org.sonar.api.batch.fs.internal.TestInputFileBuilder;
+import org.sonar.api.scan.filesystem.PathResolver;
import org.sonar.scanner.protocol.output.ScannerReportWriter;
-import org.sonar.scanner.report.SourcePublisher;
import org.sonar.scanner.scan.filesystem.InputComponentStore;
import static org.assertj.core.api.Assertions.assertThat;
private File sourceFile;
private ScannerReportWriter writer;
private DefaultInputFile inputFile;
- private InputComponentStore componentStore;
@Before
public void prepare() throws IOException {
File baseDir = temp.newFolder();
sourceFile = new File(baseDir, "src/Foo.php");
- inputFile = new TestInputFileBuilder("foo", "src/Foo.php")
+ String moduleKey = "foo";
+ inputFile = new TestInputFileBuilder(moduleKey, "src/Foo.php")
.setLines(5)
.setModuleBaseDir(baseDir.toPath())
.setCharset(StandardCharsets.ISO_8859_1)
.build();
- componentStore = new InputComponentStore();
- componentStore.put(new DefaultInputModule("foo"));
+
+ InputComponentStore componentStore = new InputComponentStore(new PathResolver());
+ componentStore.put(TestInputFileBuilder.newDefaultInputModule(moduleKey, baseDir));
componentStore.put(inputFile);
+
publisher = new SourcePublisher(componentStore);
File outputDir = temp.newFolder();
writer = new ScannerReportWriter(outputDir);
import org.junit.rules.TemporaryFolder;
import org.slf4j.Logger;
import org.sonar.api.batch.fs.internal.DefaultFileSystem;
+import org.sonar.api.batch.fs.internal.TestInputFileBuilder;
import org.sonar.api.config.Settings;
import org.sonar.api.config.MapSettings;
import org.sonar.api.utils.MessageException;
@Test
public void should_log_all_used_profiles() {
- fs.addLanguages("java", "cobol");
+ fs.add(new TestInputFileBuilder("foo", "src/Bar.java").setLanguage("java").build());
+ fs.add(new TestInputFileBuilder("foo", "src/Baz.cbl").setLanguage("cobol").build());
+
QProfileVerifier profileLogger = new QProfileVerifier(settings, fs, profiles);
Logger logger = mock(Logger.class);
profileLogger.execute(logger);
@Test
public void should_fail_if_default_profile_not_used() {
- fs.addLanguages("java", "cobol");
+ fs.add(new TestInputFileBuilder("foo", "src/Bar.java").setLanguage("java").build());
+
settings.setProperty("sonar.profile", "Unknown");
QProfileVerifier profileLogger = new QProfileVerifier(settings, fs, profiles);
@Test
public void should_not_fail_if_default_profile_used_at_least_once() {
- fs.addLanguages("java", "cobol");
+ fs.add(new TestInputFileBuilder("foo", "src/Bar.java").setLanguage("java").build());
+
settings.setProperty("sonar.profile", "My Java profile");
QProfileVerifier profileLogger = new QProfileVerifier(settings, fs, profiles);
*/
package org.sonar.scanner.scan;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
import org.junit.Before;
import org.junit.Test;
import org.sonar.api.batch.bootstrap.ProjectDefinition;
import org.sonar.api.batch.fs.InputModule;
+import org.sonar.api.scan.filesystem.PathResolver;
import org.sonar.scanner.scan.filesystem.BatchIdGenerator;
import org.sonar.scanner.scan.filesystem.InputComponentStore;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
public class ModuleIndexerTest {
private ModuleIndexer indexer;
private DefaultComponentTree tree;
@Before
public void setUp() {
reactor = mock(ImmutableProjectReactor.class);
- componentStore = new InputComponentStore();
+ componentStore = new InputComponentStore(new PathResolver());
tree = new DefaultComponentTree();
moduleHierarchy = new DefaultInputModuleHierarchy();
indexer = new ModuleIndexer(reactor, tree, componentStore, new BatchIdGenerator(), moduleHierarchy);
*/
package org.sonar.scanner.scan.filesystem;
-import static org.assertj.core.api.Assertions.assertThat;
-
+import java.io.File;
import java.nio.charset.StandardCharsets;
import java.util.LinkedList;
import java.util.List;
-
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.sonar.api.batch.fs.InputFile.Type;
import org.sonar.api.batch.fs.InputPath;
import org.sonar.api.batch.fs.internal.DefaultInputFile;
+import org.sonar.api.batch.fs.internal.DefaultInputModule;
import org.sonar.api.batch.fs.internal.TestInputFileBuilder;
+import org.sonar.api.scan.filesystem.PathResolver;
+
+import static org.assertj.core.api.Assertions.assertThat;
public class InputComponentStoreTest {
@Rule
@Test
public void should_add_input_file() throws Exception {
- InputComponentStore cache = new InputComponentStore();
- DefaultInputFile fooFile = new TestInputFileBuilder("struts", "src/main/java/Foo.java")
- .setModuleBaseDir(temp.newFolder().toPath())
+ InputComponentStore cache = new InputComponentStore(new PathResolver());
+
+ String rootModuleKey = "struts";
+ File rootBaseDir = temp.newFolder();
+ DefaultInputModule rootModule = TestInputFileBuilder.newDefaultInputModule(rootModuleKey, rootBaseDir);
+ cache.put(rootModule);
+
+ String subModuleKey = "struts-core";
+ DefaultInputModule subModule = TestInputFileBuilder.newDefaultInputModule(subModuleKey, temp.newFolder());
+ rootModule.definition().addSubProject(subModule.definition());
+ cache.put(subModule);
+
+ DefaultInputFile fooFile = new TestInputFileBuilder(rootModuleKey, "src/main/java/Foo.java")
+ .setModuleBaseDir(rootBaseDir.toPath())
.setPublish(true)
.build();
cache.put(fooFile);
- cache.put(new TestInputFileBuilder("struts-core", "src/main/java/Bar.java")
+ cache.put(new TestInputFileBuilder(subModuleKey, "src/main/java/Bar.java")
.setLanguage("bla")
.setPublish(false)
.setType(Type.MAIN)
.setModuleBaseDir(temp.newFolder().toPath())
.build());
- DefaultInputFile loadedFile = (DefaultInputFile) cache.getFile("struts-core", "src/main/java/Bar.java");
+ DefaultInputFile loadedFile = (DefaultInputFile) cache.getFile(subModuleKey, "src/main/java/Bar.java");
assertThat(loadedFile.relativePath()).isEqualTo("src/main/java/Bar.java");
assertThat(loadedFile.charset()).isEqualTo(StandardCharsets.UTF_8);
- assertThat(cache.filesByModule("struts")).hasSize(1);
- assertThat(cache.filesByModule("struts-core")).hasSize(1);
+ assertThat(cache.filesByModule(rootModuleKey)).hasSize(1);
+ assertThat(cache.filesByModule(subModuleKey)).hasSize(1);
assertThat(cache.allFiles()).hasSize(2);
for (InputPath inputPath : cache.allFiles()) {
assertThat(inputPath.relativePath()).startsWith("src/main/java/");
cache.remove(fooFile);
assertThat(cache.allFiles()).hasSize(1);
- cache.removeModule("struts");
- assertThat(cache.filesByModule("struts")).hasSize(0);
- assertThat(cache.filesByModule("struts-core")).hasSize(1);
+ cache.removeModule(rootModuleKey);
+ assertThat(cache.filesByModule(rootModuleKey)).hasSize(0);
+ assertThat(cache.filesByModule(subModuleKey)).hasSize(1);
assertThat(cache.allFiles()).hasSize(1);
}
package org.sonar.scanner.scan.filesystem;
import java.io.IOException;
+import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.fs.InputModule;
import org.sonar.api.batch.fs.internal.TestInputFileBuilder;
+import org.sonar.api.scan.filesystem.PathResolver;
+import org.sonar.scanner.sensor.SensorStrategy;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
public class ModuleInputComponentStoreTest {
+ @Rule
+ public TemporaryFolder temp = new TemporaryFolder();
+
+ private InputComponentStore componentStore;
+
+ private final String moduleKey = "dummy key";
+
+ @Before
+ public void setUp() throws IOException {
+ componentStore = new InputComponentStore(new PathResolver());
+ componentStore.put(TestInputFileBuilder.newDefaultInputModule(moduleKey, temp.newFolder()));
+ }
+
@Test
public void should_cache_files_by_filename() throws IOException {
- ModuleInputComponentStore store = new ModuleInputComponentStore(mock(InputModule.class), new InputComponentStore());
+ ModuleInputComponentStore store = newModuleInputComponentStore();
String filename = "some name";
- String moduleKey = "dummy key";
InputFile inputFile1 = new TestInputFileBuilder(moduleKey, "some/path/" + filename).build();
store.doAdd(inputFile1);
@Test
public void should_cache_files_by_extension() throws IOException {
- ModuleInputComponentStore store = new ModuleInputComponentStore(mock(InputModule.class), new InputComponentStore());
+ ModuleInputComponentStore store = newModuleInputComponentStore();
- String moduleKey = "dummy key";
InputFile inputFile1 = new TestInputFileBuilder(moduleKey, "some/path/Program.java").build();
store.doAdd(inputFile1);
@Test
public void should_not_cache_duplicates() throws IOException {
- ModuleInputComponentStore store = new ModuleInputComponentStore(mock(InputModule.class), new InputComponentStore());
+ ModuleInputComponentStore store = newModuleInputComponentStore();
String ext = "java";
String filename = "Program." + ext;
- InputFile inputFile = new TestInputFileBuilder("dummy key", "some/path/" + filename).build();
+ InputFile inputFile = new TestInputFileBuilder(moduleKey, "some/path/" + filename).build();
store.doAdd(inputFile);
store.doAdd(inputFile);
store.doAdd(inputFile);
@Test
public void should_get_empty_iterable_on_cache_miss() {
- ModuleInputComponentStore store = new ModuleInputComponentStore(mock(InputModule.class), new InputComponentStore());
+ ModuleInputComponentStore store = newModuleInputComponentStore();
String ext = "java";
String filename = "Program." + ext;
- InputFile inputFile = new TestInputFileBuilder("dummy key", "some/path/" + filename).build();
+ InputFile inputFile = new TestInputFileBuilder(moduleKey, "some/path/" + filename).build();
store.doAdd(inputFile);
assertThat(store.getFilesByName("nonexistent")).isEmpty();
assertThat(store.getFilesByExtension("nonexistent")).isEmpty();
}
+
+ private ModuleInputComponentStore newModuleInputComponentStore() {
+ return new ModuleInputComponentStore(mock(InputModule.class), componentStore, mock(SensorStrategy.class));
+ }
}