diff options
author | Janos Gyerik <janos.gyerik@sonarsource.com> | 2017-03-02 17:32:20 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-03-02 17:32:20 +0100 |
commit | bc298f995099795d8b280baa80eb579096dfcecb (patch) | |
tree | d488d7e774500a149325bd744085be425b223e23 /sonar-scanner-engine | |
parent | 96b5ef41e280b775442388dfd49dad73e29d6a7e (diff) | |
download | sonarqube-bc298f995099795d8b280baa80eb579096dfcecb.tar.gz sonarqube-bc298f995099795d8b280baa80eb579096dfcecb.zip |
SONAR-8832 Support project-level sensors (#1720)
Diffstat (limited to 'sonar-scanner-engine')
21 files changed, 367 insertions, 88 deletions
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/ScannerExtensionDictionnary.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/ScannerExtensionDictionnary.java index b68cedda7ef..705b3cc4560 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/ScannerExtensionDictionnary.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/ScannerExtensionDictionnary.java @@ -26,6 +26,7 @@ import java.lang.reflect.Modifier; 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; @@ -78,6 +79,25 @@ public class ScannerExtensionDictionnary { 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) { diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/cpd/deprecated/DeprecatedCpdBlockIndexerSensor.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/cpd/deprecated/DeprecatedCpdBlockIndexerSensor.java index 3b026185302..b8721d36167 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/cpd/deprecated/DeprecatedCpdBlockIndexerSensor.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/cpd/deprecated/DeprecatedCpdBlockIndexerSensor.java @@ -52,7 +52,8 @@ public class DeprecatedCpdBlockIndexerSensor implements Sensor { @Override public void describe(SensorDescriptor descriptor) { - descriptor.name("CPD Block Indexer"); + descriptor.name("CPD Block Indexer") + .global(); } @VisibleForTesting @@ -65,7 +66,6 @@ public class DeprecatedCpdBlockIndexerSensor implements Sensor { @Override public void execute(SensorContext context) { - for (String language : fs.languages()) { CpdBlockIndexer blockIndexer = getBlockIndexer(language); if (!blockIndexer.isLanguageSupported(language)) { diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/phases/SensorsExecutor.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/phases/SensorsExecutor.java index 73cc0c2072a..c4b1805d3ba 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/phases/SensorsExecutor.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/phases/SensorsExecutor.java @@ -20,6 +20,9 @@ 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; @@ -27,29 +30,56 @@ import org.sonar.api.batch.fs.internal.DefaultInputModule; 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) { diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ModuleScanContainer.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ModuleScanContainer.java index 3f46db55697..9053ad07f89 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ModuleScanContainer.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ModuleScanContainer.java @@ -70,6 +70,7 @@ import org.sonar.scanner.scan.filesystem.StatusDetectionFactory; 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; @@ -137,6 +138,8 @@ public class ModuleScanContainer extends ComponentContainer { IssueFilters.class, CoverageExclusions.class, + SensorStrategy.class, + // rules new RulesProfileProvider(), CheckFactory.class, diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectScanContainer.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectScanContainer.java index 332a976d76c..e905184a0ed 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectScanContainer.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectScanContainer.java @@ -245,6 +245,7 @@ public class ProjectScanContainer extends ComponentContainer { LOG.debug("Start recursive analysis of project modules"); scanRecursively(tree, tree.root()); + if (analysisMode.isMediumTest()) { getComponentByType(ScanTaskObservers.class).notifyEndOfScanTask(); } diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/InputComponentStore.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/InputComponentStore.java index 2b7d318815c..52c0167d100 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/InputComponentStore.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/InputComponentStore.java @@ -19,14 +19,19 @@ */ 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; @@ -34,11 +39,10 @@ import org.sonar.api.batch.fs.InputFile; 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 @@ -47,7 +51,12 @@ import org.sonar.api.batch.fs.internal.FilenamePredicate; @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<>(); @@ -55,6 +64,10 @@ public class InputComponentStore { 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(); } @@ -77,10 +90,6 @@ public class InputComponentStore { return inputComponents.get(key); } - public void setRoot(InputModule root) { - this.root = root; - } - @CheckForNull public InputModule root() { return root; @@ -114,38 +123,79 @@ public class InputComponentStore { 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) { @@ -155,4 +205,12 @@ public class InputComponentStore { 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()); + } } diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/ModuleInputComponentStore.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/ModuleInputComponentStore.java index efc97addbf5..cca6b49fb14 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/ModuleInputComponentStore.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/ModuleInputComponentStore.java @@ -19,36 +19,61 @@ */ 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 diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/SensorStrategy.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/SensorStrategy.java new file mode 100644 index 00000000000..ebdba341751 --- /dev/null +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/SensorStrategy.java @@ -0,0 +1,38 @@ +/* + * 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; + } +} diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/SensorWrapper.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/SensorWrapper.java index ef3114a1246..6c71a8dc05d 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/SensorWrapper.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/SensorWrapper.java @@ -61,4 +61,8 @@ public class SensorWrapper implements org.sonar.api.batch.Sensor { return wrappedSensor.getClass().getName(); } } + + public boolean isGlobal() { + return descriptor.isGlobal(); + } } diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/source/CodeColorizerSensor.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/source/CodeColorizerSensor.java index b735d817214..97a9f5f30d1 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/source/CodeColorizerSensor.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/source/CodeColorizerSensor.java @@ -42,7 +42,8 @@ public final class CodeColorizerSensor implements Sensor { @Override public void describe(SensorDescriptor descriptor) { - descriptor.name("Code Colorizer Sensor"); + descriptor.name("Code Colorizer Sensor") + .global(); } @Override diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/source/ZeroCoverageSensor.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/source/ZeroCoverageSensor.java index 64663ba4453..da5482356f4 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/source/ZeroCoverageSensor.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/source/ZeroCoverageSensor.java @@ -70,7 +70,8 @@ public final class ZeroCoverageSensor implements Sensor { @Override public void describe(SensorDescriptor descriptor) { - descriptor.name("Zero Coverage Sensor"); + descriptor.name("Zero Coverage Sensor") + .global(); } @Override diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/bootstrap/ScannerExtensionDictionnaryTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/bootstrap/ScannerExtensionDictionnaryTest.java index 0d3bc4db5c7..e805f490e2e 100644 --- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/bootstrap/ScannerExtensionDictionnaryTest.java +++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/bootstrap/ScannerExtensionDictionnaryTest.java @@ -36,13 +36,13 @@ import org.sonar.api.batch.Sensor; 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; @@ -301,10 +301,7 @@ public class ScannerExtensionDictionnaryTest { 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 @@ -321,6 +318,30 @@ public class ScannerExtensionDictionnaryTest { 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) { @@ -332,6 +353,31 @@ public class ScannerExtensionDictionnaryTest { } } + 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; diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/cpd/CpdExecutorTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/cpd/CpdExecutorTest.java index 9259a79c87c..708f5ac97bc 100644 --- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/cpd/CpdExecutorTest.java +++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/cpd/CpdExecutorTest.java @@ -32,10 +32,10 @@ import org.junit.rules.ExpectedException; 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; @@ -86,11 +86,11 @@ public class CpdExecutorTest { 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); diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/postjob/DefaultPostJobContextTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/postjob/DefaultPostJobContextTest.java index c29e5307b54..64a87b2295d 100644 --- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/postjob/DefaultPostJobContextTest.java +++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/postjob/DefaultPostJobContextTest.java @@ -19,15 +19,19 @@ */ 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; @@ -38,6 +42,9 @@ import static org.mockito.Mockito.when; public class DefaultPostJobContextTest { + @Rule + public TemporaryFolder temp = new TemporaryFolder(); + private IssueCache issueCache; private InputComponentStore componentStore; private DefaultPostJobContext context; @@ -47,14 +54,14 @@ public class DefaultPostJobContextTest { @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); @@ -78,7 +85,10 @@ public class DefaultPostJobContextTest { 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(); } diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/report/CoveragePublisherTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/report/CoveragePublisherTest.java index aabacd09799..5551ca8f679 100644 --- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/report/CoveragePublisherTest.java +++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/report/CoveragePublisherTest.java @@ -20,15 +20,16 @@ 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; @@ -49,14 +50,14 @@ public class CoveragePublisherTest { 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); diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/report/MeasuresPublisherTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/report/MeasuresPublisherTest.java index 1efd6c69f43..d3dfe4cc3e9 100644 --- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/report/MeasuresPublisherTest.java +++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/report/MeasuresPublisherTest.java @@ -33,6 +33,7 @@ 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.deprecated.test.TestPlanBuilder; import org.sonar.scanner.protocol.output.ScannerReport; @@ -58,18 +59,18 @@ public class MeasuresPublisherTest { 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()); @@ -90,7 +91,7 @@ public class MeasuresPublisherTest { 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); } diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/report/SourcePublisherTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/report/SourcePublisherTest.java index 86c8fd74bbe..3624dcabf65 100644 --- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/report/SourcePublisherTest.java +++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/report/SourcePublisherTest.java @@ -28,10 +28,9 @@ 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.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; @@ -44,20 +43,22 @@ public class SourcePublisherTest { 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); diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/rule/QProfileVerifierTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/rule/QProfileVerifierTest.java index 58dac067d48..bfb438c3fb6 100644 --- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/rule/QProfileVerifierTest.java +++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/rule/QProfileVerifierTest.java @@ -26,6 +26,7 @@ import org.junit.rules.ExpectedException; 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; @@ -58,7 +59,9 @@ public class QProfileVerifierTest { @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); @@ -69,7 +72,8 @@ public class QProfileVerifierTest { @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); @@ -92,7 +96,8 @@ public class QProfileVerifierTest { @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); diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/ModuleIndexerTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/ModuleIndexerTest.java index 3ce99df7e75..74faa55f153 100644 --- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/ModuleIndexerTest.java +++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/ModuleIndexerTest.java @@ -19,17 +19,18 @@ */ 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; @@ -40,7 +41,7 @@ public class ModuleIndexerTest { @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); diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/filesystem/InputComponentStoreTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/filesystem/InputComponentStoreTest.java index 9ec32b91523..6b5a8b1ace1 100644 --- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/filesystem/InputComponentStoreTest.java +++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/filesystem/InputComponentStoreTest.java @@ -19,12 +19,10 @@ */ 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; @@ -33,7 +31,11 @@ import org.sonar.api.batch.fs.InputFile.Status; 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 @@ -41,13 +43,24 @@ public class InputComponentStoreTest { @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) @@ -57,12 +70,12 @@ public class InputComponentStoreTest { .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/"); @@ -75,9 +88,9 @@ public class InputComponentStoreTest { 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); } diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/filesystem/ModuleInputComponentStoreTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/filesystem/ModuleInputComponentStoreTest.java index 228bf779a18..eeb3b951fb1 100644 --- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/filesystem/ModuleInputComponentStoreTest.java +++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/filesystem/ModuleInputComponentStoreTest.java @@ -20,21 +20,38 @@ 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); @@ -49,9 +66,8 @@ public class ModuleInputComponentStoreTest { @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); @@ -66,11 +82,11 @@ public class ModuleInputComponentStoreTest { @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); @@ -81,14 +97,18 @@ public class ModuleInputComponentStoreTest { @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)); + } } |