--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 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.mediumtest;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Properties;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+import javax.annotation.Priority;
+import org.apache.commons.io.FileUtils;
+import org.junit.rules.ExternalResource;
+import org.sonar.api.Plugin;
+import org.sonar.api.SonarEdition;
+import org.sonar.api.SonarProduct;
+import org.sonar.api.SonarQubeSide;
+import org.sonar.api.SonarRuntime;
+import org.sonar.api.batch.rule.LoadedActiveRule;
+import org.sonar.api.impl.server.RulesDefinitionContext;
+import org.sonar.api.measures.CoreMetrics;
+import org.sonar.api.measures.Metric;
+import org.sonar.api.rule.RuleKey;
+import org.sonar.api.server.rule.RulesDefinition;
+import org.sonar.api.server.rule.RulesDefinition.Repository;
+import org.sonar.api.utils.DateUtils;
+import org.sonar.api.utils.Version;
+import org.sonar.batch.bootstrapper.Batch;
+import org.sonar.batch.bootstrapper.EnvironmentInformation;
+import org.sonar.batch.bootstrapper.LogOutput;
+import org.sonar.scanner.bootstrap.GlobalAnalysisMode;
+import org.sonar.scanner.cache.AnalysisCacheLoader;
+import org.sonar.scanner.protocol.internal.SensorCacheData;
+import org.sonar.scanner.report.CeTaskReportDataHolder;
+import org.sonar.scanner.repository.FileData;
+import org.sonar.scanner.repository.MetricsRepository;
+import org.sonar.scanner.repository.MetricsRepositoryLoader;
+import org.sonar.scanner.repository.NewCodePeriodLoader;
+import org.sonar.scanner.repository.ProjectRepositories;
+import org.sonar.scanner.repository.ProjectRepositoriesLoader;
+import org.sonar.scanner.repository.QualityProfileLoader;
+import org.sonar.scanner.repository.SingleProjectRepository;
+import org.sonar.scanner.repository.settings.GlobalSettingsLoader;
+import org.sonar.scanner.repository.settings.ProjectSettingsLoader;
+import org.sonar.scanner.rule.ActiveRulesLoader;
+import org.sonar.scanner.rule.RulesLoader;
+import org.sonar.scanner.scan.ScanProperties;
+import org.sonar.scanner.scan.branch.BranchConfiguration;
+import org.sonar.scanner.scan.branch.BranchConfigurationLoader;
+import org.sonar.scanner.scan.branch.BranchType;
+import org.sonar.scanner.scan.branch.ProjectBranches;
+import org.sonarqube.ws.NewCodePeriods;
+import org.sonarqube.ws.Qualityprofiles.SearchWsResponse.QualityProfile;
+import org.sonarqube.ws.Rules.ListResponse.Rule;
+
+import static java.util.Collections.emptySet;
+
+/**
+ * Main utility class for writing scanner medium tests.
+ */
+public class ScannerMediumTester extends ExternalResource {
+
+ private static Path userHome = null;
+ private final Map<String, String> globalProperties = new HashMap<>();
+ private final FakeMetricsRepositoryLoader globalRefProvider = new FakeMetricsRepositoryLoader();
+ private final FakeBranchConfigurationLoader branchConfigurationLoader = new FakeBranchConfigurationLoader();
+ private final FakeBranchConfiguration branchConfiguration = new FakeBranchConfiguration();
+ private final FakeProjectRepositoriesLoader projectRefProvider = new FakeProjectRepositoriesLoader();
+ private final FakePluginInstaller pluginInstaller = new FakePluginInstaller();
+ private final FakeGlobalSettingsLoader globalSettingsLoader = new FakeGlobalSettingsLoader();
+ private final FakeProjectSettingsLoader projectSettingsLoader = new FakeProjectSettingsLoader();
+ private final FakeNewCodePeriodLoader newCodePeriodLoader = new FakeNewCodePeriodLoader();
+ private final FakeAnalysisCacheLoader analysisCacheLoader = new FakeAnalysisCacheLoader();
+ private final FakeRulesLoader rulesLoader = new FakeRulesLoader();
+ private final FakeQualityProfileLoader qualityProfiles = new FakeQualityProfileLoader();
+ private final FakeActiveRulesLoader activeRules = new FakeActiveRulesLoader();
+ private final FakeSonarRuntime sonarRuntime = new FakeSonarRuntime();
+ private final CeTaskReportDataHolder reportMetadataHolder = new CeTaskReportDataHolderExt();
+ private LogOutput logOutput = null;
+
+ private static void createWorkingDirs() throws IOException {
+ destroyWorkingDirs();
+
+ userHome = java.nio.file.Files.createTempDirectory("mediumtest-userHome");
+ }
+
+ private static void destroyWorkingDirs() throws IOException {
+ if (userHome != null) {
+ FileUtils.deleteDirectory(userHome.toFile());
+ userHome = null;
+ }
+ }
+
+ public ScannerMediumTester setLogOutput(LogOutput logOutput) {
+ this.logOutput = logOutput;
+ return this;
+ }
+
+ public ScannerMediumTester registerPlugin(String pluginKey, File location) {
+ return registerPlugin(pluginKey, location, 1L);
+ }
+
+ public ScannerMediumTester registerPlugin(String pluginKey, File location, long lastUpdatedAt) {
+ pluginInstaller.add(pluginKey, location, lastUpdatedAt);
+ return this;
+ }
+
+ public ScannerMediumTester registerPlugin(String pluginKey, Plugin instance) {
+ return registerPlugin(pluginKey, instance, 1L);
+ }
+
+ public ScannerMediumTester registerPlugin(String pluginKey, Plugin instance, long lastUpdatedAt) {
+ pluginInstaller.add(pluginKey, instance, lastUpdatedAt);
+ return this;
+ }
+
+ public ScannerMediumTester registerCoreMetrics() {
+ for (Metric<?> m : CoreMetrics.getMetrics()) {
+ registerMetric(m);
+ }
+ return this;
+ }
+
+ public ScannerMediumTester registerMetric(Metric<?> metric) {
+ globalRefProvider.add(metric);
+ return this;
+ }
+
+ public ScannerMediumTester addQProfile(String language, String name) {
+ qualityProfiles.add(language, name);
+ return this;
+ }
+
+ public ScannerMediumTester addRule(Rule rule) {
+ rulesLoader.addRule(rule);
+ return this;
+ }
+
+ public ScannerMediumTester addRule(String key, String repoKey, String internalKey, String name) {
+ Rule.Builder builder = Rule.newBuilder();
+ builder.setKey(key);
+ builder.setRepository(repoKey);
+ if (internalKey != null) {
+ builder.setInternalKey(internalKey);
+ }
+ builder.setName(name);
+
+ rulesLoader.addRule(builder.build());
+ return this;
+ }
+
+ public ScannerMediumTester addRules(RulesDefinition rulesDefinition) {
+ RulesDefinition.Context context = new RulesDefinitionContext();
+ rulesDefinition.define(context);
+ List<Repository> repositories = context.repositories();
+ for (Repository repo : repositories) {
+ for (RulesDefinition.Rule rule : repo.rules()) {
+ this.addRule(rule.key(), rule.repository().key(), rule.internalKey(), rule.name());
+ }
+ }
+ return this;
+ }
+
+ public ScannerMediumTester addDefaultQProfile(String language, String name) {
+ addQProfile(language, name);
+ return this;
+ }
+
+ public ScannerMediumTester bootstrapProperties(Map<String, String> props) {
+ globalProperties.putAll(props);
+ return this;
+ }
+
+ public ScannerMediumTester activateRule(LoadedActiveRule activeRule) {
+ activeRules.addActiveRule(activeRule);
+ return this;
+ }
+
+ public ScannerMediumTester addActiveRule(String repositoryKey, String ruleKey, @Nullable String templateRuleKey, String name, @Nullable String severity,
+ @Nullable String internalKey, @Nullable String language) {
+ LoadedActiveRule r = new LoadedActiveRule();
+
+ r.setInternalKey(internalKey);
+ r.setRuleKey(RuleKey.of(repositoryKey, ruleKey));
+ r.setName(name);
+ r.setTemplateRuleKey(templateRuleKey);
+ r.setLanguage(language);
+ r.setSeverity(severity);
+ r.setDeprecatedKeys(emptySet());
+
+ activeRules.addActiveRule(r);
+ return this;
+ }
+
+ public ScannerMediumTester addFileData(String path, FileData fileData) {
+ projectRefProvider.addFileData(path, fileData);
+ return this;
+ }
+
+ public ScannerMediumTester addGlobalServerSettings(String key, String value) {
+ globalSettingsLoader.getGlobalSettings().put(key, value);
+ return this;
+ }
+
+ public ScannerMediumTester addProjectServerSettings(String key, String value) {
+ projectSettingsLoader.getProjectSettings().put(key, value);
+ return this;
+ }
+
+ public ScannerMediumTester setNewCodePeriod(NewCodePeriods.NewCodePeriodType type, String value) {
+ newCodePeriodLoader.set(NewCodePeriods.ShowWSResponse.newBuilder().setType(type).setValue(value).build());
+ return this;
+ }
+
+ @Override
+ protected void before() {
+ try {
+ createWorkingDirs();
+ } catch (IOException e) {
+ throw new IllegalStateException(e);
+ }
+ registerCoreMetrics();
+ globalProperties.put(GlobalAnalysisMode.MEDIUM_TEST_ENABLED, "true");
+ globalProperties.put(ScanProperties.KEEP_REPORT_PROP_KEY, "true");
+ globalProperties.put("sonar.userHome", userHome.toString());
+ }
+
+ @Override
+ protected void after() {
+ try {
+ destroyWorkingDirs();
+ } catch (IOException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ public AnalysisBuilder newAnalysis() {
+ return new AnalysisBuilder(this);
+ }
+
+ public AnalysisBuilder newAnalysis(File sonarProps) {
+ Properties prop = new Properties();
+ try (Reader reader = new InputStreamReader(new FileInputStream(sonarProps), StandardCharsets.UTF_8)) {
+ prop.load(reader);
+ } catch (Exception e) {
+ throw new IllegalStateException("Unable to read configuration file", e);
+ }
+ AnalysisBuilder builder = new AnalysisBuilder(this);
+ builder.property("sonar.projectBaseDir", sonarProps.getParentFile().getAbsolutePath());
+ for (Map.Entry<Object, Object> entry : prop.entrySet()) {
+ builder.property(entry.getKey().toString(), entry.getValue().toString());
+ }
+ return builder;
+ }
+
+ public static class AnalysisBuilder {
+ private final Map<String, String> taskProperties = new HashMap<>();
+ private final ScannerMediumTester tester;
+
+ public AnalysisBuilder(ScannerMediumTester tester) {
+ this.tester = tester;
+ }
+
+ public AnalysisResult execute() {
+ AnalysisResult result = new AnalysisResult();
+ Map<String, String> props = new HashMap<>();
+ props.putAll(tester.globalProperties);
+ props.putAll(taskProperties);
+
+ Batch.builder()
+ .setGlobalProperties(props)
+ .setEnableLoggingConfiguration(true)
+ .addComponents(new EnvironmentInformation("mediumTest", "1.0"),
+ tester.pluginInstaller,
+ tester.globalRefProvider,
+ tester.qualityProfiles,
+ tester.rulesLoader,
+ tester.branchConfigurationLoader,
+ tester.projectRefProvider,
+ tester.activeRules,
+ tester.globalSettingsLoader,
+ tester.projectSettingsLoader,
+ tester.newCodePeriodLoader,
+ tester.analysisCacheLoader,
+ tester.sonarRuntime,
+ tester.reportMetadataHolder,
+ result)
+ .setLogOutput(tester.logOutput)
+ .build().execute();
+
+ return result;
+ }
+
+ public AnalysisBuilder properties(Map<String, String> props) {
+ taskProperties.putAll(props);
+ return this;
+ }
+
+ public AnalysisBuilder property(String key, String value) {
+ taskProperties.put(key, value);
+ return this;
+ }
+
+ }
+
+ @Priority(1)
+ private static class FakeRulesLoader implements RulesLoader {
+ private List<Rule> rules = new LinkedList<>();
+
+ public FakeRulesLoader addRule(Rule rule) {
+ rules.add(rule);
+ return this;
+ }
+
+ @Override
+ public List<Rule> load() {
+ return rules;
+ }
+ }
+
+ @Priority(1)
+ private static class FakeActiveRulesLoader implements ActiveRulesLoader {
+ private List<LoadedActiveRule> activeRules = new LinkedList<>();
+
+ public void addActiveRule(LoadedActiveRule activeRule) {
+ this.activeRules.add(activeRule);
+ }
+
+ @Override
+ public List<LoadedActiveRule> load(String qualityProfileKey) {
+ return activeRules;
+ }
+ }
+
+ @Priority(1)
+ private static class FakeMetricsRepositoryLoader implements MetricsRepositoryLoader {
+
+ private int metricId = 1;
+
+ private List<Metric> metrics = new ArrayList<>();
+
+ @Override
+ public MetricsRepository load() {
+ return new MetricsRepository(metrics);
+ }
+
+ public FakeMetricsRepositoryLoader add(Metric<?> metric) {
+ metric.setUuid("metric" + metricId++);
+ metrics.add(metric);
+ metricId++;
+ return this;
+ }
+
+ }
+
+ @Priority(1)
+ private static class FakeProjectRepositoriesLoader implements ProjectRepositoriesLoader {
+ private Map<String, FileData> fileDataMap = new HashMap<>();
+
+ @Override
+ public ProjectRepositories load(String projectKey, @Nullable String branchBase) {
+ return new SingleProjectRepository(fileDataMap);
+ }
+
+ public FakeProjectRepositoriesLoader addFileData(String path, FileData fileData) {
+ fileDataMap.put(path, fileData);
+ return this;
+ }
+
+ }
+
+ @Priority(1)
+ private static class FakeBranchConfiguration implements BranchConfiguration {
+
+ private BranchType branchType = BranchType.BRANCH;
+ private String branchName = null;
+ private String branchTarget = null;
+ private String referenceBranchName = null;
+
+ @Override
+ public BranchType branchType() {
+ return branchType;
+ }
+
+ @CheckForNull
+ @Override
+ public String branchName() {
+ return branchName;
+ }
+
+ @CheckForNull
+ @Override
+ public String targetBranchName() {
+ return branchTarget;
+ }
+
+ @CheckForNull
+ @Override
+ public String referenceBranchName() {
+ return referenceBranchName;
+ }
+
+ @Override
+ public String pullRequestKey() {
+ return "1'";
+ }
+ }
+
+ @Priority(1)
+ private static class FakeSonarRuntime implements SonarRuntime {
+
+ private SonarEdition edition;
+
+ FakeSonarRuntime() {
+ this.edition = SonarEdition.COMMUNITY;
+ }
+
+ @Override
+ public Version getApiVersion() {
+ return Version.create(7, 8);
+ }
+
+ @Override
+ public SonarProduct getProduct() {
+ return SonarProduct.SONARQUBE;
+ }
+
+ @Override
+ public SonarQubeSide getSonarQubeSide() {
+ return SonarQubeSide.SCANNER;
+ }
+
+ @Override
+ public SonarEdition getEdition() {
+ return edition;
+ }
+
+ public void setEdition(SonarEdition edition) {
+ this.edition = edition;
+ }
+ }
+
+ public ScannerMediumTester setBranchType(BranchType branchType) {
+ branchConfiguration.branchType = branchType;
+ return this;
+ }
+
+ public ScannerMediumTester setBranchName(String branchName) {
+ this.branchConfiguration.branchName = branchName;
+ return this;
+ }
+
+ public ScannerMediumTester setBranchTarget(String branchTarget) {
+ this.branchConfiguration.branchTarget = branchTarget;
+ return this;
+ }
+
+ public ScannerMediumTester setReferenceBranchName(String referenceBranchNam) {
+ this.branchConfiguration.referenceBranchName = referenceBranchNam;
+ return this;
+ }
+
+ public ScannerMediumTester setEdition(SonarEdition edition) {
+ this.sonarRuntime.setEdition(edition);
+ return this;
+ }
+
+ @Priority(1)
+ private class FakeBranchConfigurationLoader implements BranchConfigurationLoader {
+ @Override
+ public BranchConfiguration load(Map<String, String> projectSettings, ProjectBranches branches) {
+ return branchConfiguration;
+ }
+ }
+
+ @Priority(1)
+ private static class FakeQualityProfileLoader implements QualityProfileLoader {
+
+ private List<QualityProfile> qualityProfiles = new LinkedList<>();
+
+ public void add(String language, String name) {
+ qualityProfiles.add(QualityProfile.newBuilder()
+ .setLanguage(language)
+ .setKey(name)
+ .setName(name)
+ .setRulesUpdatedAt(DateUtils.formatDateTime(new Date(1234567891212L)))
+ .build());
+ }
+
+ @Override
+ public List<QualityProfile> load(String projectKey) {
+ return qualityProfiles;
+ }
+ }
+
+ @Priority(1)
+ private static class FakeAnalysisCacheLoader implements AnalysisCacheLoader {
+ @Override
+ public Optional<SensorCacheData> load() {
+ return Optional.empty();
+ }
+ }
+
+ @Priority(1)
+ private static class FakeGlobalSettingsLoader implements GlobalSettingsLoader {
+
+ private Map<String, String> globalSettings = new HashMap<>();
+
+ public Map<String, String> getGlobalSettings() {
+ return globalSettings;
+ }
+
+ @Override
+ public Map<String, String> loadGlobalSettings() {
+ return Collections.unmodifiableMap(globalSettings);
+ }
+ }
+
+ @Priority(1)
+ private static class FakeNewCodePeriodLoader implements NewCodePeriodLoader {
+ private NewCodePeriods.ShowWSResponse response;
+
+ @Override
+ public NewCodePeriods.ShowWSResponse load(String projectKey, String branchName) {
+ return response;
+ }
+
+ public void set(NewCodePeriods.ShowWSResponse response) {
+ this.response = response;
+ }
+ }
+
+ @Priority(1)
+ private static class FakeProjectSettingsLoader implements ProjectSettingsLoader {
+
+ private Map<String, String> projectSettings = new HashMap<>();
+
+ public Map<String, String> getProjectSettings() {
+ return projectSettings;
+ }
+
+ @Override
+ public Map<String, String> loadProjectSettings() {
+ return Collections.unmodifiableMap(projectSettings);
+ }
+ }
+
+ @Priority(1)
+ private static class CeTaskReportDataHolderExt extends CeTaskReportDataHolder {
+
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 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.mediumtest.branch;
+
+import com.google.common.collect.ImmutableMap;
+import java.io.File;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.List;
+import org.apache.commons.io.FileUtils;
+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.FileMetadata;
+import org.sonar.api.notifications.AnalysisWarnings;
+import org.sonar.api.utils.log.LogTester;
+import org.sonar.scanner.mediumtest.AnalysisResult;
+import org.sonar.scanner.mediumtest.ScannerMediumTester;
+import org.sonar.scanner.protocol.output.ScannerReport;
+import org.sonar.scanner.repository.FileData;
+import org.sonar.scanner.scan.branch.BranchType;
+import org.sonar.xoo.XooPlugin;
+import org.sonar.xoo.rule.XooRulesDefinition;
+import org.sonarqube.ws.NewCodePeriods;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+
+public class BranchMediumIT {
+
+ private static final String PROJECT_KEY = "sample";
+ private static final String FILE_PATH = "HelloJava.xoo";
+ private static final String FILE_CONTENT = "xoooo";
+ public static final String ONE_ISSUE_PER_LINE_IS_RESTRICTED_TO_CHANGED_FILES_ONLY = "Sensor One Issue Per Line is restricted to changed files only";
+ private File baseDir;
+
+ @Rule
+ public TemporaryFolder temp = new TemporaryFolder();
+
+ @Rule
+ public LogTester logTester = new LogTester();
+
+ @Rule
+ public ScannerMediumTester tester = new ScannerMediumTester()
+ .registerPlugin("xoo", new XooPlugin())
+ .addDefaultQProfile("xoo", "Sonar Way")
+ .addRules(new XooRulesDefinition())
+ .addActiveRule("xoo", "OneIssuePerLine", null, "One issue per line", "MAJOR", "OneIssuePerLine.internal", "xoo");
+
+ @Before
+ public void prepare() throws IOException {
+ baseDir = temp.newFolder();
+ Path filepath = baseDir.toPath().resolve(FILE_PATH);
+ Files.write(filepath, FILE_CONTENT.getBytes());
+
+ Path xooUtCoverageFile = baseDir.toPath().resolve(FILE_PATH + ".coverage");
+ FileUtils.write(xooUtCoverageFile.toFile(), "1:2:2:1", StandardCharsets.UTF_8);
+
+ String md5sum = new FileMetadata(mock(AnalysisWarnings.class))
+ .readMetadata(Files.newInputStream(filepath), StandardCharsets.UTF_8, FILE_PATH)
+ .hash();
+ tester.addFileData(FILE_PATH, new FileData(md5sum, "1.1"));
+ tester.setNewCodePeriod(NewCodePeriods.NewCodePeriodType.PREVIOUS_VERSION, "");
+ }
+
+ @Test
+ public void should_not_skip_report_for_unchanged_files_in_pr() {
+ // sanity check, normally report gets generated
+ AnalysisResult result = getResult(tester);
+ final DefaultInputFile file = (DefaultInputFile) result.inputFile(FILE_PATH);
+ assertThat(getResult(tester).getReportComponent(file)).isNotNull();
+ int fileId = file.scannerId();
+ assertThat(result.getReportReader().readChangesets(fileId)).isNotNull();
+ assertThat(result.getReportReader().hasCoverage(fileId)).isTrue();
+ assertThat(result.getReportReader().readFileSource(fileId)).isNotNull();
+
+ // file is not skipped for pull requests (need coverage, duplications coming soon)
+ AnalysisResult result2 = getResult(tester.setBranchType(BranchType.PULL_REQUEST));
+ final DefaultInputFile fileInPr = (DefaultInputFile) result2.inputFile(FILE_PATH);
+ assertThat(result2.getReportComponent(fileInPr)).isNotNull();
+ fileId = fileInPr.scannerId();
+ assertThat(result2.getReportReader().readChangesets(fileId)).isNull();
+ assertThat(result2.getReportReader().hasCoverage(fileId)).isTrue();
+ assertThat(result2.getReportReader().readFileSource(fileId)).isNull();
+ }
+
+ @Test
+ public void shouldSkipSensorForUnchangedFilesOnPr() {
+ AnalysisResult result = getResult(tester
+ .setBranchName("myBranch")
+ .setBranchTarget("main")
+ .setBranchType(BranchType.PULL_REQUEST));
+ final DefaultInputFile file = (DefaultInputFile) result.inputFile(FILE_PATH);
+
+ List<ScannerReport.Issue> issues = result.issuesFor(file);
+ assertThat(issues).isEmpty();
+
+ assertThat(logTester.logs()).contains(ONE_ISSUE_PER_LINE_IS_RESTRICTED_TO_CHANGED_FILES_ONLY);
+ }
+
+ @Test
+ public void shouldNotSkipSensorForUnchangedFilesOnBranch() throws Exception {
+ AnalysisResult result = getResult(tester
+ .setBranchName("myBranch")
+ .setBranchTarget("main")
+ .setBranchType(BranchType.BRANCH));
+ final DefaultInputFile file = (DefaultInputFile) result.inputFile(FILE_PATH);
+
+ List<ScannerReport.Issue> issues = result.issuesFor(file);
+ assertThat(issues).isNotEmpty();
+
+ assertThat(logTester.logs()).doesNotContain(ONE_ISSUE_PER_LINE_IS_RESTRICTED_TO_CHANGED_FILES_ONLY);
+ }
+
+ @Test
+ public void verify_metadata() {
+ String branchName = "feature";
+ String branchTarget = "branch-1.x";
+
+ AnalysisResult result = getResult(tester
+ .setBranchName(branchName)
+ .setBranchTarget(branchTarget)
+ .setReferenceBranchName(branchTarget)
+ .setBranchType(BranchType.BRANCH));
+
+ ScannerReport.Metadata metadata = result.getReportReader().readMetadata();
+ assertThat(metadata.getBranchName()).isEqualTo(branchName);
+ assertThat(metadata.getBranchType()).isEqualTo(ScannerReport.Metadata.BranchType.BRANCH);
+ assertThat(metadata.getReferenceBranchName()).isEqualTo(branchTarget);
+ }
+
+ private AnalysisResult getResult(ScannerMediumTester tester) {
+ return tester
+ .newAnalysis()
+ .properties(ImmutableMap.<String, String>builder()
+ .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
+ .put("sonar.projectKey", PROJECT_KEY)
+ .put("sonar.scm.provider", "xoo")
+ .build())
+ .execute();
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 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.mediumtest.branch;
+
+import com.google.common.collect.ImmutableMap;
+import java.io.File;
+import java.io.IOException;
+import java.util.Map;
+import org.apache.commons.io.FileUtils;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.sonar.api.utils.MessageException;
+import org.sonar.scanner.mediumtest.ScannerMediumTester;
+import org.sonar.xoo.XooPlugin;
+import org.sonar.xoo.rule.XooRulesDefinition;
+
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+public class DeprecatedBranchMediumIT {
+
+ @Rule
+ public TemporaryFolder temp = new TemporaryFolder();
+
+ @Rule
+ public ScannerMediumTester tester = new ScannerMediumTester()
+ .registerPlugin("xoo", new XooPlugin())
+ .addRules(new XooRulesDefinition())
+ // active a rule just to be sure that xoo files are published
+ .addActiveRule("xoo", "xoo:OneIssuePerFile", null, "One Issue Per File", null, null, null)
+ .addDefaultQProfile("xoo", "Sonar Way");
+
+ private File baseDir;
+
+ private Map<String, String> commonProps;
+
+ @Before
+ public void prepare() {
+ baseDir = temp.getRoot();
+
+ commonProps = ImmutableMap.<String, String>builder()
+ .put("sonar.task", "scan")
+ .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
+ .put("sonar.projectKey", "com.foo.project")
+ .put("sonar.projectName", "Foo Project")
+ .put("sonar.projectVersion", "1.0-SNAPSHOT")
+ .put("sonar.projectDescription", "Description of Foo Project")
+ .put("sonar.sources", "src")
+ .build();
+ }
+
+ @Test
+ public void scanProjectWithBranch() throws IOException {
+ File srcDir = new File(baseDir, "src");
+ srcDir.mkdir();
+
+ File xooFile = new File(srcDir, "sample.xoo");
+ FileUtils.write(xooFile, "Sample xoo\ncontent");
+
+ assertThatThrownBy(() -> tester.newAnalysis()
+ .properties(ImmutableMap.<String, String>builder()
+ .putAll(commonProps)
+ .put("sonar.branch", "branch")
+ .build())
+ .execute())
+ .isInstanceOf(MessageException.class)
+ .hasMessage("The 'sonar.branch' parameter is no longer supported. You should stop using it. " +
+ "Branch analysis is available in Developer Edition and above. See https://www.sonarsource.com/plans-and-pricing/developer/ for more information.");
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 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.mediumtest.coverage;
+
+import com.google.common.collect.ImmutableMap;
+import java.io.File;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import org.apache.commons.io.FileUtils;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.sonar.api.batch.fs.InputFile;
+import org.sonar.api.utils.log.LogTester;
+import org.sonar.api.utils.log.LoggerLevel;
+import org.sonar.scanner.mediumtest.AnalysisResult;
+import org.sonar.scanner.mediumtest.ScannerMediumTester;
+import org.sonar.scanner.protocol.output.ScannerReport;
+import org.sonar.xoo.XooPlugin;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.AssertionsForClassTypes.tuple;
+
+public class CoverageMediumIT {
+
+ @Rule
+ public LogTester logTester = new LogTester();
+
+ @Rule
+ public TemporaryFolder temp = new TemporaryFolder();
+
+ @Rule
+ public ScannerMediumTester tester = new ScannerMediumTester()
+ .registerPlugin("xoo", new XooPlugin())
+ .addDefaultQProfile("xoo", "Sonar Way");
+
+ @Test
+ public void singleReport() throws IOException {
+
+ File baseDir = temp.getRoot();
+ File srcDir = new File(baseDir, "src");
+ srcDir.mkdir();
+
+ File xooFile = new File(srcDir, "sample.xoo");
+ File xooUtCoverageFile = new File(srcDir, "sample.xoo.coverage");
+ FileUtils.write(xooFile, "function foo() {\n if (a && b) {\nalert('hello');\n}\n}", StandardCharsets.UTF_8);
+ FileUtils.write(xooUtCoverageFile, "2:2:2:1\n3:1", StandardCharsets.UTF_8);
+
+ AnalysisResult result = tester.newAnalysis()
+ .properties(ImmutableMap.<String, String>builder()
+ .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
+ .put("sonar.projectKey", "com.foo.project")
+ .put("sonar.sources", "src")
+ .build())
+ .execute();
+
+ InputFile file = result.inputFile("src/sample.xoo");
+ assertThat(result.coverageFor(file, 2).getHits()).isTrue();
+ assertThat(result.coverageFor(file, 2).getConditions()).isEqualTo(2);
+ assertThat(result.coverageFor(file, 2).getCoveredConditions()).isOne();
+ }
+
+ @Test
+ public void twoReports() throws IOException {
+
+ File baseDir = temp.getRoot();
+ File srcDir = new File(baseDir, "src");
+ srcDir.mkdir();
+
+ File xooFile = new File(srcDir, "sample.xoo");
+ FileUtils.write(xooFile, "function foo() {\n if (a && b) {\nalert('hello');\n}\n}", StandardCharsets.UTF_8);
+ File xooUtCoverageFile = new File(srcDir, "sample.xoo.coverage");
+ FileUtils.write(xooUtCoverageFile, "2:2:2:2\n4:0", StandardCharsets.UTF_8);
+ File xooItCoverageFile = new File(srcDir, "sample.xoo.itcoverage");
+ FileUtils.write(xooItCoverageFile, "2:0:2:1\n3:1\n5:0", StandardCharsets.UTF_8);
+
+ AnalysisResult result = tester.newAnalysis()
+ .properties(ImmutableMap.<String, String>builder()
+ .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
+ .put("sonar.projectKey", "com.foo.project")
+ .put("sonar.sources", "src")
+ .build())
+ .execute();
+
+ InputFile file = result.inputFile("src/sample.xoo");
+ assertThat(result.coverageFor(file, 2).getHits()).isTrue();
+ assertThat(result.coverageFor(file, 2).getConditions()).isEqualTo(2);
+ assertThat(result.coverageFor(file, 2).getCoveredConditions()).isEqualTo(2);
+ assertThat(result.coverageFor(file, 3).getHits()).isTrue();
+ }
+
+ @Test
+ public void exclusionsForSimpleProject() throws IOException {
+
+ File baseDir = temp.getRoot();
+ File srcDir = new File(baseDir, "src");
+ srcDir.mkdir();
+
+ File xooFile = new File(srcDir, "sample.xoo");
+ File xooUtCoverageFile = new File(srcDir, "sample.xoo.coverage");
+ FileUtils.write(xooFile, "function foo() {\n if (a && b) {\nalert('hello');\n}\n}", StandardCharsets.UTF_8);
+ FileUtils.write(xooUtCoverageFile, "2:2:2:1\n3:1", StandardCharsets.UTF_8);
+
+ AnalysisResult result = tester.newAnalysis()
+ .properties(ImmutableMap.<String, String>builder()
+ .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
+ .put("sonar.projectKey", "com.foo.project")
+ .put("sonar.sources", "src")
+ .put("sonar.coverage.exclusions", "**/sample.xoo")
+ .build())
+ .execute();
+
+ InputFile file = result.inputFile("src/sample.xoo");
+ assertThat(result.coverageFor(file, 2)).isNull();
+ }
+
+ @Test
+ public void warn_user_for_outdated_inherited_scanner_side_exclusions_for_multi_module_project() throws IOException {
+
+ File baseDir = temp.getRoot();
+ File baseDirModuleA = new File(baseDir, "moduleA");
+ File baseDirModuleB = new File(baseDir, "moduleB");
+ File srcDirA = new File(baseDirModuleA, "src");
+ srcDirA.mkdirs();
+ File srcDirB = new File(baseDirModuleB, "src");
+ srcDirB.mkdirs();
+
+ File xooFileA = new File(srcDirA, "sampleA.xoo");
+ File xooUtCoverageFileA = new File(srcDirA, "sampleA.xoo.coverage");
+ FileUtils.write(xooFileA, "function foo() {\n if (a && b) {\nalert('hello');\n}\n}", StandardCharsets.UTF_8);
+ FileUtils.write(xooUtCoverageFileA, "2:2:2:1\n3:1", StandardCharsets.UTF_8);
+
+ File xooFileB = new File(srcDirB, "sampleB.xoo");
+ File xooUtCoverageFileB = new File(srcDirB, "sampleB.xoo.coverage");
+ FileUtils.write(xooFileB, "function foo() {\n if (a && b) {\nalert('hello');\n}\n}", StandardCharsets.UTF_8);
+ FileUtils.write(xooUtCoverageFileB, "2:2:2:1\n3:1", StandardCharsets.UTF_8);
+
+ AnalysisResult result = tester.newAnalysis()
+ .properties(ImmutableMap.<String, String>builder()
+ .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
+ .put("sonar.projectKey", "com.foo.project")
+ .put("sonar.sources", "src")
+ .put("sonar.modules", "moduleA,moduleB")
+ .put("sonar.coverage.exclusions", "src/sampleA.xoo")
+ .build())
+ .execute();
+
+ InputFile fileA = result.inputFile("moduleA/src/sampleA.xoo");
+ assertThat(result.coverageFor(fileA, 2)).isNull();
+
+ InputFile fileB = result.inputFile("moduleB/src/sampleB.xoo");
+ assertThat(result.coverageFor(fileB, 2)).isNotNull();
+
+ assertThat(logTester.logs(LoggerLevel.WARN)).contains("Specifying module-relative paths at project level in the property 'sonar.coverage.exclusions' is deprecated. " +
+ "To continue matching files like 'moduleA/src/sampleA.xoo', update this property so that patterns refer to project-relative paths.");
+ }
+
+ @Test
+ public void module_level_exclusions_override_parent_for_multi_module_project() throws IOException {
+
+ File baseDir = temp.getRoot();
+ File baseDirModuleA = new File(baseDir, "moduleA");
+ File baseDirModuleB = new File(baseDir, "moduleB");
+ File srcDirA = new File(baseDirModuleA, "src");
+ srcDirA.mkdirs();
+ File srcDirB = new File(baseDirModuleB, "src");
+ srcDirB.mkdirs();
+
+ File xooFileA = new File(srcDirA, "sampleA.xoo");
+ File xooUtCoverageFileA = new File(srcDirA, "sampleA.xoo.coverage");
+ FileUtils.write(xooFileA, "function foo() {\n if (a && b) {\nalert('hello');\n}\n}", StandardCharsets.UTF_8);
+ FileUtils.write(xooUtCoverageFileA, "2:2:2:1\n3:1", StandardCharsets.UTF_8);
+
+ File xooFileB = new File(srcDirB, "sampleB.xoo");
+ File xooUtCoverageFileB = new File(srcDirB, "sampleB.xoo.coverage");
+ FileUtils.write(xooFileB, "function foo() {\n if (a && b) {\nalert('hello');\n}\n}", StandardCharsets.UTF_8);
+ FileUtils.write(xooUtCoverageFileB, "2:2:2:1\n3:1", StandardCharsets.UTF_8);
+
+ AnalysisResult result = tester.newAnalysis()
+ .properties(ImmutableMap.<String, String>builder()
+ .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
+ .put("sonar.projectKey", "com.foo.project")
+ .put("sonar.sources", "src")
+ .put("sonar.modules", "moduleA,moduleB")
+ .put("sonar.coverage.exclusions", "**/*.xoo")
+ .put("moduleA.sonar.coverage.exclusions", "**/*.nothing")
+ .build())
+ .execute();
+
+ InputFile fileA = result.inputFile("moduleA/src/sampleA.xoo");
+ assertThat(result.coverageFor(fileA, 2)).isNotNull();
+
+ InputFile fileB = result.inputFile("moduleB/src/sampleB.xoo");
+ assertThat(result.coverageFor(fileB, 2)).isNull();
+ }
+
+ @Test
+ public void warn_user_for_outdated_server_side_exclusions_for_multi_module_project() throws IOException {
+
+ File baseDir = temp.getRoot();
+ File baseDirModuleA = new File(baseDir, "moduleA");
+ File baseDirModuleB = new File(baseDir, "moduleB");
+ File srcDirA = new File(baseDirModuleA, "src");
+ srcDirA.mkdirs();
+ File srcDirB = new File(baseDirModuleB, "src");
+ srcDirB.mkdirs();
+
+ File xooFileA = new File(srcDirA, "sample.xoo");
+ File xooUtCoverageFileA = new File(srcDirA, "sample.xoo.coverage");
+ FileUtils.write(xooFileA, "function foo() {\n if (a && b) {\nalert('hello');\n}\n}", StandardCharsets.UTF_8);
+ FileUtils.write(xooUtCoverageFileA, "2:2:2:1\n3:1", StandardCharsets.UTF_8);
+
+ File xooFileB = new File(srcDirB, "sample.xoo");
+ File xooUtCoverageFileB = new File(srcDirB, "sample.xoo.coverage");
+ FileUtils.write(xooFileB, "function foo() {\n if (a && b) {\nalert('hello');\n}\n}", StandardCharsets.UTF_8);
+ FileUtils.write(xooUtCoverageFileB, "2:2:2:1\n3:1", StandardCharsets.UTF_8);
+
+ tester.addProjectServerSettings("sonar.coverage.exclusions", "src/sample.xoo");
+
+ AnalysisResult result = tester.newAnalysis()
+ .properties(ImmutableMap.<String, String>builder()
+ .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
+ .put("sonar.projectKey", "com.foo.project")
+ .put("sonar.sources", "src")
+ .put("sonar.modules", "moduleA,moduleB")
+ .build())
+ .execute();
+
+ InputFile fileA = result.inputFile("moduleA/src/sample.xoo");
+ assertThat(result.coverageFor(fileA, 2)).isNull();
+
+ InputFile fileB = result.inputFile("moduleB/src/sample.xoo");
+ assertThat(result.coverageFor(fileB, 2)).isNull();
+
+ assertThat(logTester.logs(LoggerLevel.WARN)).contains("Specifying module-relative paths at project level in the property 'sonar.coverage.exclusions' is deprecated. " +
+ "To continue matching files like 'moduleA/src/sample.xoo', update this property so that patterns refer to project-relative paths.");
+ }
+
+ @Test
+ public void fallbackOnExecutableLines() throws IOException {
+
+ File baseDir = temp.getRoot();
+ File srcDir = new File(baseDir, "src");
+ srcDir.mkdir();
+
+ File xooFile = new File(srcDir, "sample.xoo");
+ File measuresFile = new File(srcDir, "sample.xoo.measures");
+ FileUtils.write(xooFile, "function foo() {\n if (a && b) {\nalert('hello');\n}\n}", StandardCharsets.UTF_8);
+ FileUtils.write(measuresFile, "executable_lines_data:2=1;3=1;4=0", StandardCharsets.UTF_8);
+
+ AnalysisResult result = tester.newAnalysis()
+ .properties(ImmutableMap.<String, String>builder()
+ .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
+ .put("sonar.projectKey", "com.foo.project")
+ .put("sonar.sources", "src")
+ .build())
+ .execute();
+
+ InputFile file = result.inputFile("src/sample.xoo");
+ assertThat(result.coverageFor(file, 1)).isNull();
+
+ assertThat(result.coverageFor(file, 2).getHits()).isFalse();
+ assertThat(result.coverageFor(file, 2).getConditions()).isZero();
+ assertThat(result.coverageFor(file, 2).getCoveredConditions()).isZero();
+
+ assertThat(result.coverageFor(file, 3).getHits()).isFalse();
+ assertThat(result.coverageFor(file, 4)).isNull();
+
+ assertThat(result.allMeasures().get(file.key()))
+ .extracting(ScannerReport.Measure::getMetricKey, m -> m.getStringValue().getValue())
+ .contains(tuple("executable_lines_data", "2=1;3=1;4=0"));
+ }
+
+ // SONAR-11641
+ @Test
+ public void dontFallbackOnExecutableLinesIfNoCoverageSaved() throws IOException {
+
+ File baseDir = temp.getRoot();
+ File srcDir = new File(baseDir, "src");
+ srcDir.mkdir();
+
+ File xooFile = new File(srcDir, "sample.xoo");
+ File measuresFile = new File(srcDir, "sample.xoo.measures");
+ File coverageFile = new File(srcDir, "sample.xoo.coverage");
+ FileUtils.write(xooFile, "function foo() {\n if (a && b) {\nalert('hello');\n}\n}", StandardCharsets.UTF_8);
+ FileUtils.write(measuresFile, "# The code analyzer disagree with the coverage tool and consider some lines to be executable\nexecutable_lines_data:2=1;3=1;4=0",
+ StandardCharsets.UTF_8);
+ FileUtils.write(coverageFile, "# No lines to cover in this file according to the coverage tool", StandardCharsets.UTF_8);
+
+ AnalysisResult result = tester.newAnalysis()
+ .properties(ImmutableMap.<String, String>builder()
+ .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
+ .put("sonar.projectKey", "com.foo.project")
+ .put("sonar.sources", "src")
+ .build())
+ .execute();
+
+ InputFile file = result.inputFile("src/sample.xoo");
+ assertThat(result.coverageFor(file, 1)).isNull();
+ assertThat(result.coverageFor(file, 2)).isNull();
+ assertThat(result.coverageFor(file, 3)).isNull();
+ assertThat(result.coverageFor(file, 4)).isNull();
+ }
+
+ // SONAR-9557
+ @Test
+ public void exclusionsAndForceToZeroOnModules() throws IOException {
+
+ File baseDir = temp.getRoot();
+ File srcDir = new File(baseDir, "module1/src");
+ srcDir.mkdir();
+
+ File xooFile1 = new File(srcDir, "sample1.xoo");
+ File measuresFile1 = new File(srcDir, "sample1.xoo.measures");
+ FileUtils.write(xooFile1, "function foo() {\n if (a && b) {\nalert('hello');\n}\n}", StandardCharsets.UTF_8);
+ FileUtils.write(measuresFile1, "executable_lines_data:2=1;3=1;4=0", StandardCharsets.UTF_8);
+
+ File xooFile2 = new File(srcDir, "sample2.xoo");
+ File measuresFile2 = new File(srcDir, "sample2.xoo.measures");
+ FileUtils.write(xooFile2, "function foo() {\n if (a && b) {\nalert('hello');\n}\n}", StandardCharsets.UTF_8);
+ FileUtils.write(measuresFile2, "executable_lines_data:2=1;3=1;4=0", StandardCharsets.UTF_8);
+
+ AnalysisResult result = tester.newAnalysis()
+ .properties(ImmutableMap.<String, String>builder()
+ .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
+ .put("sonar.projectKey", "com.foo.project")
+ .put("sonar.modules", "module1")
+ .put("sonar.sources", "src")
+ .put("sonar.coverage.exclusions", "**/sample2.xoo")
+ .build())
+ .execute();
+
+ InputFile file1 = result.inputFile("module1/src/sample1.xoo");
+ assertThat(result.coverageFor(file1, 1)).isNull();
+
+ assertThat(result.coverageFor(file1, 2).getHits()).isFalse();
+ assertThat(result.coverageFor(file1, 2).getConditions()).isZero();
+ assertThat(result.coverageFor(file1, 2).getCoveredConditions()).isZero();
+
+ assertThat(result.coverageFor(file1, 3).getHits()).isFalse();
+ assertThat(result.coverageFor(file1, 4)).isNull();
+
+ InputFile file2 = result.inputFile("module1/src/sample2.xoo");
+ assertThat(result.coverageFor(file2, 1)).isNull();
+ assertThat(result.coverageFor(file2, 2)).isNull();
+ assertThat(result.coverageFor(file2, 3)).isNull();
+ assertThat(result.coverageFor(file2, 4)).isNull();
+
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 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.mediumtest.coverage;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+import org.junit.Rule;
+import org.junit.Test;
+import org.sonar.api.batch.fs.InputFile;
+import org.sonar.scanner.mediumtest.AnalysisResult;
+import org.sonar.scanner.mediumtest.ScannerMediumTester;
+import org.sonar.xoo.XooPlugin;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class GenericCoverageMediumIT {
+ private final List<String> logs = new ArrayList<>();
+
+ @Rule
+ public ScannerMediumTester tester = new ScannerMediumTester()
+ .registerPlugin("xoo", new XooPlugin())
+ .addDefaultQProfile("xoo", "Sonar Way");
+
+ @Test
+ public void singleReport() {
+
+ File projectDir = new File("test-resources/mediumtest/xoo/sample-generic-coverage");
+
+ AnalysisResult result = tester
+ .setLogOutput((msg, level) -> logs.add(msg))
+ .newAnalysis(new File(projectDir, "sonar-project.properties"))
+ .property("sonar.coverageReportPaths", "coverage.xml")
+ .execute();
+
+ InputFile noConditions = result.inputFile("xources/hello/NoConditions.xoo");
+ assertThat(result.coverageFor(noConditions, 6).getHits()).isTrue();
+ assertThat(result.coverageFor(noConditions, 6).getConditions()).isZero();
+ assertThat(result.coverageFor(noConditions, 6).getCoveredConditions()).isZero();
+
+ assertThat(result.coverageFor(noConditions, 7).getHits()).isFalse();
+
+ InputFile withConditions = result.inputFile("xources/hello/WithConditions.xoo");
+ assertThat(result.coverageFor(withConditions, 3).getHits()).isTrue();
+ assertThat(result.coverageFor(withConditions, 3).getConditions()).isEqualTo(2);
+ assertThat(result.coverageFor(withConditions, 3).getCoveredConditions()).isOne();
+
+ assertThat(logs).noneMatch(l -> l.contains("Please use 'sonar.coverageReportPaths'"));
+
+ }
+
+ @Test
+ public void twoReports() {
+
+ File projectDir = new File("test-resources/mediumtest/xoo/sample-generic-coverage");
+
+ AnalysisResult result = tester
+ .setLogOutput((msg, level) -> logs.add(msg))
+ .newAnalysis(new File(projectDir, "sonar-project.properties"))
+ .property("sonar.coverageReportPaths", "coverage.xml,coverage2.xml")
+ .execute();
+
+ InputFile noConditions = result.inputFile("xources/hello/NoConditions.xoo");
+ assertThat(result.coverageFor(noConditions, 6).getHits()).isTrue();
+ assertThat(result.coverageFor(noConditions, 6).getConditions()).isZero();
+ assertThat(result.coverageFor(noConditions, 6).getCoveredConditions()).isZero();
+
+ assertThat(result.coverageFor(noConditions, 7).getHits()).isTrue();
+
+ InputFile withConditions = result.inputFile("xources/hello/WithConditions.xoo");
+ assertThat(result.coverageFor(withConditions, 3).getHits()).isTrue();
+ assertThat(result.coverageFor(withConditions, 3).getConditions()).isEqualTo(2);
+ assertThat(result.coverageFor(withConditions, 3).getCoveredConditions()).isEqualTo(2);
+
+ assertThat(logs).noneMatch(l -> l.contains("Please use 'sonar.coverageReportPaths'"));
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 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.mediumtest.cpd;
+
+import com.google.common.collect.ImmutableMap;
+import java.io.File;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.List;
+import org.apache.commons.io.FileUtils;
+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.utils.log.LogTester;
+import org.sonar.api.utils.log.LoggerLevel;
+import org.sonar.scanner.mediumtest.AnalysisResult;
+import org.sonar.scanner.mediumtest.ScannerMediumTester;
+import org.sonar.scanner.protocol.output.ScannerReport;
+import org.sonar.xoo.XooPlugin;
+import org.sonar.xoo.rule.XooRulesDefinition;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class CpdMediumIT {
+ @Rule
+ public TemporaryFolder temp = new TemporaryFolder();
+
+ @Rule
+ public LogTester logTester = new LogTester();
+
+ private File baseDir;
+
+ @Rule
+ public ScannerMediumTester tester = new ScannerMediumTester()
+ .registerPlugin("xoo", new XooPlugin())
+ .addDefaultQProfile("xoo", "Sonar Way")
+ .addRules(new XooRulesDefinition())
+ // active a rule just to be sure that xoo files are published
+ .addActiveRule("xoo", "xoo:OneIssuePerFile", null, "One Issue Per File", null, null, null);
+
+ private ImmutableMap.Builder<String, String> builder;
+
+ @Before
+ public void prepare() {
+ baseDir = temp.getRoot();
+
+ builder = ImmutableMap.<String, String>builder()
+ .put("sonar.task", "scan")
+ .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
+ .put("sonar.projectKey", "com.foo.project")
+ .put("sonar.projectName", "Foo Project")
+ .put("sonar.projectVersion", "1.0-SNAPSHOT")
+ .put("sonar.projectDescription", "Description of Foo Project");
+ }
+
+ @Test
+ public void testCrossModuleDuplications() throws IOException {
+ builder.put("sonar.modules", "module1,module2")
+ .put("sonar.cpd.xoo.minimumTokens", "10")
+ .put("sonar.verbose", "true");
+
+ // module 1
+ builder.put("module1.sonar.projectKey", "module1");
+ builder.put("module1.sonar.projectName", "Module 1");
+ builder.put("module1.sonar.sources", ".");
+
+ // module2
+ builder.put("module2.sonar.projectKey", "module2");
+ builder.put("module2.sonar.projectName", "Module 2");
+ builder.put("module2.sonar.sources", ".");
+
+ File module1Dir = new File(baseDir, "module1");
+ File module2Dir = new File(baseDir, "module2");
+
+ module1Dir.mkdir();
+ module2Dir.mkdir();
+
+ String duplicatedStuff = "Sample xoo\ncontent\n"
+ + "foo\nbar\ntoto\ntiti\n"
+ + "foo\nbar\ntoto\ntiti\n"
+ + "bar\ntoto\ntiti\n"
+ + "foo\nbar\ntoto\ntiti";
+
+ // create duplicated file in both modules
+ File xooFile1 = new File(module1Dir, "sample1.xoo");
+ FileUtils.write(xooFile1, duplicatedStuff);
+
+ File xooFile2 = new File(module2Dir, "sample2.xoo");
+ FileUtils.write(xooFile2, duplicatedStuff);
+
+ AnalysisResult result = tester.newAnalysis().properties(builder.build()).execute();
+
+ assertThat(result.inputFiles()).hasSize(2);
+
+ InputFile inputFile1 = result.inputFile("module1/sample1.xoo");
+ InputFile inputFile2 = result.inputFile("module2/sample2.xoo");
+
+ // One clone group on each file
+ List<ScannerReport.Duplication> duplicationGroupsFile1 = result.duplicationsFor(inputFile1);
+ assertThat(duplicationGroupsFile1).hasSize(1);
+
+ ScannerReport.Duplication cloneGroupFile1 = duplicationGroupsFile1.get(0);
+ assertThat(cloneGroupFile1.getOriginPosition().getStartLine()).isOne();
+ assertThat(cloneGroupFile1.getOriginPosition().getEndLine()).isEqualTo(17);
+ assertThat(cloneGroupFile1.getDuplicateList()).hasSize(1);
+ assertThat(cloneGroupFile1.getDuplicate(0).getOtherFileRef()).isEqualTo(result.getReportComponent(inputFile2).getRef());
+
+ List<ScannerReport.Duplication> duplicationGroupsFile2 = result.duplicationsFor(inputFile2);
+ assertThat(duplicationGroupsFile2).hasSize(1);
+
+ ScannerReport.Duplication cloneGroupFile2 = duplicationGroupsFile2.get(0);
+ assertThat(cloneGroupFile2.getOriginPosition().getStartLine()).isOne();
+ assertThat(cloneGroupFile2.getOriginPosition().getEndLine()).isEqualTo(17);
+ assertThat(cloneGroupFile2.getDuplicateList()).hasSize(1);
+ assertThat(cloneGroupFile2.getDuplicate(0).getOtherFileRef()).isEqualTo(result.getReportComponent(inputFile1).getRef());
+
+ assertThat(result.duplicationBlocksFor(inputFile1)).isEmpty();
+ }
+
+ @Test
+ public void testCrossFileDuplications() throws IOException {
+ File srcDir = new File(baseDir, "src");
+ srcDir.mkdir();
+
+ String duplicatedStuff = "Sample xoo\ncontent\n"
+ + "foo\nbar\ntoto\ntiti\n"
+ + "foo\nbar\ntoto\ntiti\n"
+ + "bar\ntoto\ntiti\n"
+ + "foo\nbar\ntoto\ntiti";
+
+ File xooFile1 = new File(srcDir, "sample1.xoo");
+ FileUtils.write(xooFile1, duplicatedStuff, StandardCharsets.UTF_8);
+
+ File xooFile2 = new File(srcDir, "sample2.xoo");
+ FileUtils.write(xooFile2, duplicatedStuff, StandardCharsets.UTF_8);
+
+ AnalysisResult result = tester.newAnalysis()
+ .properties(builder
+ .put("sonar.sources", "src")
+ .put("sonar.cpd.xoo.minimumTokens", "10")
+ .put("sonar.verbose", "true")
+ .build())
+ .execute();
+
+ assertThat(result.inputFiles()).hasSize(2);
+
+ InputFile inputFile1 = result.inputFile("src/sample1.xoo");
+ InputFile inputFile2 = result.inputFile("src/sample2.xoo");
+
+ // One clone group on each file
+ List<ScannerReport.Duplication> duplicationGroupsFile1 = result.duplicationsFor(inputFile1);
+ assertThat(duplicationGroupsFile1).hasSize(1);
+
+ ScannerReport.Duplication cloneGroupFile1 = duplicationGroupsFile1.get(0);
+ assertThat(cloneGroupFile1.getOriginPosition().getStartLine()).isOne();
+ assertThat(cloneGroupFile1.getOriginPosition().getEndLine()).isEqualTo(17);
+ assertThat(cloneGroupFile1.getDuplicateList()).hasSize(1);
+ assertThat(cloneGroupFile1.getDuplicate(0).getOtherFileRef()).isEqualTo(result.getReportComponent(inputFile2).getRef());
+
+ List<ScannerReport.Duplication> duplicationGroupsFile2 = result.duplicationsFor(inputFile2);
+ assertThat(duplicationGroupsFile2).hasSize(1);
+
+ ScannerReport.Duplication cloneGroupFile2 = duplicationGroupsFile2.get(0);
+ assertThat(cloneGroupFile2.getOriginPosition().getStartLine()).isOne();
+ assertThat(cloneGroupFile2.getOriginPosition().getEndLine()).isEqualTo(17);
+ assertThat(cloneGroupFile2.getDuplicateList()).hasSize(1);
+ assertThat(cloneGroupFile2.getDuplicate(0).getOtherFileRef()).isEqualTo(result.getReportComponent(inputFile1).getRef());
+
+ assertThat(result.duplicationBlocksFor(inputFile1)).isEmpty();
+ }
+
+ @Test
+ public void testFilesWithoutBlocks() throws IOException {
+ File srcDir = new File(baseDir, "src");
+ srcDir.mkdir();
+
+ String file1 = "Sample xoo\ncontent\n"
+ + "foo\nbar\ntoto\ntiti\n"
+ + "foo\nbar\ntoto\ntiti\n"
+ + "bar\ntoto\ntiti\n"
+ + "foo\nbar\ntoto\ntiti";
+
+ String file2 = "string\n";
+
+ File xooFile1 = new File(srcDir, "sample1.xoo");
+ FileUtils.write(xooFile1, file1, StandardCharsets.UTF_8);
+
+ File xooFile2 = new File(srcDir, "sample2.xoo");
+ FileUtils.write(xooFile2, file2, StandardCharsets.UTF_8);
+
+ AnalysisResult result = tester.newAnalysis()
+ .properties(builder
+ .put("sonar.sources", "src")
+ .put("sonar.cpd.xoo.minimumTokens", "10")
+ .put("sonar.verbose", "true")
+ .build())
+ .execute();
+
+ assertThat(result.inputFiles()).hasSize(2);
+
+ assertThat(logTester.logs()).contains("Not enough content in 'src/sample2.xoo' to have CPD blocks, it will not be part of the duplication detection");
+ assertThat(logTester.logs()).contains("CPD Executor 1 file had no CPD blocks");
+
+ }
+
+ @Test
+ public void testExclusions() throws IOException {
+ File srcDir = new File(baseDir, "src");
+ srcDir.mkdir();
+
+ String duplicatedStuff = "Sample xoo\ncontent\n"
+ + "foo\nbar\ntoto\ntiti\n"
+ + "foo\nbar\ntoto\ntiti\n"
+ + "bar\ntoto\ntiti\n"
+ + "foo\nbar\ntoto\ntiti";
+
+ File xooFile1 = new File(srcDir, "sample1.xoo");
+ FileUtils.write(xooFile1, duplicatedStuff);
+
+ File xooFile2 = new File(srcDir, "sample2.xoo");
+ FileUtils.write(xooFile2, duplicatedStuff);
+
+ AnalysisResult result = tester.newAnalysis()
+ .properties(builder
+ .put("sonar.sources", "src")
+ .put("sonar.cpd.xoo.minimumTokens", "10")
+ .put("sonar.cpd.exclusions", "src/sample1.xoo")
+ .build())
+ .execute();
+
+ assertThat(result.inputFiles()).hasSize(2);
+
+ InputFile inputFile1 = result.inputFile("src/sample1.xoo");
+ InputFile inputFile2 = result.inputFile("src/sample2.xoo");
+
+ List<ScannerReport.Duplication> duplicationGroupsFile1 = result.duplicationsFor(inputFile1);
+ assertThat(duplicationGroupsFile1).isEmpty();
+
+ List<ScannerReport.Duplication> duplicationGroupsFile2 = result.duplicationsFor(inputFile2);
+ assertThat(duplicationGroupsFile2).isEmpty();
+ }
+
+ @Test
+ public void cross_module_duplication() throws IOException {
+
+ String duplicatedStuff = "Sample xoo\ncontent\n"
+ + "foo\nbar\ntoto\ntiti\n"
+ + "foo\nbar\ntoto\ntiti\n"
+ + "bar\ntoto\ntiti\n"
+ + "foo\nbar\ntoto\ntiti";
+
+ File baseDir = temp.getRoot();
+ File baseDirModuleA = new File(baseDir, "moduleA");
+ File baseDirModuleB = new File(baseDir, "moduleB");
+ File srcDirA = new File(baseDirModuleA, "src");
+ srcDirA.mkdirs();
+ File srcDirB = new File(baseDirModuleB, "src");
+ srcDirB.mkdirs();
+
+ File xooFileA = new File(srcDirA, "sampleA.xoo");
+ FileUtils.write(xooFileA, duplicatedStuff, StandardCharsets.UTF_8);
+
+ File xooFileB = new File(srcDirB, "sampleB.xoo");
+ FileUtils.write(xooFileB, duplicatedStuff, StandardCharsets.UTF_8);
+
+ AnalysisResult result = tester.newAnalysis()
+ .properties(ImmutableMap.<String, String>builder()
+ .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
+ .put("sonar.projectKey", "com.foo.project")
+ .put("sonar.sources", "src")
+ .put("sonar.modules", "moduleA,moduleB")
+ .put("sonar.cpd.xoo.minimumTokens", "10")
+ .build())
+ .execute();
+
+ InputFile inputFile1 = result.inputFile("moduleA/src/sampleA.xoo");
+ InputFile inputFile2 = result.inputFile("moduleB/src/sampleB.xoo");
+
+ List<ScannerReport.Duplication> duplicationGroupsFile1 = result.duplicationsFor(inputFile1);
+ assertThat(duplicationGroupsFile1).isNotEmpty();
+
+ List<ScannerReport.Duplication> duplicationGroupsFile2 = result.duplicationsFor(inputFile2);
+ assertThat(duplicationGroupsFile2).isNotEmpty();
+ }
+
+ @Test
+ public void warn_user_for_outdated_inherited_scanner_side_exclusions_for_multi_module_project() throws IOException {
+
+ String duplicatedStuff = "Sample xoo\ncontent\n"
+ + "foo\nbar\ntoto\ntiti\n"
+ + "foo\nbar\ntoto\ntiti\n"
+ + "bar\ntoto\ntiti\n"
+ + "foo\nbar\ntoto\ntiti";
+
+ File baseDir = temp.getRoot();
+ File baseDirModuleA = new File(baseDir, "moduleA");
+ File baseDirModuleB = new File(baseDir, "moduleB");
+ File srcDirA = new File(baseDirModuleA, "src");
+ srcDirA.mkdirs();
+ File srcDirB = new File(baseDirModuleB, "src");
+ srcDirB.mkdirs();
+
+ File xooFileA = new File(srcDirA, "sampleA.xoo");
+ FileUtils.write(xooFileA, duplicatedStuff, StandardCharsets.UTF_8);
+
+ File xooFileB = new File(srcDirB, "sampleB.xoo");
+ FileUtils.write(xooFileB, duplicatedStuff, StandardCharsets.UTF_8);
+
+ AnalysisResult result = tester.newAnalysis()
+ .properties(ImmutableMap.<String, String>builder()
+ .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
+ .put("sonar.projectKey", "com.foo.project")
+ .put("sonar.sources", "src")
+ .put("sonar.modules", "moduleA,moduleB")
+ .put("sonar.cpd.xoo.minimumTokens", "10")
+ .put("sonar.cpd.exclusions", "src/sampleA.xoo")
+ .build())
+ .execute();
+
+ InputFile inputFile1 = result.inputFile("moduleA/src/sampleA.xoo");
+ InputFile inputFile2 = result.inputFile("moduleB/src/sampleB.xoo");
+
+ List<ScannerReport.Duplication> duplicationGroupsFile1 = result.duplicationsFor(inputFile1);
+ assertThat(duplicationGroupsFile1).isEmpty();
+
+ List<ScannerReport.Duplication> duplicationGroupsFile2 = result.duplicationsFor(inputFile2);
+ assertThat(duplicationGroupsFile2).isEmpty();
+
+ assertThat(logTester.logs(LoggerLevel.WARN)).contains("Specifying module-relative paths at project level in the property 'sonar.cpd.exclusions' is deprecated. " +
+ "To continue matching files like 'moduleA/src/sampleA.xoo', update this property so that patterns refer to project-relative paths.");
+ }
+
+ @Test
+ public void module_level_exclusions_override_parent_for_multi_module_project() throws IOException {
+
+ String duplicatedStuff = "Sample xoo\ncontent\n"
+ + "foo\nbar\ntoto\ntiti\n"
+ + "foo\nbar\ntoto\ntiti\n"
+ + "bar\ntoto\ntiti\n"
+ + "foo\nbar\ntoto\ntiti";
+
+ File baseDir = temp.getRoot();
+ File baseDirModuleA = new File(baseDir, "moduleA");
+ File baseDirModuleB = new File(baseDir, "moduleB");
+ File srcDirA = new File(baseDirModuleA, "src");
+ srcDirA.mkdirs();
+ File srcDirB = new File(baseDirModuleB, "src");
+ srcDirB.mkdirs();
+
+ File xooFileA = new File(srcDirA, "sampleA.xoo");
+ FileUtils.write(xooFileA, duplicatedStuff, StandardCharsets.UTF_8);
+
+ File xooFileB = new File(srcDirB, "sampleB.xoo");
+ FileUtils.write(xooFileB, duplicatedStuff, StandardCharsets.UTF_8);
+
+ AnalysisResult result = tester.newAnalysis()
+ .properties(ImmutableMap.<String, String>builder()
+ .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
+ .put("sonar.projectKey", "com.foo.project")
+ .put("sonar.sources", "src")
+ .put("sonar.modules", "moduleA,moduleB")
+ .put("sonar.cpd.xoo.minimumTokens", "10")
+ .put("sonar.cpd.exclusions", "**/*")
+ .put("moduleA.sonar.cpd.exclusions", "**/*.nothing")
+ .put("moduleB.sonar.cpd.exclusions", "**/*.nothing")
+ .build())
+ .execute();
+
+ InputFile inputFile1 = result.inputFile("moduleA/src/sampleA.xoo");
+ InputFile inputFile2 = result.inputFile("moduleB/src/sampleB.xoo");
+
+ List<ScannerReport.Duplication> duplicationGroupsFile1 = result.duplicationsFor(inputFile1);
+ assertThat(duplicationGroupsFile1).isNotEmpty();
+
+ List<ScannerReport.Duplication> duplicationGroupsFile2 = result.duplicationsFor(inputFile2);
+ assertThat(duplicationGroupsFile2).isNotEmpty();
+ }
+
+ @Test
+ public void enableCrossProjectDuplication() throws IOException {
+ File srcDir = new File(baseDir, "src");
+ srcDir.mkdir();
+
+ String duplicatedStuff = "Sample xoo\ncontent\nfoo\nbar\ntoto\ntiti\nfoo";
+
+ File xooFile1 = new File(srcDir, "sample1.xoo");
+ FileUtils.write(xooFile1, duplicatedStuff);
+
+ AnalysisResult result = tester.newAnalysis()
+ .properties(builder
+ .put("sonar.sources", "src")
+ .put("sonar.cpd.xoo.minimumTokens", "1")
+ .put("sonar.cpd.xoo.minimumLines", "5")
+ .put("sonar.verbose", "true")
+ .put("sonar.cpd.cross_project", "true")
+ .build())
+ .execute();
+
+ InputFile inputFile1 = result.inputFile("src/sample1.xoo");
+
+ List<ScannerReport.CpdTextBlock> duplicationBlocks = result.duplicationBlocksFor(inputFile1);
+ assertThat(duplicationBlocks).hasSize(3);
+ assertThat(duplicationBlocks.get(0).getStartLine()).isOne();
+ assertThat(duplicationBlocks.get(0).getEndLine()).isEqualTo(5);
+ assertThat(duplicationBlocks.get(0).getStartTokenIndex()).isOne();
+ assertThat(duplicationBlocks.get(0).getEndTokenIndex()).isEqualTo(6);
+ assertThat(duplicationBlocks.get(0).getHash()).isNotEmpty();
+
+ assertThat(duplicationBlocks.get(1).getStartLine()).isEqualTo(2);
+ assertThat(duplicationBlocks.get(1).getEndLine()).isEqualTo(6);
+ assertThat(duplicationBlocks.get(1).getStartTokenIndex()).isEqualTo(3);
+ assertThat(duplicationBlocks.get(1).getEndTokenIndex()).isEqualTo(7);
+ assertThat(duplicationBlocks.get(0).getHash()).isNotEmpty();
+
+ assertThat(duplicationBlocks.get(2).getStartLine()).isEqualTo(3);
+ assertThat(duplicationBlocks.get(2).getEndLine()).isEqualTo(7);
+ assertThat(duplicationBlocks.get(2).getStartTokenIndex()).isEqualTo(4);
+ assertThat(duplicationBlocks.get(2).getEndTokenIndex()).isEqualTo(8);
+ assertThat(duplicationBlocks.get(0).getHash()).isNotEmpty();
+ }
+
+ @Test
+ public void testIntraFileDuplications() throws IOException {
+ File srcDir = new File(baseDir, "src");
+ srcDir.mkdir();
+
+ String content = "Sample xoo\ncontent\nfoo\nbar\nSample xoo\ncontent\n";
+
+ File xooFile = new File(srcDir, "sample.xoo");
+ FileUtils.write(xooFile, content);
+
+ AnalysisResult result = tester.newAnalysis()
+ .properties(builder
+ .put("sonar.sources", "src")
+ .put("sonar.cpd.xoo.minimumTokens", "2")
+ .put("sonar.cpd.xoo.minimumLines", "2")
+ .put("sonar.verbose", "true")
+ .build())
+ .execute();
+
+ InputFile inputFile = result.inputFile("src/sample.xoo");
+ // One clone group
+ List<ScannerReport.Duplication> duplicationGroups = result.duplicationsFor(inputFile);
+ assertThat(duplicationGroups).hasSize(1);
+
+ ScannerReport.Duplication cloneGroup = duplicationGroups.get(0);
+ assertThat(cloneGroup.getOriginPosition().getStartLine()).isOne();
+ assertThat(cloneGroup.getOriginPosition().getEndLine()).isEqualTo(2);
+ assertThat(cloneGroup.getDuplicateList()).hasSize(1);
+ assertThat(cloneGroup.getDuplicate(0).getRange().getStartLine()).isEqualTo(5);
+ assertThat(cloneGroup.getDuplicate(0).getRange().getEndLine()).isEqualTo(6);
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 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.mediumtest.fs;
+
+import com.google.common.collect.ImmutableMap;
+import java.io.File;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.LinkOption;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Random;
+import java.util.stream.Collectors;
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.lang.StringUtils;
+import org.apache.commons.lang.SystemUtils;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.sonar.api.CoreProperties;
+import org.sonar.api.SonarEdition;
+import org.sonar.api.batch.fs.InputFile;
+import org.sonar.api.batch.fs.internal.DefaultInputFile;
+import org.sonar.api.utils.MessageException;
+import org.sonar.api.utils.PathUtils;
+import org.sonar.api.utils.System2;
+import org.sonar.api.utils.log.LogTester;
+import org.sonar.api.utils.log.LoggerLevel;
+import org.sonar.scanner.mediumtest.AnalysisResult;
+import org.sonar.scanner.mediumtest.ScannerMediumTester;
+import org.sonar.scanner.mediumtest.ScannerMediumTester.AnalysisBuilder;
+import org.sonar.xoo.XooPlugin;
+import org.sonar.xoo.global.DeprecatedGlobalSensor;
+import org.sonar.xoo.global.GlobalProjectSensor;
+import org.sonar.xoo.rule.XooRulesDefinition;
+
+import static java.lang.String.format;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.assertj.core.api.Assertions.tuple;
+import static org.junit.Assume.assumeFalse;
+import static org.junit.Assume.assumeTrue;
+
+public class FileSystemMediumIT {
+
+ @Rule
+ public TemporaryFolder temp = new TemporaryFolder();
+
+ @Rule
+ public LogTester logTester = new LogTester();
+
+ @Rule
+ public ScannerMediumTester tester = new ScannerMediumTester()
+ .setEdition(SonarEdition.COMMUNITY)
+ .registerPlugin("xoo", new XooPlugin())
+ .addDefaultQProfile("xoo", "Sonar Way")
+ .addDefaultQProfile("xoo2", "Sonar Way");
+
+ private File baseDir;
+ private ImmutableMap.Builder<String, String> builder;
+
+ @Before
+ public void prepare() throws IOException {
+ baseDir = temp.newFolder().getCanonicalFile();
+
+ builder = ImmutableMap.<String, String>builder()
+ .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
+ .put("sonar.projectKey", "com.foo.project");
+ }
+
+ @Test
+ public void scan_project_without_name() throws IOException {
+ File srcDir = new File(baseDir, "src");
+ srcDir.mkdir();
+
+ writeFile(srcDir, "sample.xoo", "Sample xoo\ncontent");
+
+ AnalysisResult result = tester.newAnalysis()
+ .properties(builder
+ .put("sonar.sources", "src")
+ .build())
+ .execute();
+
+ int ref = result.getReportReader().readMetadata().getRootComponentRef();
+ assertThat(result.getReportReader().readComponent(ref).getName()).isEmpty();
+ assertThat(result.inputFiles()).hasSize(1);
+
+ DefaultInputFile file = (DefaultInputFile) result.inputFile("src/sample.xoo");
+ assertThat(file.type()).isEqualTo(InputFile.Type.MAIN);
+ assertThat(file.relativePath()).isEqualTo("src/sample.xoo");
+ assertThat(file.language()).isEqualTo("xoo");
+
+ // file was published, since language matched xoo
+ assertThat(file.isPublished()).isTrue();
+ assertThat(result.getReportComponent(file.scannerId())).isNotNull();
+ }
+
+ @Test
+ public void log_branch_name_and_type() {
+ builder.put("sonar.branch.name", "my-branch");
+ File srcDir = new File(baseDir, "src");
+ assertThat(srcDir.mkdir()).isTrue();
+
+ // Using sonar.branch.name when the branch plugin is not installed is an error.
+ assertThatThrownBy(() -> tester.newAnalysis()
+ .properties(builder
+ .put("sonar.sources", "src")
+ .build())
+ .execute())
+ .isInstanceOf(MessageException.class);
+ }
+
+ @Test
+ public void only_generate_metadata_if_needed() throws IOException {
+ File srcDir = new File(baseDir, "src");
+ srcDir.mkdir();
+
+ writeFile(srcDir, "sample.xoo", "Sample xoo\ncontent");
+ writeFile(srcDir, "sample.java", "Sample xoo\ncontent");
+
+ logTester.setLevel(LoggerLevel.DEBUG);
+
+ tester.newAnalysis()
+ .properties(builder
+ .put("sonar.sources", "src")
+ .build())
+ .execute();
+
+ assertThat(logTester.logs()).contains("2 files indexed");
+ assertThat(logTester.logs()).contains("'src/sample.xoo' generated metadata with charset 'UTF-8'");
+ assertThat(String.join("\n", logTester.logs())).doesNotContain("'src/sample.java' generated metadata");
+ }
+
+ @Test
+ public void preload_file_metadata() throws IOException {
+ builder.put("sonar.preloadFileMetadata", "true");
+
+ File srcDir = new File(baseDir, "src");
+ srcDir.mkdir();
+
+ writeFile(srcDir, "sample.xoo", "Sample xoo\ncontent");
+ writeFile(srcDir, "sample.java", "Sample xoo\ncontent");
+
+ logTester.setLevel(LoggerLevel.DEBUG);
+
+ tester.newAnalysis()
+ .properties(builder
+ .put("sonar.sources", "src")
+ .build())
+ .execute();
+
+ assertThat(logTester.logs()).contains("2 files indexed");
+ assertThat(logTester.logs()).contains("'src/sample.xoo' generated metadata with charset 'UTF-8'");
+ assertThat(logTester.logs()).contains("'src/sample.java' generated metadata with charset 'UTF-8'");
+ }
+
+ @Test
+ public void dont_publish_files_without_detected_language() throws IOException {
+ Path mainDir = baseDir.toPath().resolve("src").resolve("main");
+ Files.createDirectories(mainDir);
+
+ Path testDir = baseDir.toPath().resolve("src").resolve("test");
+ Files.createDirectories(testDir);
+
+ writeFile(testDir.toFile(), "sample.java", "Sample xoo\ncontent");
+ writeFile(mainDir.toFile(), "sample.xoo", "Sample xoo\ncontent");
+ writeFile(mainDir.toFile(), "sample.java", "Sample xoo\ncontent");
+
+ logTester.setLevel(LoggerLevel.DEBUG);
+
+ AnalysisResult result = tester.newAnalysis()
+ .properties(builder
+ .put("sonar.sources", "src/main")
+ .put("sonar.tests", "src/test")
+ .build())
+ .execute();
+
+ assertThat(logTester.logs()).containsAnyOf("'src/main/sample.java' indexed with no language", "'src\\main\\sample.java' indexed with no language");
+ assertThat(logTester.logs()).contains("3 files indexed");
+ assertThat(logTester.logs()).contains("'src/main/sample.xoo' generated metadata with charset 'UTF-8'");
+ assertThat(logTester.logs()).doesNotContain("'src/main/sample.java' generated metadata", "'src\\main\\sample.java' generated metadata");
+ assertThat(logTester.logs()).doesNotContain("'src/test/sample.java' generated metadata", "'src\\test\\sample.java' generated metadata");
+ DefaultInputFile javaInputFile = (DefaultInputFile) result.inputFile("src/main/sample.java");
+
+ assertThatThrownBy(() -> result.getReportComponent(javaInputFile))
+ .isInstanceOf(IllegalStateException.class)
+ .hasMessageContaining("Unable to find report for component");
+ }
+
+ @Test
+ public void create_issue_on_any_file() throws IOException {
+ tester
+ .addRules(new XooRulesDefinition())
+ .addActiveRule("xoo", "OneIssuePerUnknownFile", null, "OneIssuePerUnknownFile", "MAJOR", null, "xoo");
+
+ File srcDir = new File(baseDir, "src");
+ srcDir.mkdir();
+
+ writeFile(srcDir, "sample.unknown", "Sample xoo\ncontent");
+
+ logTester.setLevel(LoggerLevel.DEBUG);
+
+ AnalysisResult result = tester.newAnalysis()
+ .properties(builder
+ .put("sonar.sources", "src")
+ .build())
+ .execute();
+
+ assertThat(logTester.logs()).contains("1 file indexed");
+ assertThat(logTester.logs()).contains("'src" + File.separator + "sample.unknown' indexed with no language");
+ assertThat(logTester.logs()).contains("'src/sample.unknown' generated metadata with charset 'UTF-8'");
+ DefaultInputFile inputFile = (DefaultInputFile) result.inputFile("src/sample.unknown");
+ assertThat(result.getReportComponent(inputFile)).isNotNull();
+ }
+
+ @Test
+ public void lazyIssueExclusion() throws IOException {
+ tester
+ .addRules(new XooRulesDefinition())
+ .addActiveRule("xoo", "OneIssuePerFile", null, "OneIssuePerFile", "MAJOR", null, "xoo");
+
+ builder.put("sonar.issue.ignore.allfile", "1")
+ .put("sonar.issue.ignore.allfile.1.fileRegexp", "pattern");
+ File srcDir = new File(baseDir, "src");
+ srcDir.mkdir();
+
+ writeFile(srcDir, "sample.xoo", "Sample xoo\ncontent");
+
+ File unknownFile = new File(srcDir, "myfile.binary");
+ byte[] b = new byte[512];
+ new Random().nextBytes(b);
+ FileUtils.writeByteArrayToFile(unknownFile, b);
+
+ logTester.setLevel(LoggerLevel.DEBUG);
+
+ tester.newAnalysis()
+ .properties(builder
+ .put("sonar.sources", "src")
+ .build())
+ .execute();
+
+ assertThat(logTester.logs()).containsOnlyOnce("'src" + File.separator + "myfile.binary' indexed with no language");
+ assertThat(logTester.logs()).doesNotContain("Evaluate issue exclusions for 'src/myfile.binary'");
+ assertThat(logTester.logs()).containsOnlyOnce("Evaluate issue exclusions for 'src/sample.xoo'");
+ }
+
+ @Test
+ public void preloadIssueExclusions() throws IOException {
+ builder.put("sonar.issue.ignore.allfile", "1")
+ .put("sonar.issue.ignore.allfile.1.fileRegexp", "pattern")
+ .put("sonar.preloadFileMetadata", "true");
+ File srcDir = new File(baseDir, "src");
+ srcDir.mkdir();
+
+ writeFile(srcDir, "sample.xoo", "Sample xoo\npattern");
+ writeFile(srcDir, "myfile.binary", "some text");
+
+ logTester.setLevel(LoggerLevel.DEBUG);
+
+ tester.newAnalysis()
+ .properties(builder
+ .put("sonar.sources", "src")
+ .build())
+ .execute();
+
+ assertThat(logTester.logs()).containsSequence("Evaluate issue exclusions for 'src/sample.xoo'",
+ " - Exclusion pattern 'pattern': all issues in this file will be ignored.");
+ }
+
+ @Test
+ public void publishFilesWithIssues() throws IOException {
+ tester
+ .addRules(new XooRulesDefinition())
+ .addActiveRule("xoo", "OneIssueOnDirPerFile", null, "OneIssueOnDirPerFile", "MAJOR", null, "xoo");
+
+ File srcDir = new File(baseDir, "src");
+ srcDir.mkdir();
+
+ writeFile(srcDir, "sample.xoo", "Sample xoo\ncontent");
+
+ AnalysisResult result = tester.newAnalysis()
+ .properties(builder
+ .put("sonar.sources", "src")
+ .build())
+ .execute();
+
+ DefaultInputFile file = (DefaultInputFile) result.inputFile("src/sample.xoo");
+
+ assertThat(file.isPublished()).isTrue();
+ assertThat(result.getReportComponent(file)).isNotNull();
+ }
+
+ @Test
+ public void scanProjectWithSourceDir() throws IOException {
+ File srcDir = new File(baseDir, "src");
+ srcDir.mkdir();
+
+ writeFile(srcDir, "sample.xoo", "Sample xoo\ncontent");
+
+ AnalysisResult result = tester.newAnalysis()
+ .properties(builder
+ .put("sonar.sources", "src")
+ .build())
+ .execute();
+
+ assertThat(result.inputFiles()).hasSize(1);
+ assertThat(result.inputFile("src/sample.xoo").type()).isEqualTo(InputFile.Type.MAIN);
+ assertThat(result.inputFile("src/sample.xoo").relativePath()).isEqualTo("src/sample.xoo");
+ }
+
+ @Test
+ public void scanBigProject() throws IOException {
+ File srcDir = new File(baseDir, "src");
+ srcDir.mkdir();
+
+ int nbFiles = 100;
+ int ruleCount = 100000;
+ for (int nb = 1; nb <= nbFiles; nb++) {
+ File xooFile = new File(srcDir, "sample" + nb + ".xoo");
+ FileUtils.write(xooFile, StringUtils.repeat(StringUtils.repeat("a", 100) + "\n", ruleCount / 1000));
+ }
+
+ AnalysisResult result = tester.newAnalysis()
+ .properties(builder
+ .put("sonar.sources", "src")
+ .build())
+ .execute();
+
+ assertThat(result.inputFiles()).hasSize(100);
+ }
+
+ @Test
+ public void scanProjectWithTestDir() throws IOException {
+ File test = new File(baseDir, "test");
+ test.mkdir();
+
+ writeFile(test, "sampleTest.xoo", "Sample test xoo\ncontent");
+
+ AnalysisResult result = tester.newAnalysis()
+ .properties(builder
+ .put("sonar.sources", "")
+ .put("sonar.tests", "test")
+ .build())
+ .execute();
+
+ assertThat(result.inputFiles()).hasSize(1);
+ assertThat(result.inputFile("test/sampleTest.xoo").type()).isEqualTo(InputFile.Type.TEST);
+ }
+
+ /**
+ * SONAR-5419
+ */
+ @Test
+ public void scanProjectWithMixedSourcesAndTests() throws IOException {
+ File srcDir = new File(baseDir, "src");
+ srcDir.mkdir();
+
+ writeFile(srcDir, "sample.xoo", "Sample xoo\ncontent");
+ writeFile(baseDir, "another.xoo", "Sample xoo 2\ncontent");
+
+ File testDir = new File(baseDir, "test");
+ testDir.mkdir();
+
+ writeFile(baseDir, "sampleTest2.xoo", "Sample test xoo\ncontent");
+ writeFile(testDir, "sampleTest.xoo", "Sample test xoo 2\ncontent");
+
+ AnalysisResult result = tester.newAnalysis()
+ .properties(builder
+ .put("sonar.sources", "src,another.xoo")
+ .put("sonar.tests", "test,sampleTest2.xoo")
+ .build())
+ .execute();
+
+ assertThat(result.inputFiles()).hasSize(4);
+ }
+
+ @Test
+ public void fileInclusionsExclusions() throws IOException {
+ File srcDir = new File(baseDir, "src");
+ srcDir.mkdir();
+
+ writeFile(srcDir, "sample.xoo", "Sample xoo\ncontent");
+ writeFile(baseDir, "another.xoo", "Sample xoo 2\ncontent");
+
+ File testDir = new File(baseDir, "test");
+ testDir.mkdir();
+
+ writeFile(baseDir, "sampleTest2.xoo", "Sample test xoo\ncontent");
+ writeFile(testDir, "sampleTest.xoo", "Sample test xoo 2\ncontent");
+
+ AnalysisResult result = tester.newAnalysis()
+ .properties(builder
+ .put("sonar.sources", "src,another.xoo")
+ .put("sonar.tests", "test,sampleTest2.xoo")
+ .put("sonar.inclusions", "src/**")
+ .put("sonar.exclusions", "**/another.*")
+ .put("sonar.test.inclusions", "**/sampleTest*.*")
+ .put("sonar.test.exclusions", "**/sampleTest2.xoo")
+ .build())
+ .execute();
+
+ assertThat(result.inputFiles()).hasSize(2);
+ }
+
+ @Test
+ public void ignoreFilesWhenGreaterThanDefinedSize() throws IOException {
+ File srcDir = new File(baseDir, "src");
+ srcDir.mkdir();
+
+ File fileGreaterThanLimit = writeFile(srcDir, "sample.xoo", 1024 * 1024 + 1);
+ writeFile(srcDir, "another.xoo", "Sample xoo 2\ncontent");
+
+ AnalysisResult result = tester.newAnalysis()
+ .properties(builder
+ // set limit to 1MB
+ .put("sonar.filesize.limit", "1")
+ .build())
+ .execute();
+
+ assertThat(result.inputFiles()).hasSize(1);
+ assertThat(logTester.logs())
+ .contains(format("File '%s' is bigger than 1MB and as consequence is removed from the analysis scope.", fileGreaterThanLimit.getAbsolutePath()));
+ }
+
+ @Test
+ public void analysisFailsSymbolicLinkWithoutTargetIsInTheFolder() throws IOException {
+ assumeFalse(SystemUtils.IS_OS_WINDOWS);
+ File srcDir = new File(baseDir, "src");
+ srcDir.mkdir();
+
+ File target = writeFile(srcDir, "target.xoo", 1024 * 1024 + 1);
+ Path link = Paths.get(srcDir.getPath(), "target_link.xoo");
+ Files.createSymbolicLink(link, target.toPath());
+ Files.delete(target.toPath());
+
+ AnalysisBuilder analysis = tester.newAnalysis()
+ .properties(builder.build());
+
+ assertThatThrownBy(analysis::execute)
+ .isExactlyInstanceOf(IllegalStateException.class)
+ .hasMessageEndingWith(format("Unable to read file %s", link));
+ }
+
+ @Test
+ public void test_inclusions_on_multi_modules() throws IOException {
+ File baseDir = temp.getRoot();
+ File baseDirModuleA = new File(baseDir, "moduleA");
+ File baseDirModuleB = new File(baseDir, "moduleB");
+ File srcDirA = new File(baseDirModuleA, "tests");
+ srcDirA.mkdirs();
+ File srcDirB = new File(baseDirModuleB, "tests");
+ srcDirB.mkdirs();
+
+ writeFile(srcDirA, "sampleTestA.xoo", "Sample xoo\ncontent");
+ writeFile(srcDirB, "sampleTestB.xoo", "Sample xoo\ncontent");
+
+ final ImmutableMap.Builder<String, String> builder = ImmutableMap.<String, String>builder()
+ .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
+ .put("sonar.projectKey", "com.foo.project")
+ .put("sonar.sources", "")
+ .put("sonar.tests", "tests")
+ .put("sonar.modules", "moduleA,moduleB");
+
+ AnalysisResult result = tester.newAnalysis()
+ .properties(builder.build())
+ .execute();
+
+ assertThat(result.inputFiles()).hasSize(2);
+
+ InputFile fileA = result.inputFile("moduleA/tests/sampleTestA.xoo");
+ assertThat(fileA).isNotNull();
+
+ InputFile fileB = result.inputFile("moduleB/tests/sampleTestB.xoo");
+ assertThat(fileB).isNotNull();
+
+ result = tester.newAnalysis()
+ .properties(builder
+ .put("sonar.test.inclusions", "moduleA/tests/**")
+ .build())
+ .execute();
+
+ assertThat(result.inputFiles()).hasSize(1);
+
+ fileA = result.inputFile("moduleA/tests/sampleTestA.xoo");
+ assertThat(fileA).isNotNull();
+
+ fileB = result.inputFile("moduleB/tests/sampleTestB.xoo");
+ assertThat(fileB).isNull();
+ }
+
+ @Test
+ public void test_module_level_inclusions_override_parent_on_multi_modules() throws IOException {
+ File baseDir = temp.getRoot();
+ File baseDirModuleA = new File(baseDir, "moduleA");
+ File baseDirModuleB = new File(baseDir, "moduleB");
+ File srcDirA = new File(baseDirModuleA, "src");
+ srcDirA.mkdirs();
+ File srcDirB = new File(baseDirModuleB, "src");
+ srcDirB.mkdirs();
+
+ writeFile(srcDirA, "sampleA.xoo", "Sample xoo\ncontent");
+ writeFile(srcDirB, "sampleB.xoo", "Sample xoo\ncontent");
+
+ final ImmutableMap.Builder<String, String> builder = ImmutableMap.<String, String>builder()
+ .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
+ .put("sonar.projectKey", "com.foo.project")
+ .put("sonar.sources", "src")
+ .put("sonar.modules", "moduleA,moduleB")
+ .put("sonar.inclusions", "**/*.php");
+
+ AnalysisResult result = tester.newAnalysis()
+ .properties(builder.build())
+ .execute();
+
+ assertThat(result.inputFiles()).isEmpty();
+
+ result = tester.newAnalysis()
+ .properties(builder
+ .put("moduleA.sonar.inclusions", "**/*.xoo")
+ .build())
+ .execute();
+
+ assertThat(result.inputFiles()).hasSize(1);
+
+ InputFile fileA = result.inputFile("moduleA/src/sampleA.xoo");
+ assertThat(fileA).isNotNull();
+ }
+
+ @Test
+ public void warn_user_for_outdated_scanner_side_inherited_exclusions_for_multi_module_project() throws IOException {
+ File baseDir = temp.getRoot();
+ File baseDirModuleA = new File(baseDir, "moduleA");
+ File baseDirModuleB = new File(baseDir, "moduleB");
+ File srcDirA = new File(baseDirModuleA, "src");
+ srcDirA.mkdirs();
+ File srcDirB = new File(baseDirModuleB, "src");
+ srcDirB.mkdirs();
+
+ writeFile(srcDirA, "sample.xoo", "Sample xoo\ncontent");
+ writeFile(srcDirB, "sample.xoo", "Sample xoo\ncontent");
+
+ AnalysisResult result = tester.newAnalysis()
+ .properties(ImmutableMap.<String, String>builder()
+ .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
+ .put("sonar.projectKey", "com.foo.project")
+ .put("sonar.sources", "src")
+ .put("sonar.modules", "moduleA,moduleB")
+ .put("sonar.exclusions", "src/sample.xoo")
+ .build())
+ .execute();
+
+ InputFile fileA = result.inputFile("moduleA/src/sample.xoo");
+ assertThat(fileA).isNull();
+
+ InputFile fileB = result.inputFile("moduleB/src/sample.xoo");
+ assertThat(fileB).isNull();
+
+ assertThat(logTester.logs(LoggerLevel.WARN))
+ .contains("Specifying module-relative paths at project level in the property 'sonar.exclusions' is deprecated. " +
+ "To continue matching files like 'moduleA/src/sample.xoo', update this property so that patterns refer to project-relative paths.");
+ }
+
+ @Test
+ public void support_global_server_side_exclusions_for_multi_module_project() throws IOException {
+ File baseDir = temp.getRoot();
+ File baseDirModuleA = new File(baseDir, "moduleA");
+ File baseDirModuleB = new File(baseDir, "moduleB");
+ File srcDirA = new File(baseDirModuleA, "src");
+ srcDirA.mkdirs();
+ File srcDirB = new File(baseDirModuleB, "src");
+ srcDirB.mkdirs();
+
+ writeFile(srcDirA, "sample.xoo", "Sample xoo\ncontent");
+ writeFile(srcDirB, "sample.xoo", "Sample xoo\ncontent");
+
+ tester.addGlobalServerSettings(CoreProperties.PROJECT_EXCLUSIONS_PROPERTY, "**/*.xoo");
+
+ AnalysisResult result = tester.newAnalysis()
+ .properties(ImmutableMap.<String, String>builder()
+ .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
+ .put("sonar.projectKey", "com.foo.project")
+ .put("sonar.sources", "src")
+ .put("sonar.modules", "moduleA,moduleB")
+ .build())
+ .execute();
+
+ InputFile fileA = result.inputFile("moduleA/src/sample.xoo");
+ assertThat(fileA).isNull();
+
+ InputFile fileB = result.inputFile("moduleB/src/sample.xoo");
+ assertThat(fileB).isNull();
+ }
+
+ @Test
+ public void support_global_server_side_global_exclusions_for_multi_module_project() throws IOException {
+ File baseDir = temp.getRoot();
+ File baseDirModuleA = new File(baseDir, "moduleA");
+ File baseDirModuleB = new File(baseDir, "moduleB");
+ File srcDirA = new File(baseDirModuleA, "src");
+ srcDirA.mkdirs();
+ File srcDirB = new File(baseDirModuleB, "src");
+ srcDirB.mkdirs();
+
+ writeFile(srcDirA, "sample.xoo", "Sample xoo\ncontent");
+ writeFile(srcDirB, "sample.xoo", "Sample xoo\ncontent");
+
+ tester.addGlobalServerSettings(CoreProperties.GLOBAL_EXCLUSIONS_PROPERTY, "**/*.xoo");
+
+ AnalysisResult result = tester.newAnalysis()
+ .properties(ImmutableMap.<String, String>builder()
+ .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
+ .put("sonar.projectKey", "com.foo.project")
+ .put("sonar.sources", "src")
+ .put("sonar.modules", "moduleA,moduleB")
+ .build())
+ .execute();
+
+ InputFile fileA = result.inputFile("moduleA/src/sample.xoo");
+ assertThat(fileA).isNull();
+
+ InputFile fileB = result.inputFile("moduleB/src/sample.xoo");
+ assertThat(fileB).isNull();
+ }
+
+ @Test
+ public void warn_user_for_outdated_server_side_inherited_exclusions_for_multi_module_project() throws IOException {
+ File baseDir = temp.getRoot();
+ File baseDirModuleA = new File(baseDir, "moduleA");
+ File baseDirModuleB = new File(baseDir, "moduleB");
+ File srcDirA = new File(baseDirModuleA, "src");
+ srcDirA.mkdirs();
+ File srcDirB = new File(baseDirModuleB, "src");
+ srcDirB.mkdirs();
+
+ writeFile(srcDirA, "sample.xoo", "Sample xoo\ncontent");
+ writeFile(srcDirB, "sample.xoo", "Sample xoo\ncontent");
+
+ tester.addProjectServerSettings("sonar.exclusions", "src/sample.xoo");
+
+ AnalysisResult result = tester.newAnalysis()
+ .properties(ImmutableMap.<String, String>builder()
+ .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
+ .put("sonar.projectKey", "com.foo.project")
+ .put("sonar.sources", "src")
+ .put("sonar.modules", "moduleA,moduleB")
+ .build())
+ .execute();
+
+ InputFile fileA = result.inputFile("moduleA/src/sample.xoo");
+ assertThat(fileA).isNull();
+
+ InputFile fileB = result.inputFile("moduleB/src/sample.xoo");
+ assertThat(fileB).isNull();
+
+ assertThat(logTester.logs(LoggerLevel.WARN))
+ .contains("Specifying module-relative paths at project level in the property 'sonar.exclusions' is deprecated. " +
+ "To continue matching files like 'moduleA/src/sample.xoo', update this property so that patterns refer to project-relative paths.");
+ }
+
+ @Test
+ public void failForDuplicateInputFile() throws IOException {
+ File srcDir = new File(baseDir, "src");
+ srcDir.mkdir();
+
+ writeFile(srcDir, "sample.xoo", "Sample xoo\ncontent");
+
+ assertThatThrownBy(() -> tester.newAnalysis()
+ .properties(builder
+ .put("sonar.sources", "src,src/sample.xoo")
+ .build())
+ .execute())
+ .isInstanceOf(MessageException.class)
+ .hasMessage("File src/sample.xoo can't be indexed twice. Please check that inclusion/exclusion patterns produce disjoint sets for main and test files");
+ }
+
+ // SONAR-9574
+ @Test
+ public void failForDuplicateInputFileInDifferentModules() throws IOException {
+ File srcDir = new File(baseDir, "module1/src");
+ srcDir.mkdir();
+
+ writeFile(srcDir, "sample.xoo", "Sample xoo\ncontent");
+
+ assertThatThrownBy(() -> tester.newAnalysis()
+ .properties(builder
+ .put("sonar.sources", "module1/src")
+ .put("sonar.modules", "module1")
+ .put("module1.sonar.sources", "src")
+ .build())
+ .execute())
+ .isInstanceOf(MessageException.class)
+ .hasMessage("File module1/src/sample.xoo can't be indexed twice. Please check that inclusion/exclusion patterns produce disjoint sets for main and test files");
+ }
+
+ // SONAR-5330
+ @Test
+ public void scanProjectWithSourceSymlink() {
+ assumeTrue(!System2.INSTANCE.isOsWindows());
+ File projectDir = new File("test-resources/mediumtest/xoo/sample-with-symlink");
+ AnalysisResult result = tester
+ .newAnalysis(new File(projectDir, "sonar-project.properties"))
+ .property("sonar.exclusions", "**/*.xoo.measures,**/*.xoo.scm")
+ .property("sonar.test.exclusions", "**/*.xoo.measures,**/*.xoo.scm")
+ .property("sonar.scm.exclusions.disabled", "true")
+ .execute();
+
+ assertThat(result.inputFiles()).hasSize(3);
+ // check that symlink was not resolved to target
+ assertThat(result.inputFiles()).extractingResultOf("path").toString().startsWith(projectDir.toString());
+ }
+
+ // SONAR-6719
+ @Test
+ public void scanProjectWithWrongCase() {
+ // To please the quality gate, don't use assumeTrue, or the test will be reported as skipped
+ File projectDir = new File("test-resources/mediumtest/xoo/sample");
+ AnalysisBuilder analysis = tester
+ .newAnalysis(new File(projectDir, "sonar-project.properties"))
+ .property("sonar.sources", "XOURCES")
+ .property("sonar.tests", "TESTX")
+ .property("sonar.scm.exclusions.disabled", "true");
+
+ if (System2.INSTANCE.isOsWindows()) { // Windows is file path case-insensitive
+ AnalysisResult result = analysis.execute();
+
+ assertThat(result.inputFiles()).hasSize(8);
+ assertThat(result.inputFiles()).extractingResultOf("relativePath").containsOnly(
+ "testx/ClassOneTest.xoo.measures",
+ "xources/hello/helloscala.xoo.measures",
+ "xources/hello/HelloJava.xoo.measures",
+ "testx/ClassOneTest.xoo",
+ "xources/hello/HelloJava.xoo.scm",
+ "xources/hello/helloscala.xoo",
+ "testx/ClassOneTest.xoo.scm",
+ "xources/hello/HelloJava.xoo");
+ } else if (System2.INSTANCE.isOsMac()) {
+ AnalysisResult result = analysis.execute();
+
+ assertThat(result.inputFiles()).hasSize(8);
+ assertThat(result.inputFiles()).extractingResultOf("relativePath").containsOnly(
+ "TESTX/ClassOneTest.xoo.measures",
+ "XOURCES/hello/helloscala.xoo.measures",
+ "XOURCES/hello/HelloJava.xoo.measures",
+ "TESTX/ClassOneTest.xoo",
+ "XOURCES/hello/HelloJava.xoo.scm",
+ "XOURCES/hello/helloscala.xoo",
+ "TESTX/ClassOneTest.xoo.scm",
+ "XOURCES/hello/HelloJava.xoo");
+ } else {
+ assertThatThrownBy(() -> analysis.execute())
+ .isInstanceOf(MessageException.class)
+ .hasMessageContaining("The folder 'TESTX' does not exist for 'sample'");
+ }
+ }
+
+ @Test
+ public void indexAnyFile() throws IOException {
+ File srcDir = new File(baseDir, "src");
+ srcDir.mkdir();
+
+ writeFile(srcDir, "sample.xoo", "Sample xoo\ncontent");
+ writeFile(srcDir, "sample.other", "Sample other\ncontent");
+
+ AnalysisResult result = tester.newAnalysis()
+ .properties(builder
+ .put("sonar.sources", "src")
+ .build())
+ .execute();
+
+ assertThat(result.inputFiles()).hasSize(2);
+ assertThat(result.inputFile("src/sample.other").type()).isEqualTo(InputFile.Type.MAIN);
+ assertThat(result.inputFile("src/sample.other").relativePath()).isEqualTo("src/sample.other");
+ assertThat(result.inputFile("src/sample.other").language()).isNull();
+ }
+
+ @Test
+ public void scanMultiModuleProject() {
+ File projectDir = new File("test-resources/mediumtest/xoo/multi-modules-sample");
+ AnalysisResult result = tester
+ .newAnalysis(new File(projectDir, "sonar-project.properties"))
+ .execute();
+
+ assertThat(result.inputFiles()).hasSize(4);
+ }
+
+ @Test
+ public void deprecated_global_sensor_should_see_project_relative_paths() {
+ File projectDir = new File("test-resources/mediumtest/xoo/multi-modules-sample");
+ AnalysisResult result = tester
+ .newAnalysis(new File(projectDir, "sonar-project.properties"))
+ .property(DeprecatedGlobalSensor.ENABLE_PROP, "true")
+ .execute();
+
+ assertThat(result.inputFiles()).hasSize(4);
+ assertThat(logTester.logs(LoggerLevel.INFO)).contains(
+ "Deprecated Global Sensor: module_a/module_a1/src/main/xoo/com/sonar/it/samples/modules/a1/HelloA1.xoo",
+ "Deprecated Global Sensor: module_a/module_a2/src/main/xoo/com/sonar/it/samples/modules/a2/HelloA2.xoo",
+ "Deprecated Global Sensor: module_b/module_b1/src/main/xoo/com/sonar/it/samples/modules/b1/HelloB1.xoo",
+ "Deprecated Global Sensor: module_b/module_b2/src/main/xoo/com/sonar/it/samples/modules/b2/HelloB2.xoo");
+ }
+
+ @Test
+ public void global_sensor_should_see_project_relative_paths() {
+ File projectDir = new File("test-resources/mediumtest/xoo/multi-modules-sample");
+ AnalysisResult result = tester
+ .newAnalysis(new File(projectDir, "sonar-project.properties"))
+ .property(GlobalProjectSensor.ENABLE_PROP, "true")
+ .execute();
+
+ assertThat(result.inputFiles()).hasSize(4);
+ assertThat(logTester.logs(LoggerLevel.INFO)).contains(
+ "Global Sensor: module_a/module_a1/src/main/xoo/com/sonar/it/samples/modules/a1/HelloA1.xoo",
+ "Global Sensor: module_a/module_a2/src/main/xoo/com/sonar/it/samples/modules/a2/HelloA2.xoo",
+ "Global Sensor: module_b/module_b1/src/main/xoo/com/sonar/it/samples/modules/b1/HelloB1.xoo",
+ "Global Sensor: module_b/module_b2/src/main/xoo/com/sonar/it/samples/modules/b2/HelloB2.xoo");
+ }
+
+ @Test
+ public void scan_project_with_comma_in_source_path() throws IOException {
+ File srcDir = new File(baseDir, "src");
+ srcDir.mkdir();
+
+ writeFile(srcDir, "sample,1.xoo", "Sample xoo\ncontent");
+ writeFile(baseDir, "another,2.xoo", "Sample xoo 2\ncontent");
+
+ File testDir = new File(baseDir, "test");
+ testDir.mkdir();
+
+ writeFile(testDir, "sampleTest,1.xoo", "Sample test xoo\ncontent");
+ writeFile(baseDir, "sampleTest,2.xoo", "Sample test xoo 2\ncontent");
+
+ AnalysisResult result = tester.newAnalysis()
+ .properties(builder
+ .put("sonar.sources", "src,\"another,2.xoo\"")
+ .put("sonar.tests", "\"test\",\"sampleTest,2.xoo\"")
+ .build())
+ .execute();
+
+ assertThat(result.inputFiles()).hasSize(4);
+ }
+
+ @Test
+ public void language_without_publishAllFiles_should_not_auto_publish_files() throws IOException {
+ File srcDir = new File(baseDir, "src");
+ srcDir.mkdir();
+
+ writeFile(srcDir, "sample.xoo3", "Sample xoo\ncontent");
+ writeFile(srcDir, "sample2.xoo3", "Sample xoo 2\ncontent");
+
+ AnalysisResult result = tester.newAnalysis()
+ .properties(builder
+ .put("sonar.sources", "src")
+ .build())
+ .execute();
+
+ assertThat(result.inputFiles())
+ .extracting(InputFile::filename, InputFile::language, f -> ((DefaultInputFile) f).isPublished())
+ .containsOnly(tuple("sample.xoo3", "xoo3", false), tuple("sample2.xoo3", "xoo3", false));
+ assertThat(result.getReportReader().readComponent(result.getReportReader().readMetadata().getRootComponentRef()).getChildRefCount()).isZero();
+ }
+
+ @Test
+ public void two_languages_with_same_extension() throws IOException {
+ File srcDir = new File(baseDir, "src");
+ srcDir.mkdir();
+
+ writeFile(srcDir, "sample.xoo", "Sample xoo\ncontent");
+ writeFile(srcDir, "sample.xoo2", "Sample xoo 2\ncontent");
+
+ AnalysisResult result = tester.newAnalysis()
+ .properties(builder
+ .put("sonar.sources", "src")
+ .build())
+ .execute();
+
+ assertThat(result.inputFiles()).hasSize(2);
+
+ AnalysisBuilder analysisBuilder = tester.newAnalysis()
+ .properties(builder
+ .put("sonar.lang.patterns.xoo2", "**/*.xoo")
+ .build());
+
+ assertThatThrownBy(analysisBuilder::execute)
+ .isInstanceOf(MessageException.class)
+ .hasMessage(
+ "Language of file 'src" + File.separator
+ + "sample.xoo' can not be decided as the file matches patterns of both sonar.lang.patterns.xoo : **/*.xoo and sonar.lang.patterns.xoo2 : **/*.xoo");
+
+ // SONAR-9561
+ result = tester.newAnalysis()
+ .properties(builder
+ .put("sonar.exclusions", "**/sample.xoo")
+ .build())
+ .execute();
+
+ assertThat(result.inputFiles()).hasSize(1);
+ }
+
+ @Test
+ public void log_all_exclusions_properties_per_modules() throws IOException {
+ File baseDir = temp.getRoot();
+ File baseDirModuleA = new File(baseDir, "moduleA");
+ File baseDirModuleB = new File(baseDir, "moduleB");
+ File srcDirA = new File(baseDirModuleA, "src");
+ srcDirA.mkdirs();
+ File srcDirB = new File(baseDirModuleB, "src");
+ srcDirB.mkdirs();
+
+ writeFile(srcDirA, "sample.xoo", "Sample xoo\ncontent");
+ writeFile(srcDirB, "sample.xoo", "Sample xoo\ncontent");
+
+ AnalysisResult result = tester.newAnalysis()
+ .properties(ImmutableMap.<String, String>builder()
+ .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
+ .put("sonar.projectKey", "com.foo.project")
+ .put("sonar.sources", "src")
+ .put("sonar.modules", "moduleA,moduleB")
+ .put("sonar.inclusions", "**/global.inclusions")
+ .put("sonar.test.inclusions", "**/global.test.inclusions")
+ .put("sonar.exclusions", "**/global.exclusions")
+ .put("sonar.test.exclusions", "**/global.test.exclusions")
+ .put("sonar.coverage.exclusions", "**/coverage.exclusions")
+ .put("sonar.cpd.exclusions", "**/cpd.exclusions")
+ .build())
+ .execute();
+
+ assertThat(logTester.logs(LoggerLevel.INFO))
+ .containsSequence("Project configuration:",
+ " Included sources: **/global.inclusions",
+ " Excluded sources: **/global.exclusions, **/global.test.inclusions",
+ " Included tests: **/global.test.inclusions",
+ " Excluded tests: **/global.test.exclusions",
+ " Excluded sources for coverage: **/coverage.exclusions",
+ " Excluded sources for duplication: **/cpd.exclusions",
+ "Indexing files of module 'moduleA'",
+ " Base dir: " + baseDirModuleA.toPath().toRealPath(LinkOption.NOFOLLOW_LINKS),
+ " Source paths: src",
+ " Included sources: **/global.inclusions",
+ " Excluded sources: **/global.exclusions, **/global.test.inclusions",
+ " Included tests: **/global.test.inclusions",
+ " Excluded tests: **/global.test.exclusions",
+ " Excluded sources for coverage: **/coverage.exclusions",
+ " Excluded sources for duplication: **/cpd.exclusions",
+ "Indexing files of module 'moduleB'",
+ " Base dir: " + baseDirModuleB.toPath().toRealPath(LinkOption.NOFOLLOW_LINKS),
+ " Source paths: src",
+ " Included sources: **/global.inclusions",
+ " Excluded sources: **/global.exclusions, **/global.test.inclusions",
+ " Included tests: **/global.test.inclusions",
+ " Excluded tests: **/global.test.exclusions",
+ " Excluded sources for coverage: **/coverage.exclusions",
+ " Excluded sources for duplication: **/cpd.exclusions",
+ "Indexing files of module 'com.foo.project'",
+ " Base dir: " + baseDir.toPath().toRealPath(LinkOption.NOFOLLOW_LINKS),
+ " Included sources: **/global.inclusions",
+ " Excluded sources: **/global.exclusions, **/global.test.inclusions",
+ " Included tests: **/global.test.inclusions",
+ " Excluded tests: **/global.test.exclusions",
+ " Excluded sources for coverage: **/coverage.exclusions",
+ " Excluded sources for duplication: **/cpd.exclusions");
+ }
+
+ @Test
+ public void ignore_files_outside_project_basedir() throws IOException {
+ File srcDir = new File(baseDir, "src");
+ srcDir.mkdir();
+
+ writeFile(srcDir, "sample1.xoo", "Sample xoo\ncontent");
+
+ File outsideBaseDir = temp.newFolder().getCanonicalFile();
+ File xooFile2 = writeFile(outsideBaseDir, "another.xoo", "Sample xoo 2\ncontent");
+
+ AnalysisResult result = tester.newAnalysis()
+ .properties(builder
+ .put("sonar.sources", "src," + PathUtils.canonicalPath(xooFile2))
+ .build())
+ .execute();
+
+ assertThat(result.inputFiles()).hasSize(1);
+ assertThat(logTester.logs(LoggerLevel.WARN)).contains("File '" + xooFile2.getAbsolutePath() + "' is ignored. It is not located in project basedir '" + baseDir + "'.");
+ }
+
+ @Test
+ public void dont_log_warn_about_files_out_of_basedir_if_they_arent_included() throws IOException {
+ File srcDir = new File(baseDir, "src");
+ srcDir.mkdir();
+
+ writeFile(srcDir, "sample1.xoo", "Sample xoo\ncontent");
+
+ File outsideBaseDir = temp.newFolder().getCanonicalFile();
+ File xooFile2 = new File(outsideBaseDir, "another.xoo");
+ FileUtils.write(xooFile2, "Sample xoo 2\ncontent", StandardCharsets.UTF_8);
+
+ AnalysisResult result = tester.newAnalysis()
+ .properties(builder
+ .put("sonar.sources", "src," + PathUtils.canonicalPath(xooFile2))
+ .put("sonar.inclusions", "**/sample1.xoo")
+ .build())
+ .execute();
+
+ assertThat(result.inputFiles()).hasSize(1);
+ assertThat(logTester.logs(LoggerLevel.WARN)).doesNotContain("File '" + xooFile2.getAbsolutePath() + "' is ignored. It is not located in project basedir '" + baseDir + "'.");
+ }
+
+ @Test
+ public void ignore_files_outside_module_basedir() throws IOException {
+ File moduleA = new File(baseDir, "moduleA");
+ moduleA.mkdir();
+
+ writeFile(moduleA, "src/sampleA.xoo", "Sample xoo\ncontent");
+ File xooFile2 = writeFile(baseDir, "another.xoo", "Sample xoo 2\ncontent");
+
+ AnalysisResult result = tester.newAnalysis()
+ .properties(builder
+ .put("sonar.modules", "moduleA")
+ .put("moduleA.sonar.sources", "src," + PathUtils.canonicalPath(xooFile2))
+ .build())
+ .execute();
+
+ assertThat(result.inputFiles()).hasSize(1);
+ assertThat(logTester.logs(LoggerLevel.WARN))
+ .contains("File '" + xooFile2.getAbsolutePath() + "' is ignored. It is not located in module basedir '" + new File(baseDir, "moduleA") + "'.");
+ }
+
+ @Test
+ public void exclusion_based_on_scm_info() {
+ File projectDir = new File("test-resources/mediumtest/xoo/sample-with-ignored-file");
+ AnalysisResult result = tester
+ .newAnalysis(new File(projectDir, "sonar-project.properties"))
+ .property("sonar.exclusions", "**/*.xoo.ignore")
+ .property("sonar.test.exclusions", "**/*.xoo.ignore")
+ .execute();
+
+ assertThat(result.inputFile("xources/hello/ClassTwo.xoo")).isNull();
+ assertThat(result.inputFile("testx/ClassTwoTest.xoo")).isNull();
+
+ assertThat(result.inputFile("xources/hello/ClassOne.xoo")).isNotNull();
+ assertThat(result.inputFile("testx/ClassOneTest.xoo")).isNotNull();
+ }
+
+ @Test
+ public void no_exclusion_when_scm_exclusions_is_disabled() {
+ File projectDir = new File("test-resources/mediumtest/xoo/sample-with-ignored-file");
+ AnalysisResult result = tester
+ .newAnalysis(new File(projectDir, "sonar-project.properties"))
+ .property("sonar.scm.exclusions.disabled", "true")
+ .property("sonar.exclusions", "**/*.xoo.ignore")
+ .property("sonar.test.exclusions", "**/*.xoo.ignore")
+ .execute();
+
+ assertThat(result.inputFiles()).hasSize(4);
+
+ assertThat(result.inputFile("xources/hello/ClassTwo.xoo")).isNotNull();
+ assertThat(result.inputFile("testx/ClassTwoTest.xoo")).isNotNull();
+ assertThat(result.inputFile("xources/hello/ClassOne.xoo")).isNotNull();
+ assertThat(result.inputFile("testx/ClassOneTest.xoo")).isNotNull();
+ }
+
+ @Test
+ public void index_basedir_by_default() throws IOException {
+ writeFile(baseDir, "sample.xoo", "Sample xoo\ncontent");
+ AnalysisResult result = tester.newAnalysis()
+ .properties(builder
+ .build())
+ .execute();
+
+ assertThat(logTester.logs()).contains("1 file indexed");
+ assertThat(result.inputFile("sample.xoo")).isNotNull();
+ }
+
+ @Test
+ public void givenExclusionEndingWithOneWildcardWhenAnalysedThenOnlyDirectChildrenFilesShouldBeExcluded() throws IOException {
+ // src/src.xoo
+ File srcDir = createDir(baseDir, "src", true);
+ writeFile(srcDir, "src.xoo", "Sample xoo 2\ncontent");
+
+ // src/srcSubDir/srcSub.xoo
+ File srcSubDir = createDir(srcDir, "srcSubDir", true);
+ writeFile(srcSubDir, "srcSub.xoo", "Sample xoo\ncontent");
+
+ // src/srcSubDir/srcSubSubDir/subSubSrc.xoo
+ File srcSubSubDir = createDir(srcSubDir, "srcSubSubDir", true);
+ writeFile(srcSubSubDir, "subSubSrc.xoo", "Sample xoo\ncontent");
+
+ AnalysisResult result = tester.newAnalysis()
+ .properties(builder
+ .put("sonar.sources", "src")
+ .put("sonar.exclusions", "src/srcSubDir/*")
+ .build())
+ .execute();
+
+ assertAnalysedFiles(result, "src/src.xoo", "src/srcSubDir/srcSubSubDir/subSubSrc.xoo");
+ }
+
+ @Test
+ public void givenPathsWithoutReadPermissionWhenAllChildrenAreExcludedThenScannerShouldSkipIt() throws IOException {
+ // src/src.xoo
+ File srcDir = createDir(baseDir, "src", true);
+ writeFile(srcDir, "src.xoo", "Sample xoo 2\ncontent");
+
+ // src/srcSubDir/srcSub.xoo
+ File srcSubDir = createDir(srcDir, "srcSubDir", false);
+ writeFile(srcSubDir, "srcSub.xoo", "Sample xoo\ncontent");
+
+ // src/srcSubDir2/srcSub2.xoo
+ File srcSubDir2 = createDir(srcDir, "srcSubDir2", true);
+ boolean fileNotReadable = writeFile(srcSubDir2, "srcSub2.xoo", "Sample 2 xoo\ncontent").setReadable(false);
+ assumeTrue(fileNotReadable);
+
+ // src/srcSubDir2/srcSubSubDir2/srcSubSub2.xoo
+ File srcSubSubDir2 = createDir(srcSubDir2, "srcSubSubDir2", false);
+ writeFile(srcSubSubDir2, "srcSubSub2.xoo", "Sample xoo\ncontent");
+
+ AnalysisResult result = tester.newAnalysis()
+ .properties(builder
+ .put("sonar.sources", "src")
+ .put("sonar.exclusions", "src/srcSubDir/**/*,src/srcSubDir2/**/*")
+ .build())
+ .execute();
+
+ assertAnalysedFiles(result, "src/src.xoo");
+ assertThat(logTester.logs()).contains("1 file ignored because of inclusion/exclusion patterns");
+ }
+
+ @Test
+ public void givenFileWithoutAccessWhenChildrenAreExcludedThenThenScanShouldFail() throws IOException {
+ // src/src.xoo
+ File srcDir = createDir(baseDir, "src", true);
+ boolean fileNotReadable = writeFile(srcDir, "src.xoo", "Sample xoo\ncontent").setReadable(false);
+ assumeTrue(fileNotReadable);
+
+ AnalysisBuilder result = tester.newAnalysis()
+ .properties(builder
+ .put("sonar.sources", "src")
+ .put("sonar.exclusions", "src/src.xoo/**/*") // incorrect pattern, but still the scan should fail if src.xoo is not accessible
+ .build());
+
+ assertThatThrownBy(result::execute)
+ .isExactlyInstanceOf(IllegalStateException.class)
+ .hasMessageStartingWith(format("java.lang.IllegalStateException: Unable to read file"));
+ }
+
+ @Test
+ public void givenDirectoryWithoutReadPermissionWhenIncludedThenScanShouldFail() throws IOException {
+ // src/src.xoo
+ File srcDir = createDir(baseDir, "src", true);
+ writeFile(srcDir, "src.xoo", "Sample xoo 2\ncontent");
+
+ // src/srcSubDir/srcSub.xoo
+ File srcSubDir = createDir(srcDir, "srcSubDir", false);
+ writeFile(srcSubDir, "srcSub.xoo", "Sample xoo\ncontent");
+
+ AnalysisBuilder result = tester.newAnalysis()
+ .properties(builder
+ .put("sonar.sources", "src")
+ .put("sonar.exclusions", "src/srcSubDir/*") // srcSubDir should not be excluded unless all children are excluded (src/srcSubDir/**/*)
+ .build());
+
+ assertThatThrownBy(result::execute)
+ .isExactlyInstanceOf(IllegalStateException.class)
+ .hasMessageEndingWith(format("Failed to index files"));
+ }
+
+ @Test
+ public void givenDirectoryWhenAllChildrenAreExcludedThenSkippedFilesShouldBeReported() throws IOException {
+ // src/src.xoo
+ File srcDir = createDir(baseDir, "src", true);
+ writeFile(srcDir, "src.xoo", "Sample xoo 2\ncontent");
+
+ // src/srcSubDir/srcSub.xoo
+ File srcSubDir = createDir(srcDir, "srcSubDir", true);
+ writeFile(srcSubDir, "srcSub.xoo", "Sample xoo\ncontent");
+
+ // src/srcSubDir2/srcSub2.xoo
+ File srcSubDir2 = createDir(srcDir, "srcSubDir2", true);
+ boolean fileNotReadable = writeFile(srcSubDir2, "srcSub2.xoo", "Sample 2 xoo\ncontent").setReadable(false);
+ assumeTrue(fileNotReadable);
+
+ AnalysisResult result = tester.newAnalysis()
+ .properties(builder
+ .put("sonar.sources", "src")
+ .put("sonar.exclusions", "src/srcSubDir/**/*,src/srcSubDir2/*")
+ .build())
+ .execute();
+
+ assertAnalysedFiles(result, "src/src.xoo");
+ assertThat(logTester.logs()).contains("2 files ignored because of inclusion/exclusion patterns");
+ }
+
+ @Ignore("Fails until we can pattern match inclusions to directories, not only files.")
+ @Test
+ public void givenDirectoryWithoutReadPermissionWhenNotIncludedThenScanShouldSkipIt() throws IOException {
+ // src/src.xoo
+ File srcDir = createDir(baseDir, "src", true);
+ writeFile(srcDir, "src.xoo", "Sample xoo 2\ncontent");
+
+ // src/srcSubDir/srcSub.xoo
+ File srcSubDir = createDir(srcDir, "srcSubDir", true);
+ writeFile(srcSubDir, "srcSub.xoo", "Sample xoo\ncontent");
+
+ // src/srcSubDir2/srcSub2.xoo
+ File srcSubDir2 = createDir(srcDir, "srcSubDir2", false);
+ writeFile(srcSubDir2, "srcSub2.xoo", "Sample xoo\ncontent");
+
+ AnalysisResult result = tester.newAnalysis()
+ .properties(builder
+ .put("sonar.sources", "src")
+ .put("sonar.inclusions", "src/srcSubDir/**/*")
+ .build())
+ .execute();
+
+ assertAnalysedFiles(result, "src/srcSubDir/srcSub.xoo");
+ }
+
+ @Test
+ public void givenDirectoryWithoutReadPermissionUnderSourcesWhenAnalysedThenShouldFail() throws IOException {
+ // src/src.xoo
+ File srcDir = createDir(baseDir, "src", true);
+ writeFile(srcDir, "src.xoo", "Sample xoo 2\ncontent");
+
+ // src/srcSubDir/srcSub.xoo
+ File srcSubDir = createDir(srcDir, "srcSubDir", false);
+ writeFile(srcSubDir, "srcSub.xoo", "Sample xoo\ncontent");
+
+ AnalysisBuilder result = tester.newAnalysis()
+ .properties(builder
+ .put("sonar.sources", "src")
+ .build());
+
+ assertThatThrownBy(result::execute)
+ .isExactlyInstanceOf(IllegalStateException.class)
+ .hasMessageEndingWith(format("Failed to index files"));
+ }
+
+ private static void assertAnalysedFiles(AnalysisResult result, String... files) {
+ assertThat(result.inputFiles().stream().map(InputFile::toString).collect(Collectors.toList())).contains(files);
+ }
+
+ private File createDir(File parentDir, String name, boolean isReadable) {
+ File dir = new File(parentDir, name);
+ dir.mkdir();
+ boolean fileSystemOperationSucceded = dir.setReadable(isReadable);
+ assumeTrue(fileSystemOperationSucceded); //On windows + java there is no reliable way to play with readable/not readable flag
+ return dir;
+ }
+
+ private File writeFile(File parent, String name, String content) throws IOException {
+ File file = new File(parent, name);
+ FileUtils.write(file, content, StandardCharsets.UTF_8);
+ return file;
+ }
+
+ private File writeFile(File parent, String name, long size) throws IOException {
+ File file = new File(parent, name);
+ RandomAccessFile raf = new RandomAccessFile(file, "rw");
+ raf.setLength(size);
+ raf.close();
+ return file;
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 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.mediumtest.fs;
+
+import java.io.File;
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.io.filefilter.FileFilterUtils;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.sonar.scanner.mediumtest.ScannerMediumTester;
+import org.springframework.beans.factory.BeanCreationException;
+
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+public class NoLanguagesPluginsMediumIT {
+ @Rule
+ public TemporaryFolder temp = new TemporaryFolder();
+
+ @Rule
+ public ScannerMediumTester tester = new ScannerMediumTester();
+
+ @Test
+ public void testNoLanguagePluginsInstalled() throws Exception {
+ File projectDir = copyProject("test-resources/mediumtest/xoo/sample");
+
+ assertThatThrownBy(() -> tester
+ .newAnalysis(new File(projectDir, "sonar-project.properties"))
+ .execute())
+ .isInstanceOf(BeanCreationException.class)
+ .hasRootCauseMessage("No language plugins are installed.");
+ }
+
+ private File copyProject(String path) throws Exception {
+ File projectDir = temp.newFolder();
+ File originalProjectDir = new File(path);
+ FileUtils.copyDirectory(originalProjectDir, projectDir, FileFilterUtils.notFileFilter(FileFilterUtils.nameFileFilter(".sonar")));
+ return projectDir;
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 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.mediumtest.fs;
+
+import com.google.common.collect.ImmutableMap;
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+import org.apache.commons.io.FileUtils;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.sonar.api.SonarEdition;
+import org.sonar.api.batch.bootstrap.ProjectBuilder;
+import org.sonar.api.utils.MessageException;
+import org.sonar.scanner.mediumtest.AnalysisResult;
+import org.sonar.scanner.mediumtest.ScannerMediumTester;
+import org.sonar.scanner.protocol.output.ScannerReport.Issue;
+import org.sonar.xoo.XooPlugin;
+import org.sonar.xoo.rule.XooRulesDefinition;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.assertj.core.api.Assertions.tuple;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+
+public class ProjectBuilderMediumIT {
+
+ @Rule
+ public TemporaryFolder temp = new TemporaryFolder();
+
+ private ProjectBuilder projectBuilder = mock(ProjectBuilder.class);
+
+ @Rule
+ public ScannerMediumTester tester = new ScannerMediumTester()
+ .setEdition(SonarEdition.SONARCLOUD)
+ .registerPlugin("xoo", new XooPluginWithBuilder(projectBuilder))
+ .addRules(new XooRulesDefinition())
+ .addDefaultQProfile("xoo", "Sonar Way")
+ .addActiveRule("xoo", "OneIssuePerLine", null, "One issue per line", "MAJOR", "OneIssuePerLine.internal", "xoo");
+
+ private static class XooPluginWithBuilder extends XooPlugin {
+ private ProjectBuilder builder;
+
+ XooPluginWithBuilder(ProjectBuilder builder) {
+ this.builder = builder;
+ }
+
+ @Override
+ public void define(Context context) {
+ super.define(context);
+ context.addExtension(builder);
+ }
+ }
+
+ @Test
+ public void testProjectReactorValidation() throws IOException {
+ File baseDir = prepareProject();
+
+ doThrow(new IllegalStateException("My error message")).when(projectBuilder).build(any(ProjectBuilder.Context.class));
+
+ assertThatThrownBy(() -> tester.newAnalysis()
+ .properties(ImmutableMap.<String, String>builder()
+ .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
+ .put("sonar.projectKey", "com.foo.project")
+ .put("sonar.sources", ".")
+ .put("sonar.xoo.enableProjectBuilder", "true")
+ .build())
+ .execute())
+ .isInstanceOf(MessageException.class)
+ .hasMessageContaining("Failed to execute project builder")
+ .hasCauseInstanceOf(IllegalStateException.class);
+ }
+
+ @Test
+ public void testProjectBuilder() throws IOException {
+ File baseDir = prepareProject();
+
+ AnalysisResult result = tester.newAnalysis()
+ .properties(ImmutableMap.<String, String>builder()
+ .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
+ .put("sonar.projectKey", "com.foo.project")
+ .put("sonar.sources", ".")
+ .put("sonar.verbose", "true")
+ .put("sonar.xoo.enableProjectBuilder", "true")
+ .build())
+ .execute();
+ List<Issue> issues = result.issuesFor(result.inputFile("module1/src/sample.xoo"));
+ assertThat(issues).hasSize(10);
+
+ assertThat(issues)
+ .extracting("msg", "textRange.startLine", "gap")
+ .contains(tuple("This issue is generated on each line", 1, 0.0));
+
+ }
+
+ private File prepareProject() throws IOException {
+ File baseDir = temp.newFolder();
+ File module1Dir = new File(baseDir, "module1");
+ module1Dir.mkdir();
+
+ File srcDir = new File(module1Dir, "src");
+ srcDir.mkdir();
+
+ File xooFile = new File(srcDir, "sample.xoo");
+ FileUtils.write(xooFile, "1\n2\n3\n4\n5\n6\n7\n8\n9\n10");
+
+ return baseDir;
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 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.mediumtest.highlighting;
+
+import com.google.common.collect.ImmutableMap;
+import java.io.File;
+import java.io.IOException;
+import org.apache.commons.io.FileUtils;
+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.sensor.highlighting.TypeOfText;
+import org.sonar.scanner.mediumtest.AnalysisResult;
+import org.sonar.scanner.mediumtest.ScannerMediumTester;
+import org.sonar.xoo.XooPlugin;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.sonar.scanner.mediumtest.ScannerMediumTester.AnalysisBuilder;
+
+public class HighlightingMediumIT {
+
+ @Rule
+ public TemporaryFolder temp = new TemporaryFolder();
+
+ @Rule
+ public ScannerMediumTester tester = new ScannerMediumTester()
+ .registerPlugin("xoo", new XooPlugin())
+ .addDefaultQProfile("xoo", "Sonar Way");
+
+ @Test
+ public void computeSyntaxHighlightingOnTempProject() throws IOException {
+
+ File baseDir = temp.newFolder();
+ File srcDir = new File(baseDir, "src");
+ srcDir.mkdir();
+
+ File xooFile = new File(srcDir, "sample.xoo");
+ File xoohighlightingFile = new File(srcDir, "sample.xoo.highlighting");
+ FileUtils.write(xooFile, "Sample xoo\ncontent plop");
+ FileUtils.write(xoohighlightingFile, "1:0:2:0:s\n2:0:2:8:k");
+
+ AnalysisResult result = tester.newAnalysis()
+ .properties(ImmutableMap.<String, String>builder()
+ .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
+ .put("sonar.projectKey", "com.foo.project")
+ .put("sonar.projectName", "Foo Project")
+ .put("sonar.projectVersion", "1.0-SNAPSHOT")
+ .put("sonar.projectDescription", "Description of Foo Project")
+ .put("sonar.sources", "src")
+ .build())
+ .execute();
+
+ InputFile file = result.inputFile("src/sample.xoo");
+ assertThat(result.highlightingTypeFor(file, 1, 0)).containsExactly(TypeOfText.STRING);
+ assertThat(result.highlightingTypeFor(file, 1, 9)).containsExactly(TypeOfText.STRING);
+ assertThat(result.highlightingTypeFor(file, 2, 0)).containsExactly(TypeOfText.KEYWORD);
+ assertThat(result.highlightingTypeFor(file, 2, 8)).isEmpty();
+ }
+
+ @Test
+ public void saveTwice() throws IOException {
+ File baseDir = temp.newFolder();
+ File srcDir = new File(baseDir, "src");
+ srcDir.mkdir();
+
+ File xooFile = new File(srcDir, "sample.xoo");
+ FileUtils.write(xooFile, "Sample xoo\ncontent plop");
+
+ AnalysisBuilder analysisBuilder = tester.newAnalysis()
+ .properties(ImmutableMap.<String, String>builder()
+ .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
+ .put("sonar.projectKey", "com.foo.project")
+ .put("sonar.projectName", "Foo Project")
+ .put("sonar.projectVersion", "1.0-SNAPSHOT")
+ .put("sonar.projectDescription", "Description of Foo Project")
+ .put("sonar.sources", "src")
+ .put("sonar.it.savedatatwice", "true")
+ .build());;
+
+ assertThatThrownBy(() -> analysisBuilder.execute())
+ .isInstanceOf(UnsupportedOperationException.class)
+ .hasMessageContaining("Trying to save highlighting twice for the same file is not supported");
+ }
+
+ @Test
+ public void computeInvalidOffsets() throws IOException {
+
+ File baseDir = temp.newFolder();
+ File srcDir = new File(baseDir, "src");
+ srcDir.mkdir();
+
+ File xooFile = new File(srcDir, "sample.xoo");
+ File xoohighlightingFile = new File(srcDir, "sample.xoo.highlighting");
+ FileUtils.write(xooFile, "Sample xoo\ncontent plop");
+ FileUtils.write(xoohighlightingFile, "1:0:1:10:s\n2:18:2:18:k");
+
+ AnalysisBuilder analysisBuilder = tester.newAnalysis()
+ .properties(ImmutableMap.<String, String>builder()
+ .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
+ .put("sonar.projectKey", "com.foo.project")
+ .put("sonar.projectName", "Foo Project")
+ .put("sonar.projectVersion", "1.0-SNAPSHOT")
+ .put("sonar.projectDescription", "Description of Foo Project")
+ .put("sonar.sources", "src")
+ .build());
+
+ assertThatThrownBy(() -> analysisBuilder.execute())
+ .isInstanceOf(IllegalStateException.class)
+ .hasMessageContaining("Error processing line 2")
+ .hasCauseInstanceOf(IllegalArgumentException.class);
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 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.mediumtest.issues;
+
+import com.google.common.collect.ImmutableMap;
+import java.io.File;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import javax.annotation.Nullable;
+import org.apache.commons.io.FileUtils;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.sonar.api.batch.rule.LoadedActiveRule;
+import org.sonar.api.rule.RuleKey;
+import org.sonar.scanner.mediumtest.AnalysisResult;
+import org.sonar.scanner.mediumtest.ScannerMediumTester;
+import org.sonar.scanner.protocol.output.ScannerReport.Issue;
+import org.sonar.xoo.XooPlugin;
+import org.sonar.xoo.rule.XooRulesDefinition;
+
+import static java.util.Collections.emptySet;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.tuple;
+
+public class ChecksMediumIT {
+
+ @Rule
+ public TemporaryFolder temp = new TemporaryFolder();
+
+ @Rule
+ public ScannerMediumTester tester = new ScannerMediumTester()
+ .registerPlugin("xoo", new XooPlugin())
+ .addRules(new XooRulesDefinition())
+ .addDefaultQProfile("xoo", "Sonar Way")
+ .addRule("TemplateRule_1234", "xoo", "TemplateRule_1234", "A template rule")
+ .addRule("TemplateRule_1235", "xoo", "TemplateRule_1235", "Another template rule")
+ .activateRule(createActiveRuleWithParam("xoo", "TemplateRule_1234", "TemplateRule", "A template rule", "MAJOR", null, "xoo", "line", "1"))
+ .activateRule(createActiveRuleWithParam("xoo", "TemplateRule_1235", "TemplateRule", "Another template rule", "MAJOR", null, "xoo", "line", "2"));
+
+ @Test
+ public void testCheckWithTemplate() throws IOException {
+
+ File baseDir = temp.getRoot();
+ File srcDir = new File(baseDir, "src");
+ srcDir.mkdir();
+
+ File xooFile = new File(srcDir, "sample.xoo");
+ FileUtils.write(xooFile, "foo\nbar");
+
+ AnalysisResult result = tester.newAnalysis()
+ .properties(ImmutableMap.<String, String>builder()
+ .put("sonar.task", "scan")
+ .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
+ .put("sonar.projectKey", "com.foo.project")
+ .put("sonar.projectName", "Foo Project")
+ .put("sonar.projectVersion", "1.0-SNAPSHOT")
+ .put("sonar.projectDescription", "Description of Foo Project")
+ .put("sonar.sources", "src")
+ .build())
+ .execute();
+
+ List<Issue> issues = result.issuesFor(result.inputFile("src/sample.xoo"));
+ // If the message is the rule name. it's set by the CE. See SONAR-11531
+ assertThat(issues)
+ .extracting("msg", "textRange.startLine")
+ .containsOnly(
+ tuple("", 1),
+ tuple("", 2));
+
+ }
+
+ private LoadedActiveRule createActiveRuleWithParam(String repositoryKey, String ruleKey, @Nullable String templateRuleKey, String name,
+ @Nullable String severity, @Nullable String internalKey, @Nullable String languag, String paramKey, String paramValue) {
+ LoadedActiveRule r = new LoadedActiveRule();
+
+ r.setInternalKey(internalKey);
+ r.setRuleKey(RuleKey.of(repositoryKey, ruleKey));
+ r.setName(name);
+ r.setTemplateRuleKey(templateRuleKey);
+ r.setLanguage(languag);
+ r.setSeverity(severity);
+ r.setDeprecatedKeys(emptySet());
+
+ Map<String, String> params = new HashMap<>();
+ params.put(paramKey, paramValue);
+ r.setParams(params);
+ return r;
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 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.mediumtest.issues;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.util.List;
+import org.apache.commons.io.FileUtils;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.sonar.api.utils.log.LogTester;
+import org.sonar.scanner.mediumtest.AnalysisResult;
+import org.sonar.scanner.mediumtest.ScannerMediumTester;
+import org.sonar.scanner.protocol.Constants.Severity;
+import org.sonar.scanner.protocol.output.ScannerReport;
+import org.sonar.scanner.protocol.output.ScannerReport.ExternalIssue;
+import org.sonar.scanner.protocol.output.ScannerReport.Issue;
+import org.sonar.scanner.protocol.output.ScannerReport.IssueType;
+import org.sonar.xoo.XooPlugin;
+import org.sonar.xoo.rule.OneExternalIssuePerLineSensor;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.tuple;
+
+public class ExternalIssuesMediumIT {
+ @Rule
+ public LogTester logs = new LogTester();
+ @Rule
+ public TemporaryFolder temp = new TemporaryFolder();
+
+ @Rule
+ public ScannerMediumTester tester = new ScannerMediumTester()
+ .registerPlugin("xoo", new XooPlugin());
+
+ @Test
+ public void testOneIssuePerLine() throws Exception {
+ File projectDir = new File("test-resources/mediumtest/xoo/sample");
+ File tmpDir = temp.newFolder();
+ FileUtils.copyDirectory(projectDir, tmpDir);
+
+ AnalysisResult result = tester
+ .newAnalysis(new File(tmpDir, "sonar-project.properties"))
+ .property(OneExternalIssuePerLineSensor.ACTIVATE, "true")
+ .execute();
+
+ List<Issue> issues = result.issuesFor(result.inputFile("xources/hello/HelloJava.xoo"));
+ assertThat(issues).isEmpty();
+
+ List<ExternalIssue> externalIssues = result.externalIssuesFor(result.inputFile("xources/hello/HelloJava.xoo"));
+ assertThat(externalIssues).hasSize(8 /* lines */);
+
+ ExternalIssue issue = externalIssues.get(0);
+ assertThat(issue.getTextRange().getStartLine()).isEqualTo(issue.getTextRange().getStartLine());
+
+ assertThat(result.adHocRules()).isEmpty();
+ }
+
+ @Test
+ public void testOneIssuePerLine_register_ad_hoc_rule() throws Exception {
+ File projectDir = new File("test-resources/mediumtest/xoo/sample");
+ File tmpDir = temp.newFolder();
+ FileUtils.copyDirectory(projectDir, tmpDir);
+
+ AnalysisResult result = tester
+ .newAnalysis(new File(tmpDir, "sonar-project.properties"))
+ .property(OneExternalIssuePerLineSensor.ACTIVATE, "true")
+ .property(OneExternalIssuePerLineSensor.REGISTER_AD_HOC_RULE, "true")
+ .execute();
+
+ assertThat(result.adHocRules()).extracting(
+ ScannerReport.AdHocRule::getEngineId,
+ ScannerReport.AdHocRule::getRuleId,
+ ScannerReport.AdHocRule::getName,
+ ScannerReport.AdHocRule::getDescription,
+ ScannerReport.AdHocRule::getSeverity,
+ ScannerReport.AdHocRule::getType)
+ .containsExactlyInAnyOrder(
+ tuple(
+ OneExternalIssuePerLineSensor.ENGINE_ID,
+ OneExternalIssuePerLineSensor.RULE_ID,
+ "An ad hoc rule",
+ "blah blah",
+ Severity.BLOCKER,
+ IssueType.BUG));
+ }
+
+ @Test
+ public void testLoadIssuesFromJsonReport() throws URISyntaxException, IOException {
+ File projectDir = new File("test-resources/mediumtest/xoo/sample");
+ File tmpDir = temp.newFolder();
+ FileUtils.copyDirectory(projectDir, tmpDir);
+
+ AnalysisResult result = tester
+ .newAnalysis(new File(tmpDir, "sonar-project.properties"))
+ .property("sonar.externalIssuesReportPaths", "externalIssues.json")
+ .execute();
+
+ List<Issue> issues = result.issuesFor(result.inputFile("xources/hello/HelloJava.xoo"));
+ assertThat(issues).isEmpty();
+
+ List<ExternalIssue> externalIssues = result.externalIssuesFor(result.inputFile("xources/hello/HelloJava.xoo"));
+ assertThat(externalIssues).hasSize(2);
+
+ // precise issue location
+ ExternalIssue issue = externalIssues.get(0);
+ assertPreciseIssueLocation(issue);
+
+ // location on a line
+ issue = externalIssues.get(1);
+ assertIssueLocationLine(issue);
+
+ // One file-level issue in helloscala, with secondary location
+ List<ExternalIssue> externalIssues2 = result.externalIssuesFor(result.inputFile("xources/hello/helloscala.xoo"));
+ assertThat(externalIssues2).hasSize(1);
+
+ issue = externalIssues2.iterator().next();
+ assertSecondaryLocation(issue);
+
+ // one issue is located in a non-existing file
+ assertThat(logs.logs()).contains("External issues ignored for 1 unknown files, including: invalidFile");
+
+ }
+
+ private void assertSecondaryLocation(ExternalIssue issue) {
+ assertThat(issue.getFlowCount()).isEqualTo(2);
+ assertThat(issue.getMsg()).isEqualTo("fix the bug here");
+ assertThat(issue.getEngineId()).isEqualTo("externalXoo");
+ assertThat(issue.getRuleId()).isEqualTo("rule3");
+ assertThat(issue.getSeverity()).isEqualTo(Severity.MAJOR);
+ assertThat(issue.getType()).isEqualTo(IssueType.BUG);
+ assertThat(issue.hasTextRange()).isFalse();
+ assertThat(issue.getFlow(0).getLocationCount()).isOne();
+ assertThat(issue.getFlow(0).getLocation(0).getTextRange().getStartLine()).isOne();
+ assertThat(issue.getFlow(1).getLocationCount()).isOne();
+ assertThat(issue.getFlow(1).getLocation(0).getTextRange().getStartLine()).isEqualTo(3);
+ }
+
+ private void assertIssueLocationLine(ExternalIssue issue) {
+ assertThat(issue.getFlowCount()).isZero();
+ assertThat(issue.getMsg()).isEqualTo("fix the bug here");
+ assertThat(issue.getEngineId()).isEqualTo("externalXoo");
+ assertThat(issue.getRuleId()).isEqualTo("rule2");
+ assertThat(issue.getSeverity()).isEqualTo(Severity.CRITICAL);
+ assertThat(issue.getType()).isEqualTo(IssueType.BUG);
+ assertThat(issue.getEffort()).isZero();
+ assertThat(issue.getTextRange().getStartLine()).isEqualTo(3);
+ assertThat(issue.getTextRange().getEndLine()).isEqualTo(3);
+ assertThat(issue.getTextRange().getStartOffset()).isZero();
+ assertThat(issue.getTextRange().getEndOffset()).isEqualTo(24);
+ }
+
+ private void assertPreciseIssueLocation(ExternalIssue issue) {
+ assertThat(issue.getFlowCount()).isZero();
+ assertThat(issue.getMsg()).isEqualTo("fix the issue here");
+ assertThat(issue.getEngineId()).isEqualTo("externalXoo");
+ assertThat(issue.getRuleId()).isEqualTo("rule1");
+ assertThat(issue.getSeverity()).isEqualTo(Severity.MAJOR);
+ assertThat(issue.getEffort()).isEqualTo(50L);
+ assertThat(issue.getType()).isEqualTo(IssueType.CODE_SMELL);
+ assertThat(issue.getTextRange().getStartLine()).isEqualTo(5);
+ assertThat(issue.getTextRange().getEndLine()).isEqualTo(5);
+ assertThat(issue.getTextRange().getStartOffset()).isEqualTo(3);
+ assertThat(issue.getTextRange().getEndOffset()).isEqualTo(41);
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 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.mediumtest.issues;
+
+import com.google.common.collect.ImmutableMap;
+import java.io.File;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.List;
+import org.apache.commons.io.FileUtils;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.sonar.api.batch.rule.LoadedActiveRule;
+import org.sonar.api.rule.RuleKey;
+import org.sonar.api.utils.log.LogTester;
+import org.sonar.api.utils.log.LoggerLevel;
+import org.sonar.scanner.mediumtest.AnalysisResult;
+import org.sonar.scanner.mediumtest.ScannerMediumTester;
+import org.sonar.scanner.protocol.output.ScannerReport.ExternalIssue;
+import org.sonar.scanner.protocol.output.ScannerReport.Issue;
+import org.sonar.xoo.XooPlugin;
+import org.sonar.xoo.rule.HasTagSensor;
+import org.sonar.xoo.rule.OneExternalIssueOnProjectSensor;
+import org.sonar.xoo.rule.OneExternalIssuePerLineSensor;
+import org.sonar.xoo.rule.XooRulesDefinition;
+
+import static java.util.Collections.emptySet;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.tuple;
+
+public class IssuesMediumIT {
+
+ @Rule
+ public TemporaryFolder temp = new TemporaryFolder();
+
+ @Rule
+ public LogTester logTester = new LogTester();
+
+ @Rule
+ public ScannerMediumTester tester = new ScannerMediumTester()
+ .registerPlugin("xoo", new XooPlugin())
+ .addDefaultQProfile("xoo", "Sonar Way")
+ .addRules(new XooRulesDefinition())
+ .addActiveRule("xoo", "OneIssuePerLine", null, "One issue per line", "MAJOR", "OneIssuePerLine.internal", "xoo");
+
+ @Test
+ public void testOneIssuePerLine() throws Exception {
+ File projectDir = new File("test-resources/mediumtest/xoo/sample");
+ File tmpDir = temp.newFolder();
+ FileUtils.copyDirectory(projectDir, tmpDir);
+
+ AnalysisResult result = tester
+ .newAnalysis(new File(tmpDir, "sonar-project.properties"))
+ .execute();
+
+ List<Issue> issues = result.issuesFor(result.inputFile("xources/hello/HelloJava.xoo"));
+ assertThat(issues).hasSize(8 /* lines */);
+
+ List<ExternalIssue> externalIssues = result.externalIssuesFor(result.inputFile("xources/hello/HelloJava.xoo"));
+ assertThat(externalIssues).isEmpty();
+ }
+
+ @Test
+ public void testOneExternalIssuePerLine() throws Exception {
+ File projectDir = new File("test-resources/mediumtest/xoo/sample");
+ File tmpDir = temp.newFolder();
+ FileUtils.copyDirectory(projectDir, tmpDir);
+
+ AnalysisResult result = tester
+ .newAnalysis(new File(tmpDir, "sonar-project.properties"))
+ .property(OneExternalIssuePerLineSensor.ACTIVATE, "true")
+ .execute();
+
+ List<ExternalIssue> externalIssues = result.externalIssuesFor(result.inputFile("xources/hello/HelloJava.xoo"));
+ assertThat(externalIssues).hasSize(8 /* lines */);
+ }
+
+ @Test
+ public void testOneExternalIssueOnProject() throws Exception {
+ File projectDir = new File("test-resources/mediumtest/xoo/sample");
+ File tmpDir = temp.newFolder();
+ FileUtils.copyDirectory(projectDir, tmpDir);
+
+ AnalysisResult result = tester
+ .newAnalysis(new File(tmpDir, "sonar-project.properties"))
+ .property(OneExternalIssueOnProjectSensor.ACTIVATE, "true")
+ .execute();
+
+ List<ExternalIssue> externalIssues = result.externalIssuesFor(result.project());
+ assertThat(externalIssues).hasSize(1);
+ }
+
+ @Test
+ public void findActiveRuleByInternalKey() throws Exception {
+ File projectDir = new File("test-resources/mediumtest/xoo/sample");
+ File tmpDir = temp.newFolder();
+ FileUtils.copyDirectory(projectDir, tmpDir);
+
+ AnalysisResult result = tester
+ .newAnalysis(new File(tmpDir, "sonar-project.properties"))
+ .property("sonar.xoo.internalKey", "OneIssuePerLine.internal")
+ .execute();
+
+ List<Issue> issues = result.issuesFor(result.inputFile("xources/hello/HelloJava.xoo"));
+ assertThat(issues).hasSize(8 /* lines */ + 1 /* file */);
+ }
+
+ @Test
+ public void testOverrideQProfileSeverity() throws Exception {
+ File projectDir = new File("test-resources/mediumtest/xoo/sample");
+ File tmpDir = temp.newFolder();
+ FileUtils.copyDirectory(projectDir, tmpDir);
+
+ AnalysisResult result = tester
+ .newAnalysis(new File(tmpDir, "sonar-project.properties"))
+ .property("sonar.oneIssuePerLine.forceSeverity", "CRITICAL")
+ .execute();
+
+ List<Issue> issues = result.issuesFor(result.inputFile("xources/hello/HelloJava.xoo"));
+ assertThat(issues.get(0).getSeverity()).isEqualTo(org.sonar.scanner.protocol.Constants.Severity.CRITICAL);
+ }
+
+ @Test
+ public void testIssueExclusionByRegexp() throws Exception {
+ File projectDir = new File("test-resources/mediumtest/xoo/sample");
+ File tmpDir = temp.newFolder();
+ FileUtils.copyDirectory(projectDir, tmpDir);
+
+ AnalysisResult result = tester
+ .newAnalysis(new File(tmpDir, "sonar-project.properties"))
+ .property("sonar.issue.ignore.allfile", "1")
+ .property("sonar.issue.ignore.allfile.1.fileRegexp", "object")
+ .execute();
+
+ assertThat(result.issuesFor(result.inputFile("xources/hello/HelloJava.xoo"))).hasSize(8 /* lines */);
+ assertThat(result.issuesFor(result.inputFile("xources/hello/helloscala.xoo"))).isEmpty();
+ }
+
+ @Test
+ public void testIssueExclusionByBlock() throws Exception {
+ File baseDir = temp.newFolder();
+ File srcDir = new File(baseDir, "src");
+ srcDir.mkdir();
+
+ File xooFile = new File(srcDir, "sample.xoo");
+ FileUtils.write(xooFile, "1\nSONAR-OFF 2\n3\n4\n5\nSONAR-ON 6\n7\n8\n9\n10", StandardCharsets.UTF_8);
+
+ AnalysisResult result = tester.newAnalysis()
+ .properties(ImmutableMap.<String, String>builder()
+ .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
+ .put("sonar.projectKey", "com.foo.project")
+ .put("sonar.sources", "src")
+ .build())
+ .property("sonar.issue.ignore.block", "1")
+ .property("sonar.issue.ignore.block.1.beginBlockRegexp", "SON.*-OFF")
+ .property("sonar.issue.ignore.block.1.endBlockRegexp", "SON.*-ON")
+ .execute();
+
+ List<Issue> issues = result.issuesFor(result.inputFile("src/sample.xoo"));
+ assertThat(issues).hasSize(5);
+ assertThat(issues)
+ .extracting("textRange.startLine")
+ .containsExactlyInAnyOrder(1, 7, 8, 9, 10);
+ }
+
+ @Test
+ public void testIssueExclusionByIgnoreMultiCriteria() throws Exception {
+ File baseDir = temp.newFolder();
+ File srcDir = new File(baseDir, "src");
+ srcDir.mkdir();
+
+ activateTODORule();
+
+ File xooFile1 = new File(srcDir, "sample1.xoo");
+ FileUtils.write(xooFile1, "1\n2\n3 TODO\n4\n5\n6 TODO\n7\n8\n9\n10", StandardCharsets.UTF_8);
+ File xooFile11 = new File(srcDir, "sample11.xoo");
+ FileUtils.write(xooFile11, "1\n2\n3 TODO\n4\n5\n6 TODO\n7\n8\n9\n10", StandardCharsets.UTF_8);
+
+ AnalysisResult result = tester.newAnalysis()
+ .properties(ImmutableMap.<String, String>builder()
+ .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
+ .put("sonar.projectKey", "com.foo.project")
+ .put("sonar.sources", "src")
+ .build())
+ .property("sonar.issue.ignore.multicriteria", "1,2")
+ .property("sonar.issue.ignore.multicriteria.1.ruleKey", "xoo:HasTag")
+ .property("sonar.issue.ignore.multicriteria.1.resourceKey", "src/sample11.xoo")
+ .property("sonar.issue.ignore.multicriteria.2.ruleKey", "xoo:One*")
+ .property("sonar.issue.ignore.multicriteria.2.resourceKey", "src/sample?.xoo")
+ .execute();
+
+ List<Issue> issues = result.issuesFor(result.inputFile("src/sample1.xoo"));
+ assertThat(issues).hasSize(2);
+
+ issues = result.issuesFor(result.inputFile("src/sample11.xoo"));
+ assertThat(issues).hasSize(10);
+ }
+
+ @Test
+ public void warn_user_for_outdated_IssueExclusionByIgnoreMultiCriteria() throws Exception {
+ File baseDir = temp.getRoot();
+ File baseDirModuleA = new File(baseDir, "moduleA");
+ File baseDirModuleB = new File(baseDir, "moduleB");
+ File srcDirA = new File(baseDirModuleA, "src");
+ srcDirA.mkdirs();
+ File srcDirB = new File(baseDirModuleB, "src");
+ srcDirB.mkdirs();
+
+ File xooFileA = new File(srcDirA, "sampleA.xoo");
+ FileUtils.write(xooFileA, "1\n2\n3\n4\n5\n6 TODO\n7\n8\n9\n10", StandardCharsets.UTF_8);
+ File xooFileB = new File(srcDirB, "sampleB.xoo");
+ FileUtils.write(xooFileB, "1\n2\n3\n4\n5\n6 TODO\n7\n8\n9\n10", StandardCharsets.UTF_8);
+
+ tester
+ .addProjectServerSettings("sonar.issue.ignore.multicriteria", "1")
+ .addProjectServerSettings("sonar.issue.ignore.multicriteria.1.ruleKey", "*")
+ .addProjectServerSettings("sonar.issue.ignore.multicriteria.1.resourceKey", "src/sampleA.xoo");
+
+ AnalysisResult result = tester.newAnalysis()
+ .properties(ImmutableMap.<String, String>builder()
+ .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
+ .put("sonar.projectKey", "com.foo.project")
+ .put("sonar.modules", "moduleA,moduleB")
+ .put("sonar.sources", "src")
+ .build())
+ .execute();
+
+ assertThat(logTester.logs(LoggerLevel.WARN)).contains(
+ "Specifying module-relative paths at project level in property 'sonar.issue.ignore.multicriteria' is deprecated. To continue matching files like 'moduleA/src/sampleA.xoo', update this property so that patterns refer to project-relative paths.");
+
+ List<Issue> issues = result.issuesFor(result.inputFile("moduleA/src/sampleA.xoo"));
+ assertThat(issues).isEmpty();
+
+ issues = result.issuesFor(result.inputFile("moduleB/src/sampleB.xoo"));
+ assertThat(issues).hasSize(10);
+ }
+
+ @Test
+ public void warn_user_for_unsupported_module_level_IssueExclusion() throws Exception {
+ File baseDir = temp.getRoot();
+ File baseDirModuleA = new File(baseDir, "moduleA");
+ File baseDirModuleB = new File(baseDir, "moduleB");
+ File srcDirA = new File(baseDirModuleA, "src");
+ srcDirA.mkdirs();
+ File srcDirB = new File(baseDirModuleB, "src");
+ srcDirB.mkdirs();
+
+ File xooFileA = new File(srcDirA, "sampleA.xoo");
+ FileUtils.write(xooFileA, "1\n2\n3\n4\n5\n6 TODO\n7\n8\n9\n10", StandardCharsets.UTF_8);
+ File xooFileB = new File(srcDirB, "sampleB.xoo");
+ FileUtils.write(xooFileB, "1\n2\n3\n4\n5\n6 TODO\n7\n8\n9\n10", StandardCharsets.UTF_8);
+
+ AnalysisResult result = tester.newAnalysis()
+ .properties(ImmutableMap.<String, String>builder()
+ .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
+ .put("sonar.projectKey", "com.foo.project")
+ .put("sonar.modules", "moduleA,moduleB")
+ .put("sonar.sources", "src")
+ .put("sonar.scm.disabled", "true")
+ .put("sonar.issue.ignore.multicriteria", "1")
+ .put("sonar.issue.ignore.multicriteria.1.ruleKey", "*")
+ .put("sonar.issue.ignore.multicriteria.1.resourceKey", "*")
+ .build())
+ .execute();
+
+ assertThat(logTester.logs(LoggerLevel.WARN)).isEmpty();
+
+ result = tester.newAnalysis()
+ .properties(ImmutableMap.<String, String>builder()
+ .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
+ .put("sonar.projectKey", "com.foo.project")
+ .put("sonar.modules", "moduleA,moduleB")
+ .put("sonar.sources", "src")
+ .put("sonar.scm.disabled", "true")
+ .put("moduleA.sonar.issue.ignore.multicriteria", "1")
+ .put("moduleA.sonar.issue.ignore.multicriteria.1.ruleKey", "*")
+ .put("moduleA.sonar.issue.ignore.multicriteria.1.resourceKey", "*")
+ .build())
+ .execute();
+
+ assertThat(logTester.logs(LoggerLevel.WARN)).containsOnly(
+ "Specifying issue exclusions at module level is not supported anymore. Configure the property 'sonar.issue.ignore.multicriteria' and any other issue exclusions at project level.");
+
+ List<Issue> issues = result.issuesFor(result.inputFile("moduleA/src/sampleA.xoo"));
+ assertThat(issues).hasSize(10);
+
+ issues = result.issuesFor(result.inputFile("moduleB/src/sampleB.xoo"));
+ assertThat(issues).hasSize(10);
+
+ // SONAR-11850 The Maven scanner replicates properties defined on the root module to all modules
+ logTester.clear();
+ result = tester.newAnalysis()
+ .properties(ImmutableMap.<String, String>builder()
+ .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
+ .put("sonar.projectKey", "com.foo.project")
+ .put("sonar.modules", "moduleA,moduleB")
+ .put("sonar.sources", "src")
+ .put("sonar.scm.disabled", "true")
+ .put("sonar.issue.ignore.multicriteria", "1")
+ .put("sonar.issue.ignore.multicriteria.1.ruleKey", "*")
+ .put("sonar.issue.ignore.multicriteria.1.resourceKey", "*")
+ .put("moduleA.sonar.issue.ignore.multicriteria", "1")
+ .put("moduleA.sonar.issue.ignore.multicriteria.1.ruleKey", "*")
+ .put("moduleA.sonar.issue.ignore.multicriteria.1.resourceKey", "*")
+ .build())
+ .execute();
+
+ assertThat(logTester.logs(LoggerLevel.WARN)).isEmpty();
+ }
+
+ @Test
+ public void testIssueExclusionByEnforceMultiCriteria() throws Exception {
+ File baseDir = temp.newFolder();
+ File srcDir = new File(baseDir, "src");
+ srcDir.mkdir();
+
+ activateTODORule();
+
+ File xooFile1 = new File(srcDir, "sample1.xoo");
+ FileUtils.write(xooFile1, "1\n2\n3 TODO\n4\n5\n6 TODO\n7\n8\n9\n10", StandardCharsets.UTF_8);
+ File xooFile11 = new File(srcDir, "sample11.xoo");
+ FileUtils.write(xooFile11, "1\n2\n3 TODO\n4\n5\n6 TODO\n7\n8\n9\n10", StandardCharsets.UTF_8);
+
+ AnalysisResult result = tester.newAnalysis()
+ .properties(ImmutableMap.<String, String>builder()
+ .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
+ .put("sonar.projectKey", "com.foo.project")
+ .put("sonar.sources", "src")
+ .build())
+ .property("sonar.issue.enforce.multicriteria", "1,2")
+ .property("sonar.issue.enforce.multicriteria.1.ruleKey", "xoo:HasTag")
+ .property("sonar.issue.enforce.multicriteria.1.resourceKey", "src/sample11.xoo")
+ .property("sonar.issue.enforce.multicriteria.2.ruleKey", "xoo:One*")
+ .property("sonar.issue.enforce.multicriteria.2.resourceKey", "src/sample?.xoo")
+ .execute();
+
+ List<Issue> issues = result.issuesFor(result.inputFile("src/sample1.xoo"));
+ assertThat(issues).hasSize(10);
+
+ issues = result.issuesFor(result.inputFile("src/sample11.xoo"));
+ assertThat(issues).hasSize(2);
+ }
+
+ @Test
+ public void warn_user_for_outdated_IssueExclusionByEnforceMultiCriteria() throws Exception {
+ File baseDir = temp.getRoot();
+ File baseDirModuleA = new File(baseDir, "moduleA");
+ File baseDirModuleB = new File(baseDir, "moduleB");
+ File srcDirA = new File(baseDirModuleA, "src");
+ srcDirA.mkdirs();
+ File srcDirB = new File(baseDirModuleB, "src");
+ srcDirB.mkdirs();
+
+ File xooFileA = new File(srcDirA, "sampleA.xoo");
+ FileUtils.write(xooFileA, "1\n2\n3\n4\n5\n6 TODO\n7\n8\n9\n10", StandardCharsets.UTF_8);
+ File xooFileB = new File(srcDirB, "sampleB.xoo");
+ FileUtils.write(xooFileB, "1\n2\n3\n4\n5\n6 TODO\n7\n8\n9\n10", StandardCharsets.UTF_8);
+
+ tester
+ .addProjectServerSettings("sonar.issue.enforce.multicriteria", "1")
+ .addProjectServerSettings("sonar.issue.enforce.multicriteria.1.ruleKey", "*")
+ .addProjectServerSettings("sonar.issue.enforce.multicriteria.1.resourceKey", "src/sampleA.xoo");
+
+ AnalysisResult result = tester.newAnalysis()
+ .properties(ImmutableMap.<String, String>builder()
+ .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
+ .put("sonar.projectKey", "com.foo.project")
+ .put("sonar.modules", "moduleA,moduleB")
+ .put("sonar.sources", "src")
+ .build())
+ .execute();
+
+ assertThat(logTester.logs(LoggerLevel.WARN)).contains(
+ "Specifying module-relative paths at project level in property 'sonar.issue.enforce.multicriteria' is deprecated. To continue matching files like 'moduleA/src/sampleA.xoo', update this property so that patterns refer to project-relative paths.");
+
+ List<Issue> issues = result.issuesFor(result.inputFile("moduleA/src/sampleA.xoo"));
+ assertThat(issues).hasSize(10);
+
+ issues = result.issuesFor(result.inputFile("moduleB/src/sampleB.xoo"));
+ assertThat(issues).isEmpty();
+ }
+
+ private void activateTODORule() {
+ LoadedActiveRule r = new LoadedActiveRule();
+ r.setRuleKey(RuleKey.of("xoo", HasTagSensor.RULE_KEY));
+ r.setName("TODO");
+ r.setLanguage("xoo");
+ r.setSeverity("MAJOR");
+ r.setDeprecatedKeys(emptySet()
+ );
+ r.setParams(ImmutableMap.of("tag", "TODO"));
+ tester.activateRule(r);
+ }
+
+ @Test
+ public void testIssueDetails() throws IOException {
+ File baseDir = temp.newFolder();
+ File srcDir = new File(baseDir, "src");
+ srcDir.mkdir();
+
+ File xooFile = new File(srcDir, "sample.xoo");
+ FileUtils.write(xooFile, "1\n2\n3\n4\n5\n6\n7\n8\n9\n10", StandardCharsets.UTF_8);
+
+ AnalysisResult result = tester.newAnalysis()
+ .properties(ImmutableMap.<String, String>builder()
+ .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
+ .put("sonar.projectKey", "com.foo.project")
+ .put("sonar.sources", "src")
+ .build())
+ .execute();
+
+ List<Issue> issues = result.issuesFor(result.inputFile("src/sample.xoo"));
+ assertThat(issues).hasSize(10);
+ assertThat(issues)
+ .extracting("msg", "textRange.startLine", "gap")
+ .contains(tuple("This issue is generated on each line", 1, 0.0));
+ }
+
+ @Test
+ public void testIssueFilter() throws Exception {
+ File projectDir = new File("test-resources/mediumtest/xoo/sample");
+ File tmpDir = temp.newFolder();
+ FileUtils.copyDirectory(projectDir, tmpDir);
+
+ AnalysisResult result = tester
+ .newAnalysis(new File(tmpDir, "sonar-project.properties"))
+ .property("sonar.xoo.excludeAllIssuesOnOddLines", "true")
+ .execute();
+
+ List<Issue> issues = result.issuesFor(result.inputFile("xources/hello/HelloJava.xoo"));
+ assertThat(issues).hasSize(4 /* even lines */);
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 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.mediumtest.issues;
+
+import com.google.common.collect.ImmutableMap;
+import java.io.File;
+import java.io.IOException;
+import org.apache.commons.io.FileUtils;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.sonar.scanner.mediumtest.AnalysisResult;
+import org.sonar.scanner.mediumtest.ScannerMediumTester;
+import org.sonar.xoo.XooPlugin;
+import org.sonar.xoo.rule.XooRulesDefinition;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class IssuesOnDirMediumIT {
+
+ @Rule
+ public TemporaryFolder temp = new TemporaryFolder();
+
+ @Rule
+ public ScannerMediumTester tester = new ScannerMediumTester()
+ .registerPlugin("xoo", new XooPlugin())
+ .addDefaultQProfile("xoo", "Sonar Way")
+ .addRules(new XooRulesDefinition())
+ .addActiveRule("xoo", "OneIssueOnDirPerFile", null, "One issue per line", "MINOR", "xoo", "xoo");
+
+ @Test
+ public void scanTempProject() throws IOException {
+
+ File baseDir = temp.getRoot();
+ File srcDir = new File(baseDir, "src");
+ srcDir.mkdir();
+
+ File xooFile1 = new File(srcDir, "sample1.xoo");
+ FileUtils.write(xooFile1, "Sample1 xoo\ncontent");
+
+ File xooFile2 = new File(srcDir, "sample2.xoo");
+ FileUtils.write(xooFile2, "Sample2 xoo\ncontent");
+
+ AnalysisResult result = tester.newAnalysis()
+ .properties(ImmutableMap.<String, String>builder()
+ .put("sonar.task", "scan")
+ .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
+ .put("sonar.projectKey", "com.foo.project")
+ .put("sonar.projectName", "Foo Project")
+ .put("sonar.projectVersion", "1.0-SNAPSHOT")
+ .put("sonar.projectDescription", "Description of Foo Project")
+ .put("sonar.sources", "src")
+ .build())
+ .execute();
+
+ assertThat(result.issuesFor(result.project())).hasSize(2);
+ }
+
+ @Test
+ public void issueOnRootFolder() throws IOException {
+
+ File baseDir = temp.getRoot();
+
+ File xooFile1 = new File(baseDir, "sample1.xoo");
+ FileUtils.write(xooFile1, "Sample1 xoo\ncontent");
+
+ File xooFile2 = new File(baseDir, "sample2.xoo");
+ FileUtils.write(xooFile2, "Sample2 xoo\ncontent");
+
+ AnalysisResult result = tester.newAnalysis()
+ .properties(ImmutableMap.<String, String>builder()
+ .put("sonar.task", "scan")
+ .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
+ .put("sonar.projectKey", "com.foo.project")
+ .put("sonar.projectName", "Foo Project")
+ .put("sonar.projectVersion", "1.0-SNAPSHOT")
+ .put("sonar.projectDescription", "Description of Foo Project")
+ .put("sonar.sources", ".")
+ .build())
+ .execute();
+
+ assertThat(result.issuesFor(result.project())).hasSize(2);
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 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.mediumtest.issues;
+
+import com.google.common.collect.ImmutableMap;
+import java.io.File;
+import java.io.IOException;
+import org.apache.commons.io.FileUtils;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.sonar.scanner.mediumtest.AnalysisResult;
+import org.sonar.scanner.mediumtest.ScannerMediumTester;
+import org.sonar.xoo.XooPlugin;
+import org.sonar.xoo.rule.XooRulesDefinition;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class IssuesOnModuleMediumIT {
+
+ @Rule
+ public TemporaryFolder temp = new TemporaryFolder();
+
+ @Rule
+ public ScannerMediumTester tester = new ScannerMediumTester()
+ .registerPlugin("xoo", new XooPlugin())
+ .addDefaultQProfile("xoo", "Sonar Way")
+ .addRules(new XooRulesDefinition())
+ .addActiveRule("xoo", "OneIssuePerModule", null, "One issue per module", "MINOR", "xoo", "xoo");
+
+ @Test
+ public void scanTempProject() throws IOException {
+
+ File baseDir = temp.getRoot();
+ File srcDir = new File(baseDir, "src");
+ srcDir.mkdir();
+
+ File xooFile1 = new File(srcDir, "sample1.xoo");
+ FileUtils.write(xooFile1, "Sample1 xoo\ncontent");
+
+ AnalysisResult result = tester.newAnalysis()
+ .properties(ImmutableMap.<String, String>builder()
+ .put("sonar.task", "scan")
+ .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
+ .put("sonar.projectKey", "com.foo.project")
+ .put("sonar.projectName", "Foo Project")
+ .put("sonar.projectVersion", "1.0-SNAPSHOT")
+ .put("sonar.projectDescription", "Description of Foo Project")
+ .put("sonar.sources", "src")
+ .build())
+ .execute();
+
+ assertThat(result.issuesFor(result.project())).hasSize(1);
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 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.mediumtest.issues;
+
+import java.io.File;
+import java.util.List;
+import org.apache.commons.io.FileUtils;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.sonar.scanner.mediumtest.AnalysisResult;
+import org.sonar.scanner.mediumtest.ScannerMediumTester;
+import org.sonar.scanner.protocol.output.ScannerReport.Flow;
+import org.sonar.scanner.protocol.output.ScannerReport.FlowType;
+import org.sonar.scanner.protocol.output.ScannerReport.Issue;
+import org.sonar.scanner.protocol.output.ScannerReport.IssueLocation;
+import org.sonar.xoo.XooPlugin;
+import org.sonar.xoo.rule.XooRulesDefinition;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.tuple;
+
+public class MultilineIssuesMediumIT {
+
+ @Rule
+ public TemporaryFolder temp = new TemporaryFolder();
+
+ @Rule
+ public ScannerMediumTester tester = new ScannerMediumTester()
+ .registerPlugin("xoo", new XooPlugin())
+ .addRules(new XooRulesDefinition())
+ .addDefaultQProfile("xoo", "Sonar Way")
+ .addActiveRule("xoo", "MultilineIssue", null, "Multinile Issue", "MAJOR", null, "xoo");
+
+ private AnalysisResult result;
+
+ @Before
+ public void prepare() throws Exception {
+ File projectDir = new File("test-resources/mediumtest/xoo/sample-multiline");
+ File tmpDir = temp.getRoot();
+ FileUtils.copyDirectory(projectDir, tmpDir);
+
+ result = tester
+ .newAnalysis(new File(tmpDir, "sonar-project.properties"))
+ .execute();
+ }
+
+ @Test
+ public void testIssueRange() {
+ List<Issue> issues = result.issuesFor(result.inputFile("xources/hello/Single.xoo"));
+ assertThat(issues).hasSize(1);
+ Issue issue = issues.get(0);
+ assertThat(issue.getMsg()).isEqualTo("Primary location of the issue in xoo code");
+ assertThat(issue.getTextRange().getStartLine()).isEqualTo(6);
+ assertThat(issue.getTextRange().getStartOffset()).isEqualTo(23);
+ assertThat(issue.getTextRange().getEndLine()).isEqualTo(6);
+ assertThat(issue.getTextRange().getEndOffset()).isEqualTo(50);
+ }
+
+ @Test
+ public void testMultilineIssueRange() {
+ List<Issue> issues = result.issuesFor(result.inputFile("xources/hello/Multiline.xoo"));
+ assertThat(issues).hasSize(1);
+ Issue issue = issues.get(0);
+ assertThat(issue.getMsg()).isEqualTo("Primary location of the issue in xoo code");
+ assertThat(issue.getTextRange().getStartLine()).isEqualTo(6);
+ assertThat(issue.getTextRange().getStartOffset()).isEqualTo(23);
+ assertThat(issue.getTextRange().getEndLine()).isEqualTo(7);
+ assertThat(issue.getTextRange().getEndOffset()).isEqualTo(23);
+ }
+
+ @Test
+ public void testFlowWithSingleLocation() {
+ List<Issue> issues = result.issuesFor(result.inputFile("xources/hello/Multiple.xoo"));
+ assertThat(issues).hasSize(1);
+ Issue issue = issues.get(0);
+ assertThat(issue.getMsg()).isEqualTo("Primary location of the issue in xoo code");
+ assertThat(issue.getTextRange().getStartLine()).isEqualTo(6);
+ assertThat(issue.getTextRange().getStartOffset()).isEqualTo(23);
+ assertThat(issue.getTextRange().getEndLine()).isEqualTo(6);
+ assertThat(issue.getTextRange().getEndOffset()).isEqualTo(50);
+
+ assertThat(issue.getFlowList()).hasSize(1);
+ Flow flow = issue.getFlow(0);
+ assertThat(flow.getLocationList()).hasSize(1);
+ IssueLocation additionalLocation = flow.getLocation(0);
+ assertThat(additionalLocation.getMsg()).isEqualTo("Xoo code, flow step #1");
+ assertThat(additionalLocation.getTextRange().getStartLine()).isEqualTo(7);
+ assertThat(additionalLocation.getTextRange().getStartOffset()).isEqualTo(26);
+ assertThat(additionalLocation.getTextRange().getEndLine()).isEqualTo(7);
+ assertThat(additionalLocation.getTextRange().getEndOffset()).isEqualTo(53);
+ }
+
+ @Test
+ public void testFlowsWithMultipleElements() {
+ List<Issue> issues = result.issuesFor(result.inputFile("xources/hello/WithFlow.xoo"));
+ assertThat(issues).hasSize(1);
+ Issue issue = issues.get(0);
+ assertThat(issue.getFlowList()).hasSize(1);
+
+ Flow flow = issue.getFlow(0);
+ assertThat(flow.getLocationList()).hasSize(2);
+ // TODO more assertions
+ }
+
+ @Test
+ public void testFlowsWithTypes() {
+ List<Issue> issues = result.issuesFor(result.inputFile("xources/hello/FlowTypes.xoo"));
+ assertThat(issues).hasSize(1);
+ Issue issue = issues.get(0);
+ assertThat(issue.getFlowList()).hasSize(3);
+
+ assertThat(issue.getFlowList()).extracting(Flow::getType, Flow::getDescription, f -> f.getLocationList().size())
+ .containsExactly(
+ tuple(FlowType.DATA, "flow #1", 1),
+ tuple(FlowType.UNDEFINED, "", 1),
+ tuple(FlowType.EXECUTION, "flow #3", 1));
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 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.mediumtest.issues;
+
+import com.google.common.collect.ImmutableMap;
+import org.junit.Rule;
+import org.junit.Test;
+import org.sonar.api.utils.MessageException;
+import org.sonar.api.utils.log.LogTester;
+import org.sonar.scanner.mediumtest.ScannerMediumTester;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.fail;
+
+public class PreviewMediumIT {
+
+ @Rule
+ public LogTester logTester = new LogTester();
+
+ @Rule
+ public ScannerMediumTester tester = new ScannerMediumTester();
+
+ @Test
+ public void failWhenUsingPreviewMode() {
+ try {
+ tester.newAnalysis()
+ .properties(ImmutableMap.<String, String>builder()
+ .put("sonar.analysis.mode", "preview").build())
+ .execute();
+ fail("Expected exception");
+ } catch (Exception e) {
+ assertThat(e).isInstanceOf(MessageException.class).hasMessage("The preview mode, along with the 'sonar.analysis.mode' parameter, is no more supported. You should stop using this parameter.");
+ }
+ }
+
+ @Test
+ public void failWhenUsingIssuesMode() {
+ try {
+ tester.newAnalysis()
+ .properties(ImmutableMap.<String, String>builder()
+ .put("sonar.analysis.mode", "issues").build())
+ .execute();
+ fail("Expected exception");
+ } catch (Exception e) {
+ assertThat(e).isInstanceOf(MessageException.class).hasMessage("The preview mode, along with the 'sonar.analysis.mode' parameter, is no more supported. You should stop using this parameter.");
+ }
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 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.mediumtest.log;
+
+import java.util.Collections;
+import java.util.Map;
+import javax.annotation.Priority;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.sonar.api.utils.MessageException;
+import org.sonar.batch.bootstrapper.Batch;
+import org.sonar.batch.bootstrapper.EnvironmentInformation;
+import org.sonar.scanner.repository.settings.GlobalSettingsLoader;
+import org.springframework.beans.factory.UnsatisfiedDependencyException;
+
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+public class ExceptionHandlingMediumIT {
+
+ private Batch batch;
+ private static ErrorGlobalSettingsLoader loader;
+
+ @BeforeClass
+ public static void beforeClass() {
+ loader = new ErrorGlobalSettingsLoader();
+ }
+
+ public void setUp(boolean verbose) {
+ Batch.Builder builder = Batch.builder()
+ .setEnableLoggingConfiguration(true)
+ .addComponents(
+ loader,
+ new EnvironmentInformation("mediumTest", "1.0"));
+
+ if (verbose) {
+ builder.setGlobalProperties(Collections.singletonMap("sonar.verbose", "true"));
+ }
+ batch = builder.build();
+ }
+
+ @Test
+ public void test() throws Exception {
+ setUp(false);
+ loader.withCause = false;
+
+ assertThatThrownBy(() -> batch.execute())
+ .isInstanceOf(MessageException.class)
+ .hasMessage("Error loading settings");
+ }
+
+ @Test
+ public void testWithCause() throws Exception {
+ setUp(false);
+ loader.withCause = true;
+
+ assertThatThrownBy(() -> batch.execute())
+ .isInstanceOf(MessageException.class)
+ .hasMessage("Error loading settings")
+ .hasCauseInstanceOf(Throwable.class)
+ .hasRootCauseMessage("Code 401");
+ }
+
+ @Test
+ public void testWithVerbose() {
+ setUp(true);
+ assertThatThrownBy(() -> batch.execute())
+ .isInstanceOf(UnsatisfiedDependencyException.class)
+ .hasMessageContaining("Error loading settings");
+ }
+
+ @Priority(1)
+ private static class ErrorGlobalSettingsLoader implements GlobalSettingsLoader {
+ boolean withCause = false;
+
+ @Override
+ public Map<String, String> loadGlobalSettings() {
+ if (withCause) {
+ IllegalStateException cause = new IllegalStateException("Code 401");
+ throw MessageException.of("Error loading settings", cause);
+ } else {
+ throw MessageException.of("Error loading settings");
+ }
+ }
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 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.mediumtest.log;
+
+import com.google.common.collect.ImmutableMap;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.nio.charset.StandardCharsets;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import org.apache.commons.io.FileUtils;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.sonar.batch.bootstrapper.LogOutput;
+import org.sonar.batch.bootstrapper.LogOutput.Level;
+import org.sonar.scanner.mediumtest.ScannerMediumTester;
+import org.sonar.xoo.XooPlugin;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.fail;
+
+public class LogListenerIT {
+ @Rule
+ public TemporaryFolder temp = new TemporaryFolder();
+
+ private Pattern simpleTimePattern = Pattern.compile("\\d{2}:\\d{2}:\\d{2}");
+ private List<LogEvent> logOutput;
+ private StringBuilder logOutputStr;
+ private ByteArrayOutputStream stdOutTarget;
+ private ByteArrayOutputStream stdErrTarget;
+ private static PrintStream savedStdOut;
+ private static PrintStream savedStdErr;
+
+ @Rule
+ public ScannerMediumTester tester = new ScannerMediumTester()
+ .registerPlugin("xoo", new XooPlugin())
+ .addDefaultQProfile("xoo", "Sonar Way")
+ .setLogOutput(new SimpleLogListener());
+
+ private File baseDir;
+ private ImmutableMap.Builder<String, String> builder;
+
+ @BeforeClass
+ public static void backupStdStreams() {
+ savedStdOut = System.out;
+ savedStdErr = System.err;
+ }
+
+ @AfterClass
+ public static void resumeStdStreams() {
+ if (savedStdOut != null) {
+ System.setOut(savedStdOut);
+ }
+ if (savedStdErr != null) {
+ System.setErr(savedStdErr);
+ }
+ }
+
+ @Before
+ public void prepare() {
+ System.out.flush();
+ System.err.flush();
+ stdOutTarget = new ByteArrayOutputStream();
+ stdErrTarget = new ByteArrayOutputStream();
+ System.setOut(new PrintStream(stdOutTarget));
+ System.setErr(new PrintStream(stdErrTarget));
+ // logger from the batch might write to it asynchronously
+ logOutput = Collections.synchronizedList(new LinkedList<>());
+ logOutputStr = new StringBuilder();
+
+ baseDir = temp.getRoot();
+
+ builder = ImmutableMap.<String, String>builder()
+ .put("sonar.task", "scan")
+ .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
+ .put("sonar.projectKey", "com.foo.project")
+ .put("sonar.projectName", "Foo Project")
+ .put("sonar.projectVersion", "1.0-SNAPSHOT")
+ .put("sonar.projectDescription", "Description of Foo Project");
+ }
+
+ private void assertNoStdOutput() {
+ assertThat(new String(stdOutTarget.toByteArray())).isEmpty();
+ assertThat(new String(stdErrTarget.toByteArray())).isEmpty();
+ }
+
+ /**
+ * Check that log message is not formatted, i.e. has no log level and timestamp.
+ */
+ private void assertMsgClean(String msg) {
+ // FP: [JOURNAL_FLUSHER] WARNING Journal flush operation took 2,093ms last 8 cycles average is 262ms
+ if (msg.contains("[JOURNAL_FLUSHER]")) {
+ return;
+ }
+
+ for (Level l : Level.values()) {
+ assertThat(msg).doesNotContain(l.toString());
+ }
+
+ Matcher matcher = simpleTimePattern.matcher(msg);
+ assertThat(matcher.find()).isFalse();
+ }
+
+ @Test
+ public void testChangeLogForAnalysis() throws IOException {
+ File srcDir = new File(baseDir, "src");
+ srcDir.mkdir();
+
+ File xooFile = new File(srcDir, "sample.xoo");
+ FileUtils.write(xooFile, "Sample xoo\ncontent", StandardCharsets.UTF_8);
+
+ tester.newAnalysis()
+ .properties(builder
+ .put("sonar.sources", "src")
+ .put("sonar.verbose", "true")
+ .build())
+ .execute();
+
+ synchronized (logOutput) {
+ for (LogEvent e : logOutput) {
+ savedStdOut.println("[captured]" + e.level + " " + e.msg);
+ }
+ }
+
+ // only done in DEBUG during analysis
+ assertThat(logOutputStr.toString()).contains("Post-jobs : ");
+ }
+
+ @Test
+ public void testNoStdLog() throws IOException {
+ File srcDir = new File(baseDir, "src");
+ srcDir.mkdir();
+
+ File xooFile = new File(srcDir, "sample.xoo");
+ FileUtils.write(xooFile, "Sample xoo\ncontent", StandardCharsets.UTF_8);
+
+ tester.newAnalysis()
+ .properties(builder
+ .put("sonar.sources", "src")
+ .build())
+ .execute();
+
+ assertNoStdOutput();
+ assertThat(logOutput).isNotEmpty();
+
+ synchronized (logOutput) {
+ for (LogEvent e : logOutput) {
+ savedStdOut.println("[captured]" + e.level + " " + e.msg);
+ }
+ }
+ }
+
+ @Test
+ public void testNoFormattedMsgs() throws IOException {
+ File srcDir = new File(baseDir, "src");
+ srcDir.mkdir();
+
+ File xooFile = new File(srcDir, "sample.xoo");
+ FileUtils.write(xooFile, "Sample xoo\ncontent", StandardCharsets.UTF_8);
+
+ tester.newAnalysis()
+ .properties(builder
+ .put("sonar.sources", "src")
+ .build())
+ .execute();
+
+ assertNoStdOutput();
+
+ synchronized (logOutput) {
+ for (LogEvent e : logOutput) {
+ assertMsgClean(e.msg);
+ savedStdOut.println("[captured]" + e.level + " " + e.msg);
+ }
+ }
+ }
+
+ // SONAR-7540
+ @Test
+ public void testStackTrace() throws IOException {
+ File srcDir = new File(baseDir, "src");
+ srcDir.mkdir();
+
+ File xooFile = new File(srcDir, "sample.xoo");
+ FileUtils.write(xooFile, "Sample xoo\ncontent");
+ File xooFileMeasure = new File(srcDir, "sample.xoo.measures");
+ FileUtils.write(xooFileMeasure, "foo:bar", StandardCharsets.UTF_8);
+
+ try {
+ tester.newAnalysis()
+ .properties(builder
+ .put("sonar.sources", "src")
+ .build())
+ .execute();
+ fail("Expected exception");
+ } catch (Exception e) {
+ assertThat(e.getMessage()).contains("Error processing line 1");
+ }
+
+ assertNoStdOutput();
+
+ synchronized (logOutput) {
+ for (LogEvent e : logOutput) {
+ if (e.level == Level.ERROR) {
+ assertThat(e.msg).contains("Error processing line 1 of file", "src" + File.separator + "sample.xoo.measures",
+ "java.lang.IllegalStateException: Unknown metric with key: foo",
+ "at org.sonar.xoo.lang.MeasureSensor.saveMeasure");
+
+ }
+ }
+ }
+ }
+
+ private class SimpleLogListener implements LogOutput {
+ @Override
+ public void log(String msg, Level level) {
+ logOutput.add(new LogEvent(msg, level));
+ logOutputStr.append(msg).append("\n");
+ }
+ }
+
+ private static class LogEvent {
+ String msg;
+ Level level;
+
+ LogEvent(String msg, Level level) {
+ this.msg = msg;
+ this.level = level;
+ }
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 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.mediumtest.measures;
+
+import com.google.common.collect.ImmutableMap;
+import java.io.File;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.List;
+import java.util.Map;
+import org.apache.commons.io.FileUtils;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.sonar.api.utils.log.LogTester;
+import org.sonar.api.utils.log.LoggerLevel;
+import org.sonar.scanner.mediumtest.AnalysisResult;
+import org.sonar.scanner.mediumtest.ScannerMediumTester;
+import org.sonar.scanner.protocol.output.ScannerReport.Measure;
+import org.sonar.xoo.XooPlugin;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.tuple;
+import static org.junit.Assert.fail;
+
+public class MeasuresMediumIT {
+
+ @Rule
+ public LogTester logTester = new LogTester();
+
+ @Rule
+ public TemporaryFolder temp = new TemporaryFolder();
+
+ private File baseDir;
+ private File srcDir;
+
+ @Rule
+ public ScannerMediumTester tester = new ScannerMediumTester()
+ .registerPlugin("xoo", new XooPlugin())
+ .addDefaultQProfile("xoo", "Sonar Way");
+
+ @Before
+ public void setUp() throws Exception {
+ baseDir = temp.newFolder();
+ srcDir = new File(baseDir, "src");
+ srcDir.mkdir();
+ }
+
+ @Test
+ public void failIfTryingToSaveServerSideMeasure() throws IOException {
+ File xooFile = new File(srcDir, "sample.xoo");
+ FileUtils.write(xooFile, "Sample xoo\n\ncontent", StandardCharsets.UTF_8);
+
+ File measures = new File(srcDir, "sample.xoo.measures");
+ FileUtils.write(measures, "new_lines:2", StandardCharsets.UTF_8);
+
+ try {
+ tester.newAnalysis()
+ .properties(ImmutableMap.<String, String>builder()
+ .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
+ .put("sonar.projectKey", "com.foo.project")
+ .put("sonar.sources", "src")
+ .build())
+ .execute();
+ fail("Expected exception");
+ } catch (Exception e) {
+ assertThat(e)
+ .hasCauseInstanceOf(UnsupportedOperationException.class)
+ .hasStackTraceContaining("Metric 'new_lines' should not be computed by a Sensor");
+ }
+ }
+
+ @Test
+ public void lineMeasures() throws IOException {
+ File xooFile = new File(srcDir, "sample.xoo");
+ FileUtils.write(xooFile, "Sample xoo\n\n\ncontent", StandardCharsets.UTF_8);
+
+ File lineMeasures = new File(srcDir, "sample.xoo.linemeasures");
+ FileUtils.write(lineMeasures, "ncloc_data:1=1;2=0;4=1", StandardCharsets.UTF_8);
+
+ AnalysisResult result = tester.newAnalysis()
+ .properties(ImmutableMap.<String, String>builder()
+ .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
+ .put("sonar.projectKey", "com.foo.project")
+ .put("sonar.sources", "src")
+ .build())
+ .execute();
+
+ Map<String, List<Measure>> allMeasures = result.allMeasures();
+
+ assertThat(allMeasures.get("com.foo.project:src/sample.xoo")).extracting("metricKey", "intValue.value", "stringValue.value")
+ .containsExactly(tuple("ncloc_data", 0, "1=1;4=1"));
+ }
+
+ @Test
+ public void projectLevelMeasures() throws IOException {
+ File xooFile = new File(srcDir, "sample.xoo");
+ FileUtils.write(xooFile, "Sample xoo\n\n\ncontent", StandardCharsets.UTF_8);
+
+ File projectMeasures = new File(baseDir, "module.measures");
+ FileUtils.write(projectMeasures, "tests:10", StandardCharsets.UTF_8);
+
+ AnalysisResult result = tester.newAnalysis()
+ .properties(ImmutableMap.<String, String>builder()
+ .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
+ .put("sonar.projectKey", "com.foo.project")
+ .put("sonar.sources", "src")
+ .build())
+ .execute();
+
+ Map<String, List<Measure>> allMeasures = result.allMeasures();
+
+ assertThat(allMeasures.get("com.foo.project"))
+ .extracting("metricKey", "intValue.value", "stringValue.value")
+ .containsExactly(tuple("tests", 10, ""));
+ }
+
+ @Test
+ public void warnWhenSavingFolderMeasure() throws IOException {
+ File xooFile = new File(srcDir, "sample.xoo");
+ FileUtils.write(xooFile, "Sample xoo\n\n\ncontent", StandardCharsets.UTF_8);
+
+ File folderMeasures = new File(srcDir, "folder.measures");
+ FileUtils.write(folderMeasures, "tests:10", StandardCharsets.UTF_8);
+
+ AnalysisResult result = tester.newAnalysis()
+ .properties(ImmutableMap.<String, String>builder()
+ .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
+ .put("sonar.projectKey", "com.foo.project")
+ .put("sonar.sources", "src")
+ .build())
+ .execute();
+
+
+ assertThat(logTester.logs(LoggerLevel.WARN)).contains("Storing measures on folders or modules is deprecated. Provided value of metric 'tests' is ignored.");
+ }
+
+ @Test
+ public void warnWhenSavingModuleMeasure() throws IOException {
+ File moduleDir = new File(baseDir, "moduleA");
+ moduleDir.mkdirs();
+
+ srcDir = new File(moduleDir, "src");
+
+ File xooFile = new File(srcDir, "sample.xoo");
+ FileUtils.write(xooFile, "Sample xoo\n\n\ncontent", StandardCharsets.UTF_8);
+
+ File moduleMeasures = new File(moduleDir, "module.measures");
+ FileUtils.write(moduleMeasures, "tests:10", StandardCharsets.UTF_8);
+
+ AnalysisResult result = tester.newAnalysis()
+ .properties(ImmutableMap.<String, String>builder()
+ .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
+ .put("sonar.projectKey", "com.foo.project")
+ .put("sonar.modules", "moduleA")
+ .put("sonar.sources", "src")
+ .build())
+ .execute();
+
+
+ assertThat(logTester.logs(LoggerLevel.WARN)).contains("Storing measures on folders or modules is deprecated. Provided value of metric 'tests' is ignored.");
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 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.mediumtest.scm;
+
+import com.google.common.collect.ImmutableMap;
+import java.io.File;
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.nio.charset.StandardCharsets;
+import java.util.regex.Pattern;
+import org.apache.commons.codec.digest.DigestUtils;
+import org.apache.commons.io.FileUtils;
+import org.assertj.core.util.Files;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.sonar.api.SonarEdition;
+import org.sonar.api.utils.log.LogTester;
+import org.sonar.scanner.mediumtest.ScannerMediumTester;
+import org.sonar.scanner.mediumtest.ScannerMediumTester.AnalysisBuilder;
+import org.sonar.scanner.protocol.output.FileStructure;
+import org.sonar.scanner.protocol.output.ScannerReport;
+import org.sonar.scanner.protocol.output.ScannerReport.Changesets.Changeset;
+import org.sonar.scanner.protocol.output.ScannerReport.Component;
+import org.sonar.scanner.protocol.output.ScannerReportReader;
+import org.sonar.scanner.repository.FileData;
+import org.sonar.xoo.XooPlugin;
+import org.sonar.xoo.rule.XooRulesDefinition;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class ScmMediumIT {
+
+ private static final String MISSING_BLAME_INFORMATION_FOR_THE_FOLLOWING_FILES = "Missing blame information for the following files:";
+ private static final String CHANGED_CONTENT_SCM_ON_SERVER_XOO = "src/changed_content_scm_on_server.xoo";
+ private static final String NO_BLAME_SCM_ON_SERVER_XOO = "src/no_blame_scm_on_server.xoo";
+ private static final String SAME_CONTENT_SCM_ON_SERVER_XOO = "src/same_content_scm_on_server.xoo";
+ private static final String SAME_CONTENT_NO_SCM_ON_SERVER_XOO = "src/same_content_no_scm_on_server.xoo";
+ private static final String SAMPLE_XOO_CONTENT = "Sample xoo\ncontent";
+
+ @Rule
+ public TemporaryFolder temp = new TemporaryFolder();
+
+ @Rule
+ public LogTester logTester = new LogTester();
+
+ @Rule
+ public ScannerMediumTester tester = new ScannerMediumTester()
+ .setEdition(SonarEdition.COMMUNITY)
+ .registerPlugin("xoo", new XooPlugin())
+ .addDefaultQProfile("xoo", "Sonar Way")
+ .addRules(new XooRulesDefinition())
+ // active a rule just to be sure that xoo files are published
+ .addActiveRule("xoo", "xoo:OneIssuePerFile", null, "One Issue Per File", null, null, null)
+ .addFileData(CHANGED_CONTENT_SCM_ON_SERVER_XOO, new FileData(DigestUtils.md5Hex(SAMPLE_XOO_CONTENT), null))
+ .addFileData(SAME_CONTENT_NO_SCM_ON_SERVER_XOO, new FileData(DigestUtils.md5Hex(SAMPLE_XOO_CONTENT), null))
+ .addFileData(SAME_CONTENT_SCM_ON_SERVER_XOO, new FileData(DigestUtils.md5Hex(SAMPLE_XOO_CONTENT), "1.1"))
+ .addFileData(NO_BLAME_SCM_ON_SERVER_XOO, new FileData(DigestUtils.md5Hex(SAMPLE_XOO_CONTENT), "1.1"));
+
+ @Test
+ public void testScmMeasure() throws IOException, URISyntaxException {
+ File baseDir = prepareProject();
+
+ tester.newAnalysis()
+ .properties(ImmutableMap.<String, String>builder()
+ .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
+ .put("sonar.projectKey", "com.foo.project")
+ .put("sonar.sources", "src")
+ .put("sonar.scm.provider", "xoo")
+ .build())
+ .execute();
+
+ ScannerReport.Changesets fileScm = getChangesets(baseDir, "src/sample.xoo");
+
+ assertThat(fileScm.getChangesetIndexByLineList()).hasSize(5);
+
+ Changeset changesetLine1 = fileScm.getChangeset(fileScm.getChangesetIndexByLine(0));
+ assertThat(changesetLine1.getAuthor()).isEmpty();
+
+ Changeset changesetLine2 = fileScm.getChangeset(fileScm.getChangesetIndexByLine(1));
+ assertThat(changesetLine2.getAuthor()).isEqualTo(getNonAsciiAuthor().toLowerCase());
+
+ Changeset changesetLine3 = fileScm.getChangeset(fileScm.getChangesetIndexByLine(2));
+ assertThat(changesetLine3.getAuthor()).isEqualTo("julien");
+
+ Changeset changesetLine4 = fileScm.getChangeset(fileScm.getChangesetIndexByLine(3));
+ assertThat(changesetLine4.getAuthor()).isEqualTo("julien");
+
+ Changeset changesetLine5 = fileScm.getChangeset(fileScm.getChangesetIndexByLine(4));
+ assertThat(changesetLine5.getAuthor()).isEqualTo("simon");
+ }
+
+ private ScannerReport.Changesets getChangesets(File baseDir, String path) {
+ File reportDir = new File(baseDir, ".sonar/scanner-report");
+ FileStructure fileStructure = new FileStructure(reportDir);
+ ScannerReportReader reader = new ScannerReportReader(fileStructure);
+
+ Component project = reader.readComponent(reader.readMetadata().getRootComponentRef());
+ for (Integer fileRef : project.getChildRefList()) {
+ Component file = reader.readComponent(fileRef);
+ if (file.getProjectRelativePath().equals(path)) {
+ return reader.readChangesets(file.getRef());
+ }
+ }
+ return null;
+ }
+
+ @Test
+ public void noScmOnEmptyFile() throws IOException, URISyntaxException {
+
+ File baseDir = prepareProject();
+
+ // Clear file content
+ FileUtils.write(new File(baseDir, "src/sample.xoo"), "");
+
+ tester.newAnalysis()
+ .properties(ImmutableMap.<String, String>builder()
+ .put("sonar.task", "scan")
+ .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
+ .put("sonar.projectKey", "com.foo.project")
+ .put("sonar.projectName", "Foo Project")
+ .put("sonar.projectVersion", "1.0-SNAPSHOT")
+ .put("sonar.projectDescription", "Description of Foo Project")
+ .put("sonar.sources", "src")
+ .put("sonar.scm.provider", "xoo")
+ .build())
+ .execute();
+
+ ScannerReport.Changesets changesets = getChangesets(baseDir, "src/sample.xoo");
+
+ assertThat(changesets).isNull();
+ }
+
+ @Test
+ public void log_files_with_missing_blame() throws IOException, URISyntaxException {
+
+ File baseDir = prepareProject();
+ File xooFileWithoutBlame = new File(baseDir, "src/sample_no_blame.xoo");
+ FileUtils.write(xooFileWithoutBlame, "Sample xoo\ncontent\n3\n4\n5", StandardCharsets.UTF_8);
+
+ tester.newAnalysis()
+ .properties(ImmutableMap.<String, String>builder()
+ .put("sonar.task", "scan")
+ .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
+ .put("sonar.projectKey", "com.foo.project")
+ .put("sonar.projectName", "Foo Project")
+ .put("sonar.projectVersion", "1.0-SNAPSHOT")
+ .put("sonar.projectDescription", "Description of Foo Project")
+ .put("sonar.sources", "src")
+ .put("sonar.scm.provider", "xoo")
+ .build())
+ .execute();
+
+ ScannerReport.Changesets file1Scm = getChangesets(baseDir, "src/sample.xoo");
+ assertThat(file1Scm).isNotNull();
+
+ ScannerReport.Changesets fileWithoutBlameScm = getChangesets(baseDir, "src/sample_no_blame.xoo");
+ assertThat(fileWithoutBlameScm).isNull();
+
+ assertThat(logTester.logs()).containsSubsequence("SCM Publisher 2 source files to be analyzed", MISSING_BLAME_INFORMATION_FOR_THE_FOLLOWING_FILES,
+ " * src/sample_no_blame.xoo");
+
+ assertThat(logTester.logs().stream().anyMatch(s -> Pattern.matches("SCM Publisher 1/2 source file have been analyzed \\(done\\) \\| time=[0-9]+ms", s))).isTrue();
+ }
+
+ // SONAR-6397
+ @Test
+ public void optimize_blame() throws IOException, URISyntaxException {
+
+ File baseDir = prepareProject();
+ File changedContentScmOnServer = new File(baseDir, CHANGED_CONTENT_SCM_ON_SERVER_XOO);
+ FileUtils.write(changedContentScmOnServer, SAMPLE_XOO_CONTENT + "\nchanged", StandardCharsets.UTF_8);
+ File xooScmFile = new File(baseDir, CHANGED_CONTENT_SCM_ON_SERVER_XOO + ".scm");
+ FileUtils.write(xooScmFile,
+ // revision,author,dateTime
+ "1,foo,2013-01-04\n" +
+ "1,bar,2013-01-04\n" +
+ "2,biz,2014-01-04\n",
+ StandardCharsets.UTF_8);
+
+ File sameContentScmOnServer = new File(baseDir, SAME_CONTENT_SCM_ON_SERVER_XOO);
+ FileUtils.write(sameContentScmOnServer, SAMPLE_XOO_CONTENT, StandardCharsets.UTF_8);
+ // No need to write .scm file since this file should not be blamed
+
+ File noBlameScmOnServer = new File(baseDir, NO_BLAME_SCM_ON_SERVER_XOO);
+ FileUtils.write(noBlameScmOnServer, SAMPLE_XOO_CONTENT + "\nchanged", StandardCharsets.UTF_8);
+ // No .scm file to emulate a failure during blame
+
+ File sameContentNoScmOnServer = new File(baseDir, SAME_CONTENT_NO_SCM_ON_SERVER_XOO);
+ FileUtils.write(sameContentNoScmOnServer, SAMPLE_XOO_CONTENT, StandardCharsets.UTF_8);
+ xooScmFile = new File(baseDir, SAME_CONTENT_NO_SCM_ON_SERVER_XOO + ".scm");
+ FileUtils.write(xooScmFile,
+ // revision,author,dateTime
+ "1,foo,2013-01-04\n" +
+ "1,bar,2013-01-04\n",
+ StandardCharsets.UTF_8);
+
+ tester.newAnalysis()
+ .properties(ImmutableMap.<String, String>builder()
+ .put("sonar.task", "scan")
+ .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
+ .put("sonar.projectKey", "com.foo.project")
+ .put("sonar.projectName", "Foo Project")
+ .put("sonar.projectVersion", "1.0-SNAPSHOT")
+ .put("sonar.projectDescription", "Description of Foo Project")
+ .put("sonar.sources", "src")
+ .put("sonar.scm.provider", "xoo")
+ .build())
+ .execute();
+
+ assertThat(getChangesets(baseDir, "src/sample.xoo")).isNotNull();
+
+ assertThat(getChangesets(baseDir, CHANGED_CONTENT_SCM_ON_SERVER_XOO).getCopyFromPrevious()).isFalse();
+
+ assertThat(getChangesets(baseDir, SAME_CONTENT_SCM_ON_SERVER_XOO).getCopyFromPrevious()).isTrue();
+
+ assertThat(getChangesets(baseDir, SAME_CONTENT_NO_SCM_ON_SERVER_XOO).getCopyFromPrevious()).isFalse();
+
+ assertThat(getChangesets(baseDir, NO_BLAME_SCM_ON_SERVER_XOO)).isNull();
+
+ // 5 .xoo files + 3 .scm files, but only 4 marked for publishing. 1 file is SAME so not included in the total
+ assertThat(logTester.logs()).containsSubsequence("8 files indexed");
+ assertThat(logTester.logs()).containsSubsequence("SCM Publisher 4 source files to be analyzed");
+ assertThat(logTester.logs().stream().anyMatch(s -> Pattern.matches("SCM Publisher 3/4 source files have been analyzed \\(done\\) \\| time=[0-9]+ms", s))).isTrue();
+ assertThat(logTester.logs()).containsSubsequence(MISSING_BLAME_INFORMATION_FOR_THE_FOLLOWING_FILES, " * src/no_blame_scm_on_server.xoo");
+ }
+
+ @Test
+ public void forceReload() throws IOException, URISyntaxException {
+
+ File baseDir = prepareProject();
+ File xooFileNoScm = new File(baseDir, SAME_CONTENT_SCM_ON_SERVER_XOO);
+ FileUtils.write(xooFileNoScm, SAMPLE_XOO_CONTENT, StandardCharsets.UTF_8);
+ File xooScmFile = new File(baseDir, SAME_CONTENT_SCM_ON_SERVER_XOO + ".scm");
+ FileUtils.write(xooScmFile,
+ // revision,author,dateTime
+ "1,foo,2013-01-04\n" +
+ "1,bar,2013-01-04\n",
+ StandardCharsets.UTF_8);
+
+ AnalysisBuilder analysisBuilder = tester.newAnalysis()
+ .properties(ImmutableMap.<String, String>builder()
+ .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
+ .put("sonar.projectKey", "com.foo.project")
+ .put("sonar.sources", "src")
+ .put("sonar.scm.provider", "xoo")
+ // Force reload
+ .put("sonar.scm.forceReloadAll", "true")
+ .build());
+
+ analysisBuilder.execute();
+
+ ScannerReport.Changesets file1Scm = getChangesets(baseDir, "src/sample.xoo");
+ assertThat(file1Scm).isNotNull();
+
+ ScannerReport.Changesets file2Scm = getChangesets(baseDir, SAME_CONTENT_SCM_ON_SERVER_XOO);
+ assertThat(file2Scm).isNotNull();
+ }
+
+ @Test
+ public void configureUsingScmURL() throws IOException, URISyntaxException {
+
+ File baseDir = prepareProject();
+
+ tester.newAnalysis()
+ .properties(ImmutableMap.<String, String>builder()
+ .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
+ .put("sonar.projectKey", "com.foo.project")
+ .put("sonar.sources", "src")
+ .put("sonar.links.scm_dev", "scm:xoo:foobar")
+ .build())
+ .execute();
+
+ ScannerReport.Changesets file1Scm = getChangesets(baseDir, "src/sample.xoo");
+ assertThat(file1Scm).isNotNull();
+ }
+
+ @Test
+ public void testAutoDetection() throws IOException, URISyntaxException {
+
+ File baseDir = prepareProject();
+ new File(baseDir, ".xoo").createNewFile();
+
+ tester.newAnalysis()
+ .properties(ImmutableMap.<String, String>builder()
+ .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
+ .put("sonar.projectKey", "com.foo.project")
+ .put("sonar.sources", "src")
+ .build())
+ .execute();
+
+ ScannerReport.Changesets file1Scm = getChangesets(baseDir, "src/sample.xoo");
+ assertThat(file1Scm).isNotNull();
+ }
+
+ private String getNonAsciiAuthor() {
+ return Files.contentOf(new File("test-resources/mediumtest/blameAuthor.txt"), StandardCharsets.UTF_8);
+
+ }
+
+ private File prepareProject() throws IOException {
+ File baseDir = temp.getRoot();
+ File srcDir = new File(baseDir, "src");
+ srcDir.mkdir();
+
+ File xooFile1 = new File(srcDir, "sample.xoo");
+ FileUtils.write(xooFile1, "Sample xoo\ncontent\n3\n4\n5", StandardCharsets.UTF_8);
+ File xooScmFile1 = new File(srcDir, "sample.xoo.scm");
+ FileUtils.write(xooScmFile1,
+ // revision,author,dateTime
+ "1,,2013-01-04\n" +
+ "2," + getNonAsciiAuthor() + ",2013-01-04\n" +
+ "3,julien,2013-02-03\n" +
+ "3,julien,2013-02-03\n" +
+ "4,simon,2013-03-04\n",
+ StandardCharsets.UTF_8);
+
+ return baseDir;
+ }
+
+ @Test
+ public void testDisableScmSensor() throws IOException, URISyntaxException {
+
+ File baseDir = prepareProject();
+
+ tester.newAnalysis()
+ .properties(ImmutableMap.<String, String>builder()
+ .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
+ .put("sonar.projectKey", "com.foo.project")
+ .put("sonar.sources", "src")
+ .put("sonar.scm.disabled", "true")
+ .put("sonar.scm.provider", "xoo")
+ .put("sonar.cpd.xoo.skip", "true")
+ .build())
+ .execute();
+
+ ScannerReport.Changesets changesets = getChangesets(baseDir, "src/sample.xoo");
+ assertThat(changesets).isNull();
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 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.mediumtest.symbol;
+
+import com.google.common.collect.ImmutableMap;
+import java.io.File;
+import java.io.IOException;
+import org.apache.commons.io.FileUtils;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.sonar.api.batch.fs.InputFile;
+import org.sonar.scanner.mediumtest.AnalysisResult;
+import org.sonar.scanner.mediumtest.ScannerMediumTester;
+import org.sonar.scanner.protocol.output.ScannerReport;
+import org.sonar.xoo.XooPlugin;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class SymbolMediumIT {
+
+ @Rule
+ public TemporaryFolder temp = new TemporaryFolder();
+
+ @Rule
+ public ScannerMediumTester tester = new ScannerMediumTester()
+ .registerPlugin("xoo", new XooPlugin())
+ .addDefaultQProfile("xoo", "Sonar Way");
+
+ @Test
+ public void computeSymbolReferencesOnTempProject() throws IOException {
+
+ File baseDir = temp.getRoot();
+ File srcDir = new File(baseDir, "src");
+ srcDir.mkdir();
+
+ File xooFile = new File(srcDir, "sample.xoo");
+ File xooSymbolFile = new File(srcDir, "sample.xoo.symbol");
+ FileUtils.write(xooFile, "Sample xoo\ncontent\nanother xoo");
+ // Highlight xoo symbol
+ FileUtils.write(xooSymbolFile, "1:7:1:10,3:8:3:11");
+
+ AnalysisResult result = tester.newAnalysis()
+ .properties(ImmutableMap.<String, String>builder()
+ .put("sonar.task", "scan")
+ .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
+ .put("sonar.projectKey", "com.foo.project")
+ .put("sonar.projectName", "Foo Project")
+ .put("sonar.projectVersion", "1.0-SNAPSHOT")
+ .put("sonar.projectDescription", "Description of Foo Project")
+ .put("sonar.sources", "src")
+ .build())
+ .execute();
+
+ InputFile file = result.inputFile("src/sample.xoo");
+ assertThat(result.symbolReferencesFor(file, 1, 7)).containsOnly(ScannerReport.TextRange.newBuilder().setStartLine(3).setStartOffset(8).setEndLine(3).setEndOffset(11).build());
+ }
+
+ @Test
+ public void computeSymbolReferencesWithVariableLength() throws IOException {
+
+ File baseDir = temp.getRoot();
+ File srcDir = new File(baseDir, "src");
+ srcDir.mkdir();
+
+ File xooFile = new File(srcDir, "sample.xoo");
+ File xooSymbolFile = new File(srcDir, "sample.xoo.symbol");
+ FileUtils.write(xooFile, "Sample xoo\ncontent\nanother xoo\nyet another");
+ // Highlight xoo symbol
+ FileUtils.write(xooSymbolFile, "1:7:1:10,3:8:4:1");
+
+ AnalysisResult result = tester.newAnalysis()
+ .properties(ImmutableMap.<String, String>builder()
+ .put("sonar.task", "scan")
+ .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
+ .put("sonar.projectKey", "com.foo.project")
+ .put("sonar.projectName", "Foo Project")
+ .put("sonar.projectVersion", "1.0-SNAPSHOT")
+ .put("sonar.projectDescription", "Description of Foo Project")
+ .put("sonar.sources", "src")
+ .build())
+ .execute();
+
+ InputFile file = result.inputFile("src/sample.xoo");
+ assertThat(result.symbolReferencesFor(file, 1, 7)).containsOnly(ScannerReport.TextRange.newBuilder().setStartLine(3).setStartOffset(8).setEndLine(4).setEndOffset(1).build());
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 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.mediumtest.tasks;
+
+import com.google.common.collect.ImmutableMap;
+import org.junit.Rule;
+import org.junit.Test;
+import org.sonar.api.Plugin;
+import org.sonar.api.utils.MessageException;
+import org.sonar.api.utils.log.LogTester;
+import org.sonar.scanner.mediumtest.ScannerMediumTester;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.fail;
+
+public class TasksMediumIT {
+
+ @Rule
+ public LogTester logTester = new LogTester();
+
+ @Rule
+ public ScannerMediumTester tester = new ScannerMediumTester()
+ .registerPlugin("faketask", new FakePlugin());
+
+ @Test
+ public void failWhenCallingTask() {
+ try {
+ tester.newAnalysis()
+ .properties(ImmutableMap.<String, String>builder()
+ .put("sonar.task", "fake").build())
+ .execute();
+ fail("Expected exception");
+ } catch (Exception e) {
+ assertThat(e).isInstanceOf(MessageException.class).hasMessage("Tasks support was removed in SonarQube 7.6.");
+ }
+ }
+
+ @Test
+ public void failWhenCallingViews() {
+ try {
+ tester.newAnalysis()
+ .properties(ImmutableMap.<String, String>builder()
+ .put("sonar.task", "views").build())
+ .execute();
+ fail("Expected exception");
+ } catch (Exception e) {
+ assertThat(e).isInstanceOf(MessageException.class).hasMessage("The task 'views' was removed with SonarQube 7.1. You can safely remove this call since portfolios and applications are automatically re-calculated.");
+ }
+ }
+
+ private static class FakePlugin implements Plugin {
+
+ @Override
+ public void define(Context context) {
+ }
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 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.mediumtest.tests;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+import org.junit.Rule;
+import org.junit.Test;
+import org.sonar.api.batch.fs.InputFile;
+import org.sonar.api.measures.CoreMetrics;
+import org.sonar.scanner.mediumtest.AnalysisResult;
+import org.sonar.scanner.mediumtest.ScannerMediumTester;
+import org.sonar.xoo.XooPlugin;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.tuple;
+
+public class GenericTestExecutionMediumIT {
+ private final List<String> logs = new ArrayList<>();
+
+ @Rule
+ public ScannerMediumTester tester = new ScannerMediumTester()
+ .registerPlugin("xoo", new XooPlugin())
+ .addDefaultQProfile("xoo", "Sonar Way");
+
+ @Test
+ public void singleReport() {
+
+ File projectDir = new File("test-resources/mediumtest/xoo/sample-generic-test-exec");
+
+ AnalysisResult result = tester
+ .setLogOutput((msg, level) -> logs.add(msg))
+ .newAnalysis(new File(projectDir, "sonar-project.properties"))
+ .property("sonar.testExecutionReportPaths", "unittest.xml")
+ .execute();
+
+ InputFile testFile = result.inputFile("testx/ClassOneTest.xoo");
+ assertThat(result.allMeasures().get(testFile.key())).extracting("metricKey", "intValue.value", "longValue.value")
+ .containsOnly(
+ tuple(CoreMetrics.TESTS_KEY, 3, 0L),
+ tuple(CoreMetrics.SKIPPED_TESTS_KEY, 1, 0L),
+ tuple(CoreMetrics.TEST_ERRORS_KEY, 1, 0L),
+ tuple(CoreMetrics.TEST_EXECUTION_TIME_KEY, 0, 1105L),
+ tuple(CoreMetrics.TEST_FAILURES_KEY, 1, 0L));
+
+ assertThat(logs).noneMatch(l -> l.contains("Please use 'sonar.testExecutionReportPaths'"));
+ }
+
+ @Test
+ public void twoReports() {
+
+ File projectDir = new File("test-resources/mediumtest/xoo/sample-generic-test-exec");
+
+ AnalysisResult result = tester
+ .setLogOutput((msg, level) -> logs.add(msg))
+ .newAnalysis(new File(projectDir, "sonar-project.properties"))
+ .property("sonar.testExecutionReportPaths", "unittest.xml,unittest2.xml")
+ .execute();
+
+ InputFile testFile = result.inputFile("testx/ClassOneTest.xoo");
+ assertThat(result.allMeasures().get(testFile.key())).extracting("metricKey", "intValue.value", "longValue.value")
+ .containsOnly(
+ tuple(CoreMetrics.TESTS_KEY, 4, 0L),
+ tuple(CoreMetrics.SKIPPED_TESTS_KEY, 2, 0L),
+ tuple(CoreMetrics.TEST_ERRORS_KEY, 1, 0L),
+ tuple(CoreMetrics.TEST_EXECUTION_TIME_KEY, 0, 1610L),
+ tuple(CoreMetrics.TEST_FAILURES_KEY, 1, 0L));
+
+ assertThat(logs).noneMatch(l -> l.contains("Please use 'sonar.testExecutionReportPaths'"));
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 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.scm.svn;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardOpenOption;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.stream.IntStream;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+import org.mockito.ArgumentCaptor;
+import org.sonar.api.batch.fs.FileSystem;
+import org.sonar.api.batch.fs.InputFile;
+import org.sonar.api.batch.fs.internal.DefaultInputFile;
+import org.sonar.api.batch.fs.internal.TestInputFileBuilder;
+import org.sonar.api.batch.scm.BlameCommand.BlameInput;
+import org.sonar.api.batch.scm.BlameCommand.BlameOutput;
+import org.sonar.api.batch.scm.BlameLine;
+import org.sonar.api.utils.log.LogTester;
+import org.sonar.api.utils.log.LoggerLevel;
+import org.tmatesoft.svn.core.SVNAuthenticationException;
+import org.tmatesoft.svn.core.SVNDepth;
+import org.tmatesoft.svn.core.SVNURL;
+import org.tmatesoft.svn.core.auth.ISVNAuthenticationManager;
+import org.tmatesoft.svn.core.internal.wc2.compat.SvnCodec;
+import org.tmatesoft.svn.core.wc.ISVNOptions;
+import org.tmatesoft.svn.core.wc.SVNClientManager;
+import org.tmatesoft.svn.core.wc.SVNLogClient;
+import org.tmatesoft.svn.core.wc.SVNRevision;
+import org.tmatesoft.svn.core.wc.SVNStatus;
+import org.tmatesoft.svn.core.wc.SVNStatusClient;
+import org.tmatesoft.svn.core.wc.SVNStatusType;
+import org.tmatesoft.svn.core.wc.SVNUpdateClient;
+import org.tmatesoft.svn.core.wc.SVNWCUtil;
+import org.tmatesoft.svn.core.wc2.SvnCheckout;
+import org.tmatesoft.svn.core.wc2.SvnTarget;
+
+import static java.util.Collections.singletonList;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.Assert.assertThrows;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyBoolean;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoInteractions;
+import static org.mockito.Mockito.when;
+
+@RunWith(Parameterized.class)
+public class SvnBlameCommandIT {
+
+ /*
+ * Note about SONARSCSVN-11: The case of a project baseDir is in a subFolder of working copy is part of method tests by default
+ */
+
+ private static final String DUMMY_JAVA = "src/main/java/org/dummy/Dummy.java";
+
+ @Rule
+ public TemporaryFolder temp = new TemporaryFolder();
+
+ @Rule
+ public LogTester logTester = new LogTester();
+
+ private FileSystem fs;
+ private BlameInput input;
+ private String serverVersion;
+ private int wcVersion;
+
+ @Parameters(name = "SVN server version {0}, WC version {1}")
+ public static Iterable<Object[]> data() {
+ return Arrays.asList(new Object[][] {{"1.6", 10}, {"1.7", 29}, {"1.8", 31}, {"1.9", 31}});
+ }
+
+ public SvnBlameCommandIT(String serverVersion, int wcVersion) {
+ this.serverVersion = serverVersion;
+ this.wcVersion = wcVersion;
+ }
+
+ @Before
+ public void prepare() {
+ fs = mock(FileSystem.class);
+ input = mock(BlameInput.class);
+ when(input.fileSystem()).thenReturn(fs);
+ }
+
+ @Test
+ public void testParsingOfOutput() throws Exception {
+ File repoDir = unzip("repo-svn.zip");
+
+ String scmUrl = "file:///" + unixPath(new File(repoDir, "repo-svn"));
+ File baseDir = new File(checkout(scmUrl), "dummy-svn");
+
+ when(fs.baseDir()).thenReturn(baseDir);
+ DefaultInputFile inputFile = new TestInputFileBuilder("foo", DUMMY_JAVA)
+ .setLines(27)
+ .setModuleBaseDir(baseDir.toPath())
+ .build();
+
+ BlameOutput blameResult = mock(BlameOutput.class);
+ when(input.filesToBlame()).thenReturn(singletonList(inputFile));
+
+ newSvnBlameCommand().blame(input, blameResult);
+ ArgumentCaptor<List> captor = ArgumentCaptor.forClass(List.class);
+ verify(blameResult).blameResult(eq(inputFile), captor.capture());
+ List<BlameLine> result = captor.getValue();
+ assertThat(result).hasSize(27);
+ Date commitDate = new Date(1342691097393L);
+ BlameLine[] expected = IntStream.rangeClosed(1, 27).mapToObj(i -> new BlameLine().date(commitDate).revision("2").author("dgageot")).toArray(BlameLine[]::new);
+ assertThat(result).containsExactly(expected);
+ }
+
+ private File unzip(String repoName) throws IOException {
+ File repoDir = temp.newFolder();
+ try {
+ javaUnzip(Paths.get(this.getClass().getResource("test-repos").toURI()).resolve(serverVersion).resolve(repoName).toFile(), repoDir);
+ return repoDir;
+ } catch (URISyntaxException e) {
+ throw new IOException(e);
+ }
+ }
+
+ private File checkout(String scmUrl) throws Exception {
+ ISVNOptions options = SVNWCUtil.createDefaultOptions(true);
+ ISVNAuthenticationManager isvnAuthenticationManager = SVNWCUtil.createDefaultAuthenticationManager(null, null, (char[]) null, false);
+ SVNClientManager svnClientManager = SVNClientManager.newInstance(options, isvnAuthenticationManager);
+ File out = temp.newFolder();
+ SVNUpdateClient updateClient = svnClientManager.getUpdateClient();
+ SvnCheckout co = updateClient.getOperationsFactory().createCheckout();
+ co.setUpdateLocksOnDemand(updateClient.isUpdateLocksOnDemand());
+ co.setSource(SvnTarget.fromURL(SVNURL.parseURIEncoded(scmUrl), SVNRevision.HEAD));
+ co.setSingleTarget(SvnTarget.fromFile(out));
+ co.setRevision(SVNRevision.HEAD);
+ co.setDepth(SVNDepth.INFINITY);
+ co.setAllowUnversionedObstructions(false);
+ co.setIgnoreExternals(updateClient.isIgnoreExternals());
+ co.setExternalsHandler(SvnCodec.externalsHandler(updateClient.getExternalsHandler()));
+ co.setTargetWorkingCopyFormat(wcVersion);
+ co.run();
+ return out;
+ }
+
+ @Test
+ public void testParsingOfOutputWithMergeHistory() throws Exception {
+ File repoDir = unzip("repo-svn-with-merge.zip");
+
+ String scmUrl = "file:///" + unixPath(new File(repoDir, "repo-svn"));
+ File baseDir = new File(checkout(scmUrl), "dummy-svn/trunk");
+
+ when(fs.baseDir()).thenReturn(baseDir);
+ DefaultInputFile inputFile = new TestInputFileBuilder("foo", DUMMY_JAVA)
+ .setLines(27)
+ .setModuleBaseDir(baseDir.toPath())
+ .build();
+
+ BlameOutput blameResult = mock(BlameOutput.class);
+ when(input.filesToBlame()).thenReturn(singletonList(inputFile));
+
+ newSvnBlameCommand().blame(input, blameResult);
+ ArgumentCaptor<List> captor = ArgumentCaptor.forClass(List.class);
+ verify(blameResult).blameResult(eq(inputFile), captor.capture());
+ List<BlameLine> result = captor.getValue();
+ assertThat(result).hasSize(27);
+ Date commitDate = new Date(1342691097393L);
+ Date revision6Date = new Date(1415262184300L);
+
+ BlameLine[] expected = IntStream.rangeClosed(1, 27).mapToObj(i -> {
+ if (i == 2 || i == 24) {
+ return new BlameLine().date(revision6Date).revision("6").author("henryju");
+ } else {
+ return new BlameLine().date(commitDate).revision("2").author("dgageot");
+ }
+ }).toArray(BlameLine[]::new);
+
+ assertThat(result).containsExactly(expected);
+ }
+
+ @Test
+ public void shouldNotFailIfFileContainsLocalModification() throws Exception {
+ File repoDir = unzip("repo-svn.zip");
+
+ String scmUrl = "file:///" + unixPath(new File(repoDir, "repo-svn"));
+ File baseDir = new File(checkout(scmUrl), "dummy-svn");
+
+ when(fs.baseDir()).thenReturn(baseDir);
+ DefaultInputFile inputFile = new TestInputFileBuilder("foo", DUMMY_JAVA)
+ .setLines(28)
+ .setModuleBaseDir(baseDir.toPath())
+ .build();
+
+ Files.write(baseDir.toPath().resolve(DUMMY_JAVA), "\n//foo".getBytes(), StandardOpenOption.APPEND);
+
+ BlameOutput blameResult = mock(BlameOutput.class);
+ when(input.filesToBlame()).thenReturn(singletonList(inputFile));
+
+ newSvnBlameCommand().blame(input, blameResult);
+ verifyNoInteractions(blameResult);
+ }
+
+ // SONARSCSVN-7
+ @Test
+ public void shouldNotFailOnWrongFilename() throws Exception {
+ File repoDir = unzip("repo-svn.zip");
+
+ String scmUrl = "file:///" + unixPath(new File(repoDir, "repo-svn"));
+ File baseDir = new File(checkout(scmUrl), "dummy-svn");
+
+ when(fs.baseDir()).thenReturn(baseDir);
+ DefaultInputFile inputFile = new TestInputFileBuilder("foo", DUMMY_JAVA.toLowerCase())
+ .setLines(27)
+ .setModuleBaseDir(baseDir.toPath())
+ .build();
+
+ BlameOutput blameResult = mock(BlameOutput.class);
+ when(input.filesToBlame()).thenReturn(singletonList(inputFile));
+
+ newSvnBlameCommand().blame(input, blameResult);
+ verifyNoInteractions(blameResult);
+ }
+
+ @Test
+ public void shouldNotFailOnUncommitedFile() throws Exception {
+ File repoDir = unzip("repo-svn.zip");
+
+ String scmUrl = "file:///" + unixPath(new File(repoDir, "repo-svn"));
+ File baseDir = new File(checkout(scmUrl), "dummy-svn");
+
+ when(fs.baseDir()).thenReturn(baseDir);
+ String relativePath = "src/main/java/org/dummy/Dummy2.java";
+ DefaultInputFile inputFile = new TestInputFileBuilder("foo", relativePath)
+ .setLines(28)
+ .setModuleBaseDir(baseDir.toPath())
+ .build();
+
+ Files.write(baseDir.toPath().resolve(relativePath), "package org.dummy;\npublic class Dummy2 {}".getBytes());
+
+ BlameOutput blameResult = mock(BlameOutput.class);
+ when(input.filesToBlame()).thenReturn(singletonList(inputFile));
+
+ newSvnBlameCommand().blame(input, blameResult);
+ verifyNoInteractions(blameResult);
+ }
+
+ @Test
+ public void shouldNotFailOnUncommitedDir() throws Exception {
+ File repoDir = unzip("repo-svn.zip");
+
+ String scmUrl = "file:///" + unixPath(new File(repoDir, "repo-svn"));
+ File baseDir = new File(checkout(scmUrl), "dummy-svn");
+
+ when(fs.baseDir()).thenReturn(baseDir);
+ String relativePath = "src/main/java/org/dummy2/dummy/Dummy.java";
+ DefaultInputFile inputFile = new TestInputFileBuilder("foo", relativePath)
+ .setLines(28)
+ .setModuleBaseDir(baseDir.toPath())
+ .build();
+
+ Path filepath = new File(baseDir, relativePath).toPath();
+ Files.createDirectories(filepath.getParent());
+ Files.write(filepath, "package org.dummy;\npublic class Dummy {}".getBytes());
+
+ BlameOutput blameResult = mock(BlameOutput.class);
+ when(input.filesToBlame()).thenReturn(singletonList(inputFile));
+
+ newSvnBlameCommand().blame(input, blameResult);
+ verifyNoInteractions(blameResult);
+ }
+
+ @Test
+ public void blame_givenNoCredentials_logWarning() throws Exception {
+ BlameOutput output = mock(BlameOutput.class);
+ InputFile inputFile = mock(InputFile.class);
+ SvnBlameCommand svnBlameCommand = newSvnBlameCommand();
+
+ SVNClientManager clientManager = mock(SVNClientManager.class);
+ SVNLogClient logClient = mock(SVNLogClient.class);
+ SVNStatusClient statusClient = mock(SVNStatusClient.class);
+ SVNStatus status = mock(SVNStatus.class);
+
+ when(clientManager.getLogClient()).thenReturn(logClient);
+ when(clientManager.getStatusClient()).thenReturn(statusClient);
+ when(status.getContentsStatus()).thenReturn(SVNStatusType.STATUS_NORMAL);
+ when(inputFile.file()).thenReturn(mock(File.class));
+ when(statusClient.doStatus(any(File.class), anyBoolean())).thenReturn(status);
+
+ doThrow(SVNAuthenticationException.class).when(logClient).doAnnotate(any(File.class), any(SVNRevision.class),
+ any(SVNRevision.class), any(SVNRevision.class), anyBoolean(), anyBoolean(), any(AnnotationHandler.class),
+ eq(null));
+
+ assertThrows(IllegalStateException.class, () -> {
+ svnBlameCommand.blame(clientManager, inputFile, output);
+ assertThat(logTester.logs(LoggerLevel.WARN)).contains("Authentication to SVN server is required but no " +
+ "authentication data was passed to the scanner");
+ });
+
+ }
+
+ @Test
+ public void blame_givenCredentialsSupplied_doNotlogWarning() throws Exception {
+ BlameOutput output = mock(BlameOutput.class);
+ InputFile inputFile = mock(InputFile.class);
+ SvnConfiguration properties = mock(SvnConfiguration.class);
+ SvnBlameCommand svnBlameCommand = new SvnBlameCommand(properties);
+
+ SVNClientManager clientManager = mock(SVNClientManager.class);
+ SVNLogClient logClient = mock(SVNLogClient.class);
+ SVNStatusClient statusClient = mock(SVNStatusClient.class);
+ SVNStatus status = mock(SVNStatus.class);
+
+ when(properties.isEmpty()).thenReturn(true);
+ when(clientManager.getLogClient()).thenReturn(logClient);
+ when(clientManager.getStatusClient()).thenReturn(statusClient);
+ when(status.getContentsStatus()).thenReturn(SVNStatusType.STATUS_NORMAL);
+ when(inputFile.file()).thenReturn(mock(File.class));
+ when(statusClient.doStatus(any(File.class), anyBoolean())).thenReturn(status);
+
+ doThrow(SVNAuthenticationException.class).when(logClient).doAnnotate(any(File.class), any(SVNRevision.class),
+ any(SVNRevision.class), any(SVNRevision.class), anyBoolean(), anyBoolean(), any(AnnotationHandler.class),
+ eq(null));
+
+ assertThrows(IllegalStateException.class, () -> {
+ svnBlameCommand.blame(clientManager, inputFile, output);
+ assertThat(logTester.logs(LoggerLevel.WARN)).isEmpty();
+ });
+
+ }
+
+ private static void javaUnzip(File zip, File toDir) {
+ try {
+ try (ZipFile zipFile = new ZipFile(zip)) {
+ Enumeration<? extends ZipEntry> entries = zipFile.entries();
+ while (entries.hasMoreElements()) {
+ ZipEntry entry = entries.nextElement();
+ File to = new File(toDir, entry.getName());
+ if (entry.isDirectory()) {
+ Files.createDirectories(to.toPath());
+ } else {
+ File parent = to.getParentFile();
+ if (parent != null) {
+ Files.createDirectories(parent.toPath());
+ }
+
+ Files.copy(zipFile.getInputStream(entry), to.toPath());
+ }
+ }
+ }
+ } catch (Exception e) {
+ throw new IllegalStateException("Fail to unzip " + zip + " to " + toDir, e);
+ }
+ }
+
+ private static String unixPath(File file) {
+ return file.getAbsolutePath().replace('\\', '/');
+ }
+
+ private SvnBlameCommand newSvnBlameCommand() {
+ return new SvnBlameCommand(mock(SvnConfiguration.class));
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 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.scm.svn;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.StandardOpenOption;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
+import org.tmatesoft.svn.core.SVNDepth;
+import org.tmatesoft.svn.core.SVNException;
+import org.tmatesoft.svn.core.SVNURL;
+import org.tmatesoft.svn.core.io.SVNRepositoryFactory;
+import org.tmatesoft.svn.core.wc.SVNClientManager;
+import org.tmatesoft.svn.core.wc.SVNCopyClient;
+import org.tmatesoft.svn.core.wc.SVNCopySource;
+import org.tmatesoft.svn.core.wc.SVNRevision;
+import org.tmatesoft.svn.core.wc.SVNUpdateClient;
+import org.tmatesoft.svn.core.wc2.SvnList;
+import org.tmatesoft.svn.core.wc2.SvnOperationFactory;
+import org.tmatesoft.svn.core.wc2.SvnRemoteMkDir;
+import org.tmatesoft.svn.core.wc2.SvnTarget;
+
+public class SvnTester {
+ private final SVNClientManager manager = SVNClientManager.newInstance(new SvnOperationFactory());
+
+ private final SVNURL localRepository;
+
+ public SvnTester(Path root) throws SVNException, IOException {
+ localRepository = SVNRepositoryFactory.createLocalRepository(root.toFile(), false, false);
+ mkdir("trunk");
+ mkdir("branches");
+ }
+
+ private void mkdir(String relpath) throws IOException, SVNException {
+ SvnRemoteMkDir remoteMkDir = manager.getOperationFactory().createRemoteMkDir();
+ remoteMkDir.addTarget(SvnTarget.fromURL(localRepository.appendPath(relpath, false)));
+ remoteMkDir.run();
+ }
+
+ public void createBranch(String branchName) throws IOException, SVNException {
+ SVNCopyClient copyClient = manager.getCopyClient();
+ SVNCopySource source = new SVNCopySource(SVNRevision.HEAD, SVNRevision.HEAD, localRepository.appendPath("trunk", false));
+ copyClient.doCopy(new SVNCopySource[] {source}, localRepository.appendPath("branches/" + branchName, false), false, false, true, "Create branch", null);
+ }
+
+ public void checkout(Path worktree, String path) throws SVNException {
+ SVNUpdateClient updateClient = manager.getUpdateClient();
+ updateClient.doCheckout(localRepository.appendPath(path, false),
+ worktree.toFile(), null, null, SVNDepth.INFINITY, false);
+ }
+
+ public void add(Path worktree, String filename) throws SVNException {
+ manager.getWCClient().doAdd(worktree.resolve(filename).toFile(), true, false, false, SVNDepth.INFINITY, false, false, true);
+ }
+
+ public void copy(Path worktree, String src, String dst) throws SVNException {
+ SVNCopyClient copyClient = manager.getCopyClient();
+ SVNCopySource source = new SVNCopySource(SVNRevision.HEAD, SVNRevision.HEAD, worktree.resolve(src).toFile());
+ copyClient.doCopy(new SVNCopySource[]{source}, worktree.resolve(dst).toFile(), false, false, true);
+ }
+
+ public void commit(Path worktree) throws SVNException {
+ manager.getCommitClient().doCommit(new File[] {worktree.toFile()}, false, "commit " + worktree, null, null, false, false, SVNDepth.INFINITY);
+ }
+
+ public void update(Path worktree) throws SVNException {
+ manager.getUpdateClient().doUpdate(new File[] {worktree.toFile()}, SVNRevision.HEAD, SVNDepth.INFINITY, false, false);
+ }
+
+ public Collection<String> list(String... paths) throws SVNException {
+ Set<String> results = new HashSet<>();
+
+ SvnList list = manager.getOperationFactory().createList();
+ if (paths.length == 0) {
+ list.addTarget(SvnTarget.fromURL(localRepository));
+ } else {
+ for (String path : paths) {
+ list.addTarget(SvnTarget.fromURL(localRepository.appendPath(path, false)));
+ }
+ }
+ list.setDepth(SVNDepth.INFINITY);
+ list.setReceiver((svnTarget, svnDirEntry) -> {
+ String path = svnDirEntry.getRelativePath();
+ if (!path.isEmpty()) {
+ results.add(path);
+ }
+ });
+ list.run();
+
+ return results;
+ }
+
+ public void createFile(Path worktree, String filename, String content) throws IOException {
+ Files.write(worktree.resolve(filename), content.getBytes());
+ }
+
+ public void createFile(Path worktree, String filename) throws IOException {
+ createFile(worktree, filename, filename + "\n");
+ }
+
+ public void appendToFile(Path worktree, String filename) throws IOException {
+ Files.write(worktree.resolve(filename), (filename + "\n").getBytes(), StandardOpenOption.APPEND);
+ }
+
+ public void deleteFile(Path worktree, String filename) throws SVNException {
+ manager.getWCClient().doDelete(worktree.resolve(filename).toFile(), false, false);
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 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.scm.svn;
+
+import java.io.IOException;
+import java.nio.file.Path;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.tmatesoft.svn.core.SVNException;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class SvnTesterIT {
+ @Rule
+ public TemporaryFolder temp = new TemporaryFolder();
+
+ private SvnTester tester;
+
+ @Before
+ public void before() throws IOException, SVNException {
+ tester = new SvnTester(temp.newFolder().toPath());
+ }
+
+ @Test
+ public void test_init() throws SVNException {
+ assertThat(tester.list()).containsExactlyInAnyOrder("trunk", "branches");
+ }
+
+ @Test
+ public void test_add_and_commit() throws IOException, SVNException {
+ assertThat(tester.list("trunk")).isEmpty();
+
+ Path worktree = temp.newFolder().toPath();
+ tester.checkout(worktree, "trunk");
+ tester.createFile(worktree, "file1");
+
+ tester.add(worktree, "file1");
+ tester.commit(worktree);
+
+ assertThat(tester.list("trunk")).containsOnly("file1");
+ }
+
+ @Test
+ public void test_createBranch() throws IOException, SVNException {
+ tester.createBranch("b1");
+ assertThat(tester.list()).containsExactlyInAnyOrder("trunk", "branches", "branches/b1");
+ assertThat(tester.list("branches")).containsOnly("b1");
+ }
+}
}
@Test
- public void write_bytes_adds_entries() throws IOException {
+ public void write_bytes_adds_entries() {
byte[] b1 = new byte[] {1, 2, 3};
byte[] b2 = new byte[] {3, 4};
writeCache.write("key", b1);
}
@Test
- public void dont_write_if_its_pull_request() throws IOException {
+ public void dont_write_if_its_pull_request() {
byte[] b1 = new byte[] {1, 2, 3};
when(branchConfiguration.isPullRequest()).thenReturn(true);
writeCache.write("key1", b1);
}
@Test
- public void write_inputStream_adds_entries() throws IOException {
+ public void write_inputStream_adds_entries() {
byte[] b1 = new byte[] {1, 2, 3};
byte[] b2 = new byte[] {3, 4};
writeCache.write("key", new ByteArrayInputStream(b1));
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2023 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.mediumtest;
-
-import com.google.common.collect.LinkedHashMultimap;
-import com.google.common.collect.Multimap;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.stream.Collectors;
-import org.sonar.batch.bootstrapper.LogOutput;
-
-public class LogOutputRecorder implements LogOutput {
- private final Multimap<String, String> recordedByLevel = LinkedHashMultimap.create();
- private final List<String> recorded = new LinkedList<>();
- private final StringBuffer asString = new StringBuffer();
-
- @Override
- public synchronized void log(String formattedMessage, Level level) {
- recordedByLevel.put(level.toString(), formattedMessage);
- recorded.add(formattedMessage);
- asString.append(formattedMessage).append("\n");
- }
-
- public synchronized Collection<String> getAll() {
- return new ArrayList<>(recorded);
- }
-
- public synchronized String getAllAsString() {
- return String.join("\n", recorded);
- }
-
- public synchronized Collection<String> get(String level) {
- return new ArrayList<>(recordedByLevel.get(level));
- }
-
- public synchronized String getAsString() {
- return asString.toString();
- }
-
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2023 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.mediumtest;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.io.Reader;
-import java.nio.charset.StandardCharsets;
-import java.nio.file.Path;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
-import java.util.Properties;
-import javax.annotation.CheckForNull;
-import javax.annotation.Nullable;
-import javax.annotation.Priority;
-import org.apache.commons.io.FileUtils;
-import org.junit.rules.ExternalResource;
-import org.sonar.api.Plugin;
-import org.sonar.api.SonarEdition;
-import org.sonar.api.SonarProduct;
-import org.sonar.api.SonarQubeSide;
-import org.sonar.api.SonarRuntime;
-import org.sonar.api.batch.rule.LoadedActiveRule;
-import org.sonar.api.impl.server.RulesDefinitionContext;
-import org.sonar.api.measures.CoreMetrics;
-import org.sonar.api.measures.Metric;
-import org.sonar.api.rule.RuleKey;
-import org.sonar.api.server.rule.RulesDefinition;
-import org.sonar.api.server.rule.RulesDefinition.Repository;
-import org.sonar.api.utils.DateUtils;
-import org.sonar.api.utils.Version;
-import org.sonar.batch.bootstrapper.Batch;
-import org.sonar.batch.bootstrapper.EnvironmentInformation;
-import org.sonar.batch.bootstrapper.LogOutput;
-import org.sonar.scanner.bootstrap.GlobalAnalysisMode;
-import org.sonar.scanner.cache.AnalysisCacheLoader;
-import org.sonar.scanner.protocol.internal.SensorCacheData;
-import org.sonar.scanner.report.CeTaskReportDataHolder;
-import org.sonar.scanner.repository.FileData;
-import org.sonar.scanner.repository.MetricsRepository;
-import org.sonar.scanner.repository.MetricsRepositoryLoader;
-import org.sonar.scanner.repository.NewCodePeriodLoader;
-import org.sonar.scanner.repository.ProjectRepositories;
-import org.sonar.scanner.repository.ProjectRepositoriesLoader;
-import org.sonar.scanner.repository.QualityProfileLoader;
-import org.sonar.scanner.repository.SingleProjectRepository;
-import org.sonar.scanner.repository.settings.GlobalSettingsLoader;
-import org.sonar.scanner.repository.settings.ProjectSettingsLoader;
-import org.sonar.scanner.rule.ActiveRulesLoader;
-import org.sonar.scanner.rule.RulesLoader;
-import org.sonar.scanner.scan.ScanProperties;
-import org.sonar.scanner.scan.branch.BranchConfiguration;
-import org.sonar.scanner.scan.branch.BranchConfigurationLoader;
-import org.sonar.scanner.scan.branch.BranchType;
-import org.sonar.scanner.scan.branch.ProjectBranches;
-import org.sonarqube.ws.NewCodePeriods;
-import org.sonarqube.ws.Qualityprofiles.SearchWsResponse.QualityProfile;
-import org.sonarqube.ws.Rules.ListResponse.Rule;
-
-import static java.util.Collections.emptySet;
-
-/**
- * Main utility class for writing scanner medium tests.
- */
-public class ScannerMediumTester extends ExternalResource {
-
- private static Path userHome = null;
- private final Map<String, String> globalProperties = new HashMap<>();
- private final FakeMetricsRepositoryLoader globalRefProvider = new FakeMetricsRepositoryLoader();
- private final FakeBranchConfigurationLoader branchConfigurationLoader = new FakeBranchConfigurationLoader();
- private final FakeBranchConfiguration branchConfiguration = new FakeBranchConfiguration();
- private final FakeProjectRepositoriesLoader projectRefProvider = new FakeProjectRepositoriesLoader();
- private final FakePluginInstaller pluginInstaller = new FakePluginInstaller();
- private final FakeGlobalSettingsLoader globalSettingsLoader = new FakeGlobalSettingsLoader();
- private final FakeProjectSettingsLoader projectSettingsLoader = new FakeProjectSettingsLoader();
- private final FakeNewCodePeriodLoader newCodePeriodLoader = new FakeNewCodePeriodLoader();
- private final FakeAnalysisCacheLoader analysisCacheLoader = new FakeAnalysisCacheLoader();
- private final FakeRulesLoader rulesLoader = new FakeRulesLoader();
- private final FakeQualityProfileLoader qualityProfiles = new FakeQualityProfileLoader();
- private final FakeActiveRulesLoader activeRules = new FakeActiveRulesLoader();
- private final FakeSonarRuntime sonarRuntime = new FakeSonarRuntime();
- private final CeTaskReportDataHolder reportMetadataHolder = new CeTaskReportDataHolderExt();
- private LogOutput logOutput = null;
-
- private static void createWorkingDirs() throws IOException {
- destroyWorkingDirs();
-
- userHome = java.nio.file.Files.createTempDirectory("mediumtest-userHome");
- }
-
- private static void destroyWorkingDirs() throws IOException {
- if (userHome != null) {
- FileUtils.deleteDirectory(userHome.toFile());
- userHome = null;
- }
- }
-
- public ScannerMediumTester setLogOutput(LogOutput logOutput) {
- this.logOutput = logOutput;
- return this;
- }
-
- public ScannerMediumTester registerPlugin(String pluginKey, File location) {
- return registerPlugin(pluginKey, location, 1L);
- }
-
- public ScannerMediumTester registerPlugin(String pluginKey, File location, long lastUpdatedAt) {
- pluginInstaller.add(pluginKey, location, lastUpdatedAt);
- return this;
- }
-
- public ScannerMediumTester registerPlugin(String pluginKey, Plugin instance) {
- return registerPlugin(pluginKey, instance, 1L);
- }
-
- public ScannerMediumTester registerPlugin(String pluginKey, Plugin instance, long lastUpdatedAt) {
- pluginInstaller.add(pluginKey, instance, lastUpdatedAt);
- return this;
- }
-
- public ScannerMediumTester registerCoreMetrics() {
- for (Metric<?> m : CoreMetrics.getMetrics()) {
- registerMetric(m);
- }
- return this;
- }
-
- public ScannerMediumTester registerMetric(Metric<?> metric) {
- globalRefProvider.add(metric);
- return this;
- }
-
- public ScannerMediumTester addQProfile(String language, String name) {
- qualityProfiles.add(language, name);
- return this;
- }
-
- public ScannerMediumTester addRule(Rule rule) {
- rulesLoader.addRule(rule);
- return this;
- }
-
- public ScannerMediumTester addRule(String key, String repoKey, String internalKey, String name) {
- Rule.Builder builder = Rule.newBuilder();
- builder.setKey(key);
- builder.setRepository(repoKey);
- if (internalKey != null) {
- builder.setInternalKey(internalKey);
- }
- builder.setName(name);
-
- rulesLoader.addRule(builder.build());
- return this;
- }
-
- public ScannerMediumTester addRules(RulesDefinition rulesDefinition) {
- RulesDefinition.Context context = new RulesDefinitionContext();
- rulesDefinition.define(context);
- List<Repository> repositories = context.repositories();
- for (Repository repo : repositories) {
- for (RulesDefinition.Rule rule : repo.rules()) {
- this.addRule(rule.key(), rule.repository().key(), rule.internalKey(), rule.name());
- }
- }
- return this;
- }
-
- public ScannerMediumTester addDefaultQProfile(String language, String name) {
- addQProfile(language, name);
- return this;
- }
-
- public ScannerMediumTester bootstrapProperties(Map<String, String> props) {
- globalProperties.putAll(props);
- return this;
- }
-
- public ScannerMediumTester activateRule(LoadedActiveRule activeRule) {
- activeRules.addActiveRule(activeRule);
- return this;
- }
-
- public ScannerMediumTester addActiveRule(String repositoryKey, String ruleKey, @Nullable String templateRuleKey, String name, @Nullable String severity,
- @Nullable String internalKey, @Nullable String language) {
- LoadedActiveRule r = new LoadedActiveRule();
-
- r.setInternalKey(internalKey);
- r.setRuleKey(RuleKey.of(repositoryKey, ruleKey));
- r.setName(name);
- r.setTemplateRuleKey(templateRuleKey);
- r.setLanguage(language);
- r.setSeverity(severity);
- r.setDeprecatedKeys(emptySet());
-
- activeRules.addActiveRule(r);
- return this;
- }
-
- public ScannerMediumTester addFileData(String path, FileData fileData) {
- projectRefProvider.addFileData(path, fileData);
- return this;
- }
-
- public ScannerMediumTester addGlobalServerSettings(String key, String value) {
- globalSettingsLoader.getGlobalSettings().put(key, value);
- return this;
- }
-
- public ScannerMediumTester addProjectServerSettings(String key, String value) {
- projectSettingsLoader.getProjectSettings().put(key, value);
- return this;
- }
-
- public ScannerMediumTester setNewCodePeriod(NewCodePeriods.NewCodePeriodType type, String value) {
- newCodePeriodLoader.set(NewCodePeriods.ShowWSResponse.newBuilder().setType(type).setValue(value).build());
- return this;
- }
-
- @Override
- protected void before() {
- try {
- createWorkingDirs();
- } catch (IOException e) {
- throw new IllegalStateException(e);
- }
- registerCoreMetrics();
- globalProperties.put(GlobalAnalysisMode.MEDIUM_TEST_ENABLED, "true");
- globalProperties.put(ScanProperties.KEEP_REPORT_PROP_KEY, "true");
- globalProperties.put("sonar.userHome", userHome.toString());
- }
-
- @Override
- protected void after() {
- try {
- destroyWorkingDirs();
- } catch (IOException e) {
- throw new IllegalStateException(e);
- }
- }
-
- public AnalysisBuilder newAnalysis() {
- return new AnalysisBuilder(this);
- }
-
- public AnalysisBuilder newAnalysis(File sonarProps) {
- Properties prop = new Properties();
- try (Reader reader = new InputStreamReader(new FileInputStream(sonarProps), StandardCharsets.UTF_8)) {
- prop.load(reader);
- } catch (Exception e) {
- throw new IllegalStateException("Unable to read configuration file", e);
- }
- AnalysisBuilder builder = new AnalysisBuilder(this);
- builder.property("sonar.projectBaseDir", sonarProps.getParentFile().getAbsolutePath());
- for (Map.Entry<Object, Object> entry : prop.entrySet()) {
- builder.property(entry.getKey().toString(), entry.getValue().toString());
- }
- return builder;
- }
-
- public static class AnalysisBuilder {
- private final Map<String, String> taskProperties = new HashMap<>();
- private final ScannerMediumTester tester;
-
- public AnalysisBuilder(ScannerMediumTester tester) {
- this.tester = tester;
- }
-
- public AnalysisResult execute() {
- AnalysisResult result = new AnalysisResult();
- Map<String, String> props = new HashMap<>();
- props.putAll(tester.globalProperties);
- props.putAll(taskProperties);
-
- Batch.builder()
- .setGlobalProperties(props)
- .setEnableLoggingConfiguration(true)
- .addComponents(new EnvironmentInformation("mediumTest", "1.0"),
- tester.pluginInstaller,
- tester.globalRefProvider,
- tester.qualityProfiles,
- tester.rulesLoader,
- tester.branchConfigurationLoader,
- tester.projectRefProvider,
- tester.activeRules,
- tester.globalSettingsLoader,
- tester.projectSettingsLoader,
- tester.newCodePeriodLoader,
- tester.analysisCacheLoader,
- tester.sonarRuntime,
- tester.reportMetadataHolder,
- result)
- .setLogOutput(tester.logOutput)
- .build().execute();
-
- return result;
- }
-
- public AnalysisBuilder properties(Map<String, String> props) {
- taskProperties.putAll(props);
- return this;
- }
-
- public AnalysisBuilder property(String key, String value) {
- taskProperties.put(key, value);
- return this;
- }
-
- }
-
- @Priority(1)
- private static class FakeRulesLoader implements RulesLoader {
- private List<org.sonarqube.ws.Rules.ListResponse.Rule> rules = new LinkedList<>();
-
- public FakeRulesLoader addRule(Rule rule) {
- rules.add(rule);
- return this;
- }
-
- @Override
- public List<Rule> load() {
- return rules;
- }
- }
-
- @Priority(1)
- private static class FakeActiveRulesLoader implements ActiveRulesLoader {
- private List<LoadedActiveRule> activeRules = new LinkedList<>();
-
- public void addActiveRule(LoadedActiveRule activeRule) {
- this.activeRules.add(activeRule);
- }
-
- @Override
- public List<LoadedActiveRule> load(String qualityProfileKey) {
- return activeRules;
- }
- }
-
- @Priority(1)
- private static class FakeMetricsRepositoryLoader implements MetricsRepositoryLoader {
-
- private int metricId = 1;
-
- private List<Metric> metrics = new ArrayList<>();
-
- @Override
- public MetricsRepository load() {
- return new MetricsRepository(metrics);
- }
-
- public FakeMetricsRepositoryLoader add(Metric<?> metric) {
- metric.setUuid("metric" + metricId++);
- metrics.add(metric);
- metricId++;
- return this;
- }
-
- }
-
- @Priority(1)
- private static class FakeProjectRepositoriesLoader implements ProjectRepositoriesLoader {
- private Map<String, FileData> fileDataMap = new HashMap<>();
-
- @Override
- public ProjectRepositories load(String projectKey, @Nullable String branchBase) {
- return new SingleProjectRepository(fileDataMap);
- }
-
- public FakeProjectRepositoriesLoader addFileData(String path, FileData fileData) {
- fileDataMap.put(path, fileData);
- return this;
- }
-
- }
-
- @Priority(1)
- private static class FakeBranchConfiguration implements BranchConfiguration {
-
- private BranchType branchType = BranchType.BRANCH;
- private String branchName = null;
- private String branchTarget = null;
- private String referenceBranchName = null;
-
- @Override
- public BranchType branchType() {
- return branchType;
- }
-
- @CheckForNull
- @Override
- public String branchName() {
- return branchName;
- }
-
- @CheckForNull
- @Override
- public String targetBranchName() {
- return branchTarget;
- }
-
- @CheckForNull
- @Override
- public String referenceBranchName() {
- return referenceBranchName;
- }
-
- @Override
- public String pullRequestKey() {
- return "1'";
- }
- }
-
- @Priority(1)
- private static class FakeSonarRuntime implements SonarRuntime {
-
- private SonarEdition edition;
-
- FakeSonarRuntime() {
- this.edition = SonarEdition.COMMUNITY;
- }
-
- @Override
- public Version getApiVersion() {
- return Version.create(7, 8);
- }
-
- @Override
- public SonarProduct getProduct() {
- return SonarProduct.SONARQUBE;
- }
-
- @Override
- public SonarQubeSide getSonarQubeSide() {
- return SonarQubeSide.SCANNER;
- }
-
- @Override
- public SonarEdition getEdition() {
- return edition;
- }
-
- public void setEdition(SonarEdition edition) {
- this.edition = edition;
- }
- }
-
- public ScannerMediumTester setBranchType(BranchType branchType) {
- branchConfiguration.branchType = branchType;
- return this;
- }
-
- public ScannerMediumTester setBranchName(String branchName) {
- this.branchConfiguration.branchName = branchName;
- return this;
- }
-
- public ScannerMediumTester setBranchTarget(String branchTarget) {
- this.branchConfiguration.branchTarget = branchTarget;
- return this;
- }
-
- public ScannerMediumTester setReferenceBranchName(String referenceBranchNam) {
- this.branchConfiguration.referenceBranchName = referenceBranchNam;
- return this;
- }
-
- public ScannerMediumTester setEdition(SonarEdition edition) {
- this.sonarRuntime.setEdition(edition);
- return this;
- }
-
- @Priority(1)
- private class FakeBranchConfigurationLoader implements BranchConfigurationLoader {
- @Override
- public BranchConfiguration load(Map<String, String> projectSettings, ProjectBranches branches) {
- return branchConfiguration;
- }
- }
-
- @Priority(1)
- private static class FakeQualityProfileLoader implements QualityProfileLoader {
-
- private List<QualityProfile> qualityProfiles = new LinkedList<>();
-
- public void add(String language, String name) {
- qualityProfiles.add(QualityProfile.newBuilder()
- .setLanguage(language)
- .setKey(name)
- .setName(name)
- .setRulesUpdatedAt(DateUtils.formatDateTime(new Date(1234567891212L)))
- .build());
- }
-
- @Override
- public List<QualityProfile> load(String projectKey) {
- return qualityProfiles;
- }
- }
-
- @Priority(1)
- private static class FakeAnalysisCacheLoader implements AnalysisCacheLoader {
- @Override
- public Optional<SensorCacheData> load() {
- return Optional.empty();
- }
- }
-
- @Priority(1)
- private static class FakeGlobalSettingsLoader implements GlobalSettingsLoader {
-
- private Map<String, String> globalSettings = new HashMap<>();
-
- public Map<String, String> getGlobalSettings() {
- return globalSettings;
- }
-
- @Override
- public Map<String, String> loadGlobalSettings() {
- return Collections.unmodifiableMap(globalSettings);
- }
- }
-
- @Priority(1)
- private static class FakeNewCodePeriodLoader implements NewCodePeriodLoader {
- private NewCodePeriods.ShowWSResponse response;
-
- @Override
- public NewCodePeriods.ShowWSResponse load(String projectKey, String branchName) {
- return response;
- }
-
- public void set(NewCodePeriods.ShowWSResponse response) {
- this.response = response;
- }
- }
-
- @Priority(1)
- private static class FakeProjectSettingsLoader implements ProjectSettingsLoader {
-
- private Map<String, String> projectSettings = new HashMap<>();
-
- public Map<String, String> getProjectSettings() {
- return projectSettings;
- }
-
- @Override
- public Map<String, String> loadProjectSettings() {
- return Collections.unmodifiableMap(projectSettings);
- }
- }
-
- @Priority(1)
- private static class CeTaskReportDataHolderExt extends CeTaskReportDataHolder {
-
- }
-
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2023 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.mediumtest.branch;
-
-import com.google.common.collect.ImmutableMap;
-
-import java.io.File;
-import java.io.IOException;
-import java.nio.charset.StandardCharsets;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.util.List;
-
-import org.apache.commons.io.FileUtils;
-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.FileMetadata;
-import org.sonar.api.notifications.AnalysisWarnings;
-import org.sonar.api.utils.log.LogTester;
-import org.sonar.scanner.mediumtest.AnalysisResult;
-import org.sonar.scanner.mediumtest.ScannerMediumTester;
-import org.sonar.scanner.protocol.output.ScannerReport;
-import org.sonar.scanner.repository.FileData;
-import org.sonar.scanner.scan.branch.BranchType;
-import org.sonar.xoo.XooPlugin;
-import org.sonar.xoo.rule.XooRulesDefinition;
-import org.sonarqube.ws.NewCodePeriods;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Mockito.mock;
-
-public class BranchMediumTest {
-
- private static final String PROJECT_KEY = "sample";
- private static final String FILE_PATH = "HelloJava.xoo";
- private static final String FILE_CONTENT = "xoooo";
- public static final String ONE_ISSUE_PER_LINE_IS_RESTRICTED_TO_CHANGED_FILES_ONLY = "Sensor One Issue Per Line is restricted to changed files only";
- private File baseDir;
-
- @Rule
- public TemporaryFolder temp = new TemporaryFolder();
-
- @Rule
- public LogTester logTester = new LogTester();
-
- @Rule
- public ScannerMediumTester tester = new ScannerMediumTester()
- .registerPlugin("xoo", new XooPlugin())
- .addDefaultQProfile("xoo", "Sonar Way")
- .addRules(new XooRulesDefinition())
- .addActiveRule("xoo", "OneIssuePerLine", null, "One issue per line", "MAJOR", "OneIssuePerLine.internal", "xoo");
-
- @Before
- public void prepare() throws IOException {
- baseDir = temp.newFolder();
- Path filepath = baseDir.toPath().resolve(FILE_PATH);
- Files.write(filepath, FILE_CONTENT.getBytes());
-
- Path xooUtCoverageFile = baseDir.toPath().resolve(FILE_PATH + ".coverage");
- FileUtils.write(xooUtCoverageFile.toFile(), "1:2:2:1", StandardCharsets.UTF_8);
-
- String md5sum = new FileMetadata(mock(AnalysisWarnings.class))
- .readMetadata(Files.newInputStream(filepath), StandardCharsets.UTF_8, FILE_PATH)
- .hash();
- tester.addFileData(FILE_PATH, new FileData(md5sum, "1.1"));
- tester.setNewCodePeriod(NewCodePeriods.NewCodePeriodType.PREVIOUS_VERSION, "");
- }
-
- @Test
- public void should_not_skip_report_for_unchanged_files_in_pr() {
- // sanity check, normally report gets generated
- AnalysisResult result = getResult(tester);
- final DefaultInputFile file = (DefaultInputFile) result.inputFile(FILE_PATH);
- assertThat(getResult(tester).getReportComponent(file)).isNotNull();
- int fileId = file.scannerId();
- assertThat(result.getReportReader().readChangesets(fileId)).isNotNull();
- assertThat(result.getReportReader().hasCoverage(fileId)).isTrue();
- assertThat(result.getReportReader().readFileSource(fileId)).isNotNull();
-
- // file is not skipped for pull requests (need coverage, duplications coming soon)
- AnalysisResult result2 = getResult(tester.setBranchType(BranchType.PULL_REQUEST));
- final DefaultInputFile fileInPr = (DefaultInputFile) result2.inputFile(FILE_PATH);
- assertThat(result2.getReportComponent(fileInPr)).isNotNull();
- fileId = fileInPr.scannerId();
- assertThat(result2.getReportReader().readChangesets(fileId)).isNull();
- assertThat(result2.getReportReader().hasCoverage(fileId)).isTrue();
- assertThat(result2.getReportReader().readFileSource(fileId)).isNull();
- }
-
- @Test
- public void shouldSkipSensorForUnchangedFilesOnPr() throws Exception {
- AnalysisResult result = getResult(tester
- .setBranchName("myBranch")
- .setBranchTarget("main")
- .setBranchType(BranchType.PULL_REQUEST));
- final DefaultInputFile file = (DefaultInputFile) result.inputFile(FILE_PATH);
-
- List<ScannerReport.Issue> issues = result.issuesFor(file);
- assertThat(issues).isEmpty();
-
- assertThat(logTester.logs()).contains(ONE_ISSUE_PER_LINE_IS_RESTRICTED_TO_CHANGED_FILES_ONLY);
- }
-
- @Test
- public void shouldNotSkipSensorForUnchangedFilesOnBranch() throws Exception {
- AnalysisResult result = getResult(tester
- .setBranchName("myBranch")
- .setBranchTarget("main")
- .setBranchType(BranchType.BRANCH));
- final DefaultInputFile file = (DefaultInputFile) result.inputFile(FILE_PATH);
-
- List<ScannerReport.Issue> issues = result.issuesFor(file);
- assertThat(issues).isNotEmpty();
-
- assertThat(logTester.logs()).doesNotContain(ONE_ISSUE_PER_LINE_IS_RESTRICTED_TO_CHANGED_FILES_ONLY);
- }
-
- @Test
- public void verify_metadata() {
- String branchName = "feature";
- String branchTarget = "branch-1.x";
-
- AnalysisResult result = getResult(tester
- .setBranchName(branchName)
- .setBranchTarget(branchTarget)
- .setReferenceBranchName(branchTarget)
- .setBranchType(BranchType.BRANCH));
-
- ScannerReport.Metadata metadata = result.getReportReader().readMetadata();
- assertThat(metadata.getBranchName()).isEqualTo(branchName);
- assertThat(metadata.getBranchType()).isEqualTo(ScannerReport.Metadata.BranchType.BRANCH);
- assertThat(metadata.getReferenceBranchName()).isEqualTo(branchTarget);
- }
-
- private AnalysisResult getResult(ScannerMediumTester tester) {
- return tester
- .newAnalysis()
- .properties(ImmutableMap.<String, String>builder()
- .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
- .put("sonar.projectKey", PROJECT_KEY)
- .put("sonar.scm.provider", "xoo")
- .build())
- .execute();
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2023 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.mediumtest.branch;
-
-import com.google.common.collect.ImmutableMap;
-import java.io.File;
-import java.io.IOException;
-import java.util.Map;
-import org.apache.commons.io.FileUtils;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TemporaryFolder;
-import org.sonar.api.utils.MessageException;
-import org.sonar.scanner.mediumtest.ScannerMediumTester;
-import org.sonar.xoo.XooPlugin;
-import org.sonar.xoo.rule.XooRulesDefinition;
-
-import static org.assertj.core.api.Assertions.assertThatThrownBy;
-
-public class DeprecatedBranchMediumTest {
-
- @Rule
- public TemporaryFolder temp = new TemporaryFolder();
-
- @Rule
- public ScannerMediumTester tester = new ScannerMediumTester()
- .registerPlugin("xoo", new XooPlugin())
- .addRules(new XooRulesDefinition())
- // active a rule just to be sure that xoo files are published
- .addActiveRule("xoo", "xoo:OneIssuePerFile", null, "One Issue Per File", null, null, null)
- .addDefaultQProfile("xoo", "Sonar Way");
-
- private File baseDir;
-
- private Map<String, String> commonProps;
-
- @Before
- public void prepare() {
- baseDir = temp.getRoot();
-
- commonProps = ImmutableMap.<String, String>builder()
- .put("sonar.task", "scan")
- .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
- .put("sonar.projectKey", "com.foo.project")
- .put("sonar.projectName", "Foo Project")
- .put("sonar.projectVersion", "1.0-SNAPSHOT")
- .put("sonar.projectDescription", "Description of Foo Project")
- .put("sonar.sources", "src")
- .build();
- }
-
- @Test
- public void scanProjectWithBranch() throws IOException {
- File srcDir = new File(baseDir, "src");
- srcDir.mkdir();
-
- File xooFile = new File(srcDir, "sample.xoo");
- FileUtils.write(xooFile, "Sample xoo\ncontent");
-
- assertThatThrownBy(() -> tester.newAnalysis()
- .properties(ImmutableMap.<String, String>builder()
- .putAll(commonProps)
- .put("sonar.branch", "branch")
- .build())
- .execute())
- .isInstanceOf(MessageException.class)
- .hasMessage("The 'sonar.branch' parameter is no longer supported. You should stop using it. " +
- "Branch analysis is available in Developer Edition and above. See https://www.sonarsource.com/plans-and-pricing/developer/ for more information.");
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2023 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.mediumtest.coverage;
-
-import com.google.common.collect.ImmutableMap;
-import java.io.File;
-import java.io.IOException;
-import java.nio.charset.StandardCharsets;
-import org.apache.commons.io.FileUtils;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TemporaryFolder;
-import org.sonar.api.batch.fs.InputFile;
-import org.sonar.api.utils.log.LogTester;
-import org.sonar.api.utils.log.LoggerLevel;
-import org.sonar.scanner.mediumtest.AnalysisResult;
-import org.sonar.scanner.mediumtest.ScannerMediumTester;
-import org.sonar.scanner.protocol.output.ScannerReport;
-import org.sonar.xoo.XooPlugin;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.AssertionsForClassTypes.tuple;
-
-public class CoverageMediumTest {
-
- @Rule
- public LogTester logTester = new LogTester();
-
- @Rule
- public TemporaryFolder temp = new TemporaryFolder();
-
- @Rule
- public ScannerMediumTester tester = new ScannerMediumTester()
- .registerPlugin("xoo", new XooPlugin())
- .addDefaultQProfile("xoo", "Sonar Way");
-
- @Test
- public void singleReport() throws IOException {
-
- File baseDir = temp.getRoot();
- File srcDir = new File(baseDir, "src");
- srcDir.mkdir();
-
- File xooFile = new File(srcDir, "sample.xoo");
- File xooUtCoverageFile = new File(srcDir, "sample.xoo.coverage");
- FileUtils.write(xooFile, "function foo() {\n if (a && b) {\nalert('hello');\n}\n}", StandardCharsets.UTF_8);
- FileUtils.write(xooUtCoverageFile, "2:2:2:1\n3:1", StandardCharsets.UTF_8);
-
- AnalysisResult result = tester.newAnalysis()
- .properties(ImmutableMap.<String, String>builder()
- .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
- .put("sonar.projectKey", "com.foo.project")
- .put("sonar.sources", "src")
- .build())
- .execute();
-
- InputFile file = result.inputFile("src/sample.xoo");
- assertThat(result.coverageFor(file, 2).getHits()).isTrue();
- assertThat(result.coverageFor(file, 2).getConditions()).isEqualTo(2);
- assertThat(result.coverageFor(file, 2).getCoveredConditions()).isOne();
- }
-
- @Test
- public void twoReports() throws IOException {
-
- File baseDir = temp.getRoot();
- File srcDir = new File(baseDir, "src");
- srcDir.mkdir();
-
- File xooFile = new File(srcDir, "sample.xoo");
- FileUtils.write(xooFile, "function foo() {\n if (a && b) {\nalert('hello');\n}\n}", StandardCharsets.UTF_8);
- File xooUtCoverageFile = new File(srcDir, "sample.xoo.coverage");
- FileUtils.write(xooUtCoverageFile, "2:2:2:2\n4:0", StandardCharsets.UTF_8);
- File xooItCoverageFile = new File(srcDir, "sample.xoo.itcoverage");
- FileUtils.write(xooItCoverageFile, "2:0:2:1\n3:1\n5:0", StandardCharsets.UTF_8);
-
- AnalysisResult result = tester.newAnalysis()
- .properties(ImmutableMap.<String, String>builder()
- .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
- .put("sonar.projectKey", "com.foo.project")
- .put("sonar.sources", "src")
- .build())
- .execute();
-
- InputFile file = result.inputFile("src/sample.xoo");
- assertThat(result.coverageFor(file, 2).getHits()).isTrue();
- assertThat(result.coverageFor(file, 2).getConditions()).isEqualTo(2);
- assertThat(result.coverageFor(file, 2).getCoveredConditions()).isEqualTo(2);
- assertThat(result.coverageFor(file, 3).getHits()).isTrue();
- }
-
- @Test
- public void exclusionsForSimpleProject() throws IOException {
-
- File baseDir = temp.getRoot();
- File srcDir = new File(baseDir, "src");
- srcDir.mkdir();
-
- File xooFile = new File(srcDir, "sample.xoo");
- File xooUtCoverageFile = new File(srcDir, "sample.xoo.coverage");
- FileUtils.write(xooFile, "function foo() {\n if (a && b) {\nalert('hello');\n}\n}", StandardCharsets.UTF_8);
- FileUtils.write(xooUtCoverageFile, "2:2:2:1\n3:1", StandardCharsets.UTF_8);
-
- AnalysisResult result = tester.newAnalysis()
- .properties(ImmutableMap.<String, String>builder()
- .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
- .put("sonar.projectKey", "com.foo.project")
- .put("sonar.sources", "src")
- .put("sonar.coverage.exclusions", "**/sample.xoo")
- .build())
- .execute();
-
- InputFile file = result.inputFile("src/sample.xoo");
- assertThat(result.coverageFor(file, 2)).isNull();
- }
-
- @Test
- public void warn_user_for_outdated_inherited_scanner_side_exclusions_for_multi_module_project() throws IOException {
-
- File baseDir = temp.getRoot();
- File baseDirModuleA = new File(baseDir, "moduleA");
- File baseDirModuleB = new File(baseDir, "moduleB");
- File srcDirA = new File(baseDirModuleA, "src");
- srcDirA.mkdirs();
- File srcDirB = new File(baseDirModuleB, "src");
- srcDirB.mkdirs();
-
- File xooFileA = new File(srcDirA, "sampleA.xoo");
- File xooUtCoverageFileA = new File(srcDirA, "sampleA.xoo.coverage");
- FileUtils.write(xooFileA, "function foo() {\n if (a && b) {\nalert('hello');\n}\n}", StandardCharsets.UTF_8);
- FileUtils.write(xooUtCoverageFileA, "2:2:2:1\n3:1", StandardCharsets.UTF_8);
-
- File xooFileB = new File(srcDirB, "sampleB.xoo");
- File xooUtCoverageFileB = new File(srcDirB, "sampleB.xoo.coverage");
- FileUtils.write(xooFileB, "function foo() {\n if (a && b) {\nalert('hello');\n}\n}", StandardCharsets.UTF_8);
- FileUtils.write(xooUtCoverageFileB, "2:2:2:1\n3:1", StandardCharsets.UTF_8);
-
- AnalysisResult result = tester.newAnalysis()
- .properties(ImmutableMap.<String, String>builder()
- .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
- .put("sonar.projectKey", "com.foo.project")
- .put("sonar.sources", "src")
- .put("sonar.modules", "moduleA,moduleB")
- .put("sonar.coverage.exclusions", "src/sampleA.xoo")
- .build())
- .execute();
-
- InputFile fileA = result.inputFile("moduleA/src/sampleA.xoo");
- assertThat(result.coverageFor(fileA, 2)).isNull();
-
- InputFile fileB = result.inputFile("moduleB/src/sampleB.xoo");
- assertThat(result.coverageFor(fileB, 2)).isNotNull();
-
- assertThat(logTester.logs(LoggerLevel.WARN)).contains("Specifying module-relative paths at project level in the property 'sonar.coverage.exclusions' is deprecated. " +
- "To continue matching files like 'moduleA/src/sampleA.xoo', update this property so that patterns refer to project-relative paths.");
- }
-
- @Test
- public void module_level_exclusions_override_parent_for_multi_module_project() throws IOException {
-
- File baseDir = temp.getRoot();
- File baseDirModuleA = new File(baseDir, "moduleA");
- File baseDirModuleB = new File(baseDir, "moduleB");
- File srcDirA = new File(baseDirModuleA, "src");
- srcDirA.mkdirs();
- File srcDirB = new File(baseDirModuleB, "src");
- srcDirB.mkdirs();
-
- File xooFileA = new File(srcDirA, "sampleA.xoo");
- File xooUtCoverageFileA = new File(srcDirA, "sampleA.xoo.coverage");
- FileUtils.write(xooFileA, "function foo() {\n if (a && b) {\nalert('hello');\n}\n}", StandardCharsets.UTF_8);
- FileUtils.write(xooUtCoverageFileA, "2:2:2:1\n3:1", StandardCharsets.UTF_8);
-
- File xooFileB = new File(srcDirB, "sampleB.xoo");
- File xooUtCoverageFileB = new File(srcDirB, "sampleB.xoo.coverage");
- FileUtils.write(xooFileB, "function foo() {\n if (a && b) {\nalert('hello');\n}\n}", StandardCharsets.UTF_8);
- FileUtils.write(xooUtCoverageFileB, "2:2:2:1\n3:1", StandardCharsets.UTF_8);
-
- AnalysisResult result = tester.newAnalysis()
- .properties(ImmutableMap.<String, String>builder()
- .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
- .put("sonar.projectKey", "com.foo.project")
- .put("sonar.sources", "src")
- .put("sonar.modules", "moduleA,moduleB")
- .put("sonar.coverage.exclusions", "**/*.xoo")
- .put("moduleA.sonar.coverage.exclusions", "**/*.nothing")
- .build())
- .execute();
-
- InputFile fileA = result.inputFile("moduleA/src/sampleA.xoo");
- assertThat(result.coverageFor(fileA, 2)).isNotNull();
-
- InputFile fileB = result.inputFile("moduleB/src/sampleB.xoo");
- assertThat(result.coverageFor(fileB, 2)).isNull();
- }
-
- @Test
- public void warn_user_for_outdated_server_side_exclusions_for_multi_module_project() throws IOException {
-
- File baseDir = temp.getRoot();
- File baseDirModuleA = new File(baseDir, "moduleA");
- File baseDirModuleB = new File(baseDir, "moduleB");
- File srcDirA = new File(baseDirModuleA, "src");
- srcDirA.mkdirs();
- File srcDirB = new File(baseDirModuleB, "src");
- srcDirB.mkdirs();
-
- File xooFileA = new File(srcDirA, "sample.xoo");
- File xooUtCoverageFileA = new File(srcDirA, "sample.xoo.coverage");
- FileUtils.write(xooFileA, "function foo() {\n if (a && b) {\nalert('hello');\n}\n}", StandardCharsets.UTF_8);
- FileUtils.write(xooUtCoverageFileA, "2:2:2:1\n3:1", StandardCharsets.UTF_8);
-
- File xooFileB = new File(srcDirB, "sample.xoo");
- File xooUtCoverageFileB = new File(srcDirB, "sample.xoo.coverage");
- FileUtils.write(xooFileB, "function foo() {\n if (a && b) {\nalert('hello');\n}\n}", StandardCharsets.UTF_8);
- FileUtils.write(xooUtCoverageFileB, "2:2:2:1\n3:1", StandardCharsets.UTF_8);
-
- tester.addProjectServerSettings("sonar.coverage.exclusions", "src/sample.xoo");
-
- AnalysisResult result = tester.newAnalysis()
- .properties(ImmutableMap.<String, String>builder()
- .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
- .put("sonar.projectKey", "com.foo.project")
- .put("sonar.sources", "src")
- .put("sonar.modules", "moduleA,moduleB")
- .build())
- .execute();
-
- InputFile fileA = result.inputFile("moduleA/src/sample.xoo");
- assertThat(result.coverageFor(fileA, 2)).isNull();
-
- InputFile fileB = result.inputFile("moduleB/src/sample.xoo");
- assertThat(result.coverageFor(fileB, 2)).isNull();
-
- assertThat(logTester.logs(LoggerLevel.WARN)).contains("Specifying module-relative paths at project level in the property 'sonar.coverage.exclusions' is deprecated. " +
- "To continue matching files like 'moduleA/src/sample.xoo', update this property so that patterns refer to project-relative paths.");
- }
-
- @Test
- public void fallbackOnExecutableLines() throws IOException {
-
- File baseDir = temp.getRoot();
- File srcDir = new File(baseDir, "src");
- srcDir.mkdir();
-
- File xooFile = new File(srcDir, "sample.xoo");
- File measuresFile = new File(srcDir, "sample.xoo.measures");
- FileUtils.write(xooFile, "function foo() {\n if (a && b) {\nalert('hello');\n}\n}", StandardCharsets.UTF_8);
- FileUtils.write(measuresFile, "executable_lines_data:2=1;3=1;4=0", StandardCharsets.UTF_8);
-
- AnalysisResult result = tester.newAnalysis()
- .properties(ImmutableMap.<String, String>builder()
- .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
- .put("sonar.projectKey", "com.foo.project")
- .put("sonar.sources", "src")
- .build())
- .execute();
-
- InputFile file = result.inputFile("src/sample.xoo");
- assertThat(result.coverageFor(file, 1)).isNull();
-
- assertThat(result.coverageFor(file, 2).getHits()).isFalse();
- assertThat(result.coverageFor(file, 2).getConditions()).isZero();
- assertThat(result.coverageFor(file, 2).getCoveredConditions()).isZero();
-
- assertThat(result.coverageFor(file, 3).getHits()).isFalse();
- assertThat(result.coverageFor(file, 4)).isNull();
-
- assertThat(result.allMeasures().get(file.key()))
- .extracting(ScannerReport.Measure::getMetricKey, m -> m.getStringValue().getValue())
- .contains(tuple("executable_lines_data", "2=1;3=1;4=0"));
- }
-
- // SONAR-11641
- @Test
- public void dontFallbackOnExecutableLinesIfNoCoverageSaved() throws IOException {
-
- File baseDir = temp.getRoot();
- File srcDir = new File(baseDir, "src");
- srcDir.mkdir();
-
- File xooFile = new File(srcDir, "sample.xoo");
- File measuresFile = new File(srcDir, "sample.xoo.measures");
- File coverageFile = new File(srcDir, "sample.xoo.coverage");
- FileUtils.write(xooFile, "function foo() {\n if (a && b) {\nalert('hello');\n}\n}", StandardCharsets.UTF_8);
- FileUtils.write(measuresFile, "# The code analyzer disagree with the coverage tool and consider some lines to be executable\nexecutable_lines_data:2=1;3=1;4=0",
- StandardCharsets.UTF_8);
- FileUtils.write(coverageFile, "# No lines to cover in this file according to the coverage tool", StandardCharsets.UTF_8);
-
- AnalysisResult result = tester.newAnalysis()
- .properties(ImmutableMap.<String, String>builder()
- .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
- .put("sonar.projectKey", "com.foo.project")
- .put("sonar.sources", "src")
- .build())
- .execute();
-
- InputFile file = result.inputFile("src/sample.xoo");
- assertThat(result.coverageFor(file, 1)).isNull();
- assertThat(result.coverageFor(file, 2)).isNull();
- assertThat(result.coverageFor(file, 3)).isNull();
- assertThat(result.coverageFor(file, 4)).isNull();
- }
-
- // SONAR-9557
- @Test
- public void exclusionsAndForceToZeroOnModules() throws IOException {
-
- File baseDir = temp.getRoot();
- File srcDir = new File(baseDir, "module1/src");
- srcDir.mkdir();
-
- File xooFile1 = new File(srcDir, "sample1.xoo");
- File measuresFile1 = new File(srcDir, "sample1.xoo.measures");
- FileUtils.write(xooFile1, "function foo() {\n if (a && b) {\nalert('hello');\n}\n}", StandardCharsets.UTF_8);
- FileUtils.write(measuresFile1, "executable_lines_data:2=1;3=1;4=0", StandardCharsets.UTF_8);
-
- File xooFile2 = new File(srcDir, "sample2.xoo");
- File measuresFile2 = new File(srcDir, "sample2.xoo.measures");
- FileUtils.write(xooFile2, "function foo() {\n if (a && b) {\nalert('hello');\n}\n}", StandardCharsets.UTF_8);
- FileUtils.write(measuresFile2, "executable_lines_data:2=1;3=1;4=0", StandardCharsets.UTF_8);
-
- AnalysisResult result = tester.newAnalysis()
- .properties(ImmutableMap.<String, String>builder()
- .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
- .put("sonar.projectKey", "com.foo.project")
- .put("sonar.modules", "module1")
- .put("sonar.sources", "src")
- .put("sonar.coverage.exclusions", "**/sample2.xoo")
- .build())
- .execute();
-
- InputFile file1 = result.inputFile("module1/src/sample1.xoo");
- assertThat(result.coverageFor(file1, 1)).isNull();
-
- assertThat(result.coverageFor(file1, 2).getHits()).isFalse();
- assertThat(result.coverageFor(file1, 2).getConditions()).isZero();
- assertThat(result.coverageFor(file1, 2).getCoveredConditions()).isZero();
-
- assertThat(result.coverageFor(file1, 3).getHits()).isFalse();
- assertThat(result.coverageFor(file1, 4)).isNull();
-
- InputFile file2 = result.inputFile("module1/src/sample2.xoo");
- assertThat(result.coverageFor(file2, 1)).isNull();
- assertThat(result.coverageFor(file2, 2)).isNull();
- assertThat(result.coverageFor(file2, 3)).isNull();
- assertThat(result.coverageFor(file2, 4)).isNull();
-
- }
-
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2023 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.mediumtest.coverage;
-
-import java.io.File;
-import java.util.ArrayList;
-import java.util.List;
-import org.junit.Rule;
-import org.junit.Test;
-import org.sonar.api.batch.fs.InputFile;
-import org.sonar.scanner.mediumtest.AnalysisResult;
-import org.sonar.scanner.mediumtest.ScannerMediumTester;
-import org.sonar.xoo.XooPlugin;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class GenericCoverageMediumTest {
- private final List<String> logs = new ArrayList<>();
-
- @Rule
- public ScannerMediumTester tester = new ScannerMediumTester()
- .registerPlugin("xoo", new XooPlugin())
- .addDefaultQProfile("xoo", "Sonar Way");
-
- @Test
- public void singleReport() {
-
- File projectDir = new File("test-resources/mediumtest/xoo/sample-generic-coverage");
-
- AnalysisResult result = tester
- .setLogOutput((msg, level) -> logs.add(msg))
- .newAnalysis(new File(projectDir, "sonar-project.properties"))
- .property("sonar.coverageReportPaths", "coverage.xml")
- .execute();
-
- InputFile noConditions = result.inputFile("xources/hello/NoConditions.xoo");
- assertThat(result.coverageFor(noConditions, 6).getHits()).isTrue();
- assertThat(result.coverageFor(noConditions, 6).getConditions()).isZero();
- assertThat(result.coverageFor(noConditions, 6).getCoveredConditions()).isZero();
-
- assertThat(result.coverageFor(noConditions, 7).getHits()).isFalse();
-
- InputFile withConditions = result.inputFile("xources/hello/WithConditions.xoo");
- assertThat(result.coverageFor(withConditions, 3).getHits()).isTrue();
- assertThat(result.coverageFor(withConditions, 3).getConditions()).isEqualTo(2);
- assertThat(result.coverageFor(withConditions, 3).getCoveredConditions()).isOne();
-
- assertThat(logs).noneMatch(l -> l.contains("Please use 'sonar.coverageReportPaths'"));
-
- }
-
- @Test
- public void twoReports() {
-
- File projectDir = new File("test-resources/mediumtest/xoo/sample-generic-coverage");
-
- AnalysisResult result = tester
- .setLogOutput((msg, level) -> logs.add(msg))
- .newAnalysis(new File(projectDir, "sonar-project.properties"))
- .property("sonar.coverageReportPaths", "coverage.xml,coverage2.xml")
- .execute();
-
- InputFile noConditions = result.inputFile("xources/hello/NoConditions.xoo");
- assertThat(result.coverageFor(noConditions, 6).getHits()).isTrue();
- assertThat(result.coverageFor(noConditions, 6).getConditions()).isZero();
- assertThat(result.coverageFor(noConditions, 6).getCoveredConditions()).isZero();
-
- assertThat(result.coverageFor(noConditions, 7).getHits()).isTrue();
-
- InputFile withConditions = result.inputFile("xources/hello/WithConditions.xoo");
- assertThat(result.coverageFor(withConditions, 3).getHits()).isTrue();
- assertThat(result.coverageFor(withConditions, 3).getConditions()).isEqualTo(2);
- assertThat(result.coverageFor(withConditions, 3).getCoveredConditions()).isEqualTo(2);
-
- assertThat(logs).noneMatch(l -> l.contains("Please use 'sonar.coverageReportPaths'"));
- }
-
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2023 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.mediumtest.cpd;
-
-import com.google.common.collect.ImmutableMap;
-import java.io.File;
-import java.io.IOException;
-import java.nio.charset.StandardCharsets;
-import java.util.List;
-import org.apache.commons.io.FileUtils;
-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.utils.log.LogTester;
-import org.sonar.api.utils.log.LoggerLevel;
-import org.sonar.scanner.mediumtest.AnalysisResult;
-import org.sonar.scanner.mediumtest.ScannerMediumTester;
-import org.sonar.scanner.protocol.output.ScannerReport;
-import org.sonar.xoo.XooPlugin;
-import org.sonar.xoo.rule.XooRulesDefinition;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class CpdMediumTest {
- @Rule
- public TemporaryFolder temp = new TemporaryFolder();
-
- @Rule
- public LogTester logTester = new LogTester();
-
- private File baseDir;
-
- @Rule
- public ScannerMediumTester tester = new ScannerMediumTester()
- .registerPlugin("xoo", new XooPlugin())
- .addDefaultQProfile("xoo", "Sonar Way")
- .addRules(new XooRulesDefinition())
- // active a rule just to be sure that xoo files are published
- .addActiveRule("xoo", "xoo:OneIssuePerFile", null, "One Issue Per File", null, null, null);
-
- private ImmutableMap.Builder<String, String> builder;
-
- @Before
- public void prepare() {
- baseDir = temp.getRoot();
-
- builder = ImmutableMap.<String, String>builder()
- .put("sonar.task", "scan")
- .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
- .put("sonar.projectKey", "com.foo.project")
- .put("sonar.projectName", "Foo Project")
- .put("sonar.projectVersion", "1.0-SNAPSHOT")
- .put("sonar.projectDescription", "Description of Foo Project");
- }
-
- @Test
- public void testCrossModuleDuplications() throws IOException {
- builder.put("sonar.modules", "module1,module2")
- .put("sonar.cpd.xoo.minimumTokens", "10")
- .put("sonar.verbose", "true");
-
- // module 1
- builder.put("module1.sonar.projectKey", "module1");
- builder.put("module1.sonar.projectName", "Module 1");
- builder.put("module1.sonar.sources", ".");
-
- // module2
- builder.put("module2.sonar.projectKey", "module2");
- builder.put("module2.sonar.projectName", "Module 2");
- builder.put("module2.sonar.sources", ".");
-
- File module1Dir = new File(baseDir, "module1");
- File module2Dir = new File(baseDir, "module2");
-
- module1Dir.mkdir();
- module2Dir.mkdir();
-
- String duplicatedStuff = "Sample xoo\ncontent\n"
- + "foo\nbar\ntoto\ntiti\n"
- + "foo\nbar\ntoto\ntiti\n"
- + "bar\ntoto\ntiti\n"
- + "foo\nbar\ntoto\ntiti";
-
- // create duplicated file in both modules
- File xooFile1 = new File(module1Dir, "sample1.xoo");
- FileUtils.write(xooFile1, duplicatedStuff);
-
- File xooFile2 = new File(module2Dir, "sample2.xoo");
- FileUtils.write(xooFile2, duplicatedStuff);
-
- AnalysisResult result = tester.newAnalysis().properties(builder.build()).execute();
-
- assertThat(result.inputFiles()).hasSize(2);
-
- InputFile inputFile1 = result.inputFile("module1/sample1.xoo");
- InputFile inputFile2 = result.inputFile("module2/sample2.xoo");
-
- // One clone group on each file
- List<ScannerReport.Duplication> duplicationGroupsFile1 = result.duplicationsFor(inputFile1);
- assertThat(duplicationGroupsFile1).hasSize(1);
-
- ScannerReport.Duplication cloneGroupFile1 = duplicationGroupsFile1.get(0);
- assertThat(cloneGroupFile1.getOriginPosition().getStartLine()).isOne();
- assertThat(cloneGroupFile1.getOriginPosition().getEndLine()).isEqualTo(17);
- assertThat(cloneGroupFile1.getDuplicateList()).hasSize(1);
- assertThat(cloneGroupFile1.getDuplicate(0).getOtherFileRef()).isEqualTo(result.getReportComponent(inputFile2).getRef());
-
- List<ScannerReport.Duplication> duplicationGroupsFile2 = result.duplicationsFor(inputFile2);
- assertThat(duplicationGroupsFile2).hasSize(1);
-
- ScannerReport.Duplication cloneGroupFile2 = duplicationGroupsFile2.get(0);
- assertThat(cloneGroupFile2.getOriginPosition().getStartLine()).isOne();
- assertThat(cloneGroupFile2.getOriginPosition().getEndLine()).isEqualTo(17);
- assertThat(cloneGroupFile2.getDuplicateList()).hasSize(1);
- assertThat(cloneGroupFile2.getDuplicate(0).getOtherFileRef()).isEqualTo(result.getReportComponent(inputFile1).getRef());
-
- assertThat(result.duplicationBlocksFor(inputFile1)).isEmpty();
- }
-
- @Test
- public void testCrossFileDuplications() throws IOException {
- File srcDir = new File(baseDir, "src");
- srcDir.mkdir();
-
- String duplicatedStuff = "Sample xoo\ncontent\n"
- + "foo\nbar\ntoto\ntiti\n"
- + "foo\nbar\ntoto\ntiti\n"
- + "bar\ntoto\ntiti\n"
- + "foo\nbar\ntoto\ntiti";
-
- File xooFile1 = new File(srcDir, "sample1.xoo");
- FileUtils.write(xooFile1, duplicatedStuff, StandardCharsets.UTF_8);
-
- File xooFile2 = new File(srcDir, "sample2.xoo");
- FileUtils.write(xooFile2, duplicatedStuff, StandardCharsets.UTF_8);
-
- AnalysisResult result = tester.newAnalysis()
- .properties(builder
- .put("sonar.sources", "src")
- .put("sonar.cpd.xoo.minimumTokens", "10")
- .put("sonar.verbose", "true")
- .build())
- .execute();
-
- assertThat(result.inputFiles()).hasSize(2);
-
- InputFile inputFile1 = result.inputFile("src/sample1.xoo");
- InputFile inputFile2 = result.inputFile("src/sample2.xoo");
-
- // One clone group on each file
- List<ScannerReport.Duplication> duplicationGroupsFile1 = result.duplicationsFor(inputFile1);
- assertThat(duplicationGroupsFile1).hasSize(1);
-
- ScannerReport.Duplication cloneGroupFile1 = duplicationGroupsFile1.get(0);
- assertThat(cloneGroupFile1.getOriginPosition().getStartLine()).isOne();
- assertThat(cloneGroupFile1.getOriginPosition().getEndLine()).isEqualTo(17);
- assertThat(cloneGroupFile1.getDuplicateList()).hasSize(1);
- assertThat(cloneGroupFile1.getDuplicate(0).getOtherFileRef()).isEqualTo(result.getReportComponent(inputFile2).getRef());
-
- List<ScannerReport.Duplication> duplicationGroupsFile2 = result.duplicationsFor(inputFile2);
- assertThat(duplicationGroupsFile2).hasSize(1);
-
- ScannerReport.Duplication cloneGroupFile2 = duplicationGroupsFile2.get(0);
- assertThat(cloneGroupFile2.getOriginPosition().getStartLine()).isOne();
- assertThat(cloneGroupFile2.getOriginPosition().getEndLine()).isEqualTo(17);
- assertThat(cloneGroupFile2.getDuplicateList()).hasSize(1);
- assertThat(cloneGroupFile2.getDuplicate(0).getOtherFileRef()).isEqualTo(result.getReportComponent(inputFile1).getRef());
-
- assertThat(result.duplicationBlocksFor(inputFile1)).isEmpty();
- }
-
- @Test
- public void testFilesWithoutBlocks() throws IOException {
- File srcDir = new File(baseDir, "src");
- srcDir.mkdir();
-
- String file1 = "Sample xoo\ncontent\n"
- + "foo\nbar\ntoto\ntiti\n"
- + "foo\nbar\ntoto\ntiti\n"
- + "bar\ntoto\ntiti\n"
- + "foo\nbar\ntoto\ntiti";
-
- String file2 = "string\n";
-
- File xooFile1 = new File(srcDir, "sample1.xoo");
- FileUtils.write(xooFile1, file1, StandardCharsets.UTF_8);
-
- File xooFile2 = new File(srcDir, "sample2.xoo");
- FileUtils.write(xooFile2, file2, StandardCharsets.UTF_8);
-
- AnalysisResult result = tester.newAnalysis()
- .properties(builder
- .put("sonar.sources", "src")
- .put("sonar.cpd.xoo.minimumTokens", "10")
- .put("sonar.verbose", "true")
- .build())
- .execute();
-
- assertThat(result.inputFiles()).hasSize(2);
-
- assertThat(logTester.logs()).contains("Not enough content in 'src/sample2.xoo' to have CPD blocks, it will not be part of the duplication detection");
- assertThat(logTester.logs()).contains("CPD Executor 1 file had no CPD blocks");
-
- }
-
- @Test
- public void testExclusions() throws IOException {
- File srcDir = new File(baseDir, "src");
- srcDir.mkdir();
-
- String duplicatedStuff = "Sample xoo\ncontent\n"
- + "foo\nbar\ntoto\ntiti\n"
- + "foo\nbar\ntoto\ntiti\n"
- + "bar\ntoto\ntiti\n"
- + "foo\nbar\ntoto\ntiti";
-
- File xooFile1 = new File(srcDir, "sample1.xoo");
- FileUtils.write(xooFile1, duplicatedStuff);
-
- File xooFile2 = new File(srcDir, "sample2.xoo");
- FileUtils.write(xooFile2, duplicatedStuff);
-
- AnalysisResult result = tester.newAnalysis()
- .properties(builder
- .put("sonar.sources", "src")
- .put("sonar.cpd.xoo.minimumTokens", "10")
- .put("sonar.cpd.exclusions", "src/sample1.xoo")
- .build())
- .execute();
-
- assertThat(result.inputFiles()).hasSize(2);
-
- InputFile inputFile1 = result.inputFile("src/sample1.xoo");
- InputFile inputFile2 = result.inputFile("src/sample2.xoo");
-
- List<ScannerReport.Duplication> duplicationGroupsFile1 = result.duplicationsFor(inputFile1);
- assertThat(duplicationGroupsFile1).isEmpty();
-
- List<ScannerReport.Duplication> duplicationGroupsFile2 = result.duplicationsFor(inputFile2);
- assertThat(duplicationGroupsFile2).isEmpty();
- }
-
- @Test
- public void cross_module_duplication() throws IOException {
-
- String duplicatedStuff = "Sample xoo\ncontent\n"
- + "foo\nbar\ntoto\ntiti\n"
- + "foo\nbar\ntoto\ntiti\n"
- + "bar\ntoto\ntiti\n"
- + "foo\nbar\ntoto\ntiti";
-
- File baseDir = temp.getRoot();
- File baseDirModuleA = new File(baseDir, "moduleA");
- File baseDirModuleB = new File(baseDir, "moduleB");
- File srcDirA = new File(baseDirModuleA, "src");
- srcDirA.mkdirs();
- File srcDirB = new File(baseDirModuleB, "src");
- srcDirB.mkdirs();
-
- File xooFileA = new File(srcDirA, "sampleA.xoo");
- FileUtils.write(xooFileA, duplicatedStuff, StandardCharsets.UTF_8);
-
- File xooFileB = new File(srcDirB, "sampleB.xoo");
- FileUtils.write(xooFileB, duplicatedStuff, StandardCharsets.UTF_8);
-
- AnalysisResult result = tester.newAnalysis()
- .properties(ImmutableMap.<String, String>builder()
- .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
- .put("sonar.projectKey", "com.foo.project")
- .put("sonar.sources", "src")
- .put("sonar.modules", "moduleA,moduleB")
- .put("sonar.cpd.xoo.minimumTokens", "10")
- .build())
- .execute();
-
- InputFile inputFile1 = result.inputFile("moduleA/src/sampleA.xoo");
- InputFile inputFile2 = result.inputFile("moduleB/src/sampleB.xoo");
-
- List<ScannerReport.Duplication> duplicationGroupsFile1 = result.duplicationsFor(inputFile1);
- assertThat(duplicationGroupsFile1).isNotEmpty();
-
- List<ScannerReport.Duplication> duplicationGroupsFile2 = result.duplicationsFor(inputFile2);
- assertThat(duplicationGroupsFile2).isNotEmpty();
- }
-
- @Test
- public void warn_user_for_outdated_inherited_scanner_side_exclusions_for_multi_module_project() throws IOException {
-
- String duplicatedStuff = "Sample xoo\ncontent\n"
- + "foo\nbar\ntoto\ntiti\n"
- + "foo\nbar\ntoto\ntiti\n"
- + "bar\ntoto\ntiti\n"
- + "foo\nbar\ntoto\ntiti";
-
- File baseDir = temp.getRoot();
- File baseDirModuleA = new File(baseDir, "moduleA");
- File baseDirModuleB = new File(baseDir, "moduleB");
- File srcDirA = new File(baseDirModuleA, "src");
- srcDirA.mkdirs();
- File srcDirB = new File(baseDirModuleB, "src");
- srcDirB.mkdirs();
-
- File xooFileA = new File(srcDirA, "sampleA.xoo");
- FileUtils.write(xooFileA, duplicatedStuff, StandardCharsets.UTF_8);
-
- File xooFileB = new File(srcDirB, "sampleB.xoo");
- FileUtils.write(xooFileB, duplicatedStuff, StandardCharsets.UTF_8);
-
- AnalysisResult result = tester.newAnalysis()
- .properties(ImmutableMap.<String, String>builder()
- .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
- .put("sonar.projectKey", "com.foo.project")
- .put("sonar.sources", "src")
- .put("sonar.modules", "moduleA,moduleB")
- .put("sonar.cpd.xoo.minimumTokens", "10")
- .put("sonar.cpd.exclusions", "src/sampleA.xoo")
- .build())
- .execute();
-
- InputFile inputFile1 = result.inputFile("moduleA/src/sampleA.xoo");
- InputFile inputFile2 = result.inputFile("moduleB/src/sampleB.xoo");
-
- List<ScannerReport.Duplication> duplicationGroupsFile1 = result.duplicationsFor(inputFile1);
- assertThat(duplicationGroupsFile1).isEmpty();
-
- List<ScannerReport.Duplication> duplicationGroupsFile2 = result.duplicationsFor(inputFile2);
- assertThat(duplicationGroupsFile2).isEmpty();
-
- assertThat(logTester.logs(LoggerLevel.WARN)).contains("Specifying module-relative paths at project level in the property 'sonar.cpd.exclusions' is deprecated. " +
- "To continue matching files like 'moduleA/src/sampleA.xoo', update this property so that patterns refer to project-relative paths.");
- }
-
- @Test
- public void module_level_exclusions_override_parent_for_multi_module_project() throws IOException {
-
- String duplicatedStuff = "Sample xoo\ncontent\n"
- + "foo\nbar\ntoto\ntiti\n"
- + "foo\nbar\ntoto\ntiti\n"
- + "bar\ntoto\ntiti\n"
- + "foo\nbar\ntoto\ntiti";
-
- File baseDir = temp.getRoot();
- File baseDirModuleA = new File(baseDir, "moduleA");
- File baseDirModuleB = new File(baseDir, "moduleB");
- File srcDirA = new File(baseDirModuleA, "src");
- srcDirA.mkdirs();
- File srcDirB = new File(baseDirModuleB, "src");
- srcDirB.mkdirs();
-
- File xooFileA = new File(srcDirA, "sampleA.xoo");
- FileUtils.write(xooFileA, duplicatedStuff, StandardCharsets.UTF_8);
-
- File xooFileB = new File(srcDirB, "sampleB.xoo");
- FileUtils.write(xooFileB, duplicatedStuff, StandardCharsets.UTF_8);
-
- AnalysisResult result = tester.newAnalysis()
- .properties(ImmutableMap.<String, String>builder()
- .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
- .put("sonar.projectKey", "com.foo.project")
- .put("sonar.sources", "src")
- .put("sonar.modules", "moduleA,moduleB")
- .put("sonar.cpd.xoo.minimumTokens", "10")
- .put("sonar.cpd.exclusions", "**/*")
- .put("moduleA.sonar.cpd.exclusions", "**/*.nothing")
- .put("moduleB.sonar.cpd.exclusions", "**/*.nothing")
- .build())
- .execute();
-
- InputFile inputFile1 = result.inputFile("moduleA/src/sampleA.xoo");
- InputFile inputFile2 = result.inputFile("moduleB/src/sampleB.xoo");
-
- List<ScannerReport.Duplication> duplicationGroupsFile1 = result.duplicationsFor(inputFile1);
- assertThat(duplicationGroupsFile1).isNotEmpty();
-
- List<ScannerReport.Duplication> duplicationGroupsFile2 = result.duplicationsFor(inputFile2);
- assertThat(duplicationGroupsFile2).isNotEmpty();
- }
-
- @Test
- public void enableCrossProjectDuplication() throws IOException {
- File srcDir = new File(baseDir, "src");
- srcDir.mkdir();
-
- String duplicatedStuff = "Sample xoo\ncontent\nfoo\nbar\ntoto\ntiti\nfoo";
-
- File xooFile1 = new File(srcDir, "sample1.xoo");
- FileUtils.write(xooFile1, duplicatedStuff);
-
- AnalysisResult result = tester.newAnalysis()
- .properties(builder
- .put("sonar.sources", "src")
- .put("sonar.cpd.xoo.minimumTokens", "1")
- .put("sonar.cpd.xoo.minimumLines", "5")
- .put("sonar.verbose", "true")
- .put("sonar.cpd.cross_project", "true")
- .build())
- .execute();
-
- InputFile inputFile1 = result.inputFile("src/sample1.xoo");
-
- List<ScannerReport.CpdTextBlock> duplicationBlocks = result.duplicationBlocksFor(inputFile1);
- assertThat(duplicationBlocks).hasSize(3);
- assertThat(duplicationBlocks.get(0).getStartLine()).isOne();
- assertThat(duplicationBlocks.get(0).getEndLine()).isEqualTo(5);
- assertThat(duplicationBlocks.get(0).getStartTokenIndex()).isOne();
- assertThat(duplicationBlocks.get(0).getEndTokenIndex()).isEqualTo(6);
- assertThat(duplicationBlocks.get(0).getHash()).isNotEmpty();
-
- assertThat(duplicationBlocks.get(1).getStartLine()).isEqualTo(2);
- assertThat(duplicationBlocks.get(1).getEndLine()).isEqualTo(6);
- assertThat(duplicationBlocks.get(1).getStartTokenIndex()).isEqualTo(3);
- assertThat(duplicationBlocks.get(1).getEndTokenIndex()).isEqualTo(7);
- assertThat(duplicationBlocks.get(0).getHash()).isNotEmpty();
-
- assertThat(duplicationBlocks.get(2).getStartLine()).isEqualTo(3);
- assertThat(duplicationBlocks.get(2).getEndLine()).isEqualTo(7);
- assertThat(duplicationBlocks.get(2).getStartTokenIndex()).isEqualTo(4);
- assertThat(duplicationBlocks.get(2).getEndTokenIndex()).isEqualTo(8);
- assertThat(duplicationBlocks.get(0).getHash()).isNotEmpty();
- }
-
- @Test
- public void testIntraFileDuplications() throws IOException {
- File srcDir = new File(baseDir, "src");
- srcDir.mkdir();
-
- String content = "Sample xoo\ncontent\nfoo\nbar\nSample xoo\ncontent\n";
-
- File xooFile = new File(srcDir, "sample.xoo");
- FileUtils.write(xooFile, content);
-
- AnalysisResult result = tester.newAnalysis()
- .properties(builder
- .put("sonar.sources", "src")
- .put("sonar.cpd.xoo.minimumTokens", "2")
- .put("sonar.cpd.xoo.minimumLines", "2")
- .put("sonar.verbose", "true")
- .build())
- .execute();
-
- InputFile inputFile = result.inputFile("src/sample.xoo");
- // One clone group
- List<ScannerReport.Duplication> duplicationGroups = result.duplicationsFor(inputFile);
- assertThat(duplicationGroups).hasSize(1);
-
- ScannerReport.Duplication cloneGroup = duplicationGroups.get(0);
- assertThat(cloneGroup.getOriginPosition().getStartLine()).isOne();
- assertThat(cloneGroup.getOriginPosition().getEndLine()).isEqualTo(2);
- assertThat(cloneGroup.getDuplicateList()).hasSize(1);
- assertThat(cloneGroup.getDuplicate(0).getRange().getStartLine()).isEqualTo(5);
- assertThat(cloneGroup.getDuplicate(0).getRange().getEndLine()).isEqualTo(6);
- }
-
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2023 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.mediumtest.fs;
-
-import com.google.common.collect.ImmutableMap;
-import java.io.File;
-import java.io.IOException;
-import java.io.RandomAccessFile;
-import java.nio.charset.StandardCharsets;
-import java.nio.file.Files;
-import java.nio.file.LinkOption;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.util.Random;
-import java.util.stream.Collectors;
-import org.apache.commons.io.FileUtils;
-import org.apache.commons.lang.StringUtils;
-import org.apache.commons.lang.SystemUtils;
-import org.junit.Before;
-import org.junit.Ignore;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TemporaryFolder;
-import org.sonar.api.CoreProperties;
-import org.sonar.api.SonarEdition;
-import org.sonar.api.batch.fs.InputFile;
-import org.sonar.api.batch.fs.internal.DefaultInputFile;
-import org.sonar.api.utils.MessageException;
-import org.sonar.api.utils.PathUtils;
-import org.sonar.api.utils.System2;
-import org.sonar.api.utils.log.LogTester;
-import org.sonar.api.utils.log.LoggerLevel;
-import org.sonar.scanner.mediumtest.AnalysisResult;
-import org.sonar.scanner.mediumtest.ScannerMediumTester;
-import org.sonar.scanner.mediumtest.ScannerMediumTester.AnalysisBuilder;
-import org.sonar.xoo.XooPlugin;
-import org.sonar.xoo.global.DeprecatedGlobalSensor;
-import org.sonar.xoo.global.GlobalProjectSensor;
-import org.sonar.xoo.rule.XooRulesDefinition;
-
-import static java.lang.String.format;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.assertThatThrownBy;
-import static org.assertj.core.api.Assertions.tuple;
-import static org.junit.Assume.assumeFalse;
-import static org.junit.Assume.assumeTrue;
-
-public class FileSystemMediumTest {
-
- @Rule
- public TemporaryFolder temp = new TemporaryFolder();
-
- @Rule
- public LogTester logTester = new LogTester();
-
- @Rule
- public ScannerMediumTester tester = new ScannerMediumTester()
- .setEdition(SonarEdition.COMMUNITY)
- .registerPlugin("xoo", new XooPlugin())
- .addDefaultQProfile("xoo", "Sonar Way")
- .addDefaultQProfile("xoo2", "Sonar Way");
-
- private File baseDir;
- private ImmutableMap.Builder<String, String> builder;
-
- @Before
- public void prepare() throws IOException {
- baseDir = temp.newFolder().getCanonicalFile();
-
- builder = ImmutableMap.<String, String>builder()
- .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
- .put("sonar.projectKey", "com.foo.project");
- }
-
- @Test
- public void scan_project_without_name() throws IOException {
- File srcDir = new File(baseDir, "src");
- srcDir.mkdir();
-
- writeFile(srcDir, "sample.xoo", "Sample xoo\ncontent");
-
- AnalysisResult result = tester.newAnalysis()
- .properties(builder
- .put("sonar.sources", "src")
- .build())
- .execute();
-
- int ref = result.getReportReader().readMetadata().getRootComponentRef();
- assertThat(result.getReportReader().readComponent(ref).getName()).isEmpty();
- assertThat(result.inputFiles()).hasSize(1);
-
- DefaultInputFile file = (DefaultInputFile) result.inputFile("src/sample.xoo");
- assertThat(file.type()).isEqualTo(InputFile.Type.MAIN);
- assertThat(file.relativePath()).isEqualTo("src/sample.xoo");
- assertThat(file.language()).isEqualTo("xoo");
-
- // file was published, since language matched xoo
- assertThat(file.isPublished()).isTrue();
- assertThat(result.getReportComponent(file.scannerId())).isNotNull();
- }
-
- @Test
- public void log_branch_name_and_type() {
- builder.put("sonar.branch.name", "my-branch");
- File srcDir = new File(baseDir, "src");
- assertThat(srcDir.mkdir()).isTrue();
-
- // Using sonar.branch.name when the branch plugin is not installed is an error.
- assertThatThrownBy(() -> tester.newAnalysis()
- .properties(builder
- .put("sonar.sources", "src")
- .build())
- .execute())
- .isInstanceOf(MessageException.class);
- }
-
- @Test
- public void only_generate_metadata_if_needed() throws IOException {
- File srcDir = new File(baseDir, "src");
- srcDir.mkdir();
-
- writeFile(srcDir, "sample.xoo", "Sample xoo\ncontent");
- writeFile(srcDir, "sample.java", "Sample xoo\ncontent");
-
- logTester.setLevel(LoggerLevel.DEBUG);
-
- tester.newAnalysis()
- .properties(builder
- .put("sonar.sources", "src")
- .build())
- .execute();
-
- assertThat(logTester.logs()).contains("2 files indexed");
- assertThat(logTester.logs()).contains("'src/sample.xoo' generated metadata with charset 'UTF-8'");
- assertThat(String.join("\n", logTester.logs())).doesNotContain("'src/sample.java' generated metadata");
- }
-
- @Test
- public void preload_file_metadata() throws IOException {
- builder.put("sonar.preloadFileMetadata", "true");
-
- File srcDir = new File(baseDir, "src");
- srcDir.mkdir();
-
- writeFile(srcDir, "sample.xoo", "Sample xoo\ncontent");
- writeFile(srcDir, "sample.java", "Sample xoo\ncontent");
-
- logTester.setLevel(LoggerLevel.DEBUG);
-
- tester.newAnalysis()
- .properties(builder
- .put("sonar.sources", "src")
- .build())
- .execute();
-
- assertThat(logTester.logs()).contains("2 files indexed");
- assertThat(logTester.logs()).contains("'src/sample.xoo' generated metadata with charset 'UTF-8'");
- assertThat(logTester.logs()).contains("'src/sample.java' generated metadata with charset 'UTF-8'");
- }
-
- @Test
- public void dont_publish_files_without_detected_language() throws IOException {
- Path mainDir = baseDir.toPath().resolve("src").resolve("main");
- Files.createDirectories(mainDir);
-
- Path testDir = baseDir.toPath().resolve("src").resolve("test");
- Files.createDirectories(testDir);
-
- writeFile(testDir.toFile(), "sample.java", "Sample xoo\ncontent");
- writeFile(mainDir.toFile(), "sample.xoo", "Sample xoo\ncontent");
- writeFile(mainDir.toFile(), "sample.java", "Sample xoo\ncontent");
-
- logTester.setLevel(LoggerLevel.DEBUG);
-
- AnalysisResult result = tester.newAnalysis()
- .properties(builder
- .put("sonar.sources", "src/main")
- .put("sonar.tests", "src/test")
- .build())
- .execute();
-
- assertThat(logTester.logs()).containsAnyOf("'src/main/sample.java' indexed with no language", "'src\\main\\sample.java' indexed with no language");
- assertThat(logTester.logs()).contains("3 files indexed");
- assertThat(logTester.logs()).contains("'src/main/sample.xoo' generated metadata with charset 'UTF-8'");
- assertThat(logTester.logs()).doesNotContain("'src/main/sample.java' generated metadata", "'src\\main\\sample.java' generated metadata");
- assertThat(logTester.logs()).doesNotContain("'src/test/sample.java' generated metadata", "'src\\test\\sample.java' generated metadata");
- DefaultInputFile javaInputFile = (DefaultInputFile) result.inputFile("src/main/sample.java");
-
- assertThatThrownBy(() -> result.getReportComponent(javaInputFile))
- .isInstanceOf(IllegalStateException.class)
- .hasMessageContaining("Unable to find report for component");
- }
-
- @Test
- public void create_issue_on_any_file() throws IOException {
- tester
- .addRules(new XooRulesDefinition())
- .addActiveRule("xoo", "OneIssuePerUnknownFile", null, "OneIssuePerUnknownFile", "MAJOR", null, "xoo");
-
- File srcDir = new File(baseDir, "src");
- srcDir.mkdir();
-
- writeFile(srcDir, "sample.unknown", "Sample xoo\ncontent");
-
- logTester.setLevel(LoggerLevel.DEBUG);
-
- AnalysisResult result = tester.newAnalysis()
- .properties(builder
- .put("sonar.sources", "src")
- .build())
- .execute();
-
- assertThat(logTester.logs()).contains("1 file indexed");
- assertThat(logTester.logs()).contains("'src" + File.separator + "sample.unknown' indexed with no language");
- assertThat(logTester.logs()).contains("'src/sample.unknown' generated metadata with charset 'UTF-8'");
- DefaultInputFile inputFile = (DefaultInputFile) result.inputFile("src/sample.unknown");
- assertThat(result.getReportComponent(inputFile)).isNotNull();
- }
-
- @Test
- public void lazyIssueExclusion() throws IOException {
- tester
- .addRules(new XooRulesDefinition())
- .addActiveRule("xoo", "OneIssuePerFile", null, "OneIssuePerFile", "MAJOR", null, "xoo");
-
- builder.put("sonar.issue.ignore.allfile", "1")
- .put("sonar.issue.ignore.allfile.1.fileRegexp", "pattern");
- File srcDir = new File(baseDir, "src");
- srcDir.mkdir();
-
- writeFile(srcDir, "sample.xoo", "Sample xoo\ncontent");
-
- File unknownFile = new File(srcDir, "myfile.binary");
- byte[] b = new byte[512];
- new Random().nextBytes(b);
- FileUtils.writeByteArrayToFile(unknownFile, b);
-
- logTester.setLevel(LoggerLevel.DEBUG);
-
- tester.newAnalysis()
- .properties(builder
- .put("sonar.sources", "src")
- .build())
- .execute();
-
- assertThat(logTester.logs()).containsOnlyOnce("'src" + File.separator + "myfile.binary' indexed with no language");
- assertThat(logTester.logs()).doesNotContain("Evaluate issue exclusions for 'src/myfile.binary'");
- assertThat(logTester.logs()).containsOnlyOnce("Evaluate issue exclusions for 'src/sample.xoo'");
- }
-
- @Test
- public void preloadIssueExclusions() throws IOException {
- builder.put("sonar.issue.ignore.allfile", "1")
- .put("sonar.issue.ignore.allfile.1.fileRegexp", "pattern")
- .put("sonar.preloadFileMetadata", "true");
- File srcDir = new File(baseDir, "src");
- srcDir.mkdir();
-
- writeFile(srcDir, "sample.xoo", "Sample xoo\npattern");
- writeFile(srcDir, "myfile.binary", "some text");
-
- logTester.setLevel(LoggerLevel.DEBUG);
-
- tester.newAnalysis()
- .properties(builder
- .put("sonar.sources", "src")
- .build())
- .execute();
-
- assertThat(logTester.logs()).containsSequence("Evaluate issue exclusions for 'src/sample.xoo'",
- " - Exclusion pattern 'pattern': all issues in this file will be ignored.");
- }
-
- @Test
- public void publishFilesWithIssues() throws IOException {
- tester
- .addRules(new XooRulesDefinition())
- .addActiveRule("xoo", "OneIssueOnDirPerFile", null, "OneIssueOnDirPerFile", "MAJOR", null, "xoo");
-
- File srcDir = new File(baseDir, "src");
- srcDir.mkdir();
-
- writeFile(srcDir, "sample.xoo", "Sample xoo\ncontent");
-
- AnalysisResult result = tester.newAnalysis()
- .properties(builder
- .put("sonar.sources", "src")
- .build())
- .execute();
-
- DefaultInputFile file = (DefaultInputFile) result.inputFile("src/sample.xoo");
-
- assertThat(file.isPublished()).isTrue();
- assertThat(result.getReportComponent(file)).isNotNull();
- }
-
- @Test
- public void scanProjectWithSourceDir() throws IOException {
- File srcDir = new File(baseDir, "src");
- srcDir.mkdir();
-
- writeFile(srcDir, "sample.xoo", "Sample xoo\ncontent");
-
- AnalysisResult result = tester.newAnalysis()
- .properties(builder
- .put("sonar.sources", "src")
- .build())
- .execute();
-
- assertThat(result.inputFiles()).hasSize(1);
- assertThat(result.inputFile("src/sample.xoo").type()).isEqualTo(InputFile.Type.MAIN);
- assertThat(result.inputFile("src/sample.xoo").relativePath()).isEqualTo("src/sample.xoo");
- }
-
- @Test
- public void scanBigProject() throws IOException {
- File srcDir = new File(baseDir, "src");
- srcDir.mkdir();
-
- int nbFiles = 100;
- int ruleCount = 100000;
- for (int nb = 1; nb <= nbFiles; nb++) {
- File xooFile = new File(srcDir, "sample" + nb + ".xoo");
- FileUtils.write(xooFile, StringUtils.repeat(StringUtils.repeat("a", 100) + "\n", ruleCount / 1000));
- }
-
- AnalysisResult result = tester.newAnalysis()
- .properties(builder
- .put("sonar.sources", "src")
- .build())
- .execute();
-
- assertThat(result.inputFiles()).hasSize(100);
- }
-
- @Test
- public void scanProjectWithTestDir() throws IOException {
- File test = new File(baseDir, "test");
- test.mkdir();
-
- writeFile(test, "sampleTest.xoo", "Sample test xoo\ncontent");
-
- AnalysisResult result = tester.newAnalysis()
- .properties(builder
- .put("sonar.sources", "")
- .put("sonar.tests", "test")
- .build())
- .execute();
-
- assertThat(result.inputFiles()).hasSize(1);
- assertThat(result.inputFile("test/sampleTest.xoo").type()).isEqualTo(InputFile.Type.TEST);
- }
-
- /**
- * SONAR-5419
- */
- @Test
- public void scanProjectWithMixedSourcesAndTests() throws IOException {
- File srcDir = new File(baseDir, "src");
- srcDir.mkdir();
-
- writeFile(srcDir, "sample.xoo", "Sample xoo\ncontent");
- writeFile(baseDir, "another.xoo", "Sample xoo 2\ncontent");
-
- File testDir = new File(baseDir, "test");
- testDir.mkdir();
-
- writeFile(baseDir, "sampleTest2.xoo", "Sample test xoo\ncontent");
- writeFile(testDir, "sampleTest.xoo", "Sample test xoo 2\ncontent");
-
- AnalysisResult result = tester.newAnalysis()
- .properties(builder
- .put("sonar.sources", "src,another.xoo")
- .put("sonar.tests", "test,sampleTest2.xoo")
- .build())
- .execute();
-
- assertThat(result.inputFiles()).hasSize(4);
- }
-
- @Test
- public void fileInclusionsExclusions() throws IOException {
- File srcDir = new File(baseDir, "src");
- srcDir.mkdir();
-
- writeFile(srcDir, "sample.xoo", "Sample xoo\ncontent");
- writeFile(baseDir, "another.xoo", "Sample xoo 2\ncontent");
-
- File testDir = new File(baseDir, "test");
- testDir.mkdir();
-
- writeFile(baseDir, "sampleTest2.xoo", "Sample test xoo\ncontent");
- writeFile(testDir, "sampleTest.xoo", "Sample test xoo 2\ncontent");
-
- AnalysisResult result = tester.newAnalysis()
- .properties(builder
- .put("sonar.sources", "src,another.xoo")
- .put("sonar.tests", "test,sampleTest2.xoo")
- .put("sonar.inclusions", "src/**")
- .put("sonar.exclusions", "**/another.*")
- .put("sonar.test.inclusions", "**/sampleTest*.*")
- .put("sonar.test.exclusions", "**/sampleTest2.xoo")
- .build())
- .execute();
-
- assertThat(result.inputFiles()).hasSize(2);
- }
-
- @Test
- public void ignoreFilesWhenGreaterThanDefinedSize() throws IOException {
- File srcDir = new File(baseDir, "src");
- srcDir.mkdir();
-
- File fileGreaterThanLimit = writeFile(srcDir, "sample.xoo", 1024 * 1024 + 1);
- writeFile(srcDir, "another.xoo", "Sample xoo 2\ncontent");
-
- AnalysisResult result = tester.newAnalysis()
- .properties(builder
- // set limit to 1MB
- .put("sonar.filesize.limit", "1")
- .build())
- .execute();
-
- assertThat(result.inputFiles()).hasSize(1);
- assertThat(logTester.logs())
- .contains(format("File '%s' is bigger than 1MB and as consequence is removed from the analysis scope.", fileGreaterThanLimit.getAbsolutePath()));
- }
-
- @Test
- public void analysisFailsSymbolicLinkWithoutTargetIsInTheFolder() throws IOException {
- assumeFalse(SystemUtils.IS_OS_WINDOWS);
- File srcDir = new File(baseDir, "src");
- srcDir.mkdir();
-
- File target = writeFile(srcDir, "target.xoo", 1024 * 1024 + 1);
- Path link = Paths.get(srcDir.getPath(), "target_link.xoo");
- Files.createSymbolicLink(link, target.toPath());
- Files.delete(target.toPath());
-
- AnalysisBuilder analysis = tester.newAnalysis()
- .properties(builder.build());
-
- assertThatThrownBy(analysis::execute)
- .isExactlyInstanceOf(IllegalStateException.class)
- .hasMessageEndingWith(format("Unable to read file %s", link));
- }
-
- @Test
- public void test_inclusions_on_multi_modules() throws IOException {
- File baseDir = temp.getRoot();
- File baseDirModuleA = new File(baseDir, "moduleA");
- File baseDirModuleB = new File(baseDir, "moduleB");
- File srcDirA = new File(baseDirModuleA, "tests");
- srcDirA.mkdirs();
- File srcDirB = new File(baseDirModuleB, "tests");
- srcDirB.mkdirs();
-
- writeFile(srcDirA, "sampleTestA.xoo", "Sample xoo\ncontent");
- writeFile(srcDirB, "sampleTestB.xoo", "Sample xoo\ncontent");
-
- final ImmutableMap.Builder<String, String> builder = ImmutableMap.<String, String>builder()
- .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
- .put("sonar.projectKey", "com.foo.project")
- .put("sonar.sources", "")
- .put("sonar.tests", "tests")
- .put("sonar.modules", "moduleA,moduleB");
-
- AnalysisResult result = tester.newAnalysis()
- .properties(builder.build())
- .execute();
-
- assertThat(result.inputFiles()).hasSize(2);
-
- InputFile fileA = result.inputFile("moduleA/tests/sampleTestA.xoo");
- assertThat(fileA).isNotNull();
-
- InputFile fileB = result.inputFile("moduleB/tests/sampleTestB.xoo");
- assertThat(fileB).isNotNull();
-
- result = tester.newAnalysis()
- .properties(builder
- .put("sonar.test.inclusions", "moduleA/tests/**")
- .build())
- .execute();
-
- assertThat(result.inputFiles()).hasSize(1);
-
- fileA = result.inputFile("moduleA/tests/sampleTestA.xoo");
- assertThat(fileA).isNotNull();
-
- fileB = result.inputFile("moduleB/tests/sampleTestB.xoo");
- assertThat(fileB).isNull();
- }
-
- @Test
- public void test_module_level_inclusions_override_parent_on_multi_modules() throws IOException {
- File baseDir = temp.getRoot();
- File baseDirModuleA = new File(baseDir, "moduleA");
- File baseDirModuleB = new File(baseDir, "moduleB");
- File srcDirA = new File(baseDirModuleA, "src");
- srcDirA.mkdirs();
- File srcDirB = new File(baseDirModuleB, "src");
- srcDirB.mkdirs();
-
- writeFile(srcDirA, "sampleA.xoo", "Sample xoo\ncontent");
- writeFile(srcDirB, "sampleB.xoo", "Sample xoo\ncontent");
-
- final ImmutableMap.Builder<String, String> builder = ImmutableMap.<String, String>builder()
- .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
- .put("sonar.projectKey", "com.foo.project")
- .put("sonar.sources", "src")
- .put("sonar.modules", "moduleA,moduleB")
- .put("sonar.inclusions", "**/*.php");
-
- AnalysisResult result = tester.newAnalysis()
- .properties(builder.build())
- .execute();
-
- assertThat(result.inputFiles()).isEmpty();
-
- result = tester.newAnalysis()
- .properties(builder
- .put("moduleA.sonar.inclusions", "**/*.xoo")
- .build())
- .execute();
-
- assertThat(result.inputFiles()).hasSize(1);
-
- InputFile fileA = result.inputFile("moduleA/src/sampleA.xoo");
- assertThat(fileA).isNotNull();
- }
-
- @Test
- public void warn_user_for_outdated_scanner_side_inherited_exclusions_for_multi_module_project() throws IOException {
- File baseDir = temp.getRoot();
- File baseDirModuleA = new File(baseDir, "moduleA");
- File baseDirModuleB = new File(baseDir, "moduleB");
- File srcDirA = new File(baseDirModuleA, "src");
- srcDirA.mkdirs();
- File srcDirB = new File(baseDirModuleB, "src");
- srcDirB.mkdirs();
-
- writeFile(srcDirA, "sample.xoo", "Sample xoo\ncontent");
- writeFile(srcDirB, "sample.xoo", "Sample xoo\ncontent");
-
- AnalysisResult result = tester.newAnalysis()
- .properties(ImmutableMap.<String, String>builder()
- .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
- .put("sonar.projectKey", "com.foo.project")
- .put("sonar.sources", "src")
- .put("sonar.modules", "moduleA,moduleB")
- .put("sonar.exclusions", "src/sample.xoo")
- .build())
- .execute();
-
- InputFile fileA = result.inputFile("moduleA/src/sample.xoo");
- assertThat(fileA).isNull();
-
- InputFile fileB = result.inputFile("moduleB/src/sample.xoo");
- assertThat(fileB).isNull();
-
- assertThat(logTester.logs(LoggerLevel.WARN))
- .contains("Specifying module-relative paths at project level in the property 'sonar.exclusions' is deprecated. " +
- "To continue matching files like 'moduleA/src/sample.xoo', update this property so that patterns refer to project-relative paths.");
- }
-
- @Test
- public void support_global_server_side_exclusions_for_multi_module_project() throws IOException {
- File baseDir = temp.getRoot();
- File baseDirModuleA = new File(baseDir, "moduleA");
- File baseDirModuleB = new File(baseDir, "moduleB");
- File srcDirA = new File(baseDirModuleA, "src");
- srcDirA.mkdirs();
- File srcDirB = new File(baseDirModuleB, "src");
- srcDirB.mkdirs();
-
- writeFile(srcDirA, "sample.xoo", "Sample xoo\ncontent");
- writeFile(srcDirB, "sample.xoo", "Sample xoo\ncontent");
-
- tester.addGlobalServerSettings(CoreProperties.PROJECT_EXCLUSIONS_PROPERTY, "**/*.xoo");
-
- AnalysisResult result = tester.newAnalysis()
- .properties(ImmutableMap.<String, String>builder()
- .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
- .put("sonar.projectKey", "com.foo.project")
- .put("sonar.sources", "src")
- .put("sonar.modules", "moduleA,moduleB")
- .build())
- .execute();
-
- InputFile fileA = result.inputFile("moduleA/src/sample.xoo");
- assertThat(fileA).isNull();
-
- InputFile fileB = result.inputFile("moduleB/src/sample.xoo");
- assertThat(fileB).isNull();
- }
-
- @Test
- public void support_global_server_side_global_exclusions_for_multi_module_project() throws IOException {
- File baseDir = temp.getRoot();
- File baseDirModuleA = new File(baseDir, "moduleA");
- File baseDirModuleB = new File(baseDir, "moduleB");
- File srcDirA = new File(baseDirModuleA, "src");
- srcDirA.mkdirs();
- File srcDirB = new File(baseDirModuleB, "src");
- srcDirB.mkdirs();
-
- writeFile(srcDirA, "sample.xoo", "Sample xoo\ncontent");
- writeFile(srcDirB, "sample.xoo", "Sample xoo\ncontent");
-
- tester.addGlobalServerSettings(CoreProperties.GLOBAL_EXCLUSIONS_PROPERTY, "**/*.xoo");
-
- AnalysisResult result = tester.newAnalysis()
- .properties(ImmutableMap.<String, String>builder()
- .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
- .put("sonar.projectKey", "com.foo.project")
- .put("sonar.sources", "src")
- .put("sonar.modules", "moduleA,moduleB")
- .build())
- .execute();
-
- InputFile fileA = result.inputFile("moduleA/src/sample.xoo");
- assertThat(fileA).isNull();
-
- InputFile fileB = result.inputFile("moduleB/src/sample.xoo");
- assertThat(fileB).isNull();
- }
-
- @Test
- public void warn_user_for_outdated_server_side_inherited_exclusions_for_multi_module_project() throws IOException {
- File baseDir = temp.getRoot();
- File baseDirModuleA = new File(baseDir, "moduleA");
- File baseDirModuleB = new File(baseDir, "moduleB");
- File srcDirA = new File(baseDirModuleA, "src");
- srcDirA.mkdirs();
- File srcDirB = new File(baseDirModuleB, "src");
- srcDirB.mkdirs();
-
- writeFile(srcDirA, "sample.xoo", "Sample xoo\ncontent");
- writeFile(srcDirB, "sample.xoo", "Sample xoo\ncontent");
-
- tester.addProjectServerSettings("sonar.exclusions", "src/sample.xoo");
-
- AnalysisResult result = tester.newAnalysis()
- .properties(ImmutableMap.<String, String>builder()
- .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
- .put("sonar.projectKey", "com.foo.project")
- .put("sonar.sources", "src")
- .put("sonar.modules", "moduleA,moduleB")
- .build())
- .execute();
-
- InputFile fileA = result.inputFile("moduleA/src/sample.xoo");
- assertThat(fileA).isNull();
-
- InputFile fileB = result.inputFile("moduleB/src/sample.xoo");
- assertThat(fileB).isNull();
-
- assertThat(logTester.logs(LoggerLevel.WARN))
- .contains("Specifying module-relative paths at project level in the property 'sonar.exclusions' is deprecated. " +
- "To continue matching files like 'moduleA/src/sample.xoo', update this property so that patterns refer to project-relative paths.");
- }
-
- @Test
- public void failForDuplicateInputFile() throws IOException {
- File srcDir = new File(baseDir, "src");
- srcDir.mkdir();
-
- writeFile(srcDir, "sample.xoo", "Sample xoo\ncontent");
-
- assertThatThrownBy(() -> tester.newAnalysis()
- .properties(builder
- .put("sonar.sources", "src,src/sample.xoo")
- .build())
- .execute())
- .isInstanceOf(MessageException.class)
- .hasMessage("File src/sample.xoo can't be indexed twice. Please check that inclusion/exclusion patterns produce disjoint sets for main and test files");
- }
-
- // SONAR-9574
- @Test
- public void failForDuplicateInputFileInDifferentModules() throws IOException {
- File srcDir = new File(baseDir, "module1/src");
- srcDir.mkdir();
-
- writeFile(srcDir, "sample.xoo", "Sample xoo\ncontent");
-
- assertThatThrownBy(() -> tester.newAnalysis()
- .properties(builder
- .put("sonar.sources", "module1/src")
- .put("sonar.modules", "module1")
- .put("module1.sonar.sources", "src")
- .build())
- .execute())
- .isInstanceOf(MessageException.class)
- .hasMessage("File module1/src/sample.xoo can't be indexed twice. Please check that inclusion/exclusion patterns produce disjoint sets for main and test files");
- }
-
- // SONAR-5330
- @Test
- public void scanProjectWithSourceSymlink() {
- assumeTrue(!System2.INSTANCE.isOsWindows());
- File projectDir = new File("test-resources/mediumtest/xoo/sample-with-symlink");
- AnalysisResult result = tester
- .newAnalysis(new File(projectDir, "sonar-project.properties"))
- .property("sonar.exclusions", "**/*.xoo.measures,**/*.xoo.scm")
- .property("sonar.test.exclusions", "**/*.xoo.measures,**/*.xoo.scm")
- .property("sonar.scm.exclusions.disabled", "true")
- .execute();
-
- assertThat(result.inputFiles()).hasSize(3);
- // check that symlink was not resolved to target
- assertThat(result.inputFiles()).extractingResultOf("path").toString().startsWith(projectDir.toString());
- }
-
- // SONAR-6719
- @Test
- public void scanProjectWithWrongCase() {
- // To please the quality gate, don't use assumeTrue, or the test will be reported as skipped
- File projectDir = new File("test-resources/mediumtest/xoo/sample");
- AnalysisBuilder analysis = tester
- .newAnalysis(new File(projectDir, "sonar-project.properties"))
- .property("sonar.sources", "XOURCES")
- .property("sonar.tests", "TESTX")
- .property("sonar.scm.exclusions.disabled", "true");
-
- if (System2.INSTANCE.isOsWindows()) { // Windows is file path case-insensitive
- AnalysisResult result = analysis.execute();
-
- assertThat(result.inputFiles()).hasSize(8);
- assertThat(result.inputFiles()).extractingResultOf("relativePath").containsOnly(
- "testx/ClassOneTest.xoo.measures",
- "xources/hello/helloscala.xoo.measures",
- "xources/hello/HelloJava.xoo.measures",
- "testx/ClassOneTest.xoo",
- "xources/hello/HelloJava.xoo.scm",
- "xources/hello/helloscala.xoo",
- "testx/ClassOneTest.xoo.scm",
- "xources/hello/HelloJava.xoo");
- } else if (System2.INSTANCE.isOsMac()) {
- AnalysisResult result = analysis.execute();
-
- assertThat(result.inputFiles()).hasSize(8);
- assertThat(result.inputFiles()).extractingResultOf("relativePath").containsOnly(
- "TESTX/ClassOneTest.xoo.measures",
- "XOURCES/hello/helloscala.xoo.measures",
- "XOURCES/hello/HelloJava.xoo.measures",
- "TESTX/ClassOneTest.xoo",
- "XOURCES/hello/HelloJava.xoo.scm",
- "XOURCES/hello/helloscala.xoo",
- "TESTX/ClassOneTest.xoo.scm",
- "XOURCES/hello/HelloJava.xoo");
- } else {
- assertThatThrownBy(() -> analysis.execute())
- .isInstanceOf(MessageException.class)
- .hasMessageContaining("The folder 'TESTX' does not exist for 'sample'");
- }
- }
-
- @Test
- public void indexAnyFile() throws IOException {
- File srcDir = new File(baseDir, "src");
- srcDir.mkdir();
-
- writeFile(srcDir, "sample.xoo", "Sample xoo\ncontent");
- writeFile(srcDir, "sample.other", "Sample other\ncontent");
-
- AnalysisResult result = tester.newAnalysis()
- .properties(builder
- .put("sonar.sources", "src")
- .build())
- .execute();
-
- assertThat(result.inputFiles()).hasSize(2);
- assertThat(result.inputFile("src/sample.other").type()).isEqualTo(InputFile.Type.MAIN);
- assertThat(result.inputFile("src/sample.other").relativePath()).isEqualTo("src/sample.other");
- assertThat(result.inputFile("src/sample.other").language()).isNull();
- }
-
- @Test
- public void scanMultiModuleProject() {
- File projectDir = new File("test-resources/mediumtest/xoo/multi-modules-sample");
- AnalysisResult result = tester
- .newAnalysis(new File(projectDir, "sonar-project.properties"))
- .execute();
-
- assertThat(result.inputFiles()).hasSize(4);
- }
-
- @Test
- public void deprecated_global_sensor_should_see_project_relative_paths() {
- File projectDir = new File("test-resources/mediumtest/xoo/multi-modules-sample");
- AnalysisResult result = tester
- .newAnalysis(new File(projectDir, "sonar-project.properties"))
- .property(DeprecatedGlobalSensor.ENABLE_PROP, "true")
- .execute();
-
- assertThat(result.inputFiles()).hasSize(4);
- assertThat(logTester.logs(LoggerLevel.INFO)).contains(
- "Deprecated Global Sensor: module_a/module_a1/src/main/xoo/com/sonar/it/samples/modules/a1/HelloA1.xoo",
- "Deprecated Global Sensor: module_a/module_a2/src/main/xoo/com/sonar/it/samples/modules/a2/HelloA2.xoo",
- "Deprecated Global Sensor: module_b/module_b1/src/main/xoo/com/sonar/it/samples/modules/b1/HelloB1.xoo",
- "Deprecated Global Sensor: module_b/module_b2/src/main/xoo/com/sonar/it/samples/modules/b2/HelloB2.xoo");
- }
-
- @Test
- public void global_sensor_should_see_project_relative_paths() {
- File projectDir = new File("test-resources/mediumtest/xoo/multi-modules-sample");
- AnalysisResult result = tester
- .newAnalysis(new File(projectDir, "sonar-project.properties"))
- .property(GlobalProjectSensor.ENABLE_PROP, "true")
- .execute();
-
- assertThat(result.inputFiles()).hasSize(4);
- assertThat(logTester.logs(LoggerLevel.INFO)).contains(
- "Global Sensor: module_a/module_a1/src/main/xoo/com/sonar/it/samples/modules/a1/HelloA1.xoo",
- "Global Sensor: module_a/module_a2/src/main/xoo/com/sonar/it/samples/modules/a2/HelloA2.xoo",
- "Global Sensor: module_b/module_b1/src/main/xoo/com/sonar/it/samples/modules/b1/HelloB1.xoo",
- "Global Sensor: module_b/module_b2/src/main/xoo/com/sonar/it/samples/modules/b2/HelloB2.xoo");
- }
-
- @Test
- public void scan_project_with_comma_in_source_path() throws IOException {
- File srcDir = new File(baseDir, "src");
- srcDir.mkdir();
-
- writeFile(srcDir, "sample,1.xoo", "Sample xoo\ncontent");
- writeFile(baseDir, "another,2.xoo", "Sample xoo 2\ncontent");
-
- File testDir = new File(baseDir, "test");
- testDir.mkdir();
-
- writeFile(testDir, "sampleTest,1.xoo", "Sample test xoo\ncontent");
- writeFile(baseDir, "sampleTest,2.xoo", "Sample test xoo 2\ncontent");
-
- AnalysisResult result = tester.newAnalysis()
- .properties(builder
- .put("sonar.sources", "src,\"another,2.xoo\"")
- .put("sonar.tests", "\"test\",\"sampleTest,2.xoo\"")
- .build())
- .execute();
-
- assertThat(result.inputFiles()).hasSize(4);
- }
-
- @Test
- public void language_without_publishAllFiles_should_not_auto_publish_files() throws IOException {
- File srcDir = new File(baseDir, "src");
- srcDir.mkdir();
-
- writeFile(srcDir, "sample.xoo3", "Sample xoo\ncontent");
- writeFile(srcDir, "sample2.xoo3", "Sample xoo 2\ncontent");
-
- AnalysisResult result = tester.newAnalysis()
- .properties(builder
- .put("sonar.sources", "src")
- .build())
- .execute();
-
- assertThat(result.inputFiles())
- .extracting(InputFile::filename, InputFile::language, f -> ((DefaultInputFile) f).isPublished())
- .containsOnly(tuple("sample.xoo3", "xoo3", false), tuple("sample2.xoo3", "xoo3", false));
- assertThat(result.getReportReader().readComponent(result.getReportReader().readMetadata().getRootComponentRef()).getChildRefCount()).isZero();
- }
-
- @Test
- public void two_languages_with_same_extension() throws IOException {
- File srcDir = new File(baseDir, "src");
- srcDir.mkdir();
-
- writeFile(srcDir, "sample.xoo", "Sample xoo\ncontent");
- writeFile(srcDir, "sample.xoo2", "Sample xoo 2\ncontent");
-
- AnalysisResult result = tester.newAnalysis()
- .properties(builder
- .put("sonar.sources", "src")
- .build())
- .execute();
-
- assertThat(result.inputFiles()).hasSize(2);
-
- AnalysisBuilder analysisBuilder = tester.newAnalysis()
- .properties(builder
- .put("sonar.lang.patterns.xoo2", "**/*.xoo")
- .build());
-
- assertThatThrownBy(analysisBuilder::execute)
- .isInstanceOf(MessageException.class)
- .hasMessage(
- "Language of file 'src" + File.separator
- + "sample.xoo' can not be decided as the file matches patterns of both sonar.lang.patterns.xoo : **/*.xoo and sonar.lang.patterns.xoo2 : **/*.xoo");
-
- // SONAR-9561
- result = tester.newAnalysis()
- .properties(builder
- .put("sonar.exclusions", "**/sample.xoo")
- .build())
- .execute();
-
- assertThat(result.inputFiles()).hasSize(1);
- }
-
- @Test
- public void log_all_exclusions_properties_per_modules() throws IOException {
- File baseDir = temp.getRoot();
- File baseDirModuleA = new File(baseDir, "moduleA");
- File baseDirModuleB = new File(baseDir, "moduleB");
- File srcDirA = new File(baseDirModuleA, "src");
- srcDirA.mkdirs();
- File srcDirB = new File(baseDirModuleB, "src");
- srcDirB.mkdirs();
-
- writeFile(srcDirA, "sample.xoo", "Sample xoo\ncontent");
- writeFile(srcDirB, "sample.xoo", "Sample xoo\ncontent");
-
- AnalysisResult result = tester.newAnalysis()
- .properties(ImmutableMap.<String, String>builder()
- .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
- .put("sonar.projectKey", "com.foo.project")
- .put("sonar.sources", "src")
- .put("sonar.modules", "moduleA,moduleB")
- .put("sonar.inclusions", "**/global.inclusions")
- .put("sonar.test.inclusions", "**/global.test.inclusions")
- .put("sonar.exclusions", "**/global.exclusions")
- .put("sonar.test.exclusions", "**/global.test.exclusions")
- .put("sonar.coverage.exclusions", "**/coverage.exclusions")
- .put("sonar.cpd.exclusions", "**/cpd.exclusions")
- .build())
- .execute();
-
- assertThat(logTester.logs(LoggerLevel.INFO))
- .containsSequence("Project configuration:",
- " Included sources: **/global.inclusions",
- " Excluded sources: **/global.exclusions, **/global.test.inclusions",
- " Included tests: **/global.test.inclusions",
- " Excluded tests: **/global.test.exclusions",
- " Excluded sources for coverage: **/coverage.exclusions",
- " Excluded sources for duplication: **/cpd.exclusions",
- "Indexing files of module 'moduleA'",
- " Base dir: " + baseDirModuleA.toPath().toRealPath(LinkOption.NOFOLLOW_LINKS),
- " Source paths: src",
- " Included sources: **/global.inclusions",
- " Excluded sources: **/global.exclusions, **/global.test.inclusions",
- " Included tests: **/global.test.inclusions",
- " Excluded tests: **/global.test.exclusions",
- " Excluded sources for coverage: **/coverage.exclusions",
- " Excluded sources for duplication: **/cpd.exclusions",
- "Indexing files of module 'moduleB'",
- " Base dir: " + baseDirModuleB.toPath().toRealPath(LinkOption.NOFOLLOW_LINKS),
- " Source paths: src",
- " Included sources: **/global.inclusions",
- " Excluded sources: **/global.exclusions, **/global.test.inclusions",
- " Included tests: **/global.test.inclusions",
- " Excluded tests: **/global.test.exclusions",
- " Excluded sources for coverage: **/coverage.exclusions",
- " Excluded sources for duplication: **/cpd.exclusions",
- "Indexing files of module 'com.foo.project'",
- " Base dir: " + baseDir.toPath().toRealPath(LinkOption.NOFOLLOW_LINKS),
- " Included sources: **/global.inclusions",
- " Excluded sources: **/global.exclusions, **/global.test.inclusions",
- " Included tests: **/global.test.inclusions",
- " Excluded tests: **/global.test.exclusions",
- " Excluded sources for coverage: **/coverage.exclusions",
- " Excluded sources for duplication: **/cpd.exclusions");
- }
-
- @Test
- public void ignore_files_outside_project_basedir() throws IOException {
- File srcDir = new File(baseDir, "src");
- srcDir.mkdir();
-
- writeFile(srcDir, "sample1.xoo", "Sample xoo\ncontent");
-
- File outsideBaseDir = temp.newFolder().getCanonicalFile();
- File xooFile2 = writeFile(outsideBaseDir, "another.xoo", "Sample xoo 2\ncontent");
-
- AnalysisResult result = tester.newAnalysis()
- .properties(builder
- .put("sonar.sources", "src," + PathUtils.canonicalPath(xooFile2))
- .build())
- .execute();
-
- assertThat(result.inputFiles()).hasSize(1);
- assertThat(logTester.logs(LoggerLevel.WARN)).contains("File '" + xooFile2.getAbsolutePath() + "' is ignored. It is not located in project basedir '" + baseDir + "'.");
- }
-
- @Test
- public void dont_log_warn_about_files_out_of_basedir_if_they_arent_included() throws IOException {
- File srcDir = new File(baseDir, "src");
- srcDir.mkdir();
-
- writeFile(srcDir, "sample1.xoo", "Sample xoo\ncontent");
-
- File outsideBaseDir = temp.newFolder().getCanonicalFile();
- File xooFile2 = new File(outsideBaseDir, "another.xoo");
- FileUtils.write(xooFile2, "Sample xoo 2\ncontent", StandardCharsets.UTF_8);
-
- AnalysisResult result = tester.newAnalysis()
- .properties(builder
- .put("sonar.sources", "src," + PathUtils.canonicalPath(xooFile2))
- .put("sonar.inclusions", "**/sample1.xoo")
- .build())
- .execute();
-
- assertThat(result.inputFiles()).hasSize(1);
- assertThat(logTester.logs(LoggerLevel.WARN)).doesNotContain("File '" + xooFile2.getAbsolutePath() + "' is ignored. It is not located in project basedir '" + baseDir + "'.");
- }
-
- @Test
- public void ignore_files_outside_module_basedir() throws IOException {
- File moduleA = new File(baseDir, "moduleA");
- moduleA.mkdir();
-
- writeFile(moduleA, "src/sampleA.xoo", "Sample xoo\ncontent");
- File xooFile2 = writeFile(baseDir, "another.xoo", "Sample xoo 2\ncontent");
-
- AnalysisResult result = tester.newAnalysis()
- .properties(builder
- .put("sonar.modules", "moduleA")
- .put("moduleA.sonar.sources", "src," + PathUtils.canonicalPath(xooFile2))
- .build())
- .execute();
-
- assertThat(result.inputFiles()).hasSize(1);
- assertThat(logTester.logs(LoggerLevel.WARN))
- .contains("File '" + xooFile2.getAbsolutePath() + "' is ignored. It is not located in module basedir '" + new File(baseDir, "moduleA") + "'.");
- }
-
- @Test
- public void exclusion_based_on_scm_info() {
- File projectDir = new File("test-resources/mediumtest/xoo/sample-with-ignored-file");
- AnalysisResult result = tester
- .newAnalysis(new File(projectDir, "sonar-project.properties"))
- .property("sonar.exclusions", "**/*.xoo.ignore")
- .property("sonar.test.exclusions", "**/*.xoo.ignore")
- .execute();
-
- assertThat(result.inputFile("xources/hello/ClassTwo.xoo")).isNull();
- assertThat(result.inputFile("testx/ClassTwoTest.xoo")).isNull();
-
- assertThat(result.inputFile("xources/hello/ClassOne.xoo")).isNotNull();
- assertThat(result.inputFile("testx/ClassOneTest.xoo")).isNotNull();
- }
-
- @Test
- public void no_exclusion_when_scm_exclusions_is_disabled() {
- File projectDir = new File("test-resources/mediumtest/xoo/sample-with-ignored-file");
- AnalysisResult result = tester
- .newAnalysis(new File(projectDir, "sonar-project.properties"))
- .property("sonar.scm.exclusions.disabled", "true")
- .property("sonar.exclusions", "**/*.xoo.ignore")
- .property("sonar.test.exclusions", "**/*.xoo.ignore")
- .execute();
-
- assertThat(result.inputFiles()).hasSize(4);
-
- assertThat(result.inputFile("xources/hello/ClassTwo.xoo")).isNotNull();
- assertThat(result.inputFile("testx/ClassTwoTest.xoo")).isNotNull();
- assertThat(result.inputFile("xources/hello/ClassOne.xoo")).isNotNull();
- assertThat(result.inputFile("testx/ClassOneTest.xoo")).isNotNull();
- }
-
- @Test
- public void index_basedir_by_default() throws IOException {
- writeFile(baseDir, "sample.xoo", "Sample xoo\ncontent");
- AnalysisResult result = tester.newAnalysis()
- .properties(builder
- .build())
- .execute();
-
- assertThat(logTester.logs()).contains("1 file indexed");
- assertThat(result.inputFile("sample.xoo")).isNotNull();
- }
-
- @Test
- public void givenExclusionEndingWithOneWildcardWhenAnalysedThenOnlyDirectChildrenFilesShouldBeExcluded() throws IOException {
- // src/src.xoo
- File srcDir = createDir(baseDir, "src", true);
- writeFile(srcDir, "src.xoo", "Sample xoo 2\ncontent");
-
- // src/srcSubDir/srcSub.xoo
- File srcSubDir = createDir(srcDir, "srcSubDir", true);
- writeFile(srcSubDir, "srcSub.xoo", "Sample xoo\ncontent");
-
- // src/srcSubDir/srcSubSubDir/subSubSrc.xoo
- File srcSubSubDir = createDir(srcSubDir, "srcSubSubDir", true);
- writeFile(srcSubSubDir, "subSubSrc.xoo", "Sample xoo\ncontent");
-
- AnalysisResult result = tester.newAnalysis()
- .properties(builder
- .put("sonar.sources", "src")
- .put("sonar.exclusions", "src/srcSubDir/*")
- .build())
- .execute();
-
- assertAnalysedFiles(result, "src/src.xoo", "src/srcSubDir/srcSubSubDir/subSubSrc.xoo");
- }
-
- @Test
- public void givenPathsWithoutReadPermissionWhenAllChildrenAreExcludedThenScannerShouldSkipIt() throws IOException {
- // src/src.xoo
- File srcDir = createDir(baseDir, "src", true);
- writeFile(srcDir, "src.xoo", "Sample xoo 2\ncontent");
-
- // src/srcSubDir/srcSub.xoo
- File srcSubDir = createDir(srcDir, "srcSubDir", false);
- writeFile(srcSubDir, "srcSub.xoo", "Sample xoo\ncontent");
-
- // src/srcSubDir2/srcSub2.xoo
- File srcSubDir2 = createDir(srcDir, "srcSubDir2", true);
- boolean fileNotReadable = writeFile(srcSubDir2, "srcSub2.xoo", "Sample 2 xoo\ncontent").setReadable(false);
- assumeTrue(fileNotReadable);
-
- // src/srcSubDir2/srcSubSubDir2/srcSubSub2.xoo
- File srcSubSubDir2 = createDir(srcSubDir2, "srcSubSubDir2", false);
- writeFile(srcSubSubDir2, "srcSubSub2.xoo", "Sample xoo\ncontent");
-
- AnalysisResult result = tester.newAnalysis()
- .properties(builder
- .put("sonar.sources", "src")
- .put("sonar.exclusions", "src/srcSubDir/**/*,src/srcSubDir2/**/*")
- .build())
- .execute();
-
- assertAnalysedFiles(result, "src/src.xoo");
- assertThat(logTester.logs()).contains("1 file ignored because of inclusion/exclusion patterns");
- }
-
- @Test
- public void givenFileWithoutAccessWhenChildrenAreExcludedThenThenScanShouldFail() throws IOException {
- // src/src.xoo
- File srcDir = createDir(baseDir, "src", true);
- boolean fileNotReadable = writeFile(srcDir, "src.xoo", "Sample xoo\ncontent").setReadable(false);
- assumeTrue(fileNotReadable);
-
- AnalysisBuilder result = tester.newAnalysis()
- .properties(builder
- .put("sonar.sources", "src")
- .put("sonar.exclusions", "src/src.xoo/**/*") // incorrect pattern, but still the scan should fail if src.xoo is not accessible
- .build());
-
- assertThatThrownBy(result::execute)
- .isExactlyInstanceOf(IllegalStateException.class)
- .hasMessageStartingWith(format("java.lang.IllegalStateException: Unable to read file"));
- }
-
- @Test
- public void givenDirectoryWithoutReadPermissionWhenIncludedThenScanShouldFail() throws IOException {
- // src/src.xoo
- File srcDir = createDir(baseDir, "src", true);
- writeFile(srcDir, "src.xoo", "Sample xoo 2\ncontent");
-
- // src/srcSubDir/srcSub.xoo
- File srcSubDir = createDir(srcDir, "srcSubDir", false);
- writeFile(srcSubDir, "srcSub.xoo", "Sample xoo\ncontent");
-
- AnalysisBuilder result = tester.newAnalysis()
- .properties(builder
- .put("sonar.sources", "src")
- .put("sonar.exclusions", "src/srcSubDir/*") // srcSubDir should not be excluded unless all children are excluded (src/srcSubDir/**/*)
- .build());
-
- assertThatThrownBy(result::execute)
- .isExactlyInstanceOf(IllegalStateException.class)
- .hasMessageEndingWith(format("Failed to index files"));
- }
-
- @Test
- public void givenDirectoryWhenAllChildrenAreExcludedThenSkippedFilesShouldBeReported() throws IOException {
- // src/src.xoo
- File srcDir = createDir(baseDir, "src", true);
- writeFile(srcDir, "src.xoo", "Sample xoo 2\ncontent");
-
- // src/srcSubDir/srcSub.xoo
- File srcSubDir = createDir(srcDir, "srcSubDir", true);
- writeFile(srcSubDir, "srcSub.xoo", "Sample xoo\ncontent");
-
- // src/srcSubDir2/srcSub2.xoo
- File srcSubDir2 = createDir(srcDir, "srcSubDir2", true);
- boolean fileNotReadable = writeFile(srcSubDir2, "srcSub2.xoo", "Sample 2 xoo\ncontent").setReadable(false);
- assumeTrue(fileNotReadable);
-
- AnalysisResult result = tester.newAnalysis()
- .properties(builder
- .put("sonar.sources", "src")
- .put("sonar.exclusions", "src/srcSubDir/**/*,src/srcSubDir2/*")
- .build())
- .execute();
-
- assertAnalysedFiles(result, "src/src.xoo");
- assertThat(logTester.logs()).contains("2 files ignored because of inclusion/exclusion patterns");
- }
-
- @Ignore("Fails until we can pattern match inclusions to directories, not only files.")
- @Test
- public void givenDirectoryWithoutReadPermissionWhenNotIncludedThenScanShouldSkipIt() throws IOException {
- // src/src.xoo
- File srcDir = createDir(baseDir, "src", true);
- writeFile(srcDir, "src.xoo", "Sample xoo 2\ncontent");
-
- // src/srcSubDir/srcSub.xoo
- File srcSubDir = createDir(srcDir, "srcSubDir", true);
- writeFile(srcSubDir, "srcSub.xoo", "Sample xoo\ncontent");
-
- // src/srcSubDir2/srcSub2.xoo
- File srcSubDir2 = createDir(srcDir, "srcSubDir2", false);
- writeFile(srcSubDir2, "srcSub2.xoo", "Sample xoo\ncontent");
-
- AnalysisResult result = tester.newAnalysis()
- .properties(builder
- .put("sonar.sources", "src")
- .put("sonar.inclusions", "src/srcSubDir/**/*")
- .build())
- .execute();
-
- assertAnalysedFiles(result, "src/srcSubDir/srcSub.xoo");
- }
-
- @Test
- public void givenDirectoryWithoutReadPermissionUnderSourcesWhenAnalysedThenShouldFail() throws IOException {
- // src/src.xoo
- File srcDir = createDir(baseDir, "src", true);
- writeFile(srcDir, "src.xoo", "Sample xoo 2\ncontent");
-
- // src/srcSubDir/srcSub.xoo
- File srcSubDir = createDir(srcDir, "srcSubDir", false);
- writeFile(srcSubDir, "srcSub.xoo", "Sample xoo\ncontent");
-
- AnalysisBuilder result = tester.newAnalysis()
- .properties(builder
- .put("sonar.sources", "src")
- .build());
-
- assertThatThrownBy(result::execute)
- .isExactlyInstanceOf(IllegalStateException.class)
- .hasMessageEndingWith(format("Failed to index files"));
- }
-
- private static void assertAnalysedFiles(AnalysisResult result, String... files) {
- assertThat(result.inputFiles().stream().map(InputFile::toString).collect(Collectors.toList())).contains(files);
- }
-
- private File createDir(File parentDir, String name, boolean isReadable) {
- File dir = new File(parentDir, name);
- dir.mkdir();
- boolean fileSystemOperationSucceded = dir.setReadable(isReadable);
- assumeTrue(fileSystemOperationSucceded); //On windows + java there is no reliable way to play with readable/not readable flag
- return dir;
- }
-
- private File writeFile(File parent, String name, String content) throws IOException {
- File file = new File(parent, name);
- FileUtils.write(file, content, StandardCharsets.UTF_8);
- return file;
- }
-
- private File writeFile(File parent, String name, long size) throws IOException {
- File file = new File(parent, name);
- RandomAccessFile raf = new RandomAccessFile(file, "rw");
- raf.setLength(size);
- raf.close();
- return file;
- }
-
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2023 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.mediumtest.fs;
-
-import java.io.File;
-import org.apache.commons.io.FileUtils;
-import org.apache.commons.io.filefilter.FileFilterUtils;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TemporaryFolder;
-import org.sonar.scanner.mediumtest.ScannerMediumTester;
-import org.springframework.beans.factory.BeanCreationException;
-
-import static org.assertj.core.api.Assertions.assertThatThrownBy;
-
-public class NoLanguagesPluginsMediumTest {
- @Rule
- public TemporaryFolder temp = new TemporaryFolder();
-
- @Rule
- public ScannerMediumTester tester = new ScannerMediumTester();
-
- @Test
- public void testNoLanguagePluginsInstalled() throws Exception {
- File projectDir = copyProject("test-resources/mediumtest/xoo/sample");
-
- assertThatThrownBy(() -> tester
- .newAnalysis(new File(projectDir, "sonar-project.properties"))
- .execute())
- .isInstanceOf(BeanCreationException.class)
- .hasRootCauseMessage("No language plugins are installed.");
- }
-
- private File copyProject(String path) throws Exception {
- File projectDir = temp.newFolder();
- File originalProjectDir = new File(path);
- FileUtils.copyDirectory(originalProjectDir, projectDir, FileFilterUtils.notFileFilter(FileFilterUtils.nameFileFilter(".sonar")));
- return projectDir;
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2023 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.mediumtest.fs;
-
-import com.google.common.collect.ImmutableMap;
-import java.io.File;
-import java.io.IOException;
-import java.util.List;
-import org.apache.commons.io.FileUtils;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TemporaryFolder;
-import org.sonar.api.SonarEdition;
-import org.sonar.api.batch.bootstrap.ProjectBuilder;
-import org.sonar.api.utils.MessageException;
-import org.sonar.scanner.mediumtest.AnalysisResult;
-import org.sonar.scanner.mediumtest.ScannerMediumTester;
-import org.sonar.scanner.protocol.output.ScannerReport.Issue;
-import org.sonar.xoo.XooPlugin;
-import org.sonar.xoo.rule.XooRulesDefinition;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.assertThatThrownBy;
-import static org.assertj.core.api.Assertions.tuple;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.doThrow;
-import static org.mockito.Mockito.mock;
-
-public class ProjectBuilderMediumTest {
-
- @Rule
- public TemporaryFolder temp = new TemporaryFolder();
-
- private ProjectBuilder projectBuilder = mock(ProjectBuilder.class);
-
- @Rule
- public ScannerMediumTester tester = new ScannerMediumTester()
- .setEdition(SonarEdition.SONARCLOUD)
- .registerPlugin("xoo", new XooPluginWithBuilder(projectBuilder))
- .addRules(new XooRulesDefinition())
- .addDefaultQProfile("xoo", "Sonar Way")
- .addActiveRule("xoo", "OneIssuePerLine", null, "One issue per line", "MAJOR", "OneIssuePerLine.internal", "xoo");
-
- private static class XooPluginWithBuilder extends XooPlugin {
- private ProjectBuilder builder;
-
- XooPluginWithBuilder(ProjectBuilder builder) {
- this.builder = builder;
- }
-
- @Override
- public void define(Context context) {
- super.define(context);
- context.addExtension(builder);
- }
- }
-
- @Test
- public void testProjectReactorValidation() throws IOException {
- File baseDir = prepareProject();
-
- doThrow(new IllegalStateException("My error message")).when(projectBuilder).build(any(ProjectBuilder.Context.class));
-
- assertThatThrownBy(() -> tester.newAnalysis()
- .properties(ImmutableMap.<String, String>builder()
- .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
- .put("sonar.projectKey", "com.foo.project")
- .put("sonar.sources", ".")
- .put("sonar.xoo.enableProjectBuilder", "true")
- .build())
- .execute())
- .isInstanceOf(MessageException.class)
- .hasMessageContaining("Failed to execute project builder")
- .hasCauseInstanceOf(IllegalStateException.class);
- }
-
- @Test
- public void testProjectBuilder() throws IOException {
- File baseDir = prepareProject();
-
- AnalysisResult result = tester.newAnalysis()
- .properties(ImmutableMap.<String, String>builder()
- .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
- .put("sonar.projectKey", "com.foo.project")
- .put("sonar.sources", ".")
- .put("sonar.verbose", "true")
- .put("sonar.xoo.enableProjectBuilder", "true")
- .build())
- .execute();
- List<Issue> issues = result.issuesFor(result.inputFile("module1/src/sample.xoo"));
- assertThat(issues).hasSize(10);
-
- assertThat(issues)
- .extracting("msg", "textRange.startLine", "gap")
- .contains(tuple("This issue is generated on each line", 1, 0.0));
-
- }
-
- private File prepareProject() throws IOException {
- File baseDir = temp.newFolder();
- File module1Dir = new File(baseDir, "module1");
- module1Dir.mkdir();
-
- File srcDir = new File(module1Dir, "src");
- srcDir.mkdir();
-
- File xooFile = new File(srcDir, "sample.xoo");
- FileUtils.write(xooFile, "1\n2\n3\n4\n5\n6\n7\n8\n9\n10");
-
- return baseDir;
- }
-
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2023 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.mediumtest.highlighting;
-
-import com.google.common.collect.ImmutableMap;
-import java.io.File;
-import java.io.IOException;
-import org.apache.commons.io.FileUtils;
-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.sensor.highlighting.TypeOfText;
-import org.sonar.scanner.mediumtest.AnalysisResult;
-import org.sonar.scanner.mediumtest.ScannerMediumTester;
-import org.sonar.xoo.XooPlugin;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.assertThatThrownBy;
-import static org.sonar.scanner.mediumtest.ScannerMediumTester.AnalysisBuilder;
-
-public class HighlightingMediumTest {
-
- @Rule
- public TemporaryFolder temp = new TemporaryFolder();
-
- @Rule
- public ScannerMediumTester tester = new ScannerMediumTester()
- .registerPlugin("xoo", new XooPlugin())
- .addDefaultQProfile("xoo", "Sonar Way");
-
- @Test
- public void computeSyntaxHighlightingOnTempProject() throws IOException {
-
- File baseDir = temp.newFolder();
- File srcDir = new File(baseDir, "src");
- srcDir.mkdir();
-
- File xooFile = new File(srcDir, "sample.xoo");
- File xoohighlightingFile = new File(srcDir, "sample.xoo.highlighting");
- FileUtils.write(xooFile, "Sample xoo\ncontent plop");
- FileUtils.write(xoohighlightingFile, "1:0:2:0:s\n2:0:2:8:k");
-
- AnalysisResult result = tester.newAnalysis()
- .properties(ImmutableMap.<String, String>builder()
- .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
- .put("sonar.projectKey", "com.foo.project")
- .put("sonar.projectName", "Foo Project")
- .put("sonar.projectVersion", "1.0-SNAPSHOT")
- .put("sonar.projectDescription", "Description of Foo Project")
- .put("sonar.sources", "src")
- .build())
- .execute();
-
- InputFile file = result.inputFile("src/sample.xoo");
- assertThat(result.highlightingTypeFor(file, 1, 0)).containsExactly(TypeOfText.STRING);
- assertThat(result.highlightingTypeFor(file, 1, 9)).containsExactly(TypeOfText.STRING);
- assertThat(result.highlightingTypeFor(file, 2, 0)).containsExactly(TypeOfText.KEYWORD);
- assertThat(result.highlightingTypeFor(file, 2, 8)).isEmpty();
- }
-
- @Test
- public void saveTwice() throws IOException {
- File baseDir = temp.newFolder();
- File srcDir = new File(baseDir, "src");
- srcDir.mkdir();
-
- File xooFile = new File(srcDir, "sample.xoo");
- FileUtils.write(xooFile, "Sample xoo\ncontent plop");
-
- AnalysisBuilder analysisBuilder = tester.newAnalysis()
- .properties(ImmutableMap.<String, String>builder()
- .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
- .put("sonar.projectKey", "com.foo.project")
- .put("sonar.projectName", "Foo Project")
- .put("sonar.projectVersion", "1.0-SNAPSHOT")
- .put("sonar.projectDescription", "Description of Foo Project")
- .put("sonar.sources", "src")
- .put("sonar.it.savedatatwice", "true")
- .build());;
-
- assertThatThrownBy(() -> analysisBuilder.execute())
- .isInstanceOf(UnsupportedOperationException.class)
- .hasMessageContaining("Trying to save highlighting twice for the same file is not supported");
- }
-
- @Test
- public void computeInvalidOffsets() throws IOException {
-
- File baseDir = temp.newFolder();
- File srcDir = new File(baseDir, "src");
- srcDir.mkdir();
-
- File xooFile = new File(srcDir, "sample.xoo");
- File xoohighlightingFile = new File(srcDir, "sample.xoo.highlighting");
- FileUtils.write(xooFile, "Sample xoo\ncontent plop");
- FileUtils.write(xoohighlightingFile, "1:0:1:10:s\n2:18:2:18:k");
-
- AnalysisBuilder analysisBuilder = tester.newAnalysis()
- .properties(ImmutableMap.<String, String>builder()
- .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
- .put("sonar.projectKey", "com.foo.project")
- .put("sonar.projectName", "Foo Project")
- .put("sonar.projectVersion", "1.0-SNAPSHOT")
- .put("sonar.projectDescription", "Description of Foo Project")
- .put("sonar.sources", "src")
- .build());
-
- assertThatThrownBy(() -> analysisBuilder.execute())
- .isInstanceOf(IllegalStateException.class)
- .hasMessageContaining("Error processing line 2")
- .hasCauseInstanceOf(IllegalArgumentException.class);
- }
-
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2023 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.mediumtest.issues;
-
-import com.google.common.collect.ImmutableMap;
-import java.io.File;
-import java.io.IOException;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import javax.annotation.Nullable;
-import org.apache.commons.io.FileUtils;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TemporaryFolder;
-import org.sonar.api.batch.rule.LoadedActiveRule;
-import org.sonar.api.rule.RuleKey;
-import org.sonar.scanner.mediumtest.AnalysisResult;
-import org.sonar.scanner.mediumtest.ScannerMediumTester;
-import org.sonar.scanner.protocol.output.ScannerReport.Issue;
-import org.sonar.xoo.XooPlugin;
-import org.sonar.xoo.rule.XooRulesDefinition;
-
-import static java.util.Collections.emptySet;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.tuple;
-
-public class ChecksMediumTest {
-
- @org.junit.Rule
- public TemporaryFolder temp = new TemporaryFolder();
-
- @Rule
- public ScannerMediumTester tester = new ScannerMediumTester()
- .registerPlugin("xoo", new XooPlugin())
- .addRules(new XooRulesDefinition())
- .addDefaultQProfile("xoo", "Sonar Way")
- .addRule("TemplateRule_1234", "xoo", "TemplateRule_1234", "A template rule")
- .addRule("TemplateRule_1235", "xoo", "TemplateRule_1235", "Another template rule")
- .activateRule(createActiveRuleWithParam("xoo", "TemplateRule_1234", "TemplateRule", "A template rule", "MAJOR", null, "xoo", "line", "1"))
- .activateRule(createActiveRuleWithParam("xoo", "TemplateRule_1235", "TemplateRule", "Another template rule", "MAJOR", null, "xoo", "line", "2"));
-
- @Test
- public void testCheckWithTemplate() throws IOException {
-
- File baseDir = temp.getRoot();
- File srcDir = new File(baseDir, "src");
- srcDir.mkdir();
-
- File xooFile = new File(srcDir, "sample.xoo");
- FileUtils.write(xooFile, "foo\nbar");
-
- AnalysisResult result = tester.newAnalysis()
- .properties(ImmutableMap.<String, String>builder()
- .put("sonar.task", "scan")
- .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
- .put("sonar.projectKey", "com.foo.project")
- .put("sonar.projectName", "Foo Project")
- .put("sonar.projectVersion", "1.0-SNAPSHOT")
- .put("sonar.projectDescription", "Description of Foo Project")
- .put("sonar.sources", "src")
- .build())
- .execute();
-
- List<Issue> issues = result.issuesFor(result.inputFile("src/sample.xoo"));
- // If the message is the rule name. it's set by the CE. See SONAR-11531
- assertThat(issues)
- .extracting("msg", "textRange.startLine")
- .containsOnly(
- tuple("", 1),
- tuple("", 2));
-
- }
-
- private LoadedActiveRule createActiveRuleWithParam(String repositoryKey, String ruleKey, @Nullable String templateRuleKey, String name,
- @Nullable String severity, @Nullable String internalKey, @Nullable String languag, String paramKey, String paramValue) {
- LoadedActiveRule r = new LoadedActiveRule();
-
- r.setInternalKey(internalKey);
- r.setRuleKey(RuleKey.of(repositoryKey, ruleKey));
- r.setName(name);
- r.setTemplateRuleKey(templateRuleKey);
- r.setLanguage(languag);
- r.setSeverity(severity);
- r.setDeprecatedKeys(emptySet());
-
- Map<String, String> params = new HashMap<>();
- params.put(paramKey, paramValue);
- r.setParams(params);
- return r;
- }
-
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2023 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.mediumtest.issues;
-
-import java.io.File;
-import java.io.IOException;
-import java.net.URISyntaxException;
-import java.util.List;
-import org.apache.commons.io.FileUtils;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TemporaryFolder;
-import org.sonar.api.utils.log.LogTester;
-import org.sonar.scanner.mediumtest.ScannerMediumTester;
-import org.sonar.scanner.mediumtest.AnalysisResult;
-import org.sonar.scanner.protocol.Constants.Severity;
-import org.sonar.scanner.protocol.output.ScannerReport;
-import org.sonar.scanner.protocol.output.ScannerReport.ExternalIssue;
-import org.sonar.scanner.protocol.output.ScannerReport.Issue;
-import org.sonar.scanner.protocol.output.ScannerReport.IssueType;
-import org.sonar.xoo.XooPlugin;
-import org.sonar.xoo.rule.OneExternalIssuePerLineSensor;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.tuple;
-
-public class ExternalIssuesMediumTest {
- @Rule
- public LogTester logs = new LogTester();
- @Rule
- public TemporaryFolder temp = new TemporaryFolder();
-
- @Rule
- public ScannerMediumTester tester = new ScannerMediumTester()
- .registerPlugin("xoo", new XooPlugin());
-
- @Test
- public void testOneIssuePerLine() throws Exception {
- File projectDir = new File("test-resources/mediumtest/xoo/sample");
- File tmpDir = temp.newFolder();
- FileUtils.copyDirectory(projectDir, tmpDir);
-
- AnalysisResult result = tester
- .newAnalysis(new File(tmpDir, "sonar-project.properties"))
- .property(OneExternalIssuePerLineSensor.ACTIVATE, "true")
- .execute();
-
- List<Issue> issues = result.issuesFor(result.inputFile("xources/hello/HelloJava.xoo"));
- assertThat(issues).isEmpty();
-
- List<ExternalIssue> externalIssues = result.externalIssuesFor(result.inputFile("xources/hello/HelloJava.xoo"));
- assertThat(externalIssues).hasSize(8 /* lines */);
-
- ExternalIssue issue = externalIssues.get(0);
- assertThat(issue.getTextRange().getStartLine()).isEqualTo(issue.getTextRange().getStartLine());
-
- assertThat(result.adHocRules()).isEmpty();
- }
-
- @Test
- public void testOneIssuePerLine_register_ad_hoc_rule() throws Exception {
- File projectDir = new File("test-resources/mediumtest/xoo/sample");
- File tmpDir = temp.newFolder();
- FileUtils.copyDirectory(projectDir, tmpDir);
-
- AnalysisResult result = tester
- .newAnalysis(new File(tmpDir, "sonar-project.properties"))
- .property(OneExternalIssuePerLineSensor.ACTIVATE, "true")
- .property(OneExternalIssuePerLineSensor.REGISTER_AD_HOC_RULE, "true")
- .execute();
-
- assertThat(result.adHocRules()).extracting(
- ScannerReport.AdHocRule::getEngineId,
- ScannerReport.AdHocRule::getRuleId,
- ScannerReport.AdHocRule::getName,
- ScannerReport.AdHocRule::getDescription,
- ScannerReport.AdHocRule::getSeverity,
- ScannerReport.AdHocRule::getType)
- .containsExactlyInAnyOrder(
- tuple(
- OneExternalIssuePerLineSensor.ENGINE_ID,
- OneExternalIssuePerLineSensor.RULE_ID,
- "An ad hoc rule",
- "blah blah",
- Severity.BLOCKER,
- IssueType.BUG));
- }
-
- @Test
- public void testLoadIssuesFromJsonReport() throws URISyntaxException, IOException {
- File projectDir = new File("test-resources/mediumtest/xoo/sample");
- File tmpDir = temp.newFolder();
- FileUtils.copyDirectory(projectDir, tmpDir);
-
- AnalysisResult result = tester
- .newAnalysis(new File(tmpDir, "sonar-project.properties"))
- .property("sonar.externalIssuesReportPaths", "externalIssues.json")
- .execute();
-
- List<Issue> issues = result.issuesFor(result.inputFile("xources/hello/HelloJava.xoo"));
- assertThat(issues).isEmpty();
-
- List<ExternalIssue> externalIssues = result.externalIssuesFor(result.inputFile("xources/hello/HelloJava.xoo"));
- assertThat(externalIssues).hasSize(2);
-
- // precise issue location
- ExternalIssue issue = externalIssues.get(0);
- assertPreciseIssueLocation(issue);
-
- // location on a line
- issue = externalIssues.get(1);
- assertIssueLocationLine(issue);
-
- // One file-level issue in helloscala, with secondary location
- List<ExternalIssue> externalIssues2 = result.externalIssuesFor(result.inputFile("xources/hello/helloscala.xoo"));
- assertThat(externalIssues2).hasSize(1);
-
- issue = externalIssues2.iterator().next();
- assertSecondaryLocation(issue);
-
- // one issue is located in a non-existing file
- assertThat(logs.logs()).contains("External issues ignored for 1 unknown files, including: invalidFile");
-
- }
-
- private void assertSecondaryLocation(ExternalIssue issue) {
- assertThat(issue.getFlowCount()).isEqualTo(2);
- assertThat(issue.getMsg()).isEqualTo("fix the bug here");
- assertThat(issue.getEngineId()).isEqualTo("externalXoo");
- assertThat(issue.getRuleId()).isEqualTo("rule3");
- assertThat(issue.getSeverity()).isEqualTo(Severity.MAJOR);
- assertThat(issue.getType()).isEqualTo(IssueType.BUG);
- assertThat(issue.hasTextRange()).isFalse();
- assertThat(issue.getFlow(0).getLocationCount()).isOne();
- assertThat(issue.getFlow(0).getLocation(0).getTextRange().getStartLine()).isOne();
- assertThat(issue.getFlow(1).getLocationCount()).isOne();
- assertThat(issue.getFlow(1).getLocation(0).getTextRange().getStartLine()).isEqualTo(3);
- }
-
- private void assertIssueLocationLine(ExternalIssue issue) {
- assertThat(issue.getFlowCount()).isZero();
- assertThat(issue.getMsg()).isEqualTo("fix the bug here");
- assertThat(issue.getEngineId()).isEqualTo("externalXoo");
- assertThat(issue.getRuleId()).isEqualTo("rule2");
- assertThat(issue.getSeverity()).isEqualTo(Severity.CRITICAL);
- assertThat(issue.getType()).isEqualTo(IssueType.BUG);
- assertThat(issue.getEffort()).isZero();
- assertThat(issue.getTextRange().getStartLine()).isEqualTo(3);
- assertThat(issue.getTextRange().getEndLine()).isEqualTo(3);
- assertThat(issue.getTextRange().getStartOffset()).isZero();
- assertThat(issue.getTextRange().getEndOffset()).isEqualTo(24);
- }
-
- private void assertPreciseIssueLocation(ExternalIssue issue) {
- assertThat(issue.getFlowCount()).isZero();
- assertThat(issue.getMsg()).isEqualTo("fix the issue here");
- assertThat(issue.getEngineId()).isEqualTo("externalXoo");
- assertThat(issue.getRuleId()).isEqualTo("rule1");
- assertThat(issue.getSeverity()).isEqualTo(Severity.MAJOR);
- assertThat(issue.getEffort()).isEqualTo(50L);
- assertThat(issue.getType()).isEqualTo(IssueType.CODE_SMELL);
- assertThat(issue.getTextRange().getStartLine()).isEqualTo(5);
- assertThat(issue.getTextRange().getEndLine()).isEqualTo(5);
- assertThat(issue.getTextRange().getStartOffset()).isEqualTo(3);
- assertThat(issue.getTextRange().getEndOffset()).isEqualTo(41);
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2023 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.mediumtest.issues;
-
-import com.google.common.collect.ImmutableMap;
-import java.io.File;
-import java.io.IOException;
-import java.nio.charset.StandardCharsets;
-import java.util.List;
-import org.apache.commons.io.FileUtils;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TemporaryFolder;
-import org.sonar.api.batch.rule.LoadedActiveRule;
-import org.sonar.api.rule.RuleKey;
-import org.sonar.api.utils.log.LogTester;
-import org.sonar.api.utils.log.LoggerLevel;
-import org.sonar.scanner.mediumtest.AnalysisResult;
-import org.sonar.scanner.mediumtest.ScannerMediumTester;
-import org.sonar.scanner.protocol.output.ScannerReport.ExternalIssue;
-import org.sonar.scanner.protocol.output.ScannerReport.Issue;
-import org.sonar.xoo.XooPlugin;
-import org.sonar.xoo.rule.HasTagSensor;
-import org.sonar.xoo.rule.OneExternalIssueOnProjectSensor;
-import org.sonar.xoo.rule.OneExternalIssuePerLineSensor;
-import org.sonar.xoo.rule.XooRulesDefinition;
-
-import static java.util.Collections.emptySet;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.tuple;
-
-public class IssuesMediumTest {
-
- @Rule
- public TemporaryFolder temp = new TemporaryFolder();
-
- @Rule
- public LogTester logTester = new LogTester();
-
- @Rule
- public ScannerMediumTester tester = new ScannerMediumTester()
- .registerPlugin("xoo", new XooPlugin())
- .addDefaultQProfile("xoo", "Sonar Way")
- .addRules(new XooRulesDefinition())
- .addActiveRule("xoo", "OneIssuePerLine", null, "One issue per line", "MAJOR", "OneIssuePerLine.internal", "xoo");
-
- @Test
- public void testOneIssuePerLine() throws Exception {
- File projectDir = new File("test-resources/mediumtest/xoo/sample");
- File tmpDir = temp.newFolder();
- FileUtils.copyDirectory(projectDir, tmpDir);
-
- AnalysisResult result = tester
- .newAnalysis(new File(tmpDir, "sonar-project.properties"))
- .execute();
-
- List<Issue> issues = result.issuesFor(result.inputFile("xources/hello/HelloJava.xoo"));
- assertThat(issues).hasSize(8 /* lines */);
-
- List<ExternalIssue> externalIssues = result.externalIssuesFor(result.inputFile("xources/hello/HelloJava.xoo"));
- assertThat(externalIssues).isEmpty();
- }
-
- @Test
- public void testOneExternalIssuePerLine() throws Exception {
- File projectDir = new File("test-resources/mediumtest/xoo/sample");
- File tmpDir = temp.newFolder();
- FileUtils.copyDirectory(projectDir, tmpDir);
-
- AnalysisResult result = tester
- .newAnalysis(new File(tmpDir, "sonar-project.properties"))
- .property(OneExternalIssuePerLineSensor.ACTIVATE, "true")
- .execute();
-
- List<ExternalIssue> externalIssues = result.externalIssuesFor(result.inputFile("xources/hello/HelloJava.xoo"));
- assertThat(externalIssues).hasSize(8 /* lines */);
- }
-
- @Test
- public void testOneExternalIssueOnProject() throws Exception {
- File projectDir = new File("test-resources/mediumtest/xoo/sample");
- File tmpDir = temp.newFolder();
- FileUtils.copyDirectory(projectDir, tmpDir);
-
- AnalysisResult result = tester
- .newAnalysis(new File(tmpDir, "sonar-project.properties"))
- .property(OneExternalIssueOnProjectSensor.ACTIVATE, "true")
- .execute();
-
- List<ExternalIssue> externalIssues = result.externalIssuesFor(result.project());
- assertThat(externalIssues).hasSize(1);
- }
-
- @Test
- public void findActiveRuleByInternalKey() throws Exception {
- File projectDir = new File("test-resources/mediumtest/xoo/sample");
- File tmpDir = temp.newFolder();
- FileUtils.copyDirectory(projectDir, tmpDir);
-
- AnalysisResult result = tester
- .newAnalysis(new File(tmpDir, "sonar-project.properties"))
- .property("sonar.xoo.internalKey", "OneIssuePerLine.internal")
- .execute();
-
- List<Issue> issues = result.issuesFor(result.inputFile("xources/hello/HelloJava.xoo"));
- assertThat(issues).hasSize(8 /* lines */ + 1 /* file */);
- }
-
- @Test
- public void testOverrideQProfileSeverity() throws Exception {
- File projectDir = new File("test-resources/mediumtest/xoo/sample");
- File tmpDir = temp.newFolder();
- FileUtils.copyDirectory(projectDir, tmpDir);
-
- AnalysisResult result = tester
- .newAnalysis(new File(tmpDir, "sonar-project.properties"))
- .property("sonar.oneIssuePerLine.forceSeverity", "CRITICAL")
- .execute();
-
- List<Issue> issues = result.issuesFor(result.inputFile("xources/hello/HelloJava.xoo"));
- assertThat(issues.get(0).getSeverity()).isEqualTo(org.sonar.scanner.protocol.Constants.Severity.CRITICAL);
- }
-
- @Test
- public void testIssueExclusionByRegexp() throws Exception {
- File projectDir = new File("test-resources/mediumtest/xoo/sample");
- File tmpDir = temp.newFolder();
- FileUtils.copyDirectory(projectDir, tmpDir);
-
- AnalysisResult result = tester
- .newAnalysis(new File(tmpDir, "sonar-project.properties"))
- .property("sonar.issue.ignore.allfile", "1")
- .property("sonar.issue.ignore.allfile.1.fileRegexp", "object")
- .execute();
-
- assertThat(result.issuesFor(result.inputFile("xources/hello/HelloJava.xoo"))).hasSize(8 /* lines */);
- assertThat(result.issuesFor(result.inputFile("xources/hello/helloscala.xoo"))).isEmpty();
- }
-
- @Test
- public void testIssueExclusionByBlock() throws Exception {
- File baseDir = temp.newFolder();
- File srcDir = new File(baseDir, "src");
- srcDir.mkdir();
-
- File xooFile = new File(srcDir, "sample.xoo");
- FileUtils.write(xooFile, "1\nSONAR-OFF 2\n3\n4\n5\nSONAR-ON 6\n7\n8\n9\n10", StandardCharsets.UTF_8);
-
- AnalysisResult result = tester.newAnalysis()
- .properties(ImmutableMap.<String, String>builder()
- .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
- .put("sonar.projectKey", "com.foo.project")
- .put("sonar.sources", "src")
- .build())
- .property("sonar.issue.ignore.block", "1")
- .property("sonar.issue.ignore.block.1.beginBlockRegexp", "SON.*-OFF")
- .property("sonar.issue.ignore.block.1.endBlockRegexp", "SON.*-ON")
- .execute();
-
- List<Issue> issues = result.issuesFor(result.inputFile("src/sample.xoo"));
- assertThat(issues).hasSize(5);
- assertThat(issues)
- .extracting("textRange.startLine")
- .containsExactlyInAnyOrder(1, 7, 8, 9, 10);
- }
-
- @Test
- public void testIssueExclusionByIgnoreMultiCriteria() throws Exception {
- File baseDir = temp.newFolder();
- File srcDir = new File(baseDir, "src");
- srcDir.mkdir();
-
- activateTODORule();
-
- File xooFile1 = new File(srcDir, "sample1.xoo");
- FileUtils.write(xooFile1, "1\n2\n3 TODO\n4\n5\n6 TODO\n7\n8\n9\n10", StandardCharsets.UTF_8);
- File xooFile11 = new File(srcDir, "sample11.xoo");
- FileUtils.write(xooFile11, "1\n2\n3 TODO\n4\n5\n6 TODO\n7\n8\n9\n10", StandardCharsets.UTF_8);
-
- AnalysisResult result = tester.newAnalysis()
- .properties(ImmutableMap.<String, String>builder()
- .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
- .put("sonar.projectKey", "com.foo.project")
- .put("sonar.sources", "src")
- .build())
- .property("sonar.issue.ignore.multicriteria", "1,2")
- .property("sonar.issue.ignore.multicriteria.1.ruleKey", "xoo:HasTag")
- .property("sonar.issue.ignore.multicriteria.1.resourceKey", "src/sample11.xoo")
- .property("sonar.issue.ignore.multicriteria.2.ruleKey", "xoo:One*")
- .property("sonar.issue.ignore.multicriteria.2.resourceKey", "src/sample?.xoo")
- .execute();
-
- List<Issue> issues = result.issuesFor(result.inputFile("src/sample1.xoo"));
- assertThat(issues).hasSize(2);
-
- issues = result.issuesFor(result.inputFile("src/sample11.xoo"));
- assertThat(issues).hasSize(10);
- }
-
- @Test
- public void warn_user_for_outdated_IssueExclusionByIgnoreMultiCriteria() throws Exception {
- File baseDir = temp.getRoot();
- File baseDirModuleA = new File(baseDir, "moduleA");
- File baseDirModuleB = new File(baseDir, "moduleB");
- File srcDirA = new File(baseDirModuleA, "src");
- srcDirA.mkdirs();
- File srcDirB = new File(baseDirModuleB, "src");
- srcDirB.mkdirs();
-
- File xooFileA = new File(srcDirA, "sampleA.xoo");
- FileUtils.write(xooFileA, "1\n2\n3\n4\n5\n6 TODO\n7\n8\n9\n10", StandardCharsets.UTF_8);
- File xooFileB = new File(srcDirB, "sampleB.xoo");
- FileUtils.write(xooFileB, "1\n2\n3\n4\n5\n6 TODO\n7\n8\n9\n10", StandardCharsets.UTF_8);
-
- tester
- .addProjectServerSettings("sonar.issue.ignore.multicriteria", "1")
- .addProjectServerSettings("sonar.issue.ignore.multicriteria.1.ruleKey", "*")
- .addProjectServerSettings("sonar.issue.ignore.multicriteria.1.resourceKey", "src/sampleA.xoo");
-
- AnalysisResult result = tester.newAnalysis()
- .properties(ImmutableMap.<String, String>builder()
- .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
- .put("sonar.projectKey", "com.foo.project")
- .put("sonar.modules", "moduleA,moduleB")
- .put("sonar.sources", "src")
- .build())
- .execute();
-
- assertThat(logTester.logs(LoggerLevel.WARN)).contains(
- "Specifying module-relative paths at project level in property 'sonar.issue.ignore.multicriteria' is deprecated. To continue matching files like 'moduleA/src/sampleA.xoo', update this property so that patterns refer to project-relative paths.");
-
- List<Issue> issues = result.issuesFor(result.inputFile("moduleA/src/sampleA.xoo"));
- assertThat(issues).isEmpty();
-
- issues = result.issuesFor(result.inputFile("moduleB/src/sampleB.xoo"));
- assertThat(issues).hasSize(10);
- }
-
- @Test
- public void warn_user_for_unsupported_module_level_IssueExclusion() throws Exception {
- File baseDir = temp.getRoot();
- File baseDirModuleA = new File(baseDir, "moduleA");
- File baseDirModuleB = new File(baseDir, "moduleB");
- File srcDirA = new File(baseDirModuleA, "src");
- srcDirA.mkdirs();
- File srcDirB = new File(baseDirModuleB, "src");
- srcDirB.mkdirs();
-
- File xooFileA = new File(srcDirA, "sampleA.xoo");
- FileUtils.write(xooFileA, "1\n2\n3\n4\n5\n6 TODO\n7\n8\n9\n10", StandardCharsets.UTF_8);
- File xooFileB = new File(srcDirB, "sampleB.xoo");
- FileUtils.write(xooFileB, "1\n2\n3\n4\n5\n6 TODO\n7\n8\n9\n10", StandardCharsets.UTF_8);
-
- AnalysisResult result = tester.newAnalysis()
- .properties(ImmutableMap.<String, String>builder()
- .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
- .put("sonar.projectKey", "com.foo.project")
- .put("sonar.modules", "moduleA,moduleB")
- .put("sonar.sources", "src")
- .put("sonar.scm.disabled", "true")
- .put("sonar.issue.ignore.multicriteria", "1")
- .put("sonar.issue.ignore.multicriteria.1.ruleKey", "*")
- .put("sonar.issue.ignore.multicriteria.1.resourceKey", "*")
- .build())
- .execute();
-
- assertThat(logTester.logs(LoggerLevel.WARN)).isEmpty();
-
- result = tester.newAnalysis()
- .properties(ImmutableMap.<String, String>builder()
- .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
- .put("sonar.projectKey", "com.foo.project")
- .put("sonar.modules", "moduleA,moduleB")
- .put("sonar.sources", "src")
- .put("sonar.scm.disabled", "true")
- .put("moduleA.sonar.issue.ignore.multicriteria", "1")
- .put("moduleA.sonar.issue.ignore.multicriteria.1.ruleKey", "*")
- .put("moduleA.sonar.issue.ignore.multicriteria.1.resourceKey", "*")
- .build())
- .execute();
-
- assertThat(logTester.logs(LoggerLevel.WARN)).containsOnly(
- "Specifying issue exclusions at module level is not supported anymore. Configure the property 'sonar.issue.ignore.multicriteria' and any other issue exclusions at project level.");
-
- List<Issue> issues = result.issuesFor(result.inputFile("moduleA/src/sampleA.xoo"));
- assertThat(issues).hasSize(10);
-
- issues = result.issuesFor(result.inputFile("moduleB/src/sampleB.xoo"));
- assertThat(issues).hasSize(10);
-
- // SONAR-11850 The Maven scanner replicates properties defined on the root module to all modules
- logTester.clear();
- result = tester.newAnalysis()
- .properties(ImmutableMap.<String, String>builder()
- .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
- .put("sonar.projectKey", "com.foo.project")
- .put("sonar.modules", "moduleA,moduleB")
- .put("sonar.sources", "src")
- .put("sonar.scm.disabled", "true")
- .put("sonar.issue.ignore.multicriteria", "1")
- .put("sonar.issue.ignore.multicriteria.1.ruleKey", "*")
- .put("sonar.issue.ignore.multicriteria.1.resourceKey", "*")
- .put("moduleA.sonar.issue.ignore.multicriteria", "1")
- .put("moduleA.sonar.issue.ignore.multicriteria.1.ruleKey", "*")
- .put("moduleA.sonar.issue.ignore.multicriteria.1.resourceKey", "*")
- .build())
- .execute();
-
- assertThat(logTester.logs(LoggerLevel.WARN)).isEmpty();
- }
-
- @Test
- public void testIssueExclusionByEnforceMultiCriteria() throws Exception {
- File baseDir = temp.newFolder();
- File srcDir = new File(baseDir, "src");
- srcDir.mkdir();
-
- activateTODORule();
-
- File xooFile1 = new File(srcDir, "sample1.xoo");
- FileUtils.write(xooFile1, "1\n2\n3 TODO\n4\n5\n6 TODO\n7\n8\n9\n10", StandardCharsets.UTF_8);
- File xooFile11 = new File(srcDir, "sample11.xoo");
- FileUtils.write(xooFile11, "1\n2\n3 TODO\n4\n5\n6 TODO\n7\n8\n9\n10", StandardCharsets.UTF_8);
-
- AnalysisResult result = tester.newAnalysis()
- .properties(ImmutableMap.<String, String>builder()
- .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
- .put("sonar.projectKey", "com.foo.project")
- .put("sonar.sources", "src")
- .build())
- .property("sonar.issue.enforce.multicriteria", "1,2")
- .property("sonar.issue.enforce.multicriteria.1.ruleKey", "xoo:HasTag")
- .property("sonar.issue.enforce.multicriteria.1.resourceKey", "src/sample11.xoo")
- .property("sonar.issue.enforce.multicriteria.2.ruleKey", "xoo:One*")
- .property("sonar.issue.enforce.multicriteria.2.resourceKey", "src/sample?.xoo")
- .execute();
-
- List<Issue> issues = result.issuesFor(result.inputFile("src/sample1.xoo"));
- assertThat(issues).hasSize(10);
-
- issues = result.issuesFor(result.inputFile("src/sample11.xoo"));
- assertThat(issues).hasSize(2);
- }
-
- @Test
- public void warn_user_for_outdated_IssueExclusionByEnforceMultiCriteria() throws Exception {
- File baseDir = temp.getRoot();
- File baseDirModuleA = new File(baseDir, "moduleA");
- File baseDirModuleB = new File(baseDir, "moduleB");
- File srcDirA = new File(baseDirModuleA, "src");
- srcDirA.mkdirs();
- File srcDirB = new File(baseDirModuleB, "src");
- srcDirB.mkdirs();
-
- File xooFileA = new File(srcDirA, "sampleA.xoo");
- FileUtils.write(xooFileA, "1\n2\n3\n4\n5\n6 TODO\n7\n8\n9\n10", StandardCharsets.UTF_8);
- File xooFileB = new File(srcDirB, "sampleB.xoo");
- FileUtils.write(xooFileB, "1\n2\n3\n4\n5\n6 TODO\n7\n8\n9\n10", StandardCharsets.UTF_8);
-
- tester
- .addProjectServerSettings("sonar.issue.enforce.multicriteria", "1")
- .addProjectServerSettings("sonar.issue.enforce.multicriteria.1.ruleKey", "*")
- .addProjectServerSettings("sonar.issue.enforce.multicriteria.1.resourceKey", "src/sampleA.xoo");
-
- AnalysisResult result = tester.newAnalysis()
- .properties(ImmutableMap.<String, String>builder()
- .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
- .put("sonar.projectKey", "com.foo.project")
- .put("sonar.modules", "moduleA,moduleB")
- .put("sonar.sources", "src")
- .build())
- .execute();
-
- assertThat(logTester.logs(LoggerLevel.WARN)).contains(
- "Specifying module-relative paths at project level in property 'sonar.issue.enforce.multicriteria' is deprecated. To continue matching files like 'moduleA/src/sampleA.xoo', update this property so that patterns refer to project-relative paths.");
-
- List<Issue> issues = result.issuesFor(result.inputFile("moduleA/src/sampleA.xoo"));
- assertThat(issues).hasSize(10);
-
- issues = result.issuesFor(result.inputFile("moduleB/src/sampleB.xoo"));
- assertThat(issues).isEmpty();
- }
-
- private void activateTODORule() {
- LoadedActiveRule r = new LoadedActiveRule();
- r.setRuleKey(RuleKey.of("xoo", HasTagSensor.RULE_KEY));
- r.setName("TODO");
- r.setLanguage("xoo");
- r.setSeverity("MAJOR");
- r.setDeprecatedKeys(emptySet()
- );
- r.setParams(ImmutableMap.of("tag", "TODO"));
- tester.activateRule(r);
- }
-
- @Test
- public void testIssueDetails() throws IOException {
- File baseDir = temp.newFolder();
- File srcDir = new File(baseDir, "src");
- srcDir.mkdir();
-
- File xooFile = new File(srcDir, "sample.xoo");
- FileUtils.write(xooFile, "1\n2\n3\n4\n5\n6\n7\n8\n9\n10", StandardCharsets.UTF_8);
-
- AnalysisResult result = tester.newAnalysis()
- .properties(ImmutableMap.<String, String>builder()
- .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
- .put("sonar.projectKey", "com.foo.project")
- .put("sonar.sources", "src")
- .build())
- .execute();
-
- List<Issue> issues = result.issuesFor(result.inputFile("src/sample.xoo"));
- assertThat(issues).hasSize(10);
- assertThat(issues)
- .extracting("msg", "textRange.startLine", "gap")
- .contains(tuple("This issue is generated on each line", 1, 0.0));
- }
-
- @Test
- public void testIssueFilter() throws Exception {
- File projectDir = new File("test-resources/mediumtest/xoo/sample");
- File tmpDir = temp.newFolder();
- FileUtils.copyDirectory(projectDir, tmpDir);
-
- AnalysisResult result = tester
- .newAnalysis(new File(tmpDir, "sonar-project.properties"))
- .property("sonar.xoo.excludeAllIssuesOnOddLines", "true")
- .execute();
-
- List<Issue> issues = result.issuesFor(result.inputFile("xources/hello/HelloJava.xoo"));
- assertThat(issues).hasSize(4 /* even lines */);
- }
-
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2023 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.mediumtest.issues;
-
-import com.google.common.collect.ImmutableMap;
-import java.io.File;
-import java.io.IOException;
-import org.apache.commons.io.FileUtils;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TemporaryFolder;
-import org.sonar.scanner.mediumtest.ScannerMediumTester;
-import org.sonar.scanner.mediumtest.AnalysisResult;
-import org.sonar.xoo.XooPlugin;
-import org.sonar.xoo.rule.XooRulesDefinition;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class IssuesOnDirMediumTest {
-
- @Rule
- public TemporaryFolder temp = new TemporaryFolder();
-
- @Rule
- public ScannerMediumTester tester = new ScannerMediumTester()
- .registerPlugin("xoo", new XooPlugin())
- .addDefaultQProfile("xoo", "Sonar Way")
- .addRules(new XooRulesDefinition())
- .addActiveRule("xoo", "OneIssueOnDirPerFile", null, "One issue per line", "MINOR", "xoo", "xoo");
-
- @Test
- public void scanTempProject() throws IOException {
-
- File baseDir = temp.getRoot();
- File srcDir = new File(baseDir, "src");
- srcDir.mkdir();
-
- File xooFile1 = new File(srcDir, "sample1.xoo");
- FileUtils.write(xooFile1, "Sample1 xoo\ncontent");
-
- File xooFile2 = new File(srcDir, "sample2.xoo");
- FileUtils.write(xooFile2, "Sample2 xoo\ncontent");
-
- AnalysisResult result = tester.newAnalysis()
- .properties(ImmutableMap.<String, String>builder()
- .put("sonar.task", "scan")
- .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
- .put("sonar.projectKey", "com.foo.project")
- .put("sonar.projectName", "Foo Project")
- .put("sonar.projectVersion", "1.0-SNAPSHOT")
- .put("sonar.projectDescription", "Description of Foo Project")
- .put("sonar.sources", "src")
- .build())
- .execute();
-
- assertThat(result.issuesFor(result.project())).hasSize(2);
- }
-
- @Test
- public void issueOnRootFolder() throws IOException {
-
- File baseDir = temp.getRoot();
-
- File xooFile1 = new File(baseDir, "sample1.xoo");
- FileUtils.write(xooFile1, "Sample1 xoo\ncontent");
-
- File xooFile2 = new File(baseDir, "sample2.xoo");
- FileUtils.write(xooFile2, "Sample2 xoo\ncontent");
-
- AnalysisResult result = tester.newAnalysis()
- .properties(ImmutableMap.<String, String>builder()
- .put("sonar.task", "scan")
- .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
- .put("sonar.projectKey", "com.foo.project")
- .put("sonar.projectName", "Foo Project")
- .put("sonar.projectVersion", "1.0-SNAPSHOT")
- .put("sonar.projectDescription", "Description of Foo Project")
- .put("sonar.sources", ".")
- .build())
- .execute();
-
- assertThat(result.issuesFor(result.project())).hasSize(2);
- }
-
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2023 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.mediumtest.issues;
-
-import com.google.common.collect.ImmutableMap;
-import java.io.File;
-import java.io.IOException;
-import org.apache.commons.io.FileUtils;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TemporaryFolder;
-import org.sonar.scanner.mediumtest.ScannerMediumTester;
-import org.sonar.scanner.mediumtest.AnalysisResult;
-import org.sonar.xoo.XooPlugin;
-import org.sonar.xoo.rule.XooRulesDefinition;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class IssuesOnModuleMediumTest {
-
- @Rule
- public TemporaryFolder temp = new TemporaryFolder();
-
- @Rule
- public ScannerMediumTester tester = new ScannerMediumTester()
- .registerPlugin("xoo", new XooPlugin())
- .addDefaultQProfile("xoo", "Sonar Way")
- .addRules(new XooRulesDefinition())
- .addActiveRule("xoo", "OneIssuePerModule", null, "One issue per module", "MINOR", "xoo", "xoo");
-
- @Test
- public void scanTempProject() throws IOException {
-
- File baseDir = temp.getRoot();
- File srcDir = new File(baseDir, "src");
- srcDir.mkdir();
-
- File xooFile1 = new File(srcDir, "sample1.xoo");
- FileUtils.write(xooFile1, "Sample1 xoo\ncontent");
-
- AnalysisResult result = tester.newAnalysis()
- .properties(ImmutableMap.<String, String>builder()
- .put("sonar.task", "scan")
- .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
- .put("sonar.projectKey", "com.foo.project")
- .put("sonar.projectName", "Foo Project")
- .put("sonar.projectVersion", "1.0-SNAPSHOT")
- .put("sonar.projectDescription", "Description of Foo Project")
- .put("sonar.sources", "src")
- .build())
- .execute();
-
- assertThat(result.issuesFor(result.project())).hasSize(1);
- }
-
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2023 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.mediumtest.issues;
-
-import java.io.File;
-import java.util.List;
-import org.apache.commons.io.FileUtils;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TemporaryFolder;
-import org.sonar.scanner.mediumtest.AnalysisResult;
-import org.sonar.scanner.mediumtest.ScannerMediumTester;
-import org.sonar.scanner.protocol.output.ScannerReport.Flow;
-import org.sonar.scanner.protocol.output.ScannerReport.FlowType;
-import org.sonar.scanner.protocol.output.ScannerReport.Issue;
-import org.sonar.scanner.protocol.output.ScannerReport.IssueLocation;
-import org.sonar.xoo.XooPlugin;
-import org.sonar.xoo.rule.XooRulesDefinition;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.tuple;
-
-public class MultilineIssuesMediumTest {
-
- @Rule
- public TemporaryFolder temp = new TemporaryFolder();
-
- @Rule
- public ScannerMediumTester tester = new ScannerMediumTester()
- .registerPlugin("xoo", new XooPlugin())
- .addRules(new XooRulesDefinition())
- .addDefaultQProfile("xoo", "Sonar Way")
- .addActiveRule("xoo", "MultilineIssue", null, "Multinile Issue", "MAJOR", null, "xoo");
-
- private AnalysisResult result;
-
- @Before
- public void prepare() throws Exception {
- File projectDir = new File("test-resources/mediumtest/xoo/sample-multiline");
- File tmpDir = temp.getRoot();
- FileUtils.copyDirectory(projectDir, tmpDir);
-
- result = tester
- .newAnalysis(new File(tmpDir, "sonar-project.properties"))
- .execute();
- }
-
- @Test
- public void testIssueRange() {
- List<Issue> issues = result.issuesFor(result.inputFile("xources/hello/Single.xoo"));
- assertThat(issues).hasSize(1);
- Issue issue = issues.get(0);
- assertThat(issue.getMsg()).isEqualTo("Primary location of the issue in xoo code");
- assertThat(issue.getTextRange().getStartLine()).isEqualTo(6);
- assertThat(issue.getTextRange().getStartOffset()).isEqualTo(23);
- assertThat(issue.getTextRange().getEndLine()).isEqualTo(6);
- assertThat(issue.getTextRange().getEndOffset()).isEqualTo(50);
- }
-
- @Test
- public void testMultilineIssueRange() {
- List<Issue> issues = result.issuesFor(result.inputFile("xources/hello/Multiline.xoo"));
- assertThat(issues).hasSize(1);
- Issue issue = issues.get(0);
- assertThat(issue.getMsg()).isEqualTo("Primary location of the issue in xoo code");
- assertThat(issue.getTextRange().getStartLine()).isEqualTo(6);
- assertThat(issue.getTextRange().getStartOffset()).isEqualTo(23);
- assertThat(issue.getTextRange().getEndLine()).isEqualTo(7);
- assertThat(issue.getTextRange().getEndOffset()).isEqualTo(23);
- }
-
- @Test
- public void testFlowWithSingleLocation() {
- List<Issue> issues = result.issuesFor(result.inputFile("xources/hello/Multiple.xoo"));
- assertThat(issues).hasSize(1);
- Issue issue = issues.get(0);
- assertThat(issue.getMsg()).isEqualTo("Primary location of the issue in xoo code");
- assertThat(issue.getTextRange().getStartLine()).isEqualTo(6);
- assertThat(issue.getTextRange().getStartOffset()).isEqualTo(23);
- assertThat(issue.getTextRange().getEndLine()).isEqualTo(6);
- assertThat(issue.getTextRange().getEndOffset()).isEqualTo(50);
-
- assertThat(issue.getFlowList()).hasSize(1);
- Flow flow = issue.getFlow(0);
- assertThat(flow.getLocationList()).hasSize(1);
- IssueLocation additionalLocation = flow.getLocation(0);
- assertThat(additionalLocation.getMsg()).isEqualTo("Xoo code, flow step #1");
- assertThat(additionalLocation.getTextRange().getStartLine()).isEqualTo(7);
- assertThat(additionalLocation.getTextRange().getStartOffset()).isEqualTo(26);
- assertThat(additionalLocation.getTextRange().getEndLine()).isEqualTo(7);
- assertThat(additionalLocation.getTextRange().getEndOffset()).isEqualTo(53);
- }
-
- @Test
- public void testFlowsWithMultipleElements() {
- List<Issue> issues = result.issuesFor(result.inputFile("xources/hello/WithFlow.xoo"));
- assertThat(issues).hasSize(1);
- Issue issue = issues.get(0);
- assertThat(issue.getFlowList()).hasSize(1);
-
- Flow flow = issue.getFlow(0);
- assertThat(flow.getLocationList()).hasSize(2);
- // TODO more assertions
- }
-
- @Test
- public void testFlowsWithTypes() {
- List<Issue> issues = result.issuesFor(result.inputFile("xources/hello/FlowTypes.xoo"));
- assertThat(issues).hasSize(1);
- Issue issue = issues.get(0);
- assertThat(issue.getFlowList()).hasSize(3);
-
- assertThat(issue.getFlowList()).extracting(Flow::getType, Flow::getDescription, f -> f.getLocationList().size())
- .containsExactly(
- tuple(FlowType.DATA, "flow #1", 1),
- tuple(FlowType.UNDEFINED, "", 1),
- tuple(FlowType.EXECUTION, "flow #3", 1));
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2023 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.mediumtest.issues;
-
-import com.google.common.collect.ImmutableMap;
-import org.junit.Rule;
-import org.junit.Test;
-import org.sonar.api.utils.MessageException;
-import org.sonar.api.utils.log.LogTester;
-import org.sonar.scanner.mediumtest.ScannerMediumTester;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.fail;
-
-public class PreviewMediumTest {
-
- @Rule
- public LogTester logTester = new LogTester();
-
- @Rule
- public ScannerMediumTester tester = new ScannerMediumTester();
-
- @Test
- public void failWhenUsingPreviewMode() {
- try {
- tester.newAnalysis()
- .properties(ImmutableMap.<String, String>builder()
- .put("sonar.analysis.mode", "preview").build())
- .execute();
- fail("Expected exception");
- } catch (Exception e) {
- assertThat(e).isInstanceOf(MessageException.class).hasMessage("The preview mode, along with the 'sonar.analysis.mode' parameter, is no more supported. You should stop using this parameter.");
- }
- }
-
- @Test
- public void failWhenUsingIssuesMode() {
- try {
- tester.newAnalysis()
- .properties(ImmutableMap.<String, String>builder()
- .put("sonar.analysis.mode", "issues").build())
- .execute();
- fail("Expected exception");
- } catch (Exception e) {
- assertThat(e).isInstanceOf(MessageException.class).hasMessage("The preview mode, along with the 'sonar.analysis.mode' parameter, is no more supported. You should stop using this parameter.");
- }
- }
-
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2023 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.mediumtest.log;
-
-import java.util.Collections;
-import java.util.Map;
-import javax.annotation.Priority;
-import org.junit.BeforeClass;
-import org.junit.Test;
-import org.sonar.api.utils.MessageException;
-import org.sonar.batch.bootstrapper.Batch;
-import org.sonar.batch.bootstrapper.EnvironmentInformation;
-import org.sonar.scanner.repository.settings.GlobalSettingsLoader;
-import org.springframework.beans.factory.UnsatisfiedDependencyException;
-
-import static org.assertj.core.api.Assertions.assertThatThrownBy;
-
-public class ExceptionHandlingMediumTest {
-
- private Batch batch;
- private static ErrorGlobalSettingsLoader loader;
-
- @BeforeClass
- public static void beforeClass() {
- loader = new ErrorGlobalSettingsLoader();
- }
-
- public void setUp(boolean verbose) {
- Batch.Builder builder = Batch.builder()
- .setEnableLoggingConfiguration(true)
- .addComponents(
- loader,
- new EnvironmentInformation("mediumTest", "1.0"));
-
- if (verbose) {
- builder.setGlobalProperties(Collections.singletonMap("sonar.verbose", "true"));
- }
- batch = builder.build();
- }
-
- @Test
- public void test() throws Exception {
- setUp(false);
- loader.withCause = false;
-
- assertThatThrownBy(() -> batch.execute())
- .isInstanceOf(MessageException.class)
- .hasMessage("Error loading settings");
- }
-
- @Test
- public void testWithCause() throws Exception {
- setUp(false);
- loader.withCause = true;
-
- assertThatThrownBy(() -> batch.execute())
- .isInstanceOf(MessageException.class)
- .hasMessage("Error loading settings")
- .hasCauseInstanceOf(Throwable.class)
- .hasRootCauseMessage("Code 401");
- }
-
- @Test
- public void testWithVerbose() {
- setUp(true);
- assertThatThrownBy(() -> batch.execute())
- .isInstanceOf(UnsatisfiedDependencyException.class)
- .hasMessageContaining("Error loading settings");
- }
-
- @Priority(1)
- private static class ErrorGlobalSettingsLoader implements GlobalSettingsLoader {
- boolean withCause = false;
-
- @Override
- public Map<String, String> loadGlobalSettings() {
- if (withCause) {
- IllegalStateException cause = new IllegalStateException("Code 401");
- throw MessageException.of("Error loading settings", cause);
- } else {
- throw MessageException.of("Error loading settings");
- }
- }
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2023 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.mediumtest.log;
-
-import com.google.common.collect.ImmutableMap;
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.IOException;
-import java.io.PrintStream;
-import java.nio.charset.StandardCharsets;
-import java.util.Collections;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-import org.apache.commons.io.FileUtils;
-import org.junit.AfterClass;
-import org.junit.Before;
-import org.junit.BeforeClass;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TemporaryFolder;
-import org.sonar.batch.bootstrapper.LogOutput;
-import org.sonar.batch.bootstrapper.LogOutput.Level;
-import org.sonar.scanner.mediumtest.ScannerMediumTester;
-import org.sonar.xoo.XooPlugin;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.fail;
-
-public class LogListenerTest {
- @Rule
- public TemporaryFolder temp = new TemporaryFolder();
-
- private Pattern simpleTimePattern = Pattern.compile("\\d{2}:\\d{2}:\\d{2}");
- private List<LogEvent> logOutput;
- private StringBuilder logOutputStr;
- private ByteArrayOutputStream stdOutTarget;
- private ByteArrayOutputStream stdErrTarget;
- private static PrintStream savedStdOut;
- private static PrintStream savedStdErr;
-
- @Rule
- public ScannerMediumTester tester = new ScannerMediumTester()
- .registerPlugin("xoo", new XooPlugin())
- .addDefaultQProfile("xoo", "Sonar Way")
- .setLogOutput(new SimpleLogListener());
-
- private File baseDir;
- private ImmutableMap.Builder<String, String> builder;
-
- @BeforeClass
- public static void backupStdStreams() {
- savedStdOut = System.out;
- savedStdErr = System.err;
- }
-
- @AfterClass
- public static void resumeStdStreams() {
- if (savedStdOut != null) {
- System.setOut(savedStdOut);
- }
- if (savedStdErr != null) {
- System.setErr(savedStdErr);
- }
- }
-
- @Before
- public void prepare() {
- System.out.flush();
- System.err.flush();
- stdOutTarget = new ByteArrayOutputStream();
- stdErrTarget = new ByteArrayOutputStream();
- System.setOut(new PrintStream(stdOutTarget));
- System.setErr(new PrintStream(stdErrTarget));
- // logger from the batch might write to it asynchronously
- logOutput = Collections.synchronizedList(new LinkedList<>());
- logOutputStr = new StringBuilder();
-
- baseDir = temp.getRoot();
-
- builder = ImmutableMap.<String, String>builder()
- .put("sonar.task", "scan")
- .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
- .put("sonar.projectKey", "com.foo.project")
- .put("sonar.projectName", "Foo Project")
- .put("sonar.projectVersion", "1.0-SNAPSHOT")
- .put("sonar.projectDescription", "Description of Foo Project");
- }
-
- private void assertNoStdOutput() {
- assertThat(new String(stdOutTarget.toByteArray())).isEmpty();
- assertThat(new String(stdErrTarget.toByteArray())).isEmpty();
- }
-
- /**
- * Check that log message is not formatted, i.e. has no log level and timestamp.
- */
- private void assertMsgClean(String msg) {
- // FP: [JOURNAL_FLUSHER] WARNING Journal flush operation took 2,093ms last 8 cycles average is 262ms
- if (msg.contains("[JOURNAL_FLUSHER]")) {
- return;
- }
-
- for (LogOutput.Level l : LogOutput.Level.values()) {
- assertThat(msg).doesNotContain(l.toString());
- }
-
- Matcher matcher = simpleTimePattern.matcher(msg);
- assertThat(matcher.find()).isFalse();
- }
-
- @Test
- public void testChangeLogForAnalysis() throws IOException {
- File srcDir = new File(baseDir, "src");
- srcDir.mkdir();
-
- File xooFile = new File(srcDir, "sample.xoo");
- FileUtils.write(xooFile, "Sample xoo\ncontent", StandardCharsets.UTF_8);
-
- tester.newAnalysis()
- .properties(builder
- .put("sonar.sources", "src")
- .put("sonar.verbose", "true")
- .build())
- .execute();
-
- synchronized (logOutput) {
- for (LogEvent e : logOutput) {
- savedStdOut.println("[captured]" + e.level + " " + e.msg);
- }
- }
-
- // only done in DEBUG during analysis
- assertThat(logOutputStr.toString()).contains("Post-jobs : ");
- }
-
- @Test
- public void testNoStdLog() throws IOException {
- File srcDir = new File(baseDir, "src");
- srcDir.mkdir();
-
- File xooFile = new File(srcDir, "sample.xoo");
- FileUtils.write(xooFile, "Sample xoo\ncontent", StandardCharsets.UTF_8);
-
- tester.newAnalysis()
- .properties(builder
- .put("sonar.sources", "src")
- .build())
- .execute();
-
- assertNoStdOutput();
- assertThat(logOutput).isNotEmpty();
-
- synchronized (logOutput) {
- for (LogEvent e : logOutput) {
- savedStdOut.println("[captured]" + e.level + " " + e.msg);
- }
- }
- }
-
- @Test
- public void testNoFormattedMsgs() throws IOException {
- File srcDir = new File(baseDir, "src");
- srcDir.mkdir();
-
- File xooFile = new File(srcDir, "sample.xoo");
- FileUtils.write(xooFile, "Sample xoo\ncontent", StandardCharsets.UTF_8);
-
- tester.newAnalysis()
- .properties(builder
- .put("sonar.sources", "src")
- .build())
- .execute();
-
- assertNoStdOutput();
-
- synchronized (logOutput) {
- for (LogEvent e : logOutput) {
- assertMsgClean(e.msg);
- savedStdOut.println("[captured]" + e.level + " " + e.msg);
- }
- }
- }
-
- // SONAR-7540
- @Test
- public void testStackTrace() throws IOException {
- File srcDir = new File(baseDir, "src");
- srcDir.mkdir();
-
- File xooFile = new File(srcDir, "sample.xoo");
- FileUtils.write(xooFile, "Sample xoo\ncontent");
- File xooFileMeasure = new File(srcDir, "sample.xoo.measures");
- FileUtils.write(xooFileMeasure, "foo:bar", StandardCharsets.UTF_8);
-
- try {
- tester.newAnalysis()
- .properties(builder
- .put("sonar.sources", "src")
- .build())
- .execute();
- fail("Expected exception");
- } catch (Exception e) {
- assertThat(e.getMessage()).contains("Error processing line 1");
- }
-
- assertNoStdOutput();
-
- synchronized (logOutput) {
- for (LogEvent e : logOutput) {
- if (e.level == Level.ERROR) {
- assertThat(e.msg).contains("Error processing line 1 of file", "src" + File.separator + "sample.xoo.measures",
- "java.lang.IllegalStateException: Unknown metric with key: foo",
- "at org.sonar.xoo.lang.MeasureSensor.saveMeasure");
-
- }
- }
- }
- }
-
- private class SimpleLogListener implements LogOutput {
- @Override
- public void log(String msg, Level level) {
- logOutput.add(new LogEvent(msg, level));
- logOutputStr.append(msg).append("\n");
- }
- }
-
- private static class LogEvent {
- String msg;
- LogOutput.Level level;
-
- LogEvent(String msg, LogOutput.Level level) {
- this.msg = msg;
- this.level = level;
- }
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2023 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.mediumtest.measures;
-
-import com.google.common.collect.ImmutableMap;
-import java.io.File;
-import java.io.IOException;
-import java.nio.charset.StandardCharsets;
-import java.util.List;
-import java.util.Map;
-import org.apache.commons.io.FileUtils;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TemporaryFolder;
-import org.sonar.api.utils.log.LogTester;
-import org.sonar.api.utils.log.LoggerLevel;
-import org.sonar.scanner.mediumtest.ScannerMediumTester;
-import org.sonar.scanner.mediumtest.AnalysisResult;
-import org.sonar.scanner.protocol.output.ScannerReport.Measure;
-import org.sonar.xoo.XooPlugin;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.tuple;
-import static org.junit.Assert.fail;
-
-public class MeasuresMediumTest {
-
- @Rule
- public LogTester logTester = new LogTester();
-
- @Rule
- public TemporaryFolder temp = new TemporaryFolder();
-
- private File baseDir;
- private File srcDir;
-
- @Rule
- public ScannerMediumTester tester = new ScannerMediumTester()
- .registerPlugin("xoo", new XooPlugin())
- .addDefaultQProfile("xoo", "Sonar Way");
-
- @Before
- public void setUp() throws Exception {
- baseDir = temp.newFolder();
- srcDir = new File(baseDir, "src");
- srcDir.mkdir();
- }
-
- @Test
- public void failIfTryingToSaveServerSideMeasure() throws IOException {
- File xooFile = new File(srcDir, "sample.xoo");
- FileUtils.write(xooFile, "Sample xoo\n\ncontent", StandardCharsets.UTF_8);
-
- File measures = new File(srcDir, "sample.xoo.measures");
- FileUtils.write(measures, "new_lines:2", StandardCharsets.UTF_8);
-
- try {
- tester.newAnalysis()
- .properties(ImmutableMap.<String, String>builder()
- .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
- .put("sonar.projectKey", "com.foo.project")
- .put("sonar.sources", "src")
- .build())
- .execute();
- fail("Expected exception");
- } catch (Exception e) {
- assertThat(e)
- .hasCauseInstanceOf(UnsupportedOperationException.class)
- .hasStackTraceContaining("Metric 'new_lines' should not be computed by a Sensor");
- }
- }
-
- @Test
- public void lineMeasures() throws IOException {
- File xooFile = new File(srcDir, "sample.xoo");
- FileUtils.write(xooFile, "Sample xoo\n\n\ncontent", StandardCharsets.UTF_8);
-
- File lineMeasures = new File(srcDir, "sample.xoo.linemeasures");
- FileUtils.write(lineMeasures, "ncloc_data:1=1;2=0;4=1", StandardCharsets.UTF_8);
-
- AnalysisResult result = tester.newAnalysis()
- .properties(ImmutableMap.<String, String>builder()
- .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
- .put("sonar.projectKey", "com.foo.project")
- .put("sonar.sources", "src")
- .build())
- .execute();
-
- Map<String, List<Measure>> allMeasures = result.allMeasures();
-
- assertThat(allMeasures.get("com.foo.project:src/sample.xoo")).extracting("metricKey", "intValue.value", "stringValue.value")
- .containsExactly(tuple("ncloc_data", 0, "1=1;4=1"));
- }
-
- @Test
- public void projectLevelMeasures() throws IOException {
- File xooFile = new File(srcDir, "sample.xoo");
- FileUtils.write(xooFile, "Sample xoo\n\n\ncontent", StandardCharsets.UTF_8);
-
- File projectMeasures = new File(baseDir, "module.measures");
- FileUtils.write(projectMeasures, "tests:10", StandardCharsets.UTF_8);
-
- AnalysisResult result = tester.newAnalysis()
- .properties(ImmutableMap.<String, String>builder()
- .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
- .put("sonar.projectKey", "com.foo.project")
- .put("sonar.sources", "src")
- .build())
- .execute();
-
- Map<String, List<Measure>> allMeasures = result.allMeasures();
-
- assertThat(allMeasures.get("com.foo.project"))
- .extracting("metricKey", "intValue.value", "stringValue.value")
- .containsExactly(tuple("tests", 10, ""));
- }
-
- @Test
- public void warnWhenSavingFolderMeasure() throws IOException {
- File xooFile = new File(srcDir, "sample.xoo");
- FileUtils.write(xooFile, "Sample xoo\n\n\ncontent", StandardCharsets.UTF_8);
-
- File folderMeasures = new File(srcDir, "folder.measures");
- FileUtils.write(folderMeasures, "tests:10", StandardCharsets.UTF_8);
-
- AnalysisResult result = tester.newAnalysis()
- .properties(ImmutableMap.<String, String>builder()
- .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
- .put("sonar.projectKey", "com.foo.project")
- .put("sonar.sources", "src")
- .build())
- .execute();
-
-
- assertThat(logTester.logs(LoggerLevel.WARN)).contains("Storing measures on folders or modules is deprecated. Provided value of metric 'tests' is ignored.");
- }
-
- @Test
- public void warnWhenSavingModuleMeasure() throws IOException {
- File moduleDir = new File(baseDir, "moduleA");
- moduleDir.mkdirs();
-
- srcDir = new File(moduleDir, "src");
-
- File xooFile = new File(srcDir, "sample.xoo");
- FileUtils.write(xooFile, "Sample xoo\n\n\ncontent", StandardCharsets.UTF_8);
-
- File moduleMeasures = new File(moduleDir, "module.measures");
- FileUtils.write(moduleMeasures, "tests:10", StandardCharsets.UTF_8);
-
- AnalysisResult result = tester.newAnalysis()
- .properties(ImmutableMap.<String, String>builder()
- .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
- .put("sonar.projectKey", "com.foo.project")
- .put("sonar.modules", "moduleA")
- .put("sonar.sources", "src")
- .build())
- .execute();
-
-
- assertThat(logTester.logs(LoggerLevel.WARN)).contains("Storing measures on folders or modules is deprecated. Provided value of metric 'tests' is ignored.");
- }
-
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2023 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.mediumtest.scm;
-
-import com.google.common.collect.ImmutableMap;
-import java.io.File;
-import java.io.IOException;
-import java.net.URISyntaxException;
-import java.nio.charset.StandardCharsets;
-import java.util.regex.Pattern;
-import org.apache.commons.codec.digest.DigestUtils;
-import org.apache.commons.io.FileUtils;
-import org.assertj.core.util.Files;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TemporaryFolder;
-import org.sonar.api.SonarEdition;
-import org.sonar.api.utils.log.LogTester;
-import org.sonar.scanner.mediumtest.ScannerMediumTester;
-import org.sonar.scanner.mediumtest.ScannerMediumTester.AnalysisBuilder;
-import org.sonar.scanner.protocol.output.FileStructure;
-import org.sonar.scanner.protocol.output.ScannerReport;
-import org.sonar.scanner.protocol.output.ScannerReport.Changesets.Changeset;
-import org.sonar.scanner.protocol.output.ScannerReport.Component;
-import org.sonar.scanner.protocol.output.ScannerReportReader;
-import org.sonar.scanner.repository.FileData;
-import org.sonar.xoo.XooPlugin;
-import org.sonar.xoo.rule.XooRulesDefinition;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class ScmMediumTest {
-
- private static final String MISSING_BLAME_INFORMATION_FOR_THE_FOLLOWING_FILES = "Missing blame information for the following files:";
- private static final String CHANGED_CONTENT_SCM_ON_SERVER_XOO = "src/changed_content_scm_on_server.xoo";
- private static final String NO_BLAME_SCM_ON_SERVER_XOO = "src/no_blame_scm_on_server.xoo";
- private static final String SAME_CONTENT_SCM_ON_SERVER_XOO = "src/same_content_scm_on_server.xoo";
- private static final String SAME_CONTENT_NO_SCM_ON_SERVER_XOO = "src/same_content_no_scm_on_server.xoo";
- private static final String SAMPLE_XOO_CONTENT = "Sample xoo\ncontent";
-
- @Rule
- public TemporaryFolder temp = new TemporaryFolder();
-
- @Rule
- public LogTester logTester = new LogTester();
-
- @Rule
- public ScannerMediumTester tester = new ScannerMediumTester()
- .setEdition(SonarEdition.COMMUNITY)
- .registerPlugin("xoo", new XooPlugin())
- .addDefaultQProfile("xoo", "Sonar Way")
- .addRules(new XooRulesDefinition())
- // active a rule just to be sure that xoo files are published
- .addActiveRule("xoo", "xoo:OneIssuePerFile", null, "One Issue Per File", null, null, null)
- .addFileData(CHANGED_CONTENT_SCM_ON_SERVER_XOO, new FileData(DigestUtils.md5Hex(SAMPLE_XOO_CONTENT), null))
- .addFileData(SAME_CONTENT_NO_SCM_ON_SERVER_XOO, new FileData(DigestUtils.md5Hex(SAMPLE_XOO_CONTENT), null))
- .addFileData(SAME_CONTENT_SCM_ON_SERVER_XOO, new FileData(DigestUtils.md5Hex(SAMPLE_XOO_CONTENT), "1.1"))
- .addFileData(NO_BLAME_SCM_ON_SERVER_XOO, new FileData(DigestUtils.md5Hex(SAMPLE_XOO_CONTENT), "1.1"));
-
- @Test
- public void testScmMeasure() throws IOException, URISyntaxException {
- File baseDir = prepareProject();
-
- tester.newAnalysis()
- .properties(ImmutableMap.<String, String>builder()
- .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
- .put("sonar.projectKey", "com.foo.project")
- .put("sonar.sources", "src")
- .put("sonar.scm.provider", "xoo")
- .build())
- .execute();
-
- ScannerReport.Changesets fileScm = getChangesets(baseDir, "src/sample.xoo");
-
- assertThat(fileScm.getChangesetIndexByLineList()).hasSize(5);
-
- Changeset changesetLine1 = fileScm.getChangeset(fileScm.getChangesetIndexByLine(0));
- assertThat(changesetLine1.getAuthor()).isEmpty();
-
- Changeset changesetLine2 = fileScm.getChangeset(fileScm.getChangesetIndexByLine(1));
- assertThat(changesetLine2.getAuthor()).isEqualTo(getNonAsciiAuthor().toLowerCase());
-
- Changeset changesetLine3 = fileScm.getChangeset(fileScm.getChangesetIndexByLine(2));
- assertThat(changesetLine3.getAuthor()).isEqualTo("julien");
-
- Changeset changesetLine4 = fileScm.getChangeset(fileScm.getChangesetIndexByLine(3));
- assertThat(changesetLine4.getAuthor()).isEqualTo("julien");
-
- Changeset changesetLine5 = fileScm.getChangeset(fileScm.getChangesetIndexByLine(4));
- assertThat(changesetLine5.getAuthor()).isEqualTo("simon");
- }
-
- private ScannerReport.Changesets getChangesets(File baseDir, String path) {
- File reportDir = new File(baseDir, ".sonar/scanner-report");
- FileStructure fileStructure = new FileStructure(reportDir);
- ScannerReportReader reader = new ScannerReportReader(fileStructure);
-
- Component project = reader.readComponent(reader.readMetadata().getRootComponentRef());
- for (Integer fileRef : project.getChildRefList()) {
- Component file = reader.readComponent(fileRef);
- if (file.getProjectRelativePath().equals(path)) {
- return reader.readChangesets(file.getRef());
- }
- }
- return null;
- }
-
- @Test
- public void noScmOnEmptyFile() throws IOException, URISyntaxException {
-
- File baseDir = prepareProject();
-
- // Clear file content
- FileUtils.write(new File(baseDir, "src/sample.xoo"), "");
-
- tester.newAnalysis()
- .properties(ImmutableMap.<String, String>builder()
- .put("sonar.task", "scan")
- .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
- .put("sonar.projectKey", "com.foo.project")
- .put("sonar.projectName", "Foo Project")
- .put("sonar.projectVersion", "1.0-SNAPSHOT")
- .put("sonar.projectDescription", "Description of Foo Project")
- .put("sonar.sources", "src")
- .put("sonar.scm.provider", "xoo")
- .build())
- .execute();
-
- ScannerReport.Changesets changesets = getChangesets(baseDir, "src/sample.xoo");
-
- assertThat(changesets).isNull();
- }
-
- @Test
- public void log_files_with_missing_blame() throws IOException, URISyntaxException {
-
- File baseDir = prepareProject();
- File xooFileWithoutBlame = new File(baseDir, "src/sample_no_blame.xoo");
- FileUtils.write(xooFileWithoutBlame, "Sample xoo\ncontent\n3\n4\n5", StandardCharsets.UTF_8);
-
- tester.newAnalysis()
- .properties(ImmutableMap.<String, String>builder()
- .put("sonar.task", "scan")
- .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
- .put("sonar.projectKey", "com.foo.project")
- .put("sonar.projectName", "Foo Project")
- .put("sonar.projectVersion", "1.0-SNAPSHOT")
- .put("sonar.projectDescription", "Description of Foo Project")
- .put("sonar.sources", "src")
- .put("sonar.scm.provider", "xoo")
- .build())
- .execute();
-
- ScannerReport.Changesets file1Scm = getChangesets(baseDir, "src/sample.xoo");
- assertThat(file1Scm).isNotNull();
-
- ScannerReport.Changesets fileWithoutBlameScm = getChangesets(baseDir, "src/sample_no_blame.xoo");
- assertThat(fileWithoutBlameScm).isNull();
-
- assertThat(logTester.logs()).containsSubsequence("SCM Publisher 2 source files to be analyzed", MISSING_BLAME_INFORMATION_FOR_THE_FOLLOWING_FILES,
- " * src/sample_no_blame.xoo");
-
- assertThat(logTester.logs().stream().anyMatch(s -> Pattern.matches("SCM Publisher 1/2 source file have been analyzed \\(done\\) \\| time=[0-9]+ms", s))).isTrue();
- }
-
- // SONAR-6397
- @Test
- public void optimize_blame() throws IOException, URISyntaxException {
-
- File baseDir = prepareProject();
- File changedContentScmOnServer = new File(baseDir, CHANGED_CONTENT_SCM_ON_SERVER_XOO);
- FileUtils.write(changedContentScmOnServer, SAMPLE_XOO_CONTENT + "\nchanged", StandardCharsets.UTF_8);
- File xooScmFile = new File(baseDir, CHANGED_CONTENT_SCM_ON_SERVER_XOO + ".scm");
- FileUtils.write(xooScmFile,
- // revision,author,dateTime
- "1,foo,2013-01-04\n" +
- "1,bar,2013-01-04\n" +
- "2,biz,2014-01-04\n",
- StandardCharsets.UTF_8);
-
- File sameContentScmOnServer = new File(baseDir, SAME_CONTENT_SCM_ON_SERVER_XOO);
- FileUtils.write(sameContentScmOnServer, SAMPLE_XOO_CONTENT, StandardCharsets.UTF_8);
- // No need to write .scm file since this file should not be blamed
-
- File noBlameScmOnServer = new File(baseDir, NO_BLAME_SCM_ON_SERVER_XOO);
- FileUtils.write(noBlameScmOnServer, SAMPLE_XOO_CONTENT + "\nchanged", StandardCharsets.UTF_8);
- // No .scm file to emulate a failure during blame
-
- File sameContentNoScmOnServer = new File(baseDir, SAME_CONTENT_NO_SCM_ON_SERVER_XOO);
- FileUtils.write(sameContentNoScmOnServer, SAMPLE_XOO_CONTENT, StandardCharsets.UTF_8);
- xooScmFile = new File(baseDir, SAME_CONTENT_NO_SCM_ON_SERVER_XOO + ".scm");
- FileUtils.write(xooScmFile,
- // revision,author,dateTime
- "1,foo,2013-01-04\n" +
- "1,bar,2013-01-04\n",
- StandardCharsets.UTF_8);
-
- tester.newAnalysis()
- .properties(ImmutableMap.<String, String>builder()
- .put("sonar.task", "scan")
- .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
- .put("sonar.projectKey", "com.foo.project")
- .put("sonar.projectName", "Foo Project")
- .put("sonar.projectVersion", "1.0-SNAPSHOT")
- .put("sonar.projectDescription", "Description of Foo Project")
- .put("sonar.sources", "src")
- .put("sonar.scm.provider", "xoo")
- .build())
- .execute();
-
- assertThat(getChangesets(baseDir, "src/sample.xoo")).isNotNull();
-
- assertThat(getChangesets(baseDir, CHANGED_CONTENT_SCM_ON_SERVER_XOO).getCopyFromPrevious()).isFalse();
-
- assertThat(getChangesets(baseDir, SAME_CONTENT_SCM_ON_SERVER_XOO).getCopyFromPrevious()).isTrue();
-
- assertThat(getChangesets(baseDir, SAME_CONTENT_NO_SCM_ON_SERVER_XOO).getCopyFromPrevious()).isFalse();
-
- assertThat(getChangesets(baseDir, NO_BLAME_SCM_ON_SERVER_XOO)).isNull();
-
- // 5 .xoo files + 3 .scm files, but only 4 marked for publishing. 1 file is SAME so not included in the total
- assertThat(logTester.logs()).containsSubsequence("8 files indexed");
- assertThat(logTester.logs()).containsSubsequence("SCM Publisher 4 source files to be analyzed");
- assertThat(logTester.logs().stream().anyMatch(s -> Pattern.matches("SCM Publisher 3/4 source files have been analyzed \\(done\\) \\| time=[0-9]+ms", s))).isTrue();
- assertThat(logTester.logs()).containsSubsequence(MISSING_BLAME_INFORMATION_FOR_THE_FOLLOWING_FILES, " * src/no_blame_scm_on_server.xoo");
- }
-
- @Test
- public void forceReload() throws IOException, URISyntaxException {
-
- File baseDir = prepareProject();
- File xooFileNoScm = new File(baseDir, SAME_CONTENT_SCM_ON_SERVER_XOO);
- FileUtils.write(xooFileNoScm, SAMPLE_XOO_CONTENT, StandardCharsets.UTF_8);
- File xooScmFile = new File(baseDir, SAME_CONTENT_SCM_ON_SERVER_XOO + ".scm");
- FileUtils.write(xooScmFile,
- // revision,author,dateTime
- "1,foo,2013-01-04\n" +
- "1,bar,2013-01-04\n",
- StandardCharsets.UTF_8);
-
- AnalysisBuilder analysisBuilder = tester.newAnalysis()
- .properties(ImmutableMap.<String, String>builder()
- .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
- .put("sonar.projectKey", "com.foo.project")
- .put("sonar.sources", "src")
- .put("sonar.scm.provider", "xoo")
- // Force reload
- .put("sonar.scm.forceReloadAll", "true")
- .build());
-
- analysisBuilder.execute();
-
- ScannerReport.Changesets file1Scm = getChangesets(baseDir, "src/sample.xoo");
- assertThat(file1Scm).isNotNull();
-
- ScannerReport.Changesets file2Scm = getChangesets(baseDir, SAME_CONTENT_SCM_ON_SERVER_XOO);
- assertThat(file2Scm).isNotNull();
- }
-
- @Test
- public void configureUsingScmURL() throws IOException, URISyntaxException {
-
- File baseDir = prepareProject();
-
- tester.newAnalysis()
- .properties(ImmutableMap.<String, String>builder()
- .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
- .put("sonar.projectKey", "com.foo.project")
- .put("sonar.sources", "src")
- .put("sonar.links.scm_dev", "scm:xoo:foobar")
- .build())
- .execute();
-
- ScannerReport.Changesets file1Scm = getChangesets(baseDir, "src/sample.xoo");
- assertThat(file1Scm).isNotNull();
- }
-
- @Test
- public void testAutoDetection() throws IOException, URISyntaxException {
-
- File baseDir = prepareProject();
- new File(baseDir, ".xoo").createNewFile();
-
- tester.newAnalysis()
- .properties(ImmutableMap.<String, String>builder()
- .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
- .put("sonar.projectKey", "com.foo.project")
- .put("sonar.sources", "src")
- .build())
- .execute();
-
- ScannerReport.Changesets file1Scm = getChangesets(baseDir, "src/sample.xoo");
- assertThat(file1Scm).isNotNull();
- }
-
- private String getNonAsciiAuthor() {
- return Files.contentOf(new File("test-resources/mediumtest/blameAuthor.txt"), StandardCharsets.UTF_8);
-
- }
-
- private File prepareProject() throws IOException {
- File baseDir = temp.getRoot();
- File srcDir = new File(baseDir, "src");
- srcDir.mkdir();
-
- File xooFile1 = new File(srcDir, "sample.xoo");
- FileUtils.write(xooFile1, "Sample xoo\ncontent\n3\n4\n5", StandardCharsets.UTF_8);
- File xooScmFile1 = new File(srcDir, "sample.xoo.scm");
- FileUtils.write(xooScmFile1,
- // revision,author,dateTime
- "1,,2013-01-04\n" +
- "2," + getNonAsciiAuthor() + ",2013-01-04\n" +
- "3,julien,2013-02-03\n" +
- "3,julien,2013-02-03\n" +
- "4,simon,2013-03-04\n",
- StandardCharsets.UTF_8);
-
- return baseDir;
- }
-
- @Test
- public void testDisableScmSensor() throws IOException, URISyntaxException {
-
- File baseDir = prepareProject();
-
- tester.newAnalysis()
- .properties(ImmutableMap.<String, String>builder()
- .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
- .put("sonar.projectKey", "com.foo.project")
- .put("sonar.sources", "src")
- .put("sonar.scm.disabled", "true")
- .put("sonar.scm.provider", "xoo")
- .put("sonar.cpd.xoo.skip", "true")
- .build())
- .execute();
-
- ScannerReport.Changesets changesets = getChangesets(baseDir, "src/sample.xoo");
- assertThat(changesets).isNull();
- }
-
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2023 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.mediumtest.symbol;
-
-import com.google.common.collect.ImmutableMap;
-import java.io.File;
-import java.io.IOException;
-import org.apache.commons.io.FileUtils;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TemporaryFolder;
-import org.sonar.api.batch.fs.InputFile;
-import org.sonar.scanner.mediumtest.ScannerMediumTester;
-import org.sonar.scanner.mediumtest.AnalysisResult;
-import org.sonar.scanner.protocol.output.ScannerReport;
-import org.sonar.xoo.XooPlugin;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class SymbolMediumTest {
-
- @Rule
- public TemporaryFolder temp = new TemporaryFolder();
-
- @Rule
- public ScannerMediumTester tester = new ScannerMediumTester()
- .registerPlugin("xoo", new XooPlugin())
- .addDefaultQProfile("xoo", "Sonar Way");
-
- @Test
- public void computeSymbolReferencesOnTempProject() throws IOException {
-
- File baseDir = temp.getRoot();
- File srcDir = new File(baseDir, "src");
- srcDir.mkdir();
-
- File xooFile = new File(srcDir, "sample.xoo");
- File xooSymbolFile = new File(srcDir, "sample.xoo.symbol");
- FileUtils.write(xooFile, "Sample xoo\ncontent\nanother xoo");
- // Highlight xoo symbol
- FileUtils.write(xooSymbolFile, "1:7:1:10,3:8:3:11");
-
- AnalysisResult result = tester.newAnalysis()
- .properties(ImmutableMap.<String, String>builder()
- .put("sonar.task", "scan")
- .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
- .put("sonar.projectKey", "com.foo.project")
- .put("sonar.projectName", "Foo Project")
- .put("sonar.projectVersion", "1.0-SNAPSHOT")
- .put("sonar.projectDescription", "Description of Foo Project")
- .put("sonar.sources", "src")
- .build())
- .execute();
-
- InputFile file = result.inputFile("src/sample.xoo");
- assertThat(result.symbolReferencesFor(file, 1, 7)).containsOnly(ScannerReport.TextRange.newBuilder().setStartLine(3).setStartOffset(8).setEndLine(3).setEndOffset(11).build());
- }
-
- @Test
- public void computeSymbolReferencesWithVariableLength() throws IOException {
-
- File baseDir = temp.getRoot();
- File srcDir = new File(baseDir, "src");
- srcDir.mkdir();
-
- File xooFile = new File(srcDir, "sample.xoo");
- File xooSymbolFile = new File(srcDir, "sample.xoo.symbol");
- FileUtils.write(xooFile, "Sample xoo\ncontent\nanother xoo\nyet another");
- // Highlight xoo symbol
- FileUtils.write(xooSymbolFile, "1:7:1:10,3:8:4:1");
-
- AnalysisResult result = tester.newAnalysis()
- .properties(ImmutableMap.<String, String>builder()
- .put("sonar.task", "scan")
- .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
- .put("sonar.projectKey", "com.foo.project")
- .put("sonar.projectName", "Foo Project")
- .put("sonar.projectVersion", "1.0-SNAPSHOT")
- .put("sonar.projectDescription", "Description of Foo Project")
- .put("sonar.sources", "src")
- .build())
- .execute();
-
- InputFile file = result.inputFile("src/sample.xoo");
- assertThat(result.symbolReferencesFor(file, 1, 7)).containsOnly(ScannerReport.TextRange.newBuilder().setStartLine(3).setStartOffset(8).setEndLine(4).setEndOffset(1).build());
- }
-
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2023 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.mediumtest.tasks;
-
-import com.google.common.collect.ImmutableMap;
-import org.junit.Rule;
-import org.junit.Test;
-import org.sonar.api.Plugin;
-import org.sonar.api.utils.MessageException;
-import org.sonar.api.utils.log.LogTester;
-import org.sonar.scanner.mediumtest.ScannerMediumTester;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.fail;
-
-public class TasksMediumTest {
-
- @Rule
- public LogTester logTester = new LogTester();
-
- @Rule
- public ScannerMediumTester tester = new ScannerMediumTester()
- .registerPlugin("faketask", new FakePlugin());
-
- @Test
- public void failWhenCallingTask() {
- try {
- tester.newAnalysis()
- .properties(ImmutableMap.<String, String>builder()
- .put("sonar.task", "fake").build())
- .execute();
- fail("Expected exception");
- } catch (Exception e) {
- assertThat(e).isInstanceOf(MessageException.class).hasMessage("Tasks support was removed in SonarQube 7.6.");
- }
- }
-
- @Test
- public void failWhenCallingViews() {
- try {
- tester.newAnalysis()
- .properties(ImmutableMap.<String, String>builder()
- .put("sonar.task", "views").build())
- .execute();
- fail("Expected exception");
- } catch (Exception e) {
- assertThat(e).isInstanceOf(MessageException.class).hasMessage("The task 'views' was removed with SonarQube 7.1. You can safely remove this call since portfolios and applications are automatically re-calculated.");
- }
- }
-
- private static class FakePlugin implements Plugin {
-
- @Override
- public void define(Context context) {
- }
- }
-
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2023 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.mediumtest.tests;
-
-import java.io.File;
-import java.util.ArrayList;
-import java.util.List;
-import org.junit.Rule;
-import org.junit.Test;
-import org.sonar.api.batch.fs.InputFile;
-import org.sonar.api.measures.CoreMetrics;
-import org.sonar.scanner.mediumtest.AnalysisResult;
-import org.sonar.scanner.mediumtest.ScannerMediumTester;
-import org.sonar.xoo.XooPlugin;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.tuple;
-
-public class GenericTestExecutionMediumTest {
- private final List<String> logs = new ArrayList<>();
-
- @Rule
- public ScannerMediumTester tester = new ScannerMediumTester()
- .registerPlugin("xoo", new XooPlugin())
- .addDefaultQProfile("xoo", "Sonar Way");
-
- @Test
- public void singleReport() {
-
- File projectDir = new File("test-resources/mediumtest/xoo/sample-generic-test-exec");
-
- AnalysisResult result = tester
- .setLogOutput((msg, level) -> logs.add(msg))
- .newAnalysis(new File(projectDir, "sonar-project.properties"))
- .property("sonar.testExecutionReportPaths", "unittest.xml")
- .execute();
-
- InputFile testFile = result.inputFile("testx/ClassOneTest.xoo");
- assertThat(result.allMeasures().get(testFile.key())).extracting("metricKey", "intValue.value", "longValue.value")
- .containsOnly(
- tuple(CoreMetrics.TESTS_KEY, 3, 0L),
- tuple(CoreMetrics.SKIPPED_TESTS_KEY, 1, 0L),
- tuple(CoreMetrics.TEST_ERRORS_KEY, 1, 0L),
- tuple(CoreMetrics.TEST_EXECUTION_TIME_KEY, 0, 1105L),
- tuple(CoreMetrics.TEST_FAILURES_KEY, 1, 0L));
-
- assertThat(logs).noneMatch(l -> l.contains("Please use 'sonar.testExecutionReportPaths'"));
- }
-
- @Test
- public void twoReports() {
-
- File projectDir = new File("test-resources/mediumtest/xoo/sample-generic-test-exec");
-
- AnalysisResult result = tester
- .setLogOutput((msg, level) -> logs.add(msg))
- .newAnalysis(new File(projectDir, "sonar-project.properties"))
- .property("sonar.testExecutionReportPaths", "unittest.xml,unittest2.xml")
- .execute();
-
- InputFile testFile = result.inputFile("testx/ClassOneTest.xoo");
- assertThat(result.allMeasures().get(testFile.key())).extracting("metricKey", "intValue.value", "longValue.value")
- .containsOnly(
- tuple(CoreMetrics.TESTS_KEY, 4, 0L),
- tuple(CoreMetrics.SKIPPED_TESTS_KEY, 2, 0L),
- tuple(CoreMetrics.TEST_ERRORS_KEY, 1, 0L),
- tuple(CoreMetrics.TEST_EXECUTION_TIME_KEY, 0, 1610L),
- tuple(CoreMetrics.TEST_FAILURES_KEY, 1, 0L));
-
- assertThat(logs).noneMatch(l -> l.contains("Please use 'sonar.testExecutionReportPaths'"));
- }
-
-}
public class JavaArchitectureInformationProviderTest {
- private JavaArchitectureInformationProvider javaArchitectureInformationProvider = new JavaArchitectureInformationProvider();
+ private final JavaArchitectureInformationProvider javaArchitectureInformationProvider = new JavaArchitectureInformationProvider();
@Test
- public void is64bitJavaVersion_returnsTrue_whenRunningWith64bitJava() {
+ public void is64bitJavaVersion_whenRunningWith64bitJava_shouldReturnTrue() {
assertThat(javaArchitectureInformationProvider.is64bitJavaVersion()).isTrue();
}
import org.sonar.api.utils.MessageException;
import org.sonar.scanner.WsTestUtil;
import org.sonar.scanner.bootstrap.DefaultScannerWsClient;
-import org.sonar.scanner.scan.ScanProperties;
import org.sonarqube.ws.Qualityprofiles;
import org.sonarqube.ws.Qualityprofiles.SearchWsResponse.QualityProfile;
import org.sonarqube.ws.client.HttpException;
public class DefaultQualityProfileLoaderTest {
private final DefaultScannerWsClient wsClient = mock(DefaultScannerWsClient.class);
- private final ScanProperties properties = mock(ScanProperties.class);
private final DefaultQualityProfileLoader underTest = new DefaultQualityProfileLoader(wsClient);
@Test
*/
package org.sonar.scanner.repository;
-import java.util.Date;
import org.junit.Before;
import org.junit.Test;
@Before
public void setUp() {
- Date lastAnalysisDate = new Date();
repository = new SingleProjectRepository(singletonMap("/Abc.java", new FileData("123", "456")));
}
@Rule
public TemporaryFolder temp = new TemporaryFolder();
-
private MapSettings settings;
@Before
private final UnchangedFilesHandler unchangedFilesHandler = mock(UnchangedFilesHandler.class);
private final SonarRuntime runtime = SonarRuntimeImpl.forSonarQube(Version.parse("5.5"), SonarQubeSide.SCANNER, SonarEdition.COMMUNITY);
private DefaultFileSystem fs;
- private ModuleSensorContext adaptor;
+ private ModuleSensorContext underTest;
@Before
public void prepare() throws Exception {
fs = new DefaultFileSystem(temp.newFolder().toPath());
- adaptor = new ModuleSensorContext(mock(DefaultInputProject.class), mock(InputModule.class), settings.asConfig(), settings, fs, activeRules, sensorStorage, runtime,
+ underTest = new ModuleSensorContext(mock(DefaultInputProject.class), mock(InputModule.class), settings.asConfig(), settings, fs, activeRules, sensorStorage, runtime,
branchConfiguration, writeCache, readCache, analysisCacheEnabled, unchangedFilesHandler);
}
@Test
- public void shouldProvideComponents() {
- assertThat(adaptor.activeRules()).isEqualTo(activeRules);
- assertThat(adaptor.fileSystem()).isEqualTo(fs);
- assertThat(adaptor.getSonarQubeVersion()).isEqualTo(Version.parse("5.5"));
- assertThat(adaptor.runtime()).isEqualTo(runtime);
- assertThat(adaptor.canSkipUnchangedFiles()).isFalse();
+ public void shouldProvideComponents_returnsNotNull() {
+ assertThat(underTest.activeRules()).isEqualTo(activeRules);
+ assertThat(underTest.fileSystem()).isEqualTo(fs);
+ assertThat(underTest.getSonarQubeVersion()).isEqualTo(Version.parse("5.5"));
+ assertThat(underTest.runtime()).isEqualTo(runtime);
+ assertThat(underTest.canSkipUnchangedFiles()).isFalse();
- assertThat(adaptor.nextCache()).isEqualTo(writeCache);
- assertThat(adaptor.previousCache()).isEqualTo(readCache);
+ assertThat(underTest.nextCache()).isEqualTo(writeCache);
+ assertThat(underTest.previousCache()).isEqualTo(readCache);
- assertThat(adaptor.newIssue()).isNotNull();
- assertThat(adaptor.newExternalIssue()).isNotNull();
- assertThat(adaptor.newAdHocRule()).isNotNull();
- assertThat(adaptor.newMeasure()).isNotNull();
- assertThat(adaptor.newAnalysisError()).isEqualTo(ModuleSensorContext.NO_OP_NEW_ANALYSIS_ERROR);
- assertThat(adaptor.isCancelled()).isFalse();
- assertThat(adaptor.newSignificantCode()).isNotNull();
+ assertThat(underTest.newIssue()).isNotNull();
+ assertThat(underTest.newExternalIssue()).isNotNull();
+ assertThat(underTest.newAdHocRule()).isNotNull();
+ assertThat(underTest.newMeasure()).isNotNull();
+ assertThat(underTest.newAnalysisError()).isEqualTo(ModuleSensorContext.NO_OP_NEW_ANALYSIS_ERROR);
+ assertThat(underTest.isCancelled()).isFalse();
+ assertThat(underTest.newSignificantCode()).isNotNull();
}
@Test
public void should_delegate_to_unchanged_files_handler() {
DefaultInputFile defaultInputFile = mock(DefaultInputFile.class);
- adaptor.markAsUnchanged(defaultInputFile);
+
+ underTest.markAsUnchanged(defaultInputFile);
verify(unchangedFilesHandler).markAsUnchanged(defaultInputFile);
}
@Test
public void pull_request_can_skip_unchanged_files() {
when(branchConfiguration.isPullRequest()).thenReturn(true);
- adaptor = new ModuleSensorContext(mock(DefaultInputProject.class), mock(InputModule.class), settings.asConfig(), settings, fs, activeRules, sensorStorage, runtime,
+ underTest = new ModuleSensorContext(mock(DefaultInputProject.class), mock(InputModule.class), settings.asConfig(), settings, fs, activeRules, sensorStorage, runtime,
branchConfiguration, writeCache, readCache, analysisCacheEnabled, unchangedFilesHandler);
- assertThat(adaptor.canSkipUnchangedFiles()).isTrue();
+ assertThat(underTest.canSkipUnchangedFiles()).isTrue();
}
}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2023 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.scm.svn;
-
-import java.io.File;
-import java.io.IOException;
-import java.net.URISyntaxException;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.nio.file.StandardOpenOption;
-import java.util.Arrays;
-import java.util.Date;
-import java.util.Enumeration;
-import java.util.List;
-import java.util.stream.IntStream;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipFile;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TemporaryFolder;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-import org.junit.runners.Parameterized.Parameters;
-import org.mockito.ArgumentCaptor;
-import org.sonar.api.batch.fs.FileSystem;
-import org.sonar.api.batch.fs.InputFile;
-import org.sonar.api.batch.fs.internal.DefaultInputFile;
-import org.sonar.api.batch.fs.internal.TestInputFileBuilder;
-import org.sonar.api.batch.scm.BlameCommand.BlameInput;
-import org.sonar.api.batch.scm.BlameCommand.BlameOutput;
-import org.sonar.api.batch.scm.BlameLine;
-import org.sonar.api.utils.log.LogTester;
-import org.sonar.api.utils.log.LoggerLevel;
-import org.tmatesoft.svn.core.SVNAuthenticationException;
-import org.tmatesoft.svn.core.SVNDepth;
-import org.tmatesoft.svn.core.SVNURL;
-import org.tmatesoft.svn.core.auth.ISVNAuthenticationManager;
-import org.tmatesoft.svn.core.internal.wc2.compat.SvnCodec;
-import org.tmatesoft.svn.core.wc.ISVNOptions;
-import org.tmatesoft.svn.core.wc.SVNClientManager;
-import org.tmatesoft.svn.core.wc.SVNLogClient;
-import org.tmatesoft.svn.core.wc.SVNRevision;
-import org.tmatesoft.svn.core.wc.SVNStatus;
-import org.tmatesoft.svn.core.wc.SVNStatusClient;
-import org.tmatesoft.svn.core.wc.SVNStatusType;
-import org.tmatesoft.svn.core.wc.SVNUpdateClient;
-import org.tmatesoft.svn.core.wc.SVNWCUtil;
-import org.tmatesoft.svn.core.wc2.SvnCheckout;
-import org.tmatesoft.svn.core.wc2.SvnTarget;
-
-import static java.util.Collections.singletonList;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.junit.Assert.assertThrows;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.anyBoolean;
-import static org.mockito.Mockito.doThrow;
-import static org.mockito.Mockito.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoInteractions;
-import static org.mockito.Mockito.when;
-
-@RunWith(Parameterized.class)
-public class SvnBlameCommandTest {
-
- /*
- * Note about SONARSCSVN-11: The case of a project baseDir is in a subFolder of working copy is part of method tests by default
- */
-
- private static final String DUMMY_JAVA = "src/main/java/org/dummy/Dummy.java";
-
- @Rule
- public TemporaryFolder temp = new TemporaryFolder();
-
- @Rule
- public LogTester logTester = new LogTester();
-
- private FileSystem fs;
- private BlameInput input;
- private String serverVersion;
- private int wcVersion;
-
- @Parameters(name = "SVN server version {0}, WC version {1}")
- public static Iterable<Object[]> data() {
- return Arrays.asList(new Object[][] {{"1.6", 10}, {"1.7", 29}, {"1.8", 31}, {"1.9", 31}});
- }
-
- public SvnBlameCommandTest(String serverVersion, int wcVersion) {
- this.serverVersion = serverVersion;
- this.wcVersion = wcVersion;
- }
-
- @Before
- public void prepare() {
- fs = mock(FileSystem.class);
- input = mock(BlameInput.class);
- when(input.fileSystem()).thenReturn(fs);
- }
-
- @Test
- public void testParsingOfOutput() throws Exception {
- File repoDir = unzip("repo-svn.zip");
-
- String scmUrl = "file:///" + unixPath(new File(repoDir, "repo-svn"));
- File baseDir = new File(checkout(scmUrl), "dummy-svn");
-
- when(fs.baseDir()).thenReturn(baseDir);
- DefaultInputFile inputFile = new TestInputFileBuilder("foo", DUMMY_JAVA)
- .setLines(27)
- .setModuleBaseDir(baseDir.toPath())
- .build();
-
- BlameOutput blameResult = mock(BlameOutput.class);
- when(input.filesToBlame()).thenReturn(singletonList(inputFile));
-
- newSvnBlameCommand().blame(input, blameResult);
- ArgumentCaptor<List> captor = ArgumentCaptor.forClass(List.class);
- verify(blameResult).blameResult(eq(inputFile), captor.capture());
- List<BlameLine> result = captor.getValue();
- assertThat(result).hasSize(27);
- Date commitDate = new Date(1342691097393L);
- BlameLine[] expected = IntStream.rangeClosed(1, 27).mapToObj(i -> new BlameLine().date(commitDate).revision("2").author("dgageot")).toArray(BlameLine[]::new);
- assertThat(result).containsExactly(expected);
- }
-
- private File unzip(String repoName) throws IOException {
- File repoDir = temp.newFolder();
- try {
- javaUnzip(Paths.get(this.getClass().getResource("test-repos").toURI()).resolve(serverVersion).resolve(repoName).toFile(), repoDir);
- return repoDir;
- } catch (URISyntaxException e) {
- throw new IOException(e);
- }
- }
-
- private File checkout(String scmUrl) throws Exception {
- ISVNOptions options = SVNWCUtil.createDefaultOptions(true);
- ISVNAuthenticationManager isvnAuthenticationManager = SVNWCUtil.createDefaultAuthenticationManager(null, null, (char[]) null, false);
- SVNClientManager svnClientManager = SVNClientManager.newInstance(options, isvnAuthenticationManager);
- File out = temp.newFolder();
- SVNUpdateClient updateClient = svnClientManager.getUpdateClient();
- SvnCheckout co = updateClient.getOperationsFactory().createCheckout();
- co.setUpdateLocksOnDemand(updateClient.isUpdateLocksOnDemand());
- co.setSource(SvnTarget.fromURL(SVNURL.parseURIEncoded(scmUrl), SVNRevision.HEAD));
- co.setSingleTarget(SvnTarget.fromFile(out));
- co.setRevision(SVNRevision.HEAD);
- co.setDepth(SVNDepth.INFINITY);
- co.setAllowUnversionedObstructions(false);
- co.setIgnoreExternals(updateClient.isIgnoreExternals());
- co.setExternalsHandler(SvnCodec.externalsHandler(updateClient.getExternalsHandler()));
- co.setTargetWorkingCopyFormat(wcVersion);
- co.run();
- return out;
- }
-
- @Test
- public void testParsingOfOutputWithMergeHistory() throws Exception {
- File repoDir = unzip("repo-svn-with-merge.zip");
-
- String scmUrl = "file:///" + unixPath(new File(repoDir, "repo-svn"));
- File baseDir = new File(checkout(scmUrl), "dummy-svn/trunk");
-
- when(fs.baseDir()).thenReturn(baseDir);
- DefaultInputFile inputFile = new TestInputFileBuilder("foo", DUMMY_JAVA)
- .setLines(27)
- .setModuleBaseDir(baseDir.toPath())
- .build();
-
- BlameOutput blameResult = mock(BlameOutput.class);
- when(input.filesToBlame()).thenReturn(singletonList(inputFile));
-
- newSvnBlameCommand().blame(input, blameResult);
- ArgumentCaptor<List> captor = ArgumentCaptor.forClass(List.class);
- verify(blameResult).blameResult(eq(inputFile), captor.capture());
- List<BlameLine> result = captor.getValue();
- assertThat(result).hasSize(27);
- Date commitDate = new Date(1342691097393L);
- Date revision6Date = new Date(1415262184300L);
-
- BlameLine[] expected = IntStream.rangeClosed(1, 27).mapToObj(i -> {
- if (i == 2 || i == 24) {
- return new BlameLine().date(revision6Date).revision("6").author("henryju");
- } else {
- return new BlameLine().date(commitDate).revision("2").author("dgageot");
- }
- }).toArray(BlameLine[]::new);
-
- assertThat(result).containsExactly(expected);
- }
-
- @Test
- public void shouldNotFailIfFileContainsLocalModification() throws Exception {
- File repoDir = unzip("repo-svn.zip");
-
- String scmUrl = "file:///" + unixPath(new File(repoDir, "repo-svn"));
- File baseDir = new File(checkout(scmUrl), "dummy-svn");
-
- when(fs.baseDir()).thenReturn(baseDir);
- DefaultInputFile inputFile = new TestInputFileBuilder("foo", DUMMY_JAVA)
- .setLines(28)
- .setModuleBaseDir(baseDir.toPath())
- .build();
-
- Files.write(baseDir.toPath().resolve(DUMMY_JAVA), "\n//foo".getBytes(), StandardOpenOption.APPEND);
-
- BlameOutput blameResult = mock(BlameOutput.class);
- when(input.filesToBlame()).thenReturn(singletonList(inputFile));
-
- newSvnBlameCommand().blame(input, blameResult);
- verifyNoInteractions(blameResult);
- }
-
- // SONARSCSVN-7
- @Test
- public void shouldNotFailOnWrongFilename() throws Exception {
- File repoDir = unzip("repo-svn.zip");
-
- String scmUrl = "file:///" + unixPath(new File(repoDir, "repo-svn"));
- File baseDir = new File(checkout(scmUrl), "dummy-svn");
-
- when(fs.baseDir()).thenReturn(baseDir);
- DefaultInputFile inputFile = new TestInputFileBuilder("foo", DUMMY_JAVA.toLowerCase())
- .setLines(27)
- .setModuleBaseDir(baseDir.toPath())
- .build();
-
- BlameOutput blameResult = mock(BlameOutput.class);
- when(input.filesToBlame()).thenReturn(singletonList(inputFile));
-
- newSvnBlameCommand().blame(input, blameResult);
- verifyNoInteractions(blameResult);
- }
-
- @Test
- public void shouldNotFailOnUncommitedFile() throws Exception {
- File repoDir = unzip("repo-svn.zip");
-
- String scmUrl = "file:///" + unixPath(new File(repoDir, "repo-svn"));
- File baseDir = new File(checkout(scmUrl), "dummy-svn");
-
- when(fs.baseDir()).thenReturn(baseDir);
- String relativePath = "src/main/java/org/dummy/Dummy2.java";
- DefaultInputFile inputFile = new TestInputFileBuilder("foo", relativePath)
- .setLines(28)
- .setModuleBaseDir(baseDir.toPath())
- .build();
-
- Files.write(baseDir.toPath().resolve(relativePath), "package org.dummy;\npublic class Dummy2 {}".getBytes());
-
- BlameOutput blameResult = mock(BlameOutput.class);
- when(input.filesToBlame()).thenReturn(singletonList(inputFile));
-
- newSvnBlameCommand().blame(input, blameResult);
- verifyNoInteractions(blameResult);
- }
-
- @Test
- public void shouldNotFailOnUncommitedDir() throws Exception {
- File repoDir = unzip("repo-svn.zip");
-
- String scmUrl = "file:///" + unixPath(new File(repoDir, "repo-svn"));
- File baseDir = new File(checkout(scmUrl), "dummy-svn");
-
- when(fs.baseDir()).thenReturn(baseDir);
- String relativePath = "src/main/java/org/dummy2/dummy/Dummy.java";
- DefaultInputFile inputFile = new TestInputFileBuilder("foo", relativePath)
- .setLines(28)
- .setModuleBaseDir(baseDir.toPath())
- .build();
-
- Path filepath = new File(baseDir, relativePath).toPath();
- Files.createDirectories(filepath.getParent());
- Files.write(filepath, "package org.dummy;\npublic class Dummy {}".getBytes());
-
- BlameOutput blameResult = mock(BlameOutput.class);
- when(input.filesToBlame()).thenReturn(singletonList(inputFile));
-
- newSvnBlameCommand().blame(input, blameResult);
- verifyNoInteractions(blameResult);
- }
-
- @Test
- public void blame_givenNoCredentials_logWarning() throws Exception {
- BlameOutput output = mock(BlameOutput.class);
- InputFile inputFile = mock(InputFile.class);
- SvnBlameCommand svnBlameCommand = newSvnBlameCommand();
-
- SVNClientManager clientManager = mock(SVNClientManager.class);
- SVNLogClient logClient = mock(SVNLogClient.class);
- SVNStatusClient statusClient = mock(SVNStatusClient.class);
- SVNStatus status = mock(SVNStatus.class);
-
- when(clientManager.getLogClient()).thenReturn(logClient);
- when(clientManager.getStatusClient()).thenReturn(statusClient);
- when(status.getContentsStatus()).thenReturn(SVNStatusType.STATUS_NORMAL);
- when(inputFile.file()).thenReturn(mock(File.class));
- when(statusClient.doStatus(any(File.class), anyBoolean())).thenReturn(status);
-
- doThrow(SVNAuthenticationException.class).when(logClient).doAnnotate(any(File.class), any(SVNRevision.class),
- any(SVNRevision.class), any(SVNRevision.class), anyBoolean(), anyBoolean(), any(AnnotationHandler.class),
- eq(null));
-
- assertThrows(IllegalStateException.class, () -> {
- svnBlameCommand.blame(clientManager, inputFile, output);
- assertThat(logTester.logs(LoggerLevel.WARN)).contains("Authentication to SVN server is required but no " +
- "authentication data was passed to the scanner");
- });
-
- }
-
- @Test
- public void blame_givenCredentialsSupplied_doNotlogWarning() throws Exception {
- BlameOutput output = mock(BlameOutput.class);
- InputFile inputFile = mock(InputFile.class);
- SvnConfiguration properties = mock(SvnConfiguration.class);
- SvnBlameCommand svnBlameCommand = new SvnBlameCommand(properties);
-
- SVNClientManager clientManager = mock(SVNClientManager.class);
- SVNLogClient logClient = mock(SVNLogClient.class);
- SVNStatusClient statusClient = mock(SVNStatusClient.class);
- SVNStatus status = mock(SVNStatus.class);
-
- when(properties.isEmpty()).thenReturn(true);
- when(clientManager.getLogClient()).thenReturn(logClient);
- when(clientManager.getStatusClient()).thenReturn(statusClient);
- when(status.getContentsStatus()).thenReturn(SVNStatusType.STATUS_NORMAL);
- when(inputFile.file()).thenReturn(mock(File.class));
- when(statusClient.doStatus(any(File.class), anyBoolean())).thenReturn(status);
-
- doThrow(SVNAuthenticationException.class).when(logClient).doAnnotate(any(File.class), any(SVNRevision.class),
- any(SVNRevision.class), any(SVNRevision.class), anyBoolean(), anyBoolean(), any(AnnotationHandler.class),
- eq(null));
-
- assertThrows(IllegalStateException.class, () -> {
- svnBlameCommand.blame(clientManager, inputFile, output);
- assertThat(logTester.logs(LoggerLevel.WARN)).isEmpty();
- });
-
- }
-
- private static void javaUnzip(File zip, File toDir) {
- try {
- try (ZipFile zipFile = new ZipFile(zip)) {
- Enumeration<? extends ZipEntry> entries = zipFile.entries();
- while (entries.hasMoreElements()) {
- ZipEntry entry = entries.nextElement();
- File to = new File(toDir, entry.getName());
- if (entry.isDirectory()) {
- Files.createDirectories(to.toPath());
- } else {
- File parent = to.getParentFile();
- if (parent != null) {
- Files.createDirectories(parent.toPath());
- }
-
- Files.copy(zipFile.getInputStream(entry), to.toPath());
- }
- }
- }
- } catch (Exception e) {
- throw new IllegalStateException("Fail to unzip " + zip + " to " + toDir, e);
- }
- }
-
- private static String unixPath(File file) {
- return file.getAbsolutePath().replace('\\', '/');
- }
-
- private SvnBlameCommand newSvnBlameCommand() {
- return new SvnBlameCommand(mock(SvnConfiguration.class));
- }
-}
private SvnConfiguration config = mock(SvnConfiguration.class);
@Test
- public void getExtensions() {
+ public void getObjects_shouldNotBeEmpty() {
assertThat(SvnScmSupport.getObjects()).isNotEmpty();
}
@Test
- public void newSvnClientManager_with_auth() {
+ public void newSvnClientManager_whenPasswordConfigured_shouldNotReturnNull() {
when(config.password()).thenReturn("password");
when(config.passPhrase()).thenReturn("passPhrase");
+
assertThat(newSvnClientManager(config)).isNotNull();
}
@Test
- public void newSvnClientManager_without_auth() {
+ public void newSvnClientManager_whenPasswordNotConfigured_shouldNotReturnNull() {
assertThat(config.password()).isNull();
assertThat(config.passPhrase()).isNull();
+
assertThat(newSvnClientManager(config)).isNotNull();
}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2023 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.scm.svn;
-
-import java.io.File;
-import java.io.IOException;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.StandardOpenOption;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.Set;
-import org.tmatesoft.svn.core.SVNDepth;
-import org.tmatesoft.svn.core.SVNException;
-import org.tmatesoft.svn.core.SVNURL;
-import org.tmatesoft.svn.core.io.SVNRepositoryFactory;
-import org.tmatesoft.svn.core.wc.SVNClientManager;
-import org.tmatesoft.svn.core.wc.SVNCopyClient;
-import org.tmatesoft.svn.core.wc.SVNCopySource;
-import org.tmatesoft.svn.core.wc.SVNRevision;
-import org.tmatesoft.svn.core.wc.SVNUpdateClient;
-import org.tmatesoft.svn.core.wc2.SvnList;
-import org.tmatesoft.svn.core.wc2.SvnOperationFactory;
-import org.tmatesoft.svn.core.wc2.SvnRemoteMkDir;
-import org.tmatesoft.svn.core.wc2.SvnTarget;
-
-public class SvnTester {
- private final SVNClientManager manager = SVNClientManager.newInstance(new SvnOperationFactory());
-
- private final SVNURL localRepository;
-
- public SvnTester(Path root) throws SVNException, IOException {
- localRepository = SVNRepositoryFactory.createLocalRepository(root.toFile(), false, false);
- mkdir("trunk");
- mkdir("branches");
- }
-
- private void mkdir(String relpath) throws IOException, SVNException {
- SvnRemoteMkDir remoteMkDir = manager.getOperationFactory().createRemoteMkDir();
- remoteMkDir.addTarget(SvnTarget.fromURL(localRepository.appendPath(relpath, false)));
- remoteMkDir.run();
- }
-
- public void createBranch(String branchName) throws IOException, SVNException {
- SVNCopyClient copyClient = manager.getCopyClient();
- SVNCopySource source = new SVNCopySource(SVNRevision.HEAD, SVNRevision.HEAD, localRepository.appendPath("trunk", false));
- copyClient.doCopy(new SVNCopySource[] {source}, localRepository.appendPath("branches/" + branchName, false), false, false, true, "Create branch", null);
- }
-
- public void createBranch(String branchSource, String branchName) throws IOException, SVNException {
- SVNCopyClient copyClient = manager.getCopyClient();
- SVNCopySource source = new SVNCopySource(SVNRevision.HEAD, SVNRevision.HEAD, localRepository.appendPath(branchSource, false));
- copyClient.doCopy(new SVNCopySource[] {source}, localRepository.appendPath("branches/" + branchName, false), false, false, true, "Create branch", null);
- }
-
- public void checkout(Path worktree, String path) throws SVNException {
- SVNUpdateClient updateClient = manager.getUpdateClient();
- updateClient.doCheckout(localRepository.appendPath(path, false),
- worktree.toFile(), null, null, SVNDepth.INFINITY, false);
- }
-
- public void add(Path worktree, String filename) throws SVNException {
- manager.getWCClient().doAdd(worktree.resolve(filename).toFile(), true, false, false, SVNDepth.INFINITY, false, false, true);
- }
-
- public void copy(Path worktree, String src, String dst) throws SVNException {
- SVNCopyClient copyClient = manager.getCopyClient();
- SVNCopySource source = new SVNCopySource(SVNRevision.HEAD, SVNRevision.HEAD, worktree.resolve(src).toFile());
- copyClient.doCopy(new SVNCopySource[]{source}, worktree.resolve(dst).toFile(), false, false, true);
- }
-
- public void commit(Path worktree) throws SVNException {
- manager.getCommitClient().doCommit(new File[] {worktree.toFile()}, false, "commit " + worktree, null, null, false, false, SVNDepth.INFINITY);
- }
-
- public void update(Path worktree) throws SVNException {
- manager.getUpdateClient().doUpdate(new File[] {worktree.toFile()}, SVNRevision.HEAD, SVNDepth.INFINITY, false, false);
- }
-
- public Collection<String> list(String... paths) throws SVNException {
- Set<String> results = new HashSet<>();
-
- SvnList list = manager.getOperationFactory().createList();
- if (paths.length == 0) {
- list.addTarget(SvnTarget.fromURL(localRepository));
- } else {
- for (String path : paths) {
- list.addTarget(SvnTarget.fromURL(localRepository.appendPath(path, false)));
- }
- }
- list.setDepth(SVNDepth.INFINITY);
- list.setReceiver((svnTarget, svnDirEntry) -> {
- String path = svnDirEntry.getRelativePath();
- if (!path.isEmpty()) {
- results.add(path);
- }
- });
- list.run();
-
- return results;
- }
-
- public void createFile(Path worktree, String filename, String content) throws IOException {
- Files.write(worktree.resolve(filename), content.getBytes());
- }
-
- public void createFile(Path worktree, String filename) throws IOException {
- createFile(worktree, filename, filename + "\n");
- }
-
- public void appendToFile(Path worktree, String filename) throws IOException {
- Files.write(worktree.resolve(filename), (filename + "\n").getBytes(), StandardOpenOption.APPEND);
- }
-
- public void deleteFile(Path worktree, String filename) throws SVNException {
- manager.getWCClient().doDelete(worktree.resolve(filename).toFile(), false, false);
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2023 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.scm.svn;
-
-import java.io.IOException;
-import java.nio.file.Path;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TemporaryFolder;
-import org.tmatesoft.svn.core.SVNException;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class SvnTesterTest {
- @Rule
- public TemporaryFolder temp = new TemporaryFolder();
-
- private SvnTester tester;
-
- @Before
- public void before() throws IOException, SVNException {
- tester = new SvnTester(temp.newFolder().toPath());
- }
-
- @Test
- public void test_init() throws SVNException {
- assertThat(tester.list()).containsExactlyInAnyOrder("trunk", "branches");
- }
-
- @Test
- public void test_add_and_commit() throws IOException, SVNException {
- assertThat(tester.list("trunk")).isEmpty();
-
- Path worktree = temp.newFolder().toPath();
- tester.checkout(worktree, "trunk");
- tester.createFile(worktree, "file1");
-
- tester.add(worktree, "file1");
- tester.commit(worktree);
-
- assertThat(tester.list("trunk")).containsOnly("file1");
- }
-
- @Test
- public void test_createBranch() throws IOException, SVNException {
- tester.createBranch("b1");
- assertThat(tester.list()).containsExactlyInAnyOrder("trunk", "branches", "branches/b1");
- assertThat(tester.list("branches")).containsOnly("b1");
- }
-}