import org.sonar.ce.task.projectanalysis.issue.TrackerSourceBranchInputFactory;
import org.sonar.ce.task.projectanalysis.issue.TrackerTargetBranchInputFactory;
import org.sonar.ce.task.projectanalysis.issue.UpdateConflictResolver;
-import org.sonar.ce.task.projectanalysis.issue.commonrule.BranchCoverageRule;
-import org.sonar.ce.task.projectanalysis.issue.commonrule.CommentDensityRule;
-import org.sonar.ce.task.projectanalysis.issue.commonrule.CommonRuleEngineImpl;
-import org.sonar.ce.task.projectanalysis.issue.commonrule.DuplicatedBlockRule;
-import org.sonar.ce.task.projectanalysis.issue.commonrule.LineCoverageRule;
-import org.sonar.ce.task.projectanalysis.issue.commonrule.SkippedTestRule;
-import org.sonar.ce.task.projectanalysis.issue.commonrule.TestErrorRule;
import org.sonar.ce.task.projectanalysis.issue.filter.IssueFilter;
import org.sonar.ce.task.projectanalysis.language.LanguageRepositoryImpl;
import org.sonar.ce.task.projectanalysis.locations.flow.FlowGenerator;
// push events
PushEventFactory.class,
- // common rules
- CommonRuleEngineImpl.class,
- BranchCoverageRule.class,
- LineCoverageRule.class,
- CommentDensityRule.class,
- DuplicatedBlockRule.class,
- TestErrorRule.class,
- SkippedTestRule.class,
-
// order is important: RuleTypeCopier must be the first one. And DebtAggregator must be before NewDebtAggregator (new debt requires
// debt)
RuleTagsCopier.class,
import org.sonar.ce.task.projectanalysis.batch.BatchReportReader;
import org.sonar.ce.task.projectanalysis.component.Component;
import org.sonar.ce.task.projectanalysis.component.TreeRootHolder;
-import org.sonar.ce.task.projectanalysis.issue.commonrule.CommonRuleEngine;
import org.sonar.ce.task.projectanalysis.issue.filter.IssueFilter;
import org.sonar.ce.task.projectanalysis.qualityprofile.ActiveRulesHolder;
import org.sonar.ce.task.projectanalysis.source.SourceLinesHashRepository;
private static final long DEFAULT_EXTERNAL_ISSUE_EFFORT = 0L;
private final TreeRootHolder treeRootHolder;
private final BatchReportReader reportReader;
- private final CommonRuleEngine commonRuleEngine;
private final IssueFilter issueFilter;
private final SourceLinesHashRepository sourceLinesHash;
private final RuleRepository ruleRepository;
private final ActiveRulesHolder activeRulesHolder;
- public TrackerRawInputFactory(TreeRootHolder treeRootHolder, BatchReportReader reportReader, SourceLinesHashRepository sourceLinesHash, CommonRuleEngine commonRuleEngine,
+ public TrackerRawInputFactory(TreeRootHolder treeRootHolder, BatchReportReader reportReader, SourceLinesHashRepository sourceLinesHash,
IssueFilter issueFilter, RuleRepository ruleRepository, ActiveRulesHolder activeRulesHolder) {
this.treeRootHolder = treeRootHolder;
this.reportReader = reportReader;
this.sourceLinesHash = sourceLinesHash;
- this.commonRuleEngine = commonRuleEngine;
this.issueFilter = issueFilter;
this.ruleRepository = ruleRepository;
this.activeRulesHolder = activeRulesHolder;
protected List<DefaultIssue> loadIssues() {
List<DefaultIssue> result = new ArrayList<>();
- for (DefaultIssue commonRuleIssue : commonRuleEngine.process(component)) {
- if (issueFilter.accept(commonRuleIssue, component)) {
- result.add(init(commonRuleIssue, STATUS_OPEN));
- }
- }
-
if (component.getReportAttributes().getRef() == null) {
return result;
}
+++ /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.ce.task.projectanalysis.issue.commonrule;
-
-import java.util.Optional;
-import org.sonar.ce.task.projectanalysis.component.Component;
-import org.sonar.ce.task.projectanalysis.measure.Measure;
-import org.sonar.ce.task.projectanalysis.measure.MeasureRepository;
-import org.sonar.ce.task.projectanalysis.metric.Metric;
-import org.sonar.ce.task.projectanalysis.qualityprofile.ActiveRule;
-import org.sonar.ce.task.projectanalysis.qualityprofile.ActiveRulesHolder;
-
-public abstract class AbstractCoverageRule extends CommonRule {
-
- private final MeasureRepository measureRepository;
- private final Metric coverageMetric;
- private final Metric uncoveredMetric;
- private final Metric toCoverMetric;
- private final String minPropertyKey;
-
- public AbstractCoverageRule(ActiveRulesHolder activeRulesHolder, String ruleKey, String minPropertyKey,
- MeasureRepository measureRepository,
- Metric coverageMetric, Metric uncoveredMetric, Metric toCoverMetric) {
- super(activeRulesHolder, ruleKey);
- this.minPropertyKey = minPropertyKey;
- this.measureRepository = measureRepository;
- this.coverageMetric = coverageMetric;
- this.uncoveredMetric = uncoveredMetric;
- this.toCoverMetric = toCoverMetric;
- }
-
- @Override
- protected CommonRuleIssue doProcessFile(Component file, ActiveRule activeRule) {
- Optional<Measure> coverageMeasure = measureRepository.getRawMeasure(file, coverageMetric);
- if (!file.getFileAttributes().isUnitTest() && coverageMeasure.isPresent()) {
- double coverage = coverageMeasure.get().getDoubleValue();
- double minimumCoverage = getMinDensityParam(activeRule, minPropertyKey);
- if (coverage < minimumCoverage) {
- return generateIssue(file, minimumCoverage);
- }
- }
- return null;
- }
-
- private CommonRuleIssue generateIssue(Component file, double minimumCoverage) {
- Optional<Measure> uncoveredMeasure = measureRepository.getRawMeasure(file, uncoveredMetric);
- Optional<Measure> toCoverMeasure = measureRepository.getRawMeasure(file, toCoverMetric);
- double uncovered = uncoveredMeasure.isPresent() ? uncoveredMeasure.get().getIntValue() : 0.0;
- double toCover = toCoverMeasure.isPresent() ? toCoverMeasure.get().getIntValue() : 0.0;
-
- // effort to fix is the number of lines/conditions to cover for reaching threshold
- int effortToFix = (int) Math.ceil((toCover * minimumCoverage / 100) - (toCover - uncovered));
-
- return new CommonRuleIssue(effortToFix, formatMessage(effortToFix, minimumCoverage));
- }
-
- protected abstract String formatMessage(int effortToFix, double minCoverage);
-}
+++ /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.ce.task.projectanalysis.issue.commonrule;
-
-import org.sonar.api.measures.CoreMetrics;
-import org.sonar.ce.task.projectanalysis.measure.MeasureRepository;
-import org.sonar.ce.task.projectanalysis.metric.MetricRepository;
-import org.sonar.ce.task.projectanalysis.qualityprofile.ActiveRulesHolder;
-import org.sonar.server.rule.CommonRuleKeys;
-
-import static java.lang.String.format;
-
-public class BranchCoverageRule extends AbstractCoverageRule {
-
- public BranchCoverageRule(ActiveRulesHolder activeRulesHolder, MetricRepository metricRepository, MeasureRepository measureRepository) {
- super(activeRulesHolder, CommonRuleKeys.INSUFFICIENT_BRANCH_COVERAGE, CommonRuleKeys.INSUFFICIENT_BRANCH_COVERAGE_PROPERTY,
- measureRepository,
- metricRepository.getByKey(CoreMetrics.BRANCH_COVERAGE_KEY),
- metricRepository.getByKey(CoreMetrics.UNCOVERED_CONDITIONS_KEY),
- metricRepository.getByKey(CoreMetrics.CONDITIONS_TO_COVER_KEY));
- }
-
- @Override
- protected String formatMessage(int effortToFix, double minCoverage) {
- // FIXME declare min threshold as int but not float ?
- return format("%d more conditions need to be covered by tests to reach the minimum threshold of %s%% condition coverage.", effortToFix, minCoverage);
- }
-}
+++ /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.ce.task.projectanalysis.issue.commonrule;
-
-import java.util.Optional;
-import org.sonar.api.measures.CoreMetrics;
-import org.sonar.ce.task.projectanalysis.component.Component;
-import org.sonar.ce.task.projectanalysis.measure.Measure;
-import org.sonar.ce.task.projectanalysis.measure.MeasureRepository;
-import org.sonar.ce.task.projectanalysis.metric.Metric;
-import org.sonar.ce.task.projectanalysis.metric.MetricRepository;
-import org.sonar.ce.task.projectanalysis.qualityprofile.ActiveRule;
-import org.sonar.ce.task.projectanalysis.qualityprofile.ActiveRulesHolder;
-import org.sonar.server.rule.CommonRuleKeys;
-
-import static java.lang.String.format;
-
-public class CommentDensityRule extends CommonRule {
-
- private final MeasureRepository measureRepository;
- private final Metric commentDensityMetric;
- private final Metric commentLinesMetric;
- private final Metric nclocMetric;
-
- public CommentDensityRule(ActiveRulesHolder activeRulesHolder, MeasureRepository measureRepository, MetricRepository metricRepository) {
- super(activeRulesHolder, CommonRuleKeys.INSUFFICIENT_COMMENT_DENSITY);
- this.measureRepository = measureRepository;
- this.commentDensityMetric = metricRepository.getByKey(CoreMetrics.COMMENT_LINES_DENSITY_KEY);
- this.commentLinesMetric = metricRepository.getByKey(CoreMetrics.COMMENT_LINES_KEY);
- this.nclocMetric = metricRepository.getByKey(CoreMetrics.NCLOC_KEY);
- }
-
- @Override
- protected CommonRuleIssue doProcessFile(Component file, ActiveRule activeRule) {
- Optional<Measure> commentDensityMeasure = measureRepository.getRawMeasure(file, commentDensityMetric);
- Optional<Measure> commentLinesMeasure = measureRepository.getRawMeasure(file, commentLinesMetric);
- Optional<Measure> nclocMeasure = measureRepository.getRawMeasure(file, nclocMetric);
-
- if (!file.getFileAttributes().isUnitTest() && commentDensityMeasure.isPresent() && nclocMeasure.isPresent() && nclocMeasure.get().getIntValue() > 0) {
- // this is a small optimization to not load the minimum value when the measures are not present
- double minCommentDensity = getMinDensity(activeRule);
- if (commentDensityMeasure.get().getDoubleValue() < minCommentDensity) {
- return generateIssue(commentDensityMeasure.get(), commentLinesMeasure, nclocMeasure.get(), minCommentDensity);
- }
- }
- return null;
- }
-
- private static double getMinDensity(ActiveRule activeRule) {
- double min = getMinDensityParam(activeRule, CommonRuleKeys.INSUFFICIENT_COMMENT_DENSITY_PROPERTY);
- if (min >= 100.0) {
- throw new IllegalStateException("Minimum density of rule [" + activeRule.getRuleKey() + "] is incorrect. Got [100] but must be strictly less than 100.");
- }
- return min;
- }
-
- private static CommonRuleIssue generateIssue(Measure commentDensityMeasure, Optional<Measure> commentLinesMeasure,
- Measure nclocMeasure, double minCommentDensity) {
- int commentLines = commentLinesMeasure.map(Measure::getIntValue).orElse(0);
- int ncloc = nclocMeasure.getIntValue();
- int minExpectedCommentLines = (int) Math.ceil(minCommentDensity * ncloc / (100 - minCommentDensity));
- int missingCommentLines = minExpectedCommentLines - commentLines;
- if (missingCommentLines <= 0) {
- throw new IllegalStateException(format("Bug in measures of comment lines - density=%s, comment_lines= %d, ncloc=%d, threshold=%s%%",
- commentDensityMeasure.getDoubleValue(), commentLines, nclocMeasure.getIntValue(), minCommentDensity));
- }
-
- // TODO declare min threshold as int but not float ?
- String message = format("%d more comment lines need to be written to reach the minimum threshold of %s%% comment density.", missingCommentLines, minCommentDensity);
- return new CommonRuleIssue(missingCommentLines, message);
- }
-}
+++ /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.ce.task.projectanalysis.issue.commonrule;
-
-import java.util.Optional;
-import javax.annotation.CheckForNull;
-import org.sonar.api.rule.RuleKey;
-import org.sonar.ce.task.projectanalysis.component.Component;
-import org.sonar.ce.task.projectanalysis.qualityprofile.ActiveRule;
-import org.sonar.ce.task.projectanalysis.qualityprofile.ActiveRulesHolder;
-import org.sonar.core.issue.DefaultIssue;
-
-import static org.apache.commons.lang.StringUtils.isNotBlank;
-import static org.sonar.server.rule.CommonRuleKeys.commonRepositoryForLang;
-
-public abstract class CommonRule {
-
- private final ActiveRulesHolder activeRulesHolder;
- private final String key;
-
- public CommonRule(ActiveRulesHolder activeRulesHolder, String key) {
- this.activeRulesHolder = activeRulesHolder;
- this.key = key;
- }
-
- @CheckForNull
- public DefaultIssue processFile(Component file, String fileLanguage) {
- DefaultIssue issue = null;
- RuleKey ruleKey = RuleKey.of(commonRepositoryForLang(fileLanguage), key);
- Optional<ActiveRule> activeRule = activeRulesHolder.get(ruleKey);
- if (activeRule.isPresent()) {
- CommonRuleIssue cri = doProcessFile(file, activeRule.get());
- if (cri != null) {
- issue = new DefaultIssue();
- issue.setGap(cri.effortToFix);
- issue.setMessage(cri.message);
- issue.setRuleKey(ruleKey);
- issue.setSeverity(activeRule.get().getSeverity());
- issue.setLine(null);
- issue.setChecksum("");
- issue.setIsFromExternalRuleEngine(false);
- }
- }
- return issue;
- }
-
- /**
- * Implementations must only set the effort to fix and message, so
- * using the lite intermediary object {@link CommonRuleIssue}
- */
- @CheckForNull
- protected abstract CommonRuleIssue doProcessFile(Component file, ActiveRule activeRule);
-
- protected static class CommonRuleIssue {
- private final double effortToFix;
- // FIXME which format ? HTML or MD ?
- private final String message;
-
- public CommonRuleIssue(double effortToFix, String message) {
- this.effortToFix = effortToFix;
- this.message = message;
- }
- }
-
- protected static double getMinDensityParam(ActiveRule activeRule, String paramKey) {
- String s = activeRule.getParams().get(paramKey);
- if (isNotBlank(s)) {
- double d = Double.parseDouble(s);
- if (d < 0.0 || d > 100.0) {
- throw new IllegalStateException(String.format("Minimum density of rule [%s] is incorrect. Got [%s] but must be between 0 and 100.", activeRule.getRuleKey(), s));
- }
- return d;
- }
- throw new IllegalStateException(String.format("Required parameter [%s] is missing on rule [%s]", paramKey, activeRule.getRuleKey()));
- }
-}
+++ /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.ce.task.projectanalysis.issue.commonrule;
-
-import java.util.Collection;
-import org.sonar.ce.task.projectanalysis.component.Component;
-import org.sonar.core.issue.DefaultIssue;
-
-/**
- * Generate the issues related to "common rules", which are
- * the rules based on measure thresholds.
- */
-public interface CommonRuleEngine {
-
- Collection<DefaultIssue> process(Component component);
-
-}
+++ /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.ce.task.projectanalysis.issue.commonrule;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import javax.annotation.CheckForNull;
-import org.sonar.ce.task.projectanalysis.component.Component;
-import org.sonar.core.issue.DefaultIssue;
-
-public class CommonRuleEngineImpl implements CommonRuleEngine {
-
- private final CommonRule[] commonRules;
-
- public CommonRuleEngineImpl(CommonRule... commonRules) {
- this.commonRules = commonRules;
- }
-
- @Override
- public Collection<DefaultIssue> process(Component component) {
- Collection<DefaultIssue> result = new ArrayList<>();
- String fileLanguage = getFileLanguage(component);
- if (fileLanguage != null) {
- for (CommonRule commonRule : commonRules) {
- DefaultIssue issue = commonRule.processFile(component, fileLanguage);
- if (issue != null) {
- result.add(issue);
- }
- }
- }
- return result;
- }
-
- @CheckForNull
- private static String getFileLanguage(Component component) {
- if (component.getType() == Component.Type.FILE) {
- return component.getFileAttributes().getLanguageKey();
- }
- return null;
- }
-}
+++ /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.ce.task.projectanalysis.issue.commonrule;
-
-import java.util.Optional;
-import org.sonar.api.measures.CoreMetrics;
-import org.sonar.ce.task.projectanalysis.component.Component;
-import org.sonar.ce.task.projectanalysis.measure.Measure;
-import org.sonar.ce.task.projectanalysis.measure.MeasureRepository;
-import org.sonar.ce.task.projectanalysis.metric.Metric;
-import org.sonar.ce.task.projectanalysis.metric.MetricRepository;
-import org.sonar.ce.task.projectanalysis.qualityprofile.ActiveRule;
-import org.sonar.ce.task.projectanalysis.qualityprofile.ActiveRulesHolder;
-import org.sonar.server.rule.CommonRuleKeys;
-
-import static java.lang.String.format;
-
-public class DuplicatedBlockRule extends CommonRule {
-
- private final MeasureRepository measureRepository;
- private final Metric duplicatedBlocksMetric;
-
- public DuplicatedBlockRule(ActiveRulesHolder activeRulesHolder, MeasureRepository measureRepository, MetricRepository metricRepository) {
- super(activeRulesHolder, CommonRuleKeys.DUPLICATED_BLOCKS);
- this.measureRepository = measureRepository;
- this.duplicatedBlocksMetric = metricRepository.getByKey(CoreMetrics.DUPLICATED_BLOCKS_KEY);
- }
-
- @Override
- protected CommonRuleIssue doProcessFile(Component file, ActiveRule activeRule) {
- Optional<Measure> duplicatedBlocksMeasure = measureRepository.getRawMeasure(file, duplicatedBlocksMetric);
- if (duplicatedBlocksMeasure.isPresent() && duplicatedBlocksMeasure.get().getIntValue() > 0) {
- int duplicatedBlocks = duplicatedBlocksMeasure.get().getIntValue();
- String message = format("%d duplicated blocks of code must be removed.", duplicatedBlocks);
- return new CommonRuleIssue(duplicatedBlocks, message);
- }
- return null;
- }
-}
+++ /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.ce.task.projectanalysis.issue.commonrule;
-
-import org.sonar.api.measures.CoreMetrics;
-import org.sonar.ce.task.projectanalysis.measure.MeasureRepository;
-import org.sonar.ce.task.projectanalysis.metric.MetricRepository;
-import org.sonar.ce.task.projectanalysis.qualityprofile.ActiveRulesHolder;
-import org.sonar.server.rule.CommonRuleKeys;
-
-import static java.lang.String.format;
-
-public class LineCoverageRule extends AbstractCoverageRule {
-
- public LineCoverageRule(ActiveRulesHolder activeRulesHolder, MetricRepository metricRepository, MeasureRepository measureRepository) {
- super(activeRulesHolder, CommonRuleKeys.INSUFFICIENT_LINE_COVERAGE, CommonRuleKeys.INSUFFICIENT_LINE_COVERAGE_PROPERTY,
- measureRepository,
- metricRepository.getByKey(CoreMetrics.LINE_COVERAGE_KEY),
- metricRepository.getByKey(CoreMetrics.UNCOVERED_LINES_KEY),
- metricRepository.getByKey(CoreMetrics.LINES_TO_COVER_KEY));
- }
-
- @Override
- protected String formatMessage(int effortToFix, double minCoverage) {
- // TODO declare min threshold as int but not float ?
- return format("%d more lines of code need to be covered by tests to reach the minimum threshold of %s%% lines coverage.", effortToFix, minCoverage);
- }
-}
+++ /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.ce.task.projectanalysis.issue.commonrule;
-
-import java.util.Optional;
-import org.sonar.api.measures.CoreMetrics;
-import org.sonar.ce.task.projectanalysis.component.Component;
-import org.sonar.ce.task.projectanalysis.measure.Measure;
-import org.sonar.ce.task.projectanalysis.measure.MeasureRepository;
-import org.sonar.ce.task.projectanalysis.metric.Metric;
-import org.sonar.ce.task.projectanalysis.metric.MetricRepository;
-import org.sonar.ce.task.projectanalysis.qualityprofile.ActiveRule;
-import org.sonar.ce.task.projectanalysis.qualityprofile.ActiveRulesHolder;
-import org.sonar.server.rule.CommonRuleKeys;
-
-import static java.lang.String.format;
-
-public class SkippedTestRule extends CommonRule {
-
- private final MeasureRepository measureRepository;
- private final Metric skippedTestsMetric;
-
- public SkippedTestRule(ActiveRulesHolder activeRulesHolder, MeasureRepository measureRepository, MetricRepository metricRepository) {
- super(activeRulesHolder, CommonRuleKeys.SKIPPED_UNIT_TESTS);
- this.measureRepository = measureRepository;
- this.skippedTestsMetric = metricRepository.getByKey(CoreMetrics.SKIPPED_TESTS_KEY);
- }
-
- @Override
- protected CommonRuleIssue doProcessFile(Component file, ActiveRule activeRule) {
- Optional<Measure> measure = measureRepository.getRawMeasure(file, skippedTestsMetric);
-
- int skipped = measure.map(Measure::getIntValue).orElse(0);
- if (skipped > 0) {
- String message = format("Fix or remove skipped unit tests in file \"%s\".", file.getName());
- return new CommonRuleIssue(skipped, message);
- }
- return null;
- }
-}
+++ /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.ce.task.projectanalysis.issue.commonrule;
-
-import java.util.Optional;
-import org.sonar.api.measures.CoreMetrics;
-import org.sonar.ce.task.projectanalysis.component.Component;
-import org.sonar.ce.task.projectanalysis.measure.Measure;
-import org.sonar.ce.task.projectanalysis.measure.MeasureRepository;
-import org.sonar.ce.task.projectanalysis.metric.Metric;
-import org.sonar.ce.task.projectanalysis.metric.MetricRepository;
-import org.sonar.ce.task.projectanalysis.qualityprofile.ActiveRule;
-import org.sonar.ce.task.projectanalysis.qualityprofile.ActiveRulesHolder;
-import org.sonar.server.rule.CommonRuleKeys;
-
-import static java.lang.String.format;
-
-public class TestErrorRule extends CommonRule {
-
- private final MeasureRepository measureRepository;
- private final Metric testErrorMetric;
- private final Metric testFailureMetric;
-
- public TestErrorRule(ActiveRulesHolder activeRulesHolder, MeasureRepository measureRepository, MetricRepository metricRepository) {
- super(activeRulesHolder, CommonRuleKeys.FAILED_UNIT_TESTS);
- this.measureRepository = measureRepository;
- this.testErrorMetric = metricRepository.getByKey(CoreMetrics.TEST_ERRORS_KEY);
- this.testFailureMetric = metricRepository.getByKey(CoreMetrics.TEST_FAILURES_KEY);
- }
-
- @Override
- protected CommonRuleIssue doProcessFile(Component file, ActiveRule activeRule) {
- Optional<Measure> errorsMeasure = measureRepository.getRawMeasure(file, testErrorMetric);
- Optional<Measure> failuresMeasure = measureRepository.getRawMeasure(file, testFailureMetric);
-
- int errors = errorsMeasure.map(Measure::getIntValue).orElse(0);
- int failures = failuresMeasure.map(Measure::getIntValue).orElse(0);
- int total = errors + failures;
- if (total > 0) {
- String message = format("Fix failing unit tests on file \"%s\".", file.getName());
- return new CommonRuleIssue(total, message);
- }
- return null;
- }
-}
+++ /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.
- */
-@ParametersAreNonnullByDefault
-package org.sonar.ce.task.projectanalysis.issue.commonrule;
-
-import javax.annotation.ParametersAreNonnullByDefault;
import org.sonar.ce.task.projectanalysis.component.TreeRootHolderRule;
import org.sonar.ce.task.projectanalysis.component.TypeAwareVisitor;
import org.sonar.ce.task.projectanalysis.filemove.MovedFilesRepository;
-import org.sonar.ce.task.projectanalysis.issue.commonrule.CommonRuleEngineImpl;
import org.sonar.ce.task.projectanalysis.issue.filter.IssueFilter;
import org.sonar.ce.task.projectanalysis.qualityprofile.ActiveRulesHolder;
import org.sonar.ce.task.projectanalysis.qualityprofile.ActiveRulesHolderRule;
when(movedFilesRepository.getOriginalFile(any(Component.class))).thenReturn(Optional.empty());
DbClient dbClient = dbTester.getDbClient();
- TrackerRawInputFactory rawInputFactory = new TrackerRawInputFactory(treeRootHolder, reportReader, sourceLinesHash, new CommonRuleEngineImpl(), issueFilter,
+ TrackerRawInputFactory rawInputFactory = new TrackerRawInputFactory(treeRootHolder, reportReader, sourceLinesHash, issueFilter,
ruleRepositoryRule, activeRulesHolder);
TrackerBaseInputFactory baseInputFactory = new TrackerBaseInputFactory(issuesLoader, dbClient, movedFilesRepository);
TrackerTargetBranchInputFactory targetInputFactory = new TrackerTargetBranchInputFactory(issuesLoader, targetBranchComponentUuids, dbClient, movedFilesRepository);
import org.sonar.ce.task.projectanalysis.component.Component;
import org.sonar.ce.task.projectanalysis.component.ReportComponent;
import org.sonar.ce.task.projectanalysis.component.TreeRootHolderRule;
-import org.sonar.ce.task.projectanalysis.issue.commonrule.CommonRuleEngine;
import org.sonar.ce.task.projectanalysis.issue.filter.IssueFilter;
import org.sonar.ce.task.projectanalysis.qualityprofile.ActiveRule;
import org.sonar.ce.task.projectanalysis.qualityprofile.ActiveRulesHolderRule;
private static final ReportComponent PROJECT = ReportComponent.builder(Component.Type.PROJECT, 1).addChildren(FILE, ANOTHER_FILE).build();
private final SourceLinesHashRepository sourceLinesHash = mock(SourceLinesHashRepository.class);
- private final CommonRuleEngine commonRuleEngine = mock(CommonRuleEngine.class);
private final IssueFilter issueFilter = mock(IssueFilter.class);
private final TrackerRawInputFactory underTest = new TrackerRawInputFactory(treeRootHolder, reportReader, sourceLinesHash,
- commonRuleEngine, issueFilter, ruleRepository, activeRulesHolder);
+ issueFilter, ruleRepository, activeRulesHolder);
@Before
public void before() {
assertThat(input.getIssues()).isEmpty();
}
- @Test
- public void load_issues_of_compute_engine_common_rules() {
- RuleKey ruleKey = RuleKey.of(CommonRuleKeys.commonRepositoryForLang("java"), "InsufficientCoverage");
- markRuleAsActive(ruleKey);
- DefaultIssue ceIssue = new DefaultIssue()
- .setRuleKey(ruleKey)
- .setMessage("not enough coverage")
- .setGap(10.0);
- when(commonRuleEngine.process(FILE)).thenReturn(singletonList(ceIssue));
-
- Input<DefaultIssue> input = underTest.create(FILE);
-
- assertThat(input.getIssues()).containsOnly(ceIssue);
- assertInitializedIssue(input.getIssues().iterator().next());
- }
-
- @Test
- public void filter_exclude_issues_on_common_rule() {
- RuleKey ruleKey = RuleKey.of(CommonRuleKeys.commonRepositoryForLang("java"), "InsufficientCoverage");
- markRuleAsActive(ruleKey);
- when(issueFilter.accept(any(), eq(FILE))).thenReturn(false);
- DefaultIssue ceIssue = new DefaultIssue()
- .setRuleKey(ruleKey)
- .setMessage("not enough coverage")
- .setGap(10.0);
- when(commonRuleEngine.process(FILE)).thenReturn(singletonList(ceIssue));
-
- Input<DefaultIssue> input = underTest.create(FILE);
-
- assertThat(input.getIssues()).isEmpty();
- }
-
private ScannerReport.TextRange newTextRange(int issueOnLine) {
return ScannerReport.TextRange.newBuilder()
.setStartLine(issueOnLine)
+++ /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.ce.task.projectanalysis.issue.commonrule;
-
-import org.sonar.api.measures.CoreMetrics;
-import org.sonar.api.rule.RuleKey;
-import org.sonar.server.rule.CommonRuleKeys;
-
-public class BranchCoverageRuleTest extends CoverageRuleTest {
-
- @Override
- protected CommonRule createRule() {
- return new BranchCoverageRule(activeRuleHolder, metricRepository, measureRepository);
- }
-
- @Override
- protected RuleKey getRuleKey() {
- return RuleKey.of("common-java", CommonRuleKeys.INSUFFICIENT_BRANCH_COVERAGE);
- }
-
- @Override
- protected String getMinPropertyKey() {
- return CommonRuleKeys.INSUFFICIENT_BRANCH_COVERAGE_PROPERTY;
- }
-
- @Override
- protected String getCoverageMetricKey() {
- return CoreMetrics.BRANCH_COVERAGE_KEY;
- }
-
- @Override
- protected String getToCoverMetricKey() {
- return CoreMetrics.CONDITIONS_TO_COVER_KEY;
- }
-
- @Override
- protected String getUncoveredMetricKey() {
- return CoreMetrics.UNCOVERED_CONDITIONS_KEY;
- }
-
- @Override
- protected String getExpectedIssueMessage() {
- return "23 more conditions need to be covered by tests to reach the minimum threshold of 65.0% condition coverage.";
- }
-}
+++ /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.ce.task.projectanalysis.issue.commonrule;
-
-import com.google.common.collect.ImmutableMap;
-import org.junit.Rule;
-import org.junit.Test;
-import org.sonar.api.measures.CoreMetrics;
-import org.sonar.api.rule.RuleKey;
-import org.sonar.api.rule.Severity;
-import org.sonar.ce.task.projectanalysis.component.Component;
-import org.sonar.ce.task.projectanalysis.component.FileAttributes;
-import org.sonar.ce.task.projectanalysis.component.ReportComponent;
-import org.sonar.ce.task.projectanalysis.component.TreeRootHolderRule;
-import org.sonar.ce.task.projectanalysis.measure.Measure;
-import org.sonar.ce.task.projectanalysis.measure.MeasureRepositoryRule;
-import org.sonar.ce.task.projectanalysis.metric.MetricRepositoryRule;
-import org.sonar.ce.task.projectanalysis.qualityprofile.ActiveRule;
-import org.sonar.ce.task.projectanalysis.qualityprofile.ActiveRulesHolderRule;
-import org.sonar.core.issue.DefaultIssue;
-import org.sonar.server.rule.CommonRuleKeys;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.assertThatThrownBy;
-import static org.sonar.ce.task.projectanalysis.component.ReportComponent.DUMB_PROJECT;
-
-public class CommentDensityRuleTest {
-
- private static final String PLUGIN_KEY = "java";
- private static final String QP_KEY = "qp1";
-
- static RuleKey RULE_KEY = RuleKey.of(CommonRuleKeys.commonRepositoryForLang(PLUGIN_KEY), CommonRuleKeys.INSUFFICIENT_COMMENT_DENSITY);
-
- static ReportComponent FILE = ReportComponent.builder(Component.Type.FILE, 1)
- .setFileAttributes(new FileAttributes(false, PLUGIN_KEY, 1))
- .build();
-
- static ReportComponent TEST_FILE = ReportComponent.builder(Component.Type.FILE, 1)
- .setFileAttributes(new FileAttributes(true, PLUGIN_KEY, 1))
- .build();
-
-
- @Rule
- public ActiveRulesHolderRule activeRuleHolder = new ActiveRulesHolderRule();
-
- @Rule
- public MetricRepositoryRule metricRepository = new MetricRepositoryRule()
- .add(CoreMetrics.COMMENT_LINES_DENSITY)
- .add(CoreMetrics.COMMENT_LINES)
- .add(CoreMetrics.NCLOC);
-
- @Rule
- public TreeRootHolderRule treeRootHolder = new TreeRootHolderRule().setRoot(DUMB_PROJECT);
-
- @Rule
- public MeasureRepositoryRule measureRepository = MeasureRepositoryRule.create(treeRootHolder, metricRepository);
-
- CommentDensityRule underTest = new CommentDensityRule(activeRuleHolder, measureRepository, metricRepository);
-
- @Test
- public void no_issues_if_enough_comments() {
- activeRuleHolder.put(new ActiveRule(RULE_KEY, Severity.CRITICAL, ImmutableMap.of(CommonRuleKeys.INSUFFICIENT_COMMENT_DENSITY_PROPERTY, "25"), 1_000L, PLUGIN_KEY, QP_KEY));
- measureRepository.addRawMeasure(FILE.getReportAttributes().getRef(), CoreMetrics.COMMENT_LINES_DENSITY_KEY, Measure.newMeasureBuilder().create(90.0, 1));
-
- DefaultIssue issue = underTest.processFile(FILE, PLUGIN_KEY);
-
- assertThat(issue).isNull();
- }
-
- @Test
- public void issue_if_not_enough_comments() {
- prepareForIssue("25", FILE, 10.0, 40, 360);
-
- DefaultIssue issue = underTest.processFile(FILE, PLUGIN_KEY);
-
- assertThat(issue.ruleKey()).isEqualTo(RULE_KEY);
- assertThat(issue.severity()).isEqualTo(Severity.CRITICAL);
- // min_comments = (min_percent * ncloc) / (1 - min_percent)
- // -> threshold of 25% for 360 ncloc is 120 comment lines. 40 are already written.
- assertThat(issue.gap()).isEqualTo(120.0 - 40.0);
- assertThat(issue.message()).isEqualTo("80 more comment lines need to be written to reach the minimum threshold of 25.0% comment density.");
- }
-
- @Test
- public void no_issues_on_tests() {
- prepareForIssue("25", TEST_FILE, 10.0, 40, 360);
-
- DefaultIssue issue = underTest.processFile(TEST_FILE, PLUGIN_KEY);
-
- assertThat(issue).isNull();
- }
-
- @Test
- public void issue_if_not_enough_comments__test_ceil() {
- prepareForIssue("25", FILE, 0.0, 0, 1);
-
- DefaultIssue issue = underTest.processFile(FILE, PLUGIN_KEY);
-
- assertThat(issue.ruleKey()).isEqualTo(RULE_KEY);
- assertThat(issue.severity()).isEqualTo(Severity.CRITICAL);
- // 1 ncloc requires 1 comment line to reach 25% of comment density
- assertThat(issue.gap()).isEqualTo(1.0);
- assertThat(issue.message()).isEqualTo("1 more comment lines need to be written to reach the minimum threshold of 25.0% comment density.");
- }
-
- /**
- * SQALE-110
- */
- @Test
- public void fail_if_min_density_is_100() {
- assertThatThrownBy(() -> {
- prepareForIssue("100", FILE, 0.0, 0, 1);
- underTest.processFile(FILE, PLUGIN_KEY);
- })
- .isInstanceOf(IllegalStateException.class)
- .hasMessage("Minimum density of rule [common-java:InsufficientCommentDensity] is incorrect. Got [100] but must be strictly less than 100.");
- }
-
- private void prepareForIssue(String minDensity, ReportComponent file, double commentLineDensity, int commentLines, int ncloc) {
- activeRuleHolder.put(new ActiveRule(RULE_KEY, Severity.CRITICAL, ImmutableMap.of(CommonRuleKeys.INSUFFICIENT_COMMENT_DENSITY_PROPERTY, minDensity), 1_000L, PLUGIN_KEY, QP_KEY));
- measureRepository.addRawMeasure(file.getReportAttributes().getRef(), CoreMetrics.COMMENT_LINES_DENSITY_KEY, Measure.newMeasureBuilder().create(commentLineDensity, 1));
- measureRepository.addRawMeasure(file.getReportAttributes().getRef(), CoreMetrics.COMMENT_LINES_KEY, Measure.newMeasureBuilder().create(commentLines));
- measureRepository.addRawMeasure(file.getReportAttributes().getRef(), CoreMetrics.NCLOC_KEY, Measure.newMeasureBuilder().create(ncloc));
- }
-
-
-}
+++ /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.ce.task.projectanalysis.issue.commonrule;
-
-import java.util.Collection;
-import org.junit.Test;
-import org.sonar.ce.task.projectanalysis.component.Component;
-import org.sonar.ce.task.projectanalysis.component.FileAttributes;
-import org.sonar.ce.task.projectanalysis.component.ReportComponent;
-import org.sonar.core.issue.DefaultIssue;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verifyNoInteractions;
-import static org.mockito.Mockito.when;
-import static org.sonar.ce.task.projectanalysis.component.ReportComponent.DUMB_PROJECT;
-
-public class CommonRuleEngineImplTest {
-
- CommonRule rule1 = mock(CommonRule.class);
- CommonRule rule2 = mock(CommonRule.class);
- CommonRuleEngineImpl underTest = new CommonRuleEngineImpl(rule1, rule2);
-
- @Test
- public void process_files_with_known_language() {
- ReportComponent file = ReportComponent.builder(Component.Type.FILE, 1)
- .setKey("FILE_KEY").setUuid("FILE_UUID")
- .setFileAttributes(new FileAttributes(false, "java", 1))
- .build();
- DefaultIssue issue = new DefaultIssue();
- when(rule1.processFile(file, "java")).thenReturn(issue);
- when(rule2.processFile(file, "java")).thenReturn(null);
-
- Collection<DefaultIssue> issues = underTest.process(file);
- assertThat(issues).containsOnly(issue);
- }
-
- @Test
- public void do_not_process_files_with_unknown_language() {
- ReportComponent file = ReportComponent.builder(Component.Type.FILE, 1)
- .setKey("FILE_KEY").setUuid("FILE_UUID")
- .setFileAttributes(new FileAttributes(false, null, 1))
- .build();
-
- Collection<DefaultIssue> issues = underTest.process(file);
-
- assertThat(issues).isEmpty();
- verifyNoInteractions(rule1, rule2);
- }
-
- @Test
- public void do_not_process_non_files() {
- Collection<DefaultIssue> issues = underTest.process(DUMB_PROJECT);
-
- assertThat(issues).isEmpty();
- verifyNoInteractions(rule1, rule2);
- }
-}
+++ /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.ce.task.projectanalysis.issue.commonrule;
-
-import com.google.common.collect.ImmutableMap;
-import org.junit.Test;
-import org.sonar.api.rule.Severity;
-import org.sonar.ce.task.projectanalysis.qualityprofile.ActiveRule;
-import org.sonar.db.rule.RuleTesting;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.assertThatThrownBy;
-
-public class CommonRuleTest {
-
- private static final String PLUGIN_KEY = "java";
- private static final String QP_KEY = "qp1";
-
-
- @Test
- public void test_getMinDensityParam() {
- ActiveRule activeRule = new ActiveRule(RuleTesting.XOO_X1, Severity.MAJOR, ImmutableMap.of("minDensity", "30.5"), 1_000L, PLUGIN_KEY, QP_KEY);
- double minDensity = CommonRule.getMinDensityParam(activeRule, "minDensity");
-
- assertThat(minDensity).isEqualTo(30.5);
- }
-
- @Test
- public void getMinDensityParam_fails_if_param_value_is_absent() {
- assertThatThrownBy(() -> {
- ActiveRule activeRule = new ActiveRule(RuleTesting.XOO_X1, Severity.MAJOR, ImmutableMap.of(), 1_000L, PLUGIN_KEY, QP_KEY);
- CommonRule.getMinDensityParam(activeRule, "minDensity");
- })
- .isInstanceOf(IllegalStateException.class)
- .hasMessage("Required parameter [minDensity] is missing on rule [xoo:x1]");
- }
-
- @Test
- public void getMinDensityParam_fails_if_param_value_is_negative() {
- assertThatThrownBy(() -> {
- ActiveRule activeRule = new ActiveRule(RuleTesting.XOO_X1, Severity.MAJOR, ImmutableMap.of("minDensity", "-30.5"), 1_000L, PLUGIN_KEY, QP_KEY);
- CommonRule.getMinDensityParam(activeRule, "minDensity");
- })
- .isInstanceOf(IllegalStateException.class)
- .hasMessage("Minimum density of rule [xoo:x1] is incorrect. Got [-30.5] but must be between 0 and 100.");
- }
-
- @Test
- public void getMinDensityParam_fails_if_param_value_is_greater_than_100() {
- assertThatThrownBy(() -> {
- ActiveRule activeRule = new ActiveRule(RuleTesting.XOO_X1, Severity.MAJOR, ImmutableMap.of("minDensity", "305"), 1_000L, PLUGIN_KEY, QP_KEY);
- CommonRule.getMinDensityParam(activeRule, "minDensity");
- })
- .isInstanceOf(IllegalStateException.class)
- .hasMessage("Minimum density of rule [xoo:x1] is incorrect. Got [305] but must be between 0 and 100.");
- }
-}
+++ /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.ce.task.projectanalysis.issue.commonrule;
-
-import com.google.common.collect.ImmutableMap;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.sonar.api.measures.CoreMetrics;
-import org.sonar.api.rule.RuleKey;
-import org.sonar.api.rule.Severity;
-import org.sonar.ce.task.projectanalysis.component.Component;
-import org.sonar.ce.task.projectanalysis.component.FileAttributes;
-import org.sonar.ce.task.projectanalysis.component.ReportComponent;
-import org.sonar.ce.task.projectanalysis.component.TreeRootHolderRule;
-import org.sonar.ce.task.projectanalysis.measure.Measure;
-import org.sonar.ce.task.projectanalysis.measure.MeasureRepositoryRule;
-import org.sonar.ce.task.projectanalysis.metric.MetricRepositoryRule;
-import org.sonar.ce.task.projectanalysis.qualityprofile.ActiveRule;
-import org.sonar.ce.task.projectanalysis.qualityprofile.ActiveRulesHolderRule;
-import org.sonar.core.issue.DefaultIssue;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public abstract class CoverageRuleTest {
-
- private static final String PLUGIN_KEY = "java";
- private static final String QP_KEY = "qp1";
-
- static ReportComponent FILE = ReportComponent.builder(Component.Type.FILE, 1)
- .setFileAttributes(new FileAttributes(false, "java", 1))
- .build();
-
- @Rule
- public ActiveRulesHolderRule activeRuleHolder = new ActiveRulesHolderRule();
-
- @Rule
- public MetricRepositoryRule metricRepository = new MetricRepositoryRule()
- .add(CoreMetrics.LINE_COVERAGE)
- .add(CoreMetrics.LINES_TO_COVER)
- .add(CoreMetrics.UNCOVERED_LINES)
- .add(CoreMetrics.BRANCH_COVERAGE)
- .add(CoreMetrics.CONDITIONS_TO_COVER)
- .add(CoreMetrics.UNCOVERED_CONDITIONS);
-
- @Rule
- public TreeRootHolderRule treeRootHolder = new TreeRootHolderRule();
-
- @Rule
- public MeasureRepositoryRule measureRepository = MeasureRepositoryRule.create(treeRootHolder, metricRepository);
-
- CommonRule underTest = createRule();
-
- @Before
- public void setUp() {
- treeRootHolder.setRoot(ReportComponent.DUMB_PROJECT);
- }
-
- protected abstract CommonRule createRule();
-
- protected abstract RuleKey getRuleKey();
-
- protected abstract String getMinPropertyKey();
-
- protected abstract String getCoverageMetricKey();
-
- protected abstract String getToCoverMetricKey();
-
- protected abstract String getUncoveredMetricKey();
-
- @Test
- public void no_issue_if_enough_coverage() {
- activeRuleHolder.put(new ActiveRule(getRuleKey(), Severity.CRITICAL, ImmutableMap.of(getMinPropertyKey(), "65"), 1_000L, PLUGIN_KEY, QP_KEY));
- measureRepository.addRawMeasure(FILE.getReportAttributes().getRef(), getCoverageMetricKey(), Measure.newMeasureBuilder().create(90.0, 1));
-
- DefaultIssue issue = underTest.processFile(FILE, "java");
-
- assertThat(issue).isNull();
- }
-
- @Test
- public void issue_if_coverage_is_too_low() {
- activeRuleHolder.put(new ActiveRule(getRuleKey(), Severity.CRITICAL, ImmutableMap.of(getMinPropertyKey(), "65"), 1_000L, PLUGIN_KEY, QP_KEY));
- measureRepository.addRawMeasure(FILE.getReportAttributes().getRef(), getCoverageMetricKey(), Measure.newMeasureBuilder().create(20.0, 1));
- measureRepository.addRawMeasure(FILE.getReportAttributes().getRef(), getUncoveredMetricKey(), Measure.newMeasureBuilder().create(40));
- measureRepository.addRawMeasure(FILE.getReportAttributes().getRef(), getToCoverMetricKey(), Measure.newMeasureBuilder().create(50));
-
- DefaultIssue issue = underTest.processFile(FILE, "java");
-
- assertThat(issue.ruleKey()).isEqualTo(getRuleKey());
- assertThat(issue.severity()).isEqualTo(Severity.CRITICAL);
- // FIXME explain
- assertThat(issue.gap()).isEqualTo(23.0);
- assertThat(issue.message()).isEqualTo(getExpectedIssueMessage());
- }
-
- protected abstract String getExpectedIssueMessage();
-
- @Test
- public void no_issue_if_coverage_is_not_set() {
- activeRuleHolder.put(new ActiveRule(getRuleKey(), Severity.CRITICAL, ImmutableMap.of(getMinPropertyKey(), "65"), 1_000L, PLUGIN_KEY, QP_KEY));
-
- DefaultIssue issue = underTest.processFile(FILE, "java");
-
- assertThat(issue).isNull();
- }
-
- @Test
- public void ignored_if_rule_is_deactivated() {
- // coverage is too low, but rule is not activated
- measureRepository.addRawMeasure(FILE.getReportAttributes().getRef(), getCoverageMetricKey(), Measure.newMeasureBuilder().create(20.0, 1));
-
- DefaultIssue issue = underTest.processFile(FILE, "java");
-
- assertThat(issue).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.ce.task.projectanalysis.issue.commonrule;
-
-import java.util.Collections;
-import org.junit.Rule;
-import org.junit.Test;
-import org.sonar.api.measures.CoreMetrics;
-import org.sonar.api.rule.RuleKey;
-import org.sonar.api.rule.Severity;
-import org.sonar.ce.task.projectanalysis.component.Component;
-import org.sonar.ce.task.projectanalysis.component.FileAttributes;
-import org.sonar.ce.task.projectanalysis.component.ReportComponent;
-import org.sonar.ce.task.projectanalysis.component.TreeRootHolderRule;
-import org.sonar.ce.task.projectanalysis.measure.Measure;
-import org.sonar.ce.task.projectanalysis.measure.MeasureRepositoryRule;
-import org.sonar.ce.task.projectanalysis.metric.MetricRepositoryRule;
-import org.sonar.ce.task.projectanalysis.qualityprofile.ActiveRule;
-import org.sonar.ce.task.projectanalysis.qualityprofile.ActiveRulesHolderRule;
-import org.sonar.core.issue.DefaultIssue;
-import org.sonar.server.rule.CommonRuleKeys;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class DuplicatedBlockRuleTest {
-
- private static final String PLUGIN_KEY = "java";
- private static final String QP_KEY = "qp1";
-
- static RuleKey RULE_KEY = RuleKey.of(CommonRuleKeys.commonRepositoryForLang("java"), CommonRuleKeys.DUPLICATED_BLOCKS);
-
- static ReportComponent FILE = ReportComponent.builder(Component.Type.FILE, 1)
- .setFileAttributes(new FileAttributes(false, "java", 1))
- .build();
-
- @Rule
- public ActiveRulesHolderRule activeRuleHolder = new ActiveRulesHolderRule();
-
- @Rule
- public MetricRepositoryRule metricRepository = new MetricRepositoryRule()
- .add(CoreMetrics.DUPLICATED_BLOCKS);
-
- @Rule
- public TreeRootHolderRule treeRootHolder = new TreeRootHolderRule().setRoot(ReportComponent.DUMB_PROJECT);
-
- @Rule
- public MeasureRepositoryRule measureRepository = MeasureRepositoryRule.create(treeRootHolder, metricRepository);
-
- DuplicatedBlockRule underTest = new DuplicatedBlockRule(activeRuleHolder, measureRepository, metricRepository);
-
- @Test
- public void no_issue_if_no_duplicated_blocks() {
- activeRuleHolder.put(new ActiveRule(RULE_KEY, Severity.CRITICAL, Collections.emptyMap(), 1_000L, PLUGIN_KEY, QP_KEY));
- measureRepository.addRawMeasure(FILE.getReportAttributes().getRef(), CoreMetrics.DUPLICATED_BLOCKS_KEY, Measure.newMeasureBuilder().create(0));
-
- DefaultIssue issue = underTest.processFile(FILE, "java");
-
- assertThat(issue).isNull();
- }
-
- @Test
- public void issue_if_duplicated_blocks() {
- activeRuleHolder.put(new ActiveRule(RULE_KEY, Severity.CRITICAL, Collections.emptyMap(), 1_000L, PLUGIN_KEY, QP_KEY));
- measureRepository.addRawMeasure(FILE.getReportAttributes().getRef(), CoreMetrics.DUPLICATED_BLOCKS_KEY, Measure.newMeasureBuilder().create(3));
-
- DefaultIssue issue = underTest.processFile(FILE, "java");
-
- assertThat(issue.ruleKey()).isEqualTo(RULE_KEY);
- assertThat(issue.severity()).isEqualTo(Severity.CRITICAL);
- assertThat(issue.gap()).isEqualTo(3.0);
- assertThat(issue.message()).isEqualTo("3 duplicated blocks of code must be removed.");
- }
-}
+++ /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.ce.task.projectanalysis.issue.commonrule;
-
-import org.sonar.api.measures.CoreMetrics;
-import org.sonar.api.rule.RuleKey;
-import org.sonar.server.rule.CommonRuleKeys;
-
-public class LineCoverageRuleTest extends CoverageRuleTest {
-
- @Override
- protected CommonRule createRule() {
- return new LineCoverageRule(activeRuleHolder, metricRepository, measureRepository);
- }
-
- @Override
- protected RuleKey getRuleKey() {
- return RuleKey.of("common-java", CommonRuleKeys.INSUFFICIENT_LINE_COVERAGE);
- }
-
- @Override
- protected String getMinPropertyKey() {
- return CommonRuleKeys.INSUFFICIENT_LINE_COVERAGE_PROPERTY;
- }
-
- @Override
- protected String getCoverageMetricKey() {
- return CoreMetrics.LINE_COVERAGE_KEY;
- }
-
- @Override
- protected String getToCoverMetricKey() {
- return CoreMetrics.LINES_TO_COVER_KEY;
- }
-
- @Override
- protected String getUncoveredMetricKey() {
- return CoreMetrics.UNCOVERED_LINES_KEY;
- }
-
- @Override
- protected String getExpectedIssueMessage() {
- return "23 more lines of code need to be covered by tests to reach the minimum threshold of 65.0% lines coverage.";
- }
-}
+++ /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.ce.task.projectanalysis.issue.commonrule;
-
-import java.util.Collections;
-import org.junit.Rule;
-import org.junit.Test;
-import org.sonar.api.measures.CoreMetrics;
-import org.sonar.api.rule.RuleKey;
-import org.sonar.api.rule.Severity;
-import org.sonar.ce.task.projectanalysis.component.Component;
-import org.sonar.ce.task.projectanalysis.component.FileAttributes;
-import org.sonar.ce.task.projectanalysis.component.ReportComponent;
-import org.sonar.ce.task.projectanalysis.component.TreeRootHolderRule;
-import org.sonar.ce.task.projectanalysis.measure.Measure;
-import org.sonar.ce.task.projectanalysis.measure.MeasureRepositoryRule;
-import org.sonar.ce.task.projectanalysis.metric.MetricRepositoryRule;
-import org.sonar.ce.task.projectanalysis.qualityprofile.ActiveRule;
-import org.sonar.ce.task.projectanalysis.qualityprofile.ActiveRulesHolderRule;
-import org.sonar.core.issue.DefaultIssue;
-import org.sonar.server.rule.CommonRuleKeys;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class SkippedTestRuleTest {
-
- private static final String PLUGIN_KEY = "java";
- private static final String QP_KEY = "qp1";
-
- static RuleKey RULE_KEY = RuleKey.of(CommonRuleKeys.commonRepositoryForLang("java"), CommonRuleKeys.SKIPPED_UNIT_TESTS);
-
- static ReportComponent FILE = ReportComponent.builder(Component.Type.FILE, 1)
- .setFileAttributes(new FileAttributes(true, "java", 1))
- .setName("FooTest.java")
- .build();
-
- @Rule
- public ActiveRulesHolderRule activeRuleHolder = new ActiveRulesHolderRule();
-
- @Rule
- public MetricRepositoryRule metricRepository = new MetricRepositoryRule()
- .add(CoreMetrics.SKIPPED_TESTS);
-
- @Rule
- public TreeRootHolderRule treeRootHolder = new TreeRootHolderRule().setRoot(ReportComponent.DUMB_PROJECT);
-
- @Rule
- public MeasureRepositoryRule measureRepository = MeasureRepositoryRule.create(treeRootHolder, metricRepository);
-
- CommonRule underTest = new SkippedTestRule(activeRuleHolder, measureRepository, metricRepository);
-
- @Test
- public void issue_if_skipped_tests() {
- activeRuleHolder.put(new ActiveRule(RULE_KEY, Severity.CRITICAL, Collections.emptyMap(), 1_000L, PLUGIN_KEY, QP_KEY));
- measureRepository.addRawMeasure(FILE.getReportAttributes().getRef(), CoreMetrics.SKIPPED_TESTS_KEY, Measure.newMeasureBuilder().create(2));
-
- DefaultIssue issue = underTest.processFile(FILE, "java");
-
- assertThat(issue.ruleKey()).isEqualTo(RULE_KEY);
- assertThat(issue.severity()).isEqualTo(Severity.CRITICAL);
- assertThat(issue.gap()).isEqualTo(2.0);
- assertThat(issue.message()).isEqualTo("Fix or remove skipped unit tests in file \"FooTest.java\".");
- }
-
- @Test
- public void no_issues_if_zero_skipped_tests() {
- activeRuleHolder.put(new ActiveRule(RULE_KEY, Severity.CRITICAL, Collections.emptyMap(), 1_000L, PLUGIN_KEY, QP_KEY));
- measureRepository.addRawMeasure(FILE.getReportAttributes().getRef(), CoreMetrics.SKIPPED_TESTS_KEY, Measure.newMeasureBuilder().create(0));
-
- DefaultIssue issue = underTest.processFile(FILE, "java");
-
- assertThat(issue).isNull();
- }
-
- @Test
- public void no_issues_if_measure_is_absent() {
- activeRuleHolder.put(new ActiveRule(RULE_KEY, Severity.CRITICAL, Collections.emptyMap(), 1_000L, PLUGIN_KEY, QP_KEY));
-
- DefaultIssue issue = underTest.processFile(FILE, "java");
-
- assertThat(issue).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.ce.task.projectanalysis.issue.commonrule;
-
-import java.util.Collections;
-import org.junit.Rule;
-import org.junit.Test;
-import org.sonar.api.measures.CoreMetrics;
-import org.sonar.api.rule.RuleKey;
-import org.sonar.api.rule.Severity;
-import org.sonar.ce.task.projectanalysis.component.Component;
-import org.sonar.ce.task.projectanalysis.component.FileAttributes;
-import org.sonar.ce.task.projectanalysis.component.ReportComponent;
-import org.sonar.ce.task.projectanalysis.component.TreeRootHolderRule;
-import org.sonar.ce.task.projectanalysis.measure.Measure;
-import org.sonar.ce.task.projectanalysis.measure.MeasureRepositoryRule;
-import org.sonar.ce.task.projectanalysis.metric.MetricRepositoryRule;
-import org.sonar.ce.task.projectanalysis.qualityprofile.ActiveRule;
-import org.sonar.ce.task.projectanalysis.qualityprofile.ActiveRulesHolderRule;
-import org.sonar.core.issue.DefaultIssue;
-import org.sonar.server.rule.CommonRuleKeys;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.sonar.ce.task.projectanalysis.component.ReportComponent.DUMB_PROJECT;
-
-public class TestErrorRuleTest {
-
- private static final String PLUGIN_KEY = "java";
- private static final String QP_KEY = "qp1";
-
- static RuleKey RULE_KEY = RuleKey.of(CommonRuleKeys.commonRepositoryForLang("java"), CommonRuleKeys.FAILED_UNIT_TESTS);
-
- static ReportComponent FILE = ReportComponent.builder(Component.Type.FILE, 1)
- .setFileAttributes(new FileAttributes(true, "java", 1))
- .setName("FooTest.java")
- .build();
-
- @Rule
- public ActiveRulesHolderRule activeRuleHolder = new ActiveRulesHolderRule();
-
- @Rule
- public MetricRepositoryRule metricRepository = new MetricRepositoryRule()
- .add(CoreMetrics.TEST_ERRORS)
- .add(CoreMetrics.TEST_FAILURES);
-
- @Rule
- public TreeRootHolderRule treeRootHolder = new TreeRootHolderRule().setRoot(DUMB_PROJECT);
-
- @Rule
- public MeasureRepositoryRule measureRepository = MeasureRepositoryRule.create(treeRootHolder, metricRepository);
-
- CommonRule underTest = new TestErrorRule(activeRuleHolder, measureRepository, metricRepository);
-
- @Test
- public void issue_if_errors_or_failures() {
- activeRuleHolder.put(new ActiveRule(RULE_KEY, Severity.CRITICAL, Collections.emptyMap(), 1_000L, PLUGIN_KEY, QP_KEY));
- measureRepository.addRawMeasure(FILE.getReportAttributes().getRef(), CoreMetrics.TEST_ERRORS_KEY, Measure.newMeasureBuilder().create(2));
- measureRepository.addRawMeasure(FILE.getReportAttributes().getRef(), CoreMetrics.TEST_FAILURES_KEY, Measure.newMeasureBuilder().create(1));
-
- DefaultIssue issue = underTest.processFile(FILE, "java");
-
- assertThat(issue.ruleKey()).isEqualTo(RULE_KEY);
- assertThat(issue.severity()).isEqualTo(Severity.CRITICAL);
- assertThat(issue.gap()).isEqualTo(3.0);
- assertThat(issue.message()).isEqualTo("Fix failing unit tests on file \"FooTest.java\".");
- }
-
- @Test
- public void no_issues_if_zero_errors_and_failures() {
- activeRuleHolder.put(new ActiveRule(RULE_KEY, Severity.CRITICAL, Collections.emptyMap(), 1_000L, PLUGIN_KEY, QP_KEY));
- measureRepository.addRawMeasure(FILE.getReportAttributes().getRef(), CoreMetrics.TEST_ERRORS_KEY, Measure.newMeasureBuilder().create(0));
- measureRepository.addRawMeasure(FILE.getReportAttributes().getRef(), CoreMetrics.TEST_FAILURES_KEY, Measure.newMeasureBuilder().create(0));
-
- DefaultIssue issue = underTest.processFile(FILE, "java");
-
- assertThat(issue).isNull();
- }
-
- @Test
- public void no_issues_if_test_measures_are_absent() {
- activeRuleHolder.put(new ActiveRule(RULE_KEY, Severity.CRITICAL, Collections.emptyMap(), 1_000L, PLUGIN_KEY, QP_KEY));
-
- DefaultIssue issue = underTest.processFile(FILE, "java");
-
- assertThat(issue).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.server.rule;
-
-import org.sonar.api.server.rule.RulesDefinition;
-
-public interface CommonRuleDefinitions {
- void define(RulesDefinition.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.server.rule;
-
-import java.util.Arrays;
-import java.util.List;
-import java.util.function.Predicate;
-import org.sonar.api.resources.Language;
-import org.sonar.api.resources.Languages;
-import org.sonar.api.rule.Severity;
-import org.sonar.api.server.rule.RuleParamType;
-import org.sonar.api.server.rule.RulesDefinition;
-
-import static org.sonar.api.rule.RuleStatus.DEPRECATED;
-import static org.sonar.server.rule.CommonRuleKeys.commonRepositoryForLang;
-
-/**
- * Declare the few rules that are automatically created by core for all languages. These rules
- * check measure values against thresholds defined in Quality profiles.
- */
-// this class must not be mixed with other RulesDefinition so it does implement the interface RulesDefinitions.
-// It replaces the common-rules that are still embedded within plugins.
-public class CommonRuleDefinitionsImpl implements CommonRuleDefinitions {
-
- private static final List<String> LANGUAGES_TO_SKIP = List.of(
- "terraform",
- "cloudformation",
- "kubernetes",
- "docker",
- "web",
- "css",
- "xml",
- "yaml",
- "json",
- "jsp",
- "text",
- "secrets");
- private static final String MINUTES_10 = "10min";
-
- private final Languages languages;
-
- public CommonRuleDefinitionsImpl(Languages languages) {
- this.languages = languages;
- }
-
- @Override
- public void define(RulesDefinition.Context context) {
- for (Language language : getActiveLanguages(languages.all())) {
- RulesDefinition.NewRepository repo = context.createRepository(commonRepositoryForLang(language.getKey()), language.getKey());
- repo.setName("Common " + language.getName());
- defineBranchCoverageRule(repo);
- defineLineCoverageRule(repo);
- defineCommentDensityRule(repo);
- defineDuplicatedBlocksRule(repo);
- defineFailedUnitTestRule(repo);
- defineSkippedUnitTestRule(repo);
- repo.done();
- }
- }
-
- private static List<Language> getActiveLanguages(Language[] allLanguages) {
- return Arrays.stream(allLanguages)
- .filter(Predicate.not(language -> LANGUAGES_TO_SKIP.contains(language.getKey())))
- .toList();
- }
-
- private static void defineBranchCoverageRule(RulesDefinition.NewRepository repo) {
- RulesDefinition.NewRule rule = repo.createRule(CommonRuleKeys.INSUFFICIENT_BRANCH_COVERAGE);
- rule.setName("Branches should have sufficient coverage by tests")
- .addTags("bad-practice")
- .setHtmlDescription("An issue is created on a file as soon as the branch coverage on this file is less than the required threshold. "
- + "It gives the number of branches to be covered in order to reach the required threshold.")
- .setDebtRemediationFunction(rule.debtRemediationFunctions().linear("5min"))
- .setGapDescription("number of uncovered conditions")
- .setSeverity(Severity.MAJOR);
- rule.createParam(CommonRuleKeys.INSUFFICIENT_BRANCH_COVERAGE_PROPERTY)
- .setName("The minimum required branch coverage ratio")
- .setDefaultValue("65")
- .setType(RuleParamType.FLOAT);
- rule.setStatus(DEPRECATED);
- }
-
- private static void defineLineCoverageRule(RulesDefinition.NewRepository repo) {
- RulesDefinition.NewRule rule = repo.createRule(CommonRuleKeys.INSUFFICIENT_LINE_COVERAGE);
- rule.setName("Lines should have sufficient coverage by tests")
- .addTags("bad-practice")
- .setHtmlDescription("An issue is created on a file as soon as the line coverage on this file is less than the required threshold. " +
- "It gives the number of lines to be covered in order to reach the required threshold.")
- .setDebtRemediationFunction(rule.debtRemediationFunctions().linear("2min"))
- .setGapDescription("number of lines under the coverage threshold")
- .setSeverity(Severity.MAJOR);
- rule.createParam(CommonRuleKeys.INSUFFICIENT_LINE_COVERAGE_PROPERTY)
- .setName("The minimum required line coverage ratio")
- .setDefaultValue("65")
- .setType(RuleParamType.FLOAT);
- rule.setStatus(DEPRECATED);
- }
-
- private static void defineCommentDensityRule(RulesDefinition.NewRepository repo) {
- RulesDefinition.NewRule rule = repo.createRule(CommonRuleKeys.INSUFFICIENT_COMMENT_DENSITY);
- rule.setName("Source files should have a sufficient density of comment lines")
- .addTags("convention")
- .setHtmlDescription("An issue is created on a file as soon as the density of comment lines on this file is less than the required threshold. " +
- "The number of comment lines to be written in order to reach the required threshold is provided by each issue message.")
- .setDebtRemediationFunction(rule.debtRemediationFunctions().linear("2min"))
- .setGapDescription("number of lines required to meet minimum density")
- .setSeverity(Severity.MAJOR);
- rule.createParam(CommonRuleKeys.INSUFFICIENT_COMMENT_DENSITY_PROPERTY)
- .setName("The minimum required comment density")
- .setDefaultValue("25")
- .setType(RuleParamType.FLOAT);
- rule.setStatus(DEPRECATED);
- }
-
- private static void defineDuplicatedBlocksRule(RulesDefinition.NewRepository repo) {
- RulesDefinition.NewRule rule = repo.createRule(CommonRuleKeys.DUPLICATED_BLOCKS);
- rule.setName("Source files should not have any duplicated blocks")
- .addTags("pitfall")
- .setHtmlDescription("An issue is created on a file as soon as there is at least one block of duplicated code on this file")
- .setDebtRemediationFunction(rule.debtRemediationFunctions().linearWithOffset(MINUTES_10, MINUTES_10))
- .setGapDescription("number of duplicate blocks")
- .setSeverity(Severity.MAJOR)
- .setStatus(DEPRECATED);
- }
-
- private static void defineFailedUnitTestRule(RulesDefinition.NewRepository repo) {
- RulesDefinition.NewRule rule = repo.createRule(CommonRuleKeys.FAILED_UNIT_TESTS);
- rule
- .setName("Failed unit tests should be fixed")
- .addTags("bug")
- .setHtmlDescription("Test failures or errors generally indicate that regressions have been introduced. "
- + "Those tests should be handled as soon as possible to reduce the cost to fix the corresponding regressions.")
- .setDebtRemediationFunction(rule.debtRemediationFunctions().linear(MINUTES_10))
- .setGapDescription("number of failed tests")
- .setSeverity(Severity.MAJOR)
- .setStatus(DEPRECATED);
- }
-
- private static void defineSkippedUnitTestRule(RulesDefinition.NewRepository repo) {
- RulesDefinition.NewRule rule = repo.createRule(CommonRuleKeys.SKIPPED_UNIT_TESTS);
- rule.setName("Skipped unit tests should be either removed or fixed")
- .addTags("pitfall")
- .setHtmlDescription("Skipped unit tests are considered as dead code. Either they should be activated again (and updated) or they should be removed.")
- .setDebtRemediationFunction(rule.debtRemediationFunctions().linear(MINUTES_10))
- .setGapDescription("number of skipped tests")
- .setSeverity(Severity.MAJOR)
- .setStatus(DEPRECATED);
- }
-}
*/
public class RuleDefinitionsLoader {
- private final CommonRuleDefinitions coreCommonDefs;
private final RulesDefinition[] pluginDefs;
private final ServerPluginRepository serverPluginRepository;
@Autowired(required = false)
- public RuleDefinitionsLoader(CommonRuleDefinitions coreCommonDefs, ServerPluginRepository serverPluginRepository, RulesDefinition[] pluginDefs) {
- this.coreCommonDefs = coreCommonDefs;
+ public RuleDefinitionsLoader(ServerPluginRepository serverPluginRepository, RulesDefinition[] pluginDefs) {
this.serverPluginRepository = serverPluginRepository;
this.pluginDefs = pluginDefs;
}
* Used when no definitions at all.
*/
@Autowired(required = false)
- public RuleDefinitionsLoader(CommonRuleDefinitions coreCommonDefs, ServerPluginRepository serverPluginRepository) {
- this(coreCommonDefs, serverPluginRepository, new RulesDefinition[0]);
+ public RuleDefinitionsLoader(ServerPluginRepository serverPluginRepository) {
+ this(serverPluginRepository, new RulesDefinition[0]);
}
public RulesDefinition.Context load() {
pluginDefinition.define(context);
}
context.setCurrentPluginKey(null);
- coreCommonDefs.define(context);
return 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.server.rule;
-
-import org.junit.Test;
-import org.sonar.api.impl.server.RulesDefinitionContext;
-import org.sonar.api.resources.AbstractLanguage;
-import org.sonar.api.resources.Language;
-import org.sonar.api.resources.Languages;
-import org.sonar.api.server.rule.RulesDefinition;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.sonar.api.rule.RuleStatus.DEPRECATED;
-
-public class CommonRuleDefinitionsImplTest {
-
- @Test
- public void instantiate_common_rules_for_correct_languages_only() {
- CommonRuleDefinitionsImpl commonRuleDefinitions = new CommonRuleDefinitionsImpl(getLanguages());
- RulesDefinition.Context underTest = new RulesDefinitionContext();
- commonRuleDefinitions.define(underTest);
-
- assertThat(underTest.repositories()).hasSize(3);
- assertThat(underTest.repository("common-java")).isNotNull();
- assertThat(underTest.repository("common-php")).isNotNull();
- assertThat(underTest.repository("common-js")).isNotNull();
-
- for (RulesDefinition.Repository repository : underTest.repositories()) {
- assertThat(repository.rules()).hasSize(6);
- for (RulesDefinition.Rule rule : repository.rules()) {
- assertThat(rule.status()).isEqualTo(DEPRECATED);
- }
- }
- }
-
- private Languages getLanguages() {
- return new Languages(
- createLanguage("java"),
- createLanguage("php"),
- createLanguage("js"),
- createLanguage("terraform"),
- createLanguage("cloudformation"),
- createLanguage("kubernetes"),
- createLanguage("docker"),
- createLanguage("web"),
- createLanguage("css"),
- createLanguage("xml"),
- createLanguage("yaml"),
- createLanguage("json"),
- createLanguage("jsp"),
- createLanguage("text"),
- createLanguage("secrets")
- );
- }
-
- private Language createLanguage(String languageKey) {
- return new AbstractLanguage(languageKey, languageKey + "_name") {
- @Override
- public String[] getFileSuffixes() {
- return new String[0];
- }
- };
- }
-
-}
private void execute(RulesDefinition... defs) {
ServerPluginRepository pluginRepository = mock(ServerPluginRepository.class);
when(pluginRepository.getPluginKey(any(RulesDefinition.class))).thenReturn(FAKE_PLUGIN_KEY);
- RuleDefinitionsLoader loader = new RuleDefinitionsLoader(mock(CommonRuleDefinitionsImpl.class), pluginRepository, defs);
+ RuleDefinitionsLoader loader = new RuleDefinitionsLoader(pluginRepository, defs);
Languages languages = mock(Languages.class);
when(languages.get(any())).thenReturn(mock(Language.class));
reset(webServerRuleFinder);
@Test
public void no_definitions() {
- CommonRuleDefinitions commonRulesDefinitions = mock(CommonRuleDefinitions.class);
- RulesDefinition.Context context = new RuleDefinitionsLoader(commonRulesDefinitions, mock(ServerPluginRepository.class)).load();
+ RulesDefinition.Context context = new RuleDefinitionsLoader(mock(ServerPluginRepository.class)).load();
assertThat(context.repositories()).isEmpty();
}
@Test
public void load_definitions() {
- CommonRuleDefinitions commonRulesDefinitions = mock(CommonRuleDefinitions.class);
- RulesDefinition.Context context = new RuleDefinitionsLoader(commonRulesDefinitions, mock(ServerPluginRepository.class),
+ RulesDefinition.Context context = new RuleDefinitionsLoader(mock(ServerPluginRepository.class),
new RulesDefinition[] {
new FindbugsDefinitions(), new JavaDefinitions()
}).load();
assertThat(context.repository("java")).isNotNull();
}
- @Test
- public void define_common_rules() {
- CommonRuleDefinitions commonRulesDefinitions = new FakeCommonRuleDefinitions();
- RulesDefinition.Context context = new RuleDefinitionsLoader(commonRulesDefinitions, mock(ServerPluginRepository.class),
- new RulesDefinition[] {
- new JavaDefinitions()
- }).load();
-
- assertThat(context.repositories()).extracting("key").containsOnly("java", "common-java");
- assertThat(context.repository("common-java").rules()).extracting("key").containsOnly("InsufficientBranchCoverage");
- }
-
- /**
- * "common-rules" are merged into core 5.2. Previously they were embedded by some plugins. Only the core definition
- * is taken into account. Others are ignored.
- */
- @Test
- public void plugin_common_rules_are_overridden() {
- CommonRuleDefinitions commonRulesDefinitions = new FakeCommonRuleDefinitions();
- RulesDefinition.Context context = new RuleDefinitionsLoader(commonRulesDefinitions, mock(ServerPluginRepository.class),
- new RulesDefinition[] {
- new PluginCommonRuleDefinitions()
- }).load();
-
- assertThat(context.repositories()).extracting("key").containsOnly("common-java");
- assertThat(context.repository("common-java").rules()).extracting("key").containsOnly("InsufficientBranchCoverage");
- assertThat(context.repository("common-java").rule("InsufficientBranchCoverage").name()).isEqualTo("The name as defined by core");
- }
-
static class FindbugsDefinitions implements RulesDefinition {
@Override
public void define(Context context) {
repo.done();
}
}
-
- static class PluginCommonRuleDefinitions implements RulesDefinition {
- @Override
- public void define(RulesDefinition.Context context) {
- RulesDefinition.NewRepository repo = context.createRepository("common-java", "java");
- repo.createRule("InsufficientBranchCoverage")
- .setName("The name as defined by plugin")
- .setHtmlDescription("The description as defined by plugin");
- repo.done();
- }
- }
-
- static class FakeCommonRuleDefinitions implements CommonRuleDefinitions {
- @Override
- public void define(RulesDefinition.Context context) {
- RulesDefinition.NewRepository repo = context.createRepository("common-java", "java");
- repo.createRule("InsufficientBranchCoverage")
- .setName("The name as defined by core")
- .setHtmlDescription("The description as defined by core");
- repo.done();
- }
- }
}
import org.sonar.server.qualityprofile.builtin.RuleActivator;
import org.sonar.server.qualityprofile.index.ActiveRuleIndexer;
import org.sonar.server.qualityprofile.ws.QProfilesWsModule;
-import org.sonar.server.rule.CommonRuleDefinitionsImpl;
import org.sonar.server.rule.RuleCreator;
import org.sonar.server.rule.RuleDefinitionsLoader;
import org.sonar.server.rule.RuleDescriptionFormatter;
AnnotationRuleParser.class,
WebServerRuleFinderImpl.class,
RuleDefinitionsLoader.class,
- CommonRuleDefinitionsImpl.class,
RulesDefinitionXmlLoader.class,
RuleUpdater.class,
RuleCreator.class,