/* * SonarQube * Copyright (C) 2009-2020 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.api.batch.sensor.internal; import java.io.File; import java.io.Serializable; import java.nio.charset.Charset; import java.nio.file.Path; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.stream.Stream; import javax.annotation.CheckForNull; import javax.annotation.Nullable; import org.sonar.api.SonarQubeSide; import org.sonar.api.SonarRuntime; import org.sonar.api.batch.bootstrap.ProjectDefinition; import org.sonar.api.batch.fs.InputFile; import org.sonar.api.batch.fs.InputModule; import org.sonar.api.batch.fs.TextRange; import org.sonar.api.batch.fs.internal.DefaultFileSystem; import org.sonar.api.batch.fs.internal.DefaultInputFile; import org.sonar.api.batch.fs.internal.DefaultInputModule; import org.sonar.api.batch.fs.internal.DefaultInputProject; import org.sonar.api.batch.fs.internal.DefaultTextPointer; import org.sonar.api.batch.rule.ActiveRules; import org.sonar.api.batch.rule.internal.ActiveRulesBuilder; import org.sonar.api.batch.sensor.Sensor; import org.sonar.api.batch.sensor.SensorContext; import org.sonar.api.batch.sensor.code.NewSignificantCode; import org.sonar.api.batch.sensor.code.internal.DefaultSignificantCode; import org.sonar.api.batch.sensor.coverage.NewCoverage; import org.sonar.api.batch.sensor.coverage.internal.DefaultCoverage; import org.sonar.api.batch.sensor.cpd.NewCpdTokens; import org.sonar.api.batch.sensor.cpd.internal.DefaultCpdTokens; import org.sonar.api.batch.sensor.cpd.internal.TokensLine; import org.sonar.api.batch.sensor.error.AnalysisError; import org.sonar.api.batch.sensor.error.NewAnalysisError; import org.sonar.api.batch.sensor.error.internal.DefaultAnalysisError; import org.sonar.api.batch.sensor.highlighting.NewHighlighting; import org.sonar.api.batch.sensor.highlighting.TypeOfText; import org.sonar.api.batch.sensor.highlighting.internal.DefaultHighlighting; import org.sonar.api.batch.sensor.highlighting.internal.SyntaxHighlightingRule; import org.sonar.api.batch.sensor.issue.ExternalIssue; import org.sonar.api.batch.sensor.issue.Issue; import org.sonar.api.batch.sensor.issue.NewExternalIssue; import org.sonar.api.batch.sensor.issue.NewIssue; import org.sonar.api.batch.sensor.issue.internal.DefaultExternalIssue; import org.sonar.api.batch.sensor.issue.internal.DefaultIssue; import org.sonar.api.batch.sensor.measure.Measure; import org.sonar.api.batch.sensor.measure.NewMeasure; import org.sonar.api.batch.sensor.measure.internal.DefaultMeasure; import org.sonar.api.batch.sensor.rule.AdHocRule; import org.sonar.api.batch.sensor.rule.NewAdHocRule; import org.sonar.api.batch.sensor.rule.internal.DefaultAdHocRule; import org.sonar.api.batch.sensor.symbol.NewSymbolTable; import org.sonar.api.batch.sensor.symbol.internal.DefaultSymbolTable; import org.sonar.api.config.Configuration; import org.sonar.api.config.internal.ConfigurationBridge; import org.sonar.api.config.internal.MapSettings; import org.sonar.api.internal.MetadataLoader; import org.sonar.api.internal.SonarRuntimeImpl; import org.sonar.api.measures.Metric; import org.sonar.api.scanner.fs.InputProject; import org.sonar.api.utils.System2; import org.sonar.api.utils.Version; import static java.util.Collections.unmodifiableMap; /** * Utility class to help testing {@link Sensor}. This is not an API and method signature may evolve. *
* Usage: call {@link #create(File)} to create an "in memory" implementation of {@link SensorContext} with a filesystem initialized with provided baseDir. *
* You have to manually register inputFiles using: *
* sensorContextTester.fileSystem().add(new DefaultInputFile("myProjectKey", "src/Foo.java") * .setLanguage("java") * .initMetadata("public class Foo {\n}")); **
* Then pass it to your {@link Sensor}. You can then query elements provided by your sensor using methods {@link #allIssues()}, ...
*/
public class SensorContextTester implements SensorContext {
private MapSettings settings;
private DefaultFileSystem fs;
private ActiveRules activeRules;
private InMemorySensorStorage sensorStorage;
private DefaultInputProject project;
private DefaultInputModule module;
private SonarRuntime runtime;
private boolean cancelled;
private SensorContextTester(Path moduleBaseDir) {
this.settings = new MapSettings();
this.fs = new DefaultFileSystem(moduleBaseDir).setEncoding(Charset.defaultCharset());
this.activeRules = new ActiveRulesBuilder().build();
this.sensorStorage = new InMemorySensorStorage();
this.project = new DefaultInputProject(ProjectDefinition.create().setKey("projectKey").setBaseDir(moduleBaseDir.toFile()).setWorkDir(moduleBaseDir.resolve(".sonar").toFile()));
this.module = new DefaultInputModule(ProjectDefinition.create().setKey("projectKey").setBaseDir(moduleBaseDir.toFile()).setWorkDir(moduleBaseDir.resolve(".sonar").toFile()));
this.runtime = SonarRuntimeImpl.forSonarQube(MetadataLoader.loadVersion(System2.INSTANCE), SonarQubeSide.SCANNER, MetadataLoader.loadEdition(System2.INSTANCE));
}
public static SensorContextTester create(File moduleBaseDir) {
return new SensorContextTester(moduleBaseDir.toPath());
}
public static SensorContextTester create(Path moduleBaseDir) {
return new SensorContextTester(moduleBaseDir);
}
public MapSettings settings() {
return settings;
}
@Override
public Configuration config() {
return new ConfigurationBridge(settings);
}
public SensorContextTester setSettings(MapSettings settings) {
this.settings = settings;
return this;
}
@Override
public DefaultFileSystem fileSystem() {
return fs;
}
public SensorContextTester setFileSystem(DefaultFileSystem fs) {
this.fs = fs;
return this;
}
@Override
public ActiveRules activeRules() {
return activeRules;
}
public SensorContextTester setActiveRules(ActiveRules activeRules) {
this.activeRules = activeRules;
return this;
}
/**
* Default value is the version of this API at compilation time. You can override it
* using {@link #setRuntime(SonarRuntime)} to test your Sensor behaviour.
*/
@Override
public Version getSonarQubeVersion() {
return runtime().getApiVersion();
}
/**
* @see #setRuntime(SonarRuntime) to override defaults (SonarQube scanner with version
* of this API as used at compilation time).
*/
@Override
public SonarRuntime runtime() {
return runtime;
}
public SensorContextTester setRuntime(SonarRuntime runtime) {
this.runtime = runtime;
return this;
}
@Override
public boolean isCancelled() {
return cancelled;
}
public void setCancelled(boolean cancelled) {
this.cancelled = cancelled;
}
@Override
public InputModule module() {
return module;
}
@Override
public InputProject project() {
return project;
}
@Override
public