diff options
author | Julien Lancelot <julien.lancelot@sonarsource.com> | 2013-11-19 08:22:23 +0100 |
---|---|---|
committer | Julien Lancelot <julien.lancelot@sonarsource.com> | 2013-11-20 08:12:02 +0100 |
commit | c1bbe9af51af88e0f5c6a78833ef646cb512bd6e (patch) | |
tree | 1b112ac559af5ea4cdfa3cd732e09ccedbfcb08d /sonar-core | |
parent | 081e080bf8b3e7e16bd6459dcb4e9f43857b6cf1 (diff) | |
download | sonarqube-c1bbe9af51af88e0f5c6a78833ef646cb512bd6e.tar.gz sonarqube-c1bbe9af51af88e0f5c6a78833ef646cb512bd6e.zip |
SONAR-4775 The technical debt should be related only to issues
Diffstat (limited to 'sonar-core')
26 files changed, 294 insertions, 1059 deletions
diff --git a/sonar-core/src/main/java/org/sonar/core/technicaldebt/TechnicalDebtCalculator.java b/sonar-core/src/main/java/org/sonar/core/technicaldebt/TechnicalDebtCalculator.java index fabda2a3b89..d6a6cdc6c93 100644 --- a/sonar-core/src/main/java/org/sonar/core/technicaldebt/TechnicalDebtCalculator.java +++ b/sonar-core/src/main/java/org/sonar/core/technicaldebt/TechnicalDebtCalculator.java @@ -19,132 +19,41 @@ */ package org.sonar.core.technicaldebt; -import com.google.common.annotations.VisibleForTesting; -import com.google.common.collect.ArrayListMultimap; -import com.google.common.collect.ListMultimap; -import com.google.common.collect.Maps; -import org.slf4j.LoggerFactory; +import com.google.common.base.Objects; import org.sonar.api.BatchExtension; -import org.sonar.api.batch.DecoratorContext; import org.sonar.api.issue.Issue; import org.sonar.api.issue.internal.WorkDayDuration; -import org.sonar.api.measures.CoreMetrics; -import org.sonar.api.measures.Measure; -import org.sonar.api.measures.MeasuresFilters; -import org.sonar.api.measures.Metric; -import org.sonar.api.rules.Violation; -import org.sonar.core.technicaldebt.functions.Functions; - -import java.util.Collection; -import java.util.List; -import java.util.Map; /** * Computes the remediation cost based on the quality and analysis models. */ public class TechnicalDebtCalculator implements BatchExtension { - private double total = 0.0; - private Map<TechnicalDebtCharacteristic, Double> characteristicCosts = Maps.newHashMap(); - private Map<TechnicalDebtRequirement, Double> requirementCosts = Maps.newHashMap(); - - private Functions functions; private final TechnicalDebtConverter converter; private TechnicalDebtModel technicalDebtModel; - public TechnicalDebtCalculator(TechnicalDebtModel technicalDebtModel, Functions functions, TechnicalDebtConverter converter) { + public TechnicalDebtCalculator(TechnicalDebtModel technicalDebtModel, TechnicalDebtConverter converter) { this.technicalDebtModel = technicalDebtModel; - this.functions = functions; this.converter = converter; } public WorkDayDuration calculTechnicalDebt(Issue issue) { TechnicalDebtRequirement requirement = technicalDebtModel.getRequirementByRule(issue.ruleKey().repository(), issue.ruleKey().rule()); if (requirement != null) { - return converter.fromMinutes(functions.costInMinutes(requirement, issue)); + return converter.fromMinutes(calculTechnicalDebt(requirement, issue)); } return null; } - public void compute(DecoratorContext context) { - reset(); - - // group violations by requirement - ListMultimap<TechnicalDebtRequirement, Violation> violationsByRequirement = groupViolations(context); - - // the total cost is: cost(violations) - for (TechnicalDebtRequirement requirement : technicalDebtModel.getAllRequirements()) { - List<Violation> violations = violationsByRequirement.get(requirement); - double allViolationsCost = computeTechnicalDebt(CoreMetrics.TECHNICAL_DEBT, context, requirement, violations); - updateRequirementCosts(requirement, allViolationsCost); - } - } - - public double getTotal() { - return total; - } - - public Map<TechnicalDebtCharacteristic, Double> getCharacteristicCosts() { - return characteristicCosts; - } - - public Map<TechnicalDebtRequirement, Double> getRequirementCosts() { - return requirementCosts; - } - - @VisibleForTesting - protected ListMultimap<TechnicalDebtRequirement, Violation> groupViolations(DecoratorContext context) { - ListMultimap<TechnicalDebtRequirement, Violation> violationsByRequirement = ArrayListMultimap.create(); - for (Violation violation : context.getViolations()) { - String repositoryKey = violation.getRule().getRepositoryKey(); - String key = violation.getRule().getKey(); - TechnicalDebtRequirement requirement = technicalDebtModel.getRequirementByRule(repositoryKey, key); - if (requirement == null) { - LoggerFactory.getLogger(getClass()).debug("No technical debt requirement for: " + repositoryKey + "/" + key); - } else { - violationsByRequirement.put(requirement, violation); - } - } - return violationsByRequirement; - } - - @VisibleForTesting - protected void updateRequirementCosts(TechnicalDebtRequirement requirement, double cost) { - requirementCosts.put(requirement, cost); - total += cost; - propagateCostInParents(requirement.getParent(), cost); - } - - private double computeTechnicalDebt(Metric metric, DecoratorContext context, TechnicalDebtRequirement requirement, Collection<Violation> violations) { - double cost = 0.0; - if (violations != null) { - cost = functions.costInHours(requirement, violations); - } + private long calculTechnicalDebt(TechnicalDebtRequirement requirement, Issue issue) { + long effortToFix = Objects.firstNonNull(issue.effortToFix(), 1l).longValue(); - for (Measure measure : context.getChildrenMeasures(MeasuresFilters.characteristic(metric, requirement.toCharacteristic()))) { - if (measure.getCharacteristic() != null && measure.getCharacteristic().equals(requirement.toCharacteristic()) && measure.getValue() != null) { - cost += measure.getValue(); - } - } - return cost; - } + WorkUnit factorUnit = requirement.getRemediationFactor(); + long factor = factorUnit != null ? converter.toMinutes(factorUnit) : 0l; - private void reset() { - total = 0.0; - characteristicCosts.clear(); - requirementCosts.clear(); - } + WorkUnit offsetUnit = requirement.getOffset(); + long offset = offsetUnit != null ? converter.toMinutes(offsetUnit) : 0l; - private void propagateCostInParents(TechnicalDebtCharacteristic characteristic, double cost) { - if (characteristic != null) { - Double parentCost = characteristicCosts.get(characteristic); - if (parentCost == null) { - characteristicCosts.put(characteristic, cost); - } else { - characteristicCosts.put(characteristic, cost + parentCost); - } - propagateCostInParents(characteristic.getParent(), cost); - } + return effortToFix * factor + offset; } - } diff --git a/sonar-core/src/main/java/org/sonar/core/technicaldebt/TechnicalDebtConverter.java b/sonar-core/src/main/java/org/sonar/core/technicaldebt/TechnicalDebtConverter.java index 962483a6887..c2b204a0a2b 100644 --- a/sonar-core/src/main/java/org/sonar/core/technicaldebt/TechnicalDebtConverter.java +++ b/sonar-core/src/main/java/org/sonar/core/technicaldebt/TechnicalDebtConverter.java @@ -35,21 +35,6 @@ public class TechnicalDebtConverter implements BatchComponent, ServerComponent { this.hoursInDay = settings.getInt(PROPERTY_HOURS_IN_DAY); } - public double toDays(WorkUnit factor) { - if (StringUtils.equals(WorkUnit.DAYS, factor.getUnit())) { - return factor.getValue(); - - } else if (StringUtils.equals(WorkUnit.HOURS, factor.getUnit())) { - return factor.getValue() / hoursInDay; - - } else if (StringUtils.equals(WorkUnit.MINUTES, factor.getUnit())) { - return factor.getValue() / (hoursInDay * 60.0); - - } else { - throw new IllegalArgumentException("Unknown remediation factor unit: " + factor.getUnit()); - } - } - public long toMinutes(WorkUnit factor) { if (StringUtils.equals(WorkUnit.DAYS, factor.getUnit())) { return Double.valueOf(factor.getValue() * hoursInDay * 60d).longValue(); diff --git a/sonar-core/src/main/java/org/sonar/core/technicaldebt/TechnicalDebtRequirement.java b/sonar-core/src/main/java/org/sonar/core/technicaldebt/TechnicalDebtRequirement.java index f597f4bace3..df07400c8d6 100644 --- a/sonar-core/src/main/java/org/sonar/core/technicaldebt/TechnicalDebtRequirement.java +++ b/sonar-core/src/main/java/org/sonar/core/technicaldebt/TechnicalDebtRequirement.java @@ -21,9 +21,8 @@ package org.sonar.core.technicaldebt; import org.sonar.api.qualitymodel.Characteristic; import org.sonar.api.rules.Rule; -import org.sonar.core.technicaldebt.functions.LinearFunction; -import org.sonar.core.technicaldebt.functions.LinearWithOffsetFunction; -import org.sonar.core.technicaldebt.functions.LinearWithThresholdFunction; + +import javax.annotation.CheckForNull; public class TechnicalDebtRequirement { @@ -31,6 +30,10 @@ public class TechnicalDebtRequirement { public static final String PROPERTY_REMEDIATION_FACTOR = "remediationFactor"; public static final String PROPERTY_OFFSET = "offset"; + public static final String FUNCTION_LINEAR = "linear"; + public static final String FUNCTION_LINEAR_WITH_OFFSET = "linear_offset"; + public static final String FUNCTION_CONSTANT_PER_ISSUE = "constant_issue"; + private Rule rule; private TechnicalDebtCharacteristic parent; private org.sonar.api.qualitymodel.Characteristic characteristic; @@ -49,16 +52,17 @@ public class TechnicalDebtRequirement { } private void initFunction() { - function = characteristic.getPropertyTextValue(PROPERTY_REMEDIATION_FUNCTION, LinearFunction.FUNCTION_LINEAR); + function = characteristic.getPropertyTextValue(PROPERTY_REMEDIATION_FUNCTION, FUNCTION_LINEAR); } private void initFactor() { - factor = WorkUnit.create(characteristic.getPropertyValue(PROPERTY_REMEDIATION_FACTOR, null), - characteristic.getPropertyTextValue(PROPERTY_REMEDIATION_FACTOR, null)); + if (FUNCTION_LINEAR.equals(function) || FUNCTION_LINEAR_WITH_OFFSET.equals(function)) { + factor = WorkUnit.create(characteristic.getPropertyValue(PROPERTY_REMEDIATION_FACTOR, null), characteristic.getPropertyTextValue(PROPERTY_REMEDIATION_FACTOR, null)); + } } private void initOffset() { - if (LinearWithOffsetFunction.FUNCTION_LINEAR_WITH_OFFSET.equals(function) || LinearWithThresholdFunction.FUNCTION_LINEAR_WITH_THRESHOLD.equals(function)) { + if (FUNCTION_LINEAR_WITH_OFFSET.equals(function) || FUNCTION_CONSTANT_PER_ISSUE.equals(function)) { offset = WorkUnit.create(characteristic.getPropertyValue(PROPERTY_OFFSET, null), characteristic.getPropertyTextValue(PROPERTY_OFFSET, null)); } @@ -76,10 +80,12 @@ public class TechnicalDebtRequirement { return function; } + @CheckForNull public WorkUnit getRemediationFactor() { return factor; } + @CheckForNull public WorkUnit getOffset() { return offset; } diff --git a/sonar-core/src/main/java/org/sonar/core/technicaldebt/TechnicalDebtXMLImporter.java b/sonar-core/src/main/java/org/sonar/core/technicaldebt/TechnicalDebtXMLImporter.java index 44ea20fbcd7..860956d5f32 100644 --- a/sonar-core/src/main/java/org/sonar/core/technicaldebt/TechnicalDebtXMLImporter.java +++ b/sonar-core/src/main/java/org/sonar/core/technicaldebt/TechnicalDebtXMLImporter.java @@ -30,6 +30,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.sonar.api.ServerExtension; import org.sonar.api.qualitymodel.Characteristic; +import org.sonar.api.qualitymodel.CharacteristicProperty; import org.sonar.api.qualitymodel.Model; import org.sonar.api.rules.Rule; import org.sonar.api.utils.ValidationMessages; @@ -124,8 +125,11 @@ public class TechnicalDebtXMLImporter implements ServerExtension { fillRule(characteristic, ruleRepositoryKey, ruleKey, messages, technicalDebtRuleCache); if (StringUtils.isNotBlank(characteristic.getKey()) || characteristic.getRule() != null) { - addCharacteristicToModel(model, characteristic, children); - return characteristic; + Characteristic convertedCharacteristic = processDeprecatedFunctionsOnRequirement(characteristic, messages); + if (convertedCharacteristic != null) { + addCharacteristicToModel(model, characteristic, children); + return characteristic; + } } return null; } @@ -152,6 +156,27 @@ public class TechnicalDebtXMLImporter implements ServerExtension { } } + private Characteristic processDeprecatedFunctionsOnRequirement(Characteristic characteristic, ValidationMessages messages) { + CharacteristicProperty function = characteristic.getProperty(TechnicalDebtRequirement.PROPERTY_REMEDIATION_FUNCTION); + if (function != null) { + if ("linear_threshold".equals(function.getTextValue())) { + function.setTextValue(TechnicalDebtRequirement.FUNCTION_LINEAR); + CharacteristicProperty offset = characteristic.getProperty(TechnicalDebtRequirement.PROPERTY_OFFSET); + offset.setValue(0d); + + String message = String.format("Linear with threshold function is no more used, the function of the requirement '%s' is replaced by linear.", characteristic.getRule()); + LOG.warn(message); + messages.addWarningText(message); + } else if ("constant_resource".equals(function.getTextValue())) { + String message = String.format("Constant / file function is no more used, requirement '%s' is ignore.", characteristic.getRule()); + LOG.warn(message); + messages.addWarningText(message); + return null; + } + } + return characteristic; + } + private void processProperty(Characteristic characteristic, SMInputCursor cursor, ValidationMessages messages) throws XMLStreamException { SMInputCursor c = cursor.childElementCursor(); String key = null; diff --git a/sonar-core/src/main/java/org/sonar/core/technicaldebt/functions/AbstractFunction.java b/sonar-core/src/main/java/org/sonar/core/technicaldebt/functions/AbstractFunction.java deleted file mode 100644 index 86146993b1b..00000000000 --- a/sonar-core/src/main/java/org/sonar/core/technicaldebt/functions/AbstractFunction.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * SonarQube, open source software quality management tool. - * Copyright (C) 2008-2013 SonarSource - * mailto:contact AT sonarsource DOT com - * - * SonarQube 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. - * - * SonarQube 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.core.technicaldebt.functions; - -import org.sonar.api.issue.Issue; -import org.sonar.api.rules.Violation; -import org.sonar.core.technicaldebt.TechnicalDebtConverter; -import org.sonar.core.technicaldebt.TechnicalDebtRequirement; - -import java.util.Collection; - -public abstract class AbstractFunction implements Function { - - private TechnicalDebtConverter converter; - - public AbstractFunction(TechnicalDebtConverter converter) { - this.converter = converter; - } - - protected TechnicalDebtConverter getConverter() { - return converter; - } - - public abstract String getKey(); - - public abstract double costInHours(TechnicalDebtRequirement requirement, Collection<Violation> violations); - - public abstract long costInMinutes(TechnicalDebtRequirement requirement, Issue issue); - - protected long factorInMinutes(TechnicalDebtRequirement requirement) { - return getConverter().toMinutes(requirement.getRemediationFactor()); - } - -} diff --git a/sonar-core/src/main/java/org/sonar/core/technicaldebt/functions/ConstantFunction.java b/sonar-core/src/main/java/org/sonar/core/technicaldebt/functions/ConstantFunction.java deleted file mode 100644 index 7f92e8604b7..00000000000 --- a/sonar-core/src/main/java/org/sonar/core/technicaldebt/functions/ConstantFunction.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * SonarQube, open source software quality management tool. - * Copyright (C) 2008-2013 SonarSource - * mailto:contact AT sonarsource DOT com - * - * SonarQube 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. - * - * SonarQube 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.core.technicaldebt.functions; - -import org.sonar.api.issue.Issue; -import org.sonar.api.rules.Violation; -import org.sonar.core.technicaldebt.TechnicalDebtConverter; -import org.sonar.core.technicaldebt.TechnicalDebtRequirement; - -import java.util.Collection; - -public final class ConstantFunction extends AbstractFunction { - - public static final String FUNCTION_CONSTANT_RESOURCE = "constant_resource"; - - public ConstantFunction(TechnicalDebtConverter converter) { - super(converter); - } - - public String getKey() { - return FUNCTION_CONSTANT_RESOURCE; - } - - public double costInHours(TechnicalDebtRequirement requirement, Collection<Violation> violations) { - double cost = 0.0; - if (!violations.isEmpty()) { - cost = getConverter().toDays(requirement.getRemediationFactor()); - } - return cost; - } - - public long costInMinutes(TechnicalDebtRequirement requirement, Issue issue) { - return factorInMinutes(requirement); - } - -} diff --git a/sonar-core/src/main/java/org/sonar/core/technicaldebt/functions/Function.java b/sonar-core/src/main/java/org/sonar/core/technicaldebt/functions/Function.java deleted file mode 100644 index 65a37918499..00000000000 --- a/sonar-core/src/main/java/org/sonar/core/technicaldebt/functions/Function.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * SonarQube, open source software quality management tool. - * Copyright (C) 2008-2013 SonarSource - * mailto:contact AT sonarsource DOT com - * - * SonarQube 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. - * - * SonarQube 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.core.technicaldebt.functions; - -import org.sonar.api.BatchComponent; -import org.sonar.api.issue.Issue; -import org.sonar.api.rules.Violation; -import org.sonar.core.technicaldebt.TechnicalDebtRequirement; - -import java.util.Collection; - -public interface Function extends BatchComponent { - - String getKey(); - - double costInHours(TechnicalDebtRequirement requirement, Collection<Violation> violations); - - long costInMinutes(TechnicalDebtRequirement requirement, Issue issue); - -} diff --git a/sonar-core/src/main/java/org/sonar/core/technicaldebt/functions/Functions.java b/sonar-core/src/main/java/org/sonar/core/technicaldebt/functions/Functions.java deleted file mode 100644 index da43d06a508..00000000000 --- a/sonar-core/src/main/java/org/sonar/core/technicaldebt/functions/Functions.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * SonarQube, open source software quality management tool. - * Copyright (C) 2008-2013 SonarSource - * mailto:contact AT sonarsource DOT com - * - * SonarQube 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. - * - * SonarQube 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.core.technicaldebt.functions; - -import com.google.common.collect.Maps; -import org.sonar.api.BatchComponent; -import org.sonar.api.issue.Issue; -import org.sonar.api.rules.Violation; -import org.sonar.core.technicaldebt.TechnicalDebtRequirement; - -import java.util.Collection; -import java.util.Map; - -public class Functions implements BatchComponent { - - private final Map<String, Function> functionsByKey = Maps.newHashMap(); - - public Functions(final Function[] functions) { - for (Function function : functions) { - functionsByKey.put(function.getKey(), function); - } - } - - Function getFunction(String key) { - return functionsByKey.get(key); - } - - public Function getFunction(TechnicalDebtRequirement requirement) { - return getFunction(requirement.getRemediationFunction()); - } - - public double costInHours(TechnicalDebtRequirement requirement, Collection<Violation> violations) { - return getFunction(requirement).costInHours(requirement, violations); - } - - public long costInMinutes(TechnicalDebtRequirement requirement, Issue issue) { - return getFunction(requirement).costInMinutes(requirement, issue); - } - -} diff --git a/sonar-core/src/main/java/org/sonar/core/technicaldebt/functions/LinearFunction.java b/sonar-core/src/main/java/org/sonar/core/technicaldebt/functions/LinearFunction.java deleted file mode 100644 index d351372576b..00000000000 --- a/sonar-core/src/main/java/org/sonar/core/technicaldebt/functions/LinearFunction.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * SonarQube, open source software quality management tool. - * Copyright (C) 2008-2013 SonarSource - * mailto:contact AT sonarsource DOT com - * - * SonarQube 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. - * - * SonarQube 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.core.technicaldebt.functions; - -import org.sonar.api.issue.Issue; -import org.sonar.api.rules.Violation; -import org.sonar.core.technicaldebt.TechnicalDebtConverter; -import org.sonar.core.technicaldebt.TechnicalDebtRequirement; - -import java.util.Collection; - -public class LinearFunction extends AbstractFunction { - - public static final String FUNCTION_LINEAR = "linear"; - - public static final double DEFAULT_VIOLATION_COST = 1.0; - - public LinearFunction(TechnicalDebtConverter converter) { - super(converter); - } - - public String getKey() { - return FUNCTION_LINEAR; - } - - public double costInHours(TechnicalDebtRequirement requirement, Collection<Violation> violations) { - double points = 0.0; - for (Violation violation : violations) { - Double effortToFix = violation.getCost(); - points += effortToFix != null ? effortToFix : DEFAULT_VIOLATION_COST; - } - return points * getConverter().toDays(requirement.getRemediationFactor()); - } - - public long costInMinutes(TechnicalDebtRequirement requirement, Issue issue) { - Double effortToFix = issue.effortToFix(); - double points = effortToFix != null ? effortToFix : DEFAULT_VIOLATION_COST; - return Double.valueOf(points * factorInMinutes(requirement)).longValue(); - } -} diff --git a/sonar-core/src/main/java/org/sonar/core/technicaldebt/functions/LinearWithOffsetFunction.java b/sonar-core/src/main/java/org/sonar/core/technicaldebt/functions/LinearWithOffsetFunction.java deleted file mode 100644 index 890dc779ec3..00000000000 --- a/sonar-core/src/main/java/org/sonar/core/technicaldebt/functions/LinearWithOffsetFunction.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * SonarQube, open source software quality management tool. - * Copyright (C) 2008-2013 SonarSource - * mailto:contact AT sonarsource DOT com - * - * SonarQube 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. - * - * SonarQube 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.core.technicaldebt.functions; - -import org.sonar.api.rules.Violation; -import org.sonar.core.technicaldebt.TechnicalDebtConverter; -import org.sonar.core.technicaldebt.TechnicalDebtRequirement; - -import java.util.Collection; - -public final class LinearWithOffsetFunction extends LinearFunction { - - public static final String FUNCTION_LINEAR_WITH_OFFSET = "linear_offset"; - - public LinearWithOffsetFunction(TechnicalDebtConverter converter) { - super(converter); - } - - public String getKey() { - return FUNCTION_LINEAR_WITH_OFFSET; - } - - public double costInHours(TechnicalDebtRequirement requirement, Collection<Violation> violations) { - if (violations.isEmpty()) { - return 0.0; - } - double minimunCost = getConverter().toDays(requirement.getOffset()); - return minimunCost + super.costInHours(requirement, violations); - } - -} diff --git a/sonar-core/src/main/java/org/sonar/core/technicaldebt/functions/LinearWithThresholdFunction.java b/sonar-core/src/main/java/org/sonar/core/technicaldebt/functions/LinearWithThresholdFunction.java deleted file mode 100644 index f8fc198556e..00000000000 --- a/sonar-core/src/main/java/org/sonar/core/technicaldebt/functions/LinearWithThresholdFunction.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * SonarQube, open source software quality management tool. - * Copyright (C) 2008-2013 SonarSource - * mailto:contact AT sonarsource DOT com - * - * SonarQube 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. - * - * SonarQube 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.core.technicaldebt.functions; - -import org.sonar.api.rules.Violation; -import org.sonar.core.technicaldebt.TechnicalDebtConverter; -import org.sonar.core.technicaldebt.TechnicalDebtRequirement; - -import java.util.Collection; - -public final class LinearWithThresholdFunction extends LinearFunction { - - public static final String FUNCTION_LINEAR_WITH_THRESHOLD = "linear_threshold"; - - public LinearWithThresholdFunction(TechnicalDebtConverter converter) { - super(converter); - } - - public String getKey() { - return FUNCTION_LINEAR_WITH_THRESHOLD; - } - - public double costInHours(TechnicalDebtRequirement requirement, Collection<Violation> violations) { - if (violations.isEmpty()) { - return 0.0; - } - double thresholdCost = getConverter().toDays(requirement.getOffset()); - double violationsCost = super.costInHours(requirement, violations); - return violationsCost > thresholdCost ? violationsCost : thresholdCost; - } - -} diff --git a/sonar-core/src/main/java/org/sonar/core/technicaldebt/functions/package-info.java b/sonar-core/src/main/java/org/sonar/core/technicaldebt/functions/package-info.java deleted file mode 100644 index dfc07e1508a..00000000000 --- a/sonar-core/src/main/java/org/sonar/core/technicaldebt/functions/package-info.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * SonarQube, open source software quality management tool. - * Copyright (C) 2008-2013 SonarSource - * mailto:contact AT sonarsource DOT com - * - * SonarQube 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. - * - * SonarQube 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.core.technicaldebt.functions; - -import javax.annotation.ParametersAreNonnullByDefault; diff --git a/sonar-core/src/test/java/org/sonar/core/technicaldebt/TechnicalDebtCalculatorTest.java b/sonar-core/src/test/java/org/sonar/core/technicaldebt/TechnicalDebtCalculatorTest.java index ef3289b938f..2da03d4f46a 100644 --- a/sonar-core/src/test/java/org/sonar/core/technicaldebt/TechnicalDebtCalculatorTest.java +++ b/sonar-core/src/test/java/org/sonar/core/technicaldebt/TechnicalDebtCalculatorTest.java @@ -19,192 +19,104 @@ */ package org.sonar.core.technicaldebt; -import com.google.common.collect.ListMultimap; -import org.apache.commons.lang.time.DateUtils; import org.junit.Before; import org.junit.Test; -import org.sonar.api.batch.DecoratorContext; -import org.sonar.api.issue.Issue; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.runners.MockitoJUnitRunner; import org.sonar.api.issue.internal.DefaultIssue; -import org.sonar.api.measures.Measure; -import org.sonar.api.measures.MeasuresFilter; -import org.sonar.api.qualitymodel.Characteristic; import org.sonar.api.rule.RuleKey; -import org.sonar.api.rules.Rule; -import org.sonar.api.rules.Violation; -import org.sonar.core.technicaldebt.functions.Functions; -import java.util.Collection; -import java.util.Collections; -import java.util.Date; -import java.util.List; - -import static com.google.common.collect.Lists.newArrayList; import static org.fest.assertions.Assertions.assertThat; -import static org.mockito.Matchers.any; import static org.mockito.Mockito.*; +@RunWith(MockitoJUnitRunner.class) public class TechnicalDebtCalculatorTest { - private static final Date NOW = new Date(System.currentTimeMillis()); - private static final Date YESTERDAY = DateUtils.addDays(NOW, -1); - private static final Date LAST_MONTH = DateUtils.addMonths(NOW, -1); - - private TechnicalDebtModel technicalDebtModel; - private Functions functions; - private TechnicalDebtCalculator remediationCostCalculator; - - @Before - public void initMocks() { - technicalDebtModel = mock(TechnicalDebtModel.class); - functions = mock(Functions.class); - TechnicalDebtConverter converter = mock(TechnicalDebtConverter.class); - remediationCostCalculator = new TechnicalDebtCalculator(technicalDebtModel, functions, converter); - } - - @Test - public void group_violations_by_requirement() throws Exception { - - TechnicalDebtRequirement requirement1 = mock(TechnicalDebtRequirement.class); - TechnicalDebtRequirement requirement2 = mock(TechnicalDebtRequirement.class); + @Mock + TechnicalDebtModel technicalDebtModel; - Violation violation1 = buildViolation("rule1", "repo1", NOW); - Violation violation2 = buildViolation("rule1", "repo1", NOW); - Violation violation3 = buildViolation("rule2", "repo2", NOW); - Violation violation4 = buildViolation("unmatchable", "repo2", NOW); + @Mock + TechnicalDebtConverter converter; - List<Violation> violations = newArrayList(violation1, violation2, violation3, violation4); + WorkUnit tenMinutes = WorkUnit.create(10d, WorkUnit.MINUTES); + WorkUnit fiveMinutes = WorkUnit.create(5d, WorkUnit.MINUTES); - when(technicalDebtModel.getRequirementByRule("repo1", "rule1")).thenReturn(requirement1); - when(technicalDebtModel.getRequirementByRule("repo2", "rule2")).thenReturn(requirement2); + TechnicalDebtCalculator remediationCostCalculator; - DecoratorContext context = mock(DecoratorContext.class); - when(context.getViolations()).thenReturn(violations); - - ListMultimap<TechnicalDebtRequirement, Violation> groupedViolations = remediationCostCalculator.groupViolations(context); + @Before + public void before() { + when(converter.toMinutes(tenMinutes)).thenReturn(10l); + when(converter.toMinutes(fiveMinutes)).thenReturn(5l); - assertThat(groupedViolations.keySet().size()).isEqualTo(2); - assertThat(groupedViolations.get(requirement1)).containsExactly(violation1, violation2); - assertThat(groupedViolations.get(requirement2)).containsExactly(violation3); + remediationCostCalculator = new TechnicalDebtCalculator(technicalDebtModel, converter); } @Test - public void add_cost_with_no_parent() throws Exception { - - double requirementCost = 1.0; + public void calcul_technical_debt() throws Exception { + DefaultIssue issue = new DefaultIssue().setKey("ABCDE").setRuleKey(RuleKey.of("squid", "AvoidCycle")); TechnicalDebtRequirement requirement = mock(TechnicalDebtRequirement.class); - when(requirement.getParent()).thenReturn(null); + Mockito.when(requirement.getRemediationFactor()).thenReturn(tenMinutes); + Mockito.when(requirement.getOffset()).thenReturn(fiveMinutes); + when(technicalDebtModel.getRequirementByRule("squid", "AvoidCycle")).thenReturn(requirement); - remediationCostCalculator.updateRequirementCosts(requirement, requirementCost); + remediationCostCalculator.calculTechnicalDebt(issue); - assertThat(remediationCostCalculator.getRequirementCosts().get(requirement)).isEqualTo(requirementCost); - assertThat(remediationCostCalculator.getTotal()).isEqualTo(requirementCost); + verify(converter).fromMinutes(10l + 5l); } @Test - public void add_cost_and_propagate_to_parents() throws Exception { - - double requirementCost = 1.0; - - TechnicalDebtCharacteristic parentCharacteristic = new TechnicalDebtCharacteristic(Characteristic.create()); - - TechnicalDebtCharacteristic characteristic = new TechnicalDebtCharacteristic(Characteristic.create(), parentCharacteristic); + public void calcul_technical_debt_with_effort_to_fix() throws Exception { + DefaultIssue issue = new DefaultIssue().setKey("ABCDE").setRuleKey(RuleKey.of("squid", "AvoidCycle")).setEffortToFix(2d); TechnicalDebtRequirement requirement = mock(TechnicalDebtRequirement.class); - when(requirement.getParent()).thenReturn(characteristic); + Mockito.when(requirement.getRemediationFactor()).thenReturn(tenMinutes); + Mockito.when(requirement.getOffset()).thenReturn(fiveMinutes); + when(technicalDebtModel.getRequirementByRule("squid", "AvoidCycle")).thenReturn(requirement); - remediationCostCalculator.updateRequirementCosts(requirement, requirementCost); + remediationCostCalculator.calculTechnicalDebt(issue); - assertThat(remediationCostCalculator.getRequirementCosts().get(requirement)).isEqualTo(requirementCost); - assertThat(remediationCostCalculator.getCharacteristicCosts().get(characteristic)).isEqualTo(requirementCost); - assertThat(remediationCostCalculator.getCharacteristicCosts().get(parentCharacteristic)).isEqualTo(requirementCost); + verify(converter).fromMinutes(10l * 2 + 5l); } @Test - public void compute_totals_costs() throws Exception { - - TechnicalDebtRequirement requirement1 = mock(TechnicalDebtRequirement.class); - TechnicalDebtRequirement requirement2 = mock(TechnicalDebtRequirement.class); + public void calcul_technical_debt_with_no_offset() throws Exception { + DefaultIssue issue = new DefaultIssue().setKey("ABCDE").setRuleKey(RuleKey.of("squid", "AvoidCycle")).setEffortToFix(2d); - Violation violation1 = buildViolation("rule1", "repo1", NOW); - Violation violation2 = buildViolation("rule1", "repo1", NOW); - Violation violation3 = buildViolation("rule2", "repo2", YESTERDAY); - Violation violation4 = buildViolation("rule2", "repo2", LAST_MONTH); - - List<Violation> violations = newArrayList(violation1, violation2, violation3, violation4); - - when(technicalDebtModel.getRequirementByRule("repo1", "rule1")).thenReturn(requirement1); - when(technicalDebtModel.getRequirementByRule("repo2", "rule2")).thenReturn(requirement2); - when(technicalDebtModel.getAllRequirements()).thenReturn(newArrayList(requirement1, requirement2)); - - when(functions.costInHours(any(TechnicalDebtRequirement.class), any(Collection.class))).thenReturn(1.0); - - DecoratorContext context = mock(DecoratorContext.class); - when(context.getViolations()).thenReturn(violations); - when(context.getChildrenMeasures(any(MeasuresFilter.class))).thenReturn(Collections.EMPTY_LIST); + TechnicalDebtRequirement requirement = mock(TechnicalDebtRequirement.class); + Mockito.when(requirement.getRemediationFactor()).thenReturn(tenMinutes); + Mockito.when(requirement.getOffset()).thenReturn(null); + when(technicalDebtModel.getRequirementByRule("squid", "AvoidCycle")).thenReturn(requirement); - remediationCostCalculator.compute(context); + remediationCostCalculator.calculTechnicalDebt(issue); - assertThat(remediationCostCalculator.getTotal()).isEqualTo(2.0); - assertThat(remediationCostCalculator.getRequirementCosts().get(requirement1)).isEqualTo(1.0); - assertThat(remediationCostCalculator.getRequirementCosts().get(requirement2)).isEqualTo(1.0); + verify(converter).fromMinutes(10l * 2 + 0l); } @Test - public void compute_totals_costs_from_children() throws Exception { - TechnicalDebtCharacteristic parentCharacteristic = new TechnicalDebtCharacteristic(Characteristic.create()); - TechnicalDebtRequirement requirement1 = new TechnicalDebtRequirement(Characteristic.create(), parentCharacteristic);; - - Violation violation1 = buildViolation("rule1", "repo1", NOW); - Violation violation2 = buildViolation("rule1", "repo1", NOW); - Violation violation3 = buildViolation("rule2", "repo2", YESTERDAY); - Violation violation4 = buildViolation("rule2", "repo2", LAST_MONTH); - - List<Violation> violations = newArrayList(violation1, violation2, violation3, violation4); - - when(technicalDebtModel.getRequirementByRule("repo1", "rule1")).thenReturn(requirement1); - when(technicalDebtModel.getAllRequirements()).thenReturn(newArrayList(requirement1)); + public void calcul_technical_debt_with_no_factor() throws Exception { + DefaultIssue issue = new DefaultIssue().setKey("ABCDE").setRuleKey(RuleKey.of("squid", "AvoidCycle")).setEffortToFix(2d); - when(functions.costInHours(any(TechnicalDebtRequirement.class), any(Collection.class))).thenReturn(1.0); - - DecoratorContext context = mock(DecoratorContext.class); - when(context.getViolations()).thenReturn(violations); - - Measure measure = new Measure().setCharacteristic(requirement1.toCharacteristic()).setValue(5.0); - when(context.getChildrenMeasures(any(MeasuresFilter.class))).thenReturn(newArrayList(measure)); - - remediationCostCalculator.compute(context); - - assertThat(remediationCostCalculator.getTotal()).isEqualTo(6.0); - assertThat(remediationCostCalculator.getRequirementCosts().get(requirement1)).isEqualTo(6.0); - } - - @Test - public void technical_debt_from_one_issue() throws Exception { - DefaultIssue issue = new DefaultIssue().setKey("ABCDE").setRuleKey(RuleKey.of("squid", "AvoidCycle")); TechnicalDebtRequirement requirement = mock(TechnicalDebtRequirement.class); + Mockito.when(requirement.getRemediationFactor()).thenReturn(null); + Mockito.when(requirement.getOffset()).thenReturn(fiveMinutes); when(technicalDebtModel.getRequirementByRule("squid", "AvoidCycle")).thenReturn(requirement); - when(functions.costInMinutes(eq(requirement), eq(issue))).thenReturn(10L); remediationCostCalculator.calculTechnicalDebt(issue); - verify(functions).costInMinutes(eq(requirement), eq(issue)); + + verify(converter).fromMinutes(0l * 2 + 5l); } @Test - public void no_technical_debt_from_one_issue_if_requirement_not_found() throws Exception { + public void no_technical_debt_if_requirement_not_found() throws Exception { DefaultIssue issue = new DefaultIssue().setKey("ABCDE").setRuleKey(RuleKey.of("squid", "AvoidCycle")); when(technicalDebtModel.getRequirementByRule("squid", "AvoidCycle")).thenReturn(null); assertThat(remediationCostCalculator.calculTechnicalDebt(issue)).isNull(); - verify(functions, never()).costInMinutes(any(TechnicalDebtRequirement.class), any(Issue.class)); + verify(converter, never()).fromMinutes(anyLong()); } - private Violation buildViolation(String ruleKey, String repositoryKey, Date creationDate) { - Violation violation = mock(Violation.class); - stub(violation.getRule()).toReturn(Rule.create(repositoryKey, ruleKey)); - stub(violation.getCreatedAt()).toReturn(creationDate); - return violation; - } } diff --git a/sonar-core/src/test/java/org/sonar/core/technicaldebt/TechnicalDebtConverterTest.java b/sonar-core/src/test/java/org/sonar/core/technicaldebt/TechnicalDebtConverterTest.java index d72511e1a29..a2c04fa960c 100644 --- a/sonar-core/src/test/java/org/sonar/core/technicaldebt/TechnicalDebtConverterTest.java +++ b/sonar-core/src/test/java/org/sonar/core/technicaldebt/TechnicalDebtConverterTest.java @@ -40,13 +40,6 @@ public class TechnicalDebtConverterTest { } @Test - public void convert_work_unit_to_days() { - assertThat(converter.toDays(WorkUnit.create(6.0, WorkUnit.DAYS))).isEqualTo(6.0); - assertThat(converter.toDays(WorkUnit.create(6.0, WorkUnit.HOURS))).isEqualTo(6.0 / 12.0); - assertThat(converter.toDays(WorkUnit.create(60.0, WorkUnit.MINUTES))).isEqualTo(1.0 / 12.0); - } - - @Test public void concert_work_unit_to_minutes() { assertThat(converter.toMinutes(WorkUnit.create(2.0, WorkUnit.DAYS))).isEqualTo(2 * 12 * 60L); assertThat(converter.toMinutes(WorkUnit.create(6.0, WorkUnit.HOURS))).isEqualTo(6 * 60L); diff --git a/sonar-core/src/test/java/org/sonar/core/technicaldebt/TechnicalDebtRequirementTest.java b/sonar-core/src/test/java/org/sonar/core/technicaldebt/TechnicalDebtRequirementTest.java index 1cf6f740e25..f56e86072f8 100644 --- a/sonar-core/src/test/java/org/sonar/core/technicaldebt/TechnicalDebtRequirementTest.java +++ b/sonar-core/src/test/java/org/sonar/core/technicaldebt/TechnicalDebtRequirementTest.java @@ -21,95 +21,90 @@ package org.sonar.core.technicaldebt; import org.junit.Test; import org.sonar.api.qualitymodel.Characteristic; -import org.sonar.core.technicaldebt.functions.ConstantFunction; -import org.sonar.core.technicaldebt.functions.LinearFunction; -import org.sonar.core.technicaldebt.functions.LinearWithOffsetFunction; -import org.sonar.core.technicaldebt.functions.LinearWithThresholdFunction; -import static org.hamcrest.Matchers.nullValue; -import static org.hamcrest.core.Is.is; -import static org.junit.Assert.assertThat; +import static org.fest.assertions.Assertions.assertThat; public class TechnicalDebtRequirementTest { @Test - public void defaultFactor() { + public void default_factor() { Characteristic persistedRequirement = Characteristic.createByName("Efficiency"); + TechnicalDebtRequirement requirement = new TechnicalDebtRequirement(persistedRequirement, null); - assertThat(requirement.getRemediationFactor().getValue(), is(WorkUnit.DEFAULT_VALUE)); - assertThat(requirement.getRemediationFactor().getUnit(), is(WorkUnit.DEFAULT_UNIT)); + assertThat(requirement.getRemediationFactor().getValue()).isEqualTo(WorkUnit.DEFAULT_VALUE); + assertThat(requirement.getRemediationFactor().getUnit()).isEqualTo(WorkUnit.DEFAULT_UNIT); } @Test - public void testOverriddenFactor() { + public void overridde_factor() { Characteristic persistedRequirement = Characteristic.createByName("Efficiency"); persistedRequirement.setProperty(TechnicalDebtRequirement.PROPERTY_REMEDIATION_FACTOR, 3.14); + TechnicalDebtRequirement requirement = new TechnicalDebtRequirement(persistedRequirement, null); - assertThat(requirement.getRemediationFactor().getValue(), is(3.14)); - assertThat(requirement.getRemediationFactor().getUnit(), is(WorkUnit.DAYS)); + assertThat(requirement.getRemediationFactor().getValue()).isEqualTo(3.14); + assertThat(requirement.getRemediationFactor().getUnit()).isEqualTo(WorkUnit.DAYS); } @Test - public void defaultFunctionIsLinear() { + public void default_function_is_linear() { Characteristic persistedRequirement = Characteristic.createByName("Efficiency"); + TechnicalDebtRequirement requirement = new TechnicalDebtRequirement(persistedRequirement, null); - assertThat(requirement.getRemediationFunction(), is(LinearFunction.FUNCTION_LINEAR)); - assertThat(requirement.getOffset(), is(nullValue())); + assertThat(requirement.getRemediationFunction()).isEqualTo(TechnicalDebtRequirement.FUNCTION_LINEAR); + assertThat(requirement.getOffset()).isNull(); } @Test - public void testOverriddenFunction() { + public void linear() { Characteristic persistedRequirement = Characteristic.createByName("Efficiency"); - persistedRequirement.setProperty(TechnicalDebtRequirement.PROPERTY_REMEDIATION_FUNCTION, ConstantFunction.FUNCTION_CONSTANT_RESOURCE); + persistedRequirement.setProperty(TechnicalDebtRequirement.PROPERTY_REMEDIATION_FUNCTION, TechnicalDebtRequirement.FUNCTION_LINEAR); + persistedRequirement.setProperty(TechnicalDebtRequirement.PROPERTY_REMEDIATION_FACTOR, 3.14); + TechnicalDebtRequirement requirement = new TechnicalDebtRequirement(persistedRequirement, null); - assertThat(requirement.getRemediationFunction(), is(ConstantFunction.FUNCTION_CONSTANT_RESOURCE)); + assertThat(requirement.getRemediationFunction()).isEqualTo(TechnicalDebtRequirement.FUNCTION_LINEAR); + assertThat(requirement.getRemediationFactor().getValue()).isEqualTo(3.14); + assertThat(requirement.getRemediationFactor().getUnit()).isEqualTo(WorkUnit.DAYS); + assertThat(requirement.getOffset()).isNull(); } @Test - public void testDefaultLinearWithOffset() { + public void default_linear_with_offset() { Characteristic persistedRequirement = Characteristic.createByName("Efficiency"); - persistedRequirement.setProperty(TechnicalDebtRequirement.PROPERTY_REMEDIATION_FUNCTION, LinearWithOffsetFunction.FUNCTION_LINEAR_WITH_OFFSET); + persistedRequirement.setProperty(TechnicalDebtRequirement.PROPERTY_REMEDIATION_FUNCTION, TechnicalDebtRequirement.FUNCTION_LINEAR_WITH_OFFSET); + TechnicalDebtRequirement requirement = new TechnicalDebtRequirement(persistedRequirement, null); - assertThat(requirement.getRemediationFunction(), is(LinearWithOffsetFunction.FUNCTION_LINEAR_WITH_OFFSET)); - assertThat(requirement.getRemediationFactor().getValue(), is(WorkUnit.DEFAULT_VALUE)); - assertThat(requirement.getRemediationFactor().getUnit(), is(WorkUnit.DEFAULT_UNIT)); - assertThat(requirement.getOffset().getValue(), is(WorkUnit.DEFAULT_VALUE)); - assertThat(requirement.getOffset().getUnit(), is(WorkUnit.DEFAULT_UNIT)); + assertThat(requirement.getRemediationFunction()).isEqualTo(TechnicalDebtRequirement.FUNCTION_LINEAR_WITH_OFFSET); + assertThat(requirement.getRemediationFactor().getValue()).isEqualTo(WorkUnit.DEFAULT_VALUE); + assertThat(requirement.getRemediationFactor().getUnit()).isEqualTo(WorkUnit.DEFAULT_UNIT); + assertThat(requirement.getOffset().getValue()).isEqualTo(WorkUnit.DEFAULT_VALUE); + assertThat(requirement.getOffset().getUnit()).isEqualTo(WorkUnit.DEFAULT_UNIT); } @Test - public void testCustomizedLinearWithOffset() { + public void linear_with_offset() { Characteristic persistedRequirement = Characteristic.createByName("Efficiency"); - persistedRequirement.setProperty(TechnicalDebtRequirement.PROPERTY_REMEDIATION_FUNCTION, LinearWithOffsetFunction.FUNCTION_LINEAR_WITH_OFFSET); + persistedRequirement.setProperty(TechnicalDebtRequirement.PROPERTY_REMEDIATION_FUNCTION, TechnicalDebtRequirement.FUNCTION_LINEAR_WITH_OFFSET); persistedRequirement.setProperty(TechnicalDebtRequirement.PROPERTY_OFFSET, 5.0); persistedRequirement.addProperty(persistedRequirement.getProperty(TechnicalDebtRequirement.PROPERTY_OFFSET).setTextValue("h")); - TechnicalDebtRequirement requirement = new TechnicalDebtRequirement(persistedRequirement, null); - assertThat(requirement.getRemediationFunction(), is(LinearWithOffsetFunction.FUNCTION_LINEAR_WITH_OFFSET)); - assertThat(requirement.getOffset().getValue(), is(5.0)); - assertThat(requirement.getOffset().getUnit(), is(WorkUnit.HOURS)); - } - @Test - public void testDefaultLinearWithThreshold() { - Characteristic persistedRequirement = Characteristic.createByName("Efficiency"); - persistedRequirement.setProperty(TechnicalDebtRequirement.PROPERTY_REMEDIATION_FUNCTION, LinearWithThresholdFunction.FUNCTION_LINEAR_WITH_THRESHOLD); TechnicalDebtRequirement requirement = new TechnicalDebtRequirement(persistedRequirement, null); - assertThat(requirement.getRemediationFunction(), is(LinearWithThresholdFunction.FUNCTION_LINEAR_WITH_THRESHOLD)); - assertThat(requirement.getRemediationFactor().getValue(), is(WorkUnit.DEFAULT_VALUE)); - assertThat(requirement.getRemediationFactor().getUnit(), is(WorkUnit.DEFAULT_UNIT)); - assertThat(requirement.getOffset().getValue(), is(WorkUnit.DEFAULT_VALUE)); - assertThat(requirement.getOffset().getUnit(), is(WorkUnit.DEFAULT_UNIT)); + assertThat(requirement.getRemediationFunction()).isEqualTo(TechnicalDebtRequirement.FUNCTION_LINEAR_WITH_OFFSET); + assertThat(requirement.getOffset().getValue()).isEqualTo(5.0); + assertThat(requirement.getOffset().getUnit()).isEqualTo(WorkUnit.HOURS); } @Test - public void testCustomizedLinearWithThreshold() { + public void constant_per_issue() { Characteristic persistedRequirement = Characteristic.createByName("Efficiency"); - persistedRequirement.setProperty(TechnicalDebtRequirement.PROPERTY_REMEDIATION_FUNCTION, LinearWithThresholdFunction.FUNCTION_LINEAR_WITH_THRESHOLD); + persistedRequirement.setProperty(TechnicalDebtRequirement.PROPERTY_REMEDIATION_FUNCTION, TechnicalDebtRequirement.FUNCTION_CONSTANT_PER_ISSUE); persistedRequirement.setProperty(TechnicalDebtRequirement.PROPERTY_OFFSET, 5.0); persistedRequirement.addProperty(persistedRequirement.getProperty(TechnicalDebtRequirement.PROPERTY_OFFSET).setTextValue("h")); + TechnicalDebtRequirement requirement = new TechnicalDebtRequirement(persistedRequirement, null); - assertThat(requirement.getRemediationFunction(), is(LinearWithThresholdFunction.FUNCTION_LINEAR_WITH_THRESHOLD)); - assertThat(requirement.getOffset().getValue(), is(5.0)); - assertThat(requirement.getOffset().getUnit(), is(WorkUnit.HOURS)); + assertThat(requirement.getRemediationFunction()).isEqualTo(TechnicalDebtRequirement.FUNCTION_CONSTANT_PER_ISSUE); + assertThat(requirement.getRemediationFactor()).isNull(); + assertThat(requirement.getOffset().getValue()).isEqualTo(5.0); + assertThat(requirement.getOffset().getUnit()).isEqualTo(WorkUnit.HOURS); } + } diff --git a/sonar-core/src/test/java/org/sonar/core/technicaldebt/TechnicalDebtXMLImporterTest.java b/sonar-core/src/test/java/org/sonar/core/technicaldebt/TechnicalDebtXMLImporterTest.java index cac08a416cb..6e9c94e246a 100644 --- a/sonar-core/src/test/java/org/sonar/core/technicaldebt/TechnicalDebtXMLImporterTest.java +++ b/sonar-core/src/test/java/org/sonar/core/technicaldebt/TechnicalDebtXMLImporterTest.java @@ -22,7 +22,6 @@ package org.sonar.core.technicaldebt; import com.google.common.base.Charsets; import com.google.common.collect.Lists; import com.google.common.io.Resources; -import org.fest.assertions.Assertions; import org.junit.Test; import org.mockito.Matchers; import org.mockito.Mockito; @@ -35,13 +34,15 @@ import org.sonar.api.utils.ValidationMessages; import java.io.IOException; +import static org.fest.assertions.Assertions.assertThat; + public class TechnicalDebtXMLImporterTest { @Test - public void shouldImportXML() { + public void import_xml_with_linear_function() { TechnicalDebtRuleCache technicalDebtRuleCache = mockRuleCache(); - String xml = getFileContent("shouldImportXML.xml"); + String xml = getFileContent("shouldImportXML_with_linear.xml"); ValidationMessages messages = ValidationMessages.create(); Model sqale = new TechnicalDebtXMLImporter().importXML(xml, messages, technicalDebtRuleCache); @@ -50,6 +51,48 @@ public class TechnicalDebtXMLImporterTest { } @Test + public void import_xml_with_linear_with_offset() { + TechnicalDebtRuleCache technicalDebtRuleCache = mockRuleCache(); + + String xml = getFileContent("shouldImportXML_with_linear_with_offset.xml"); + + ValidationMessages messages = ValidationMessages.create(); + Model sqale = new TechnicalDebtXMLImporter().importXML(xml, messages, technicalDebtRuleCache); + + checkXmlCorrectlyImported(sqale, 1.0, messages); + } + + @Test + public void convert_deprecated_linear_with_threshold_function_by_linear_function() { + TechnicalDebtRuleCache technicalDebtRuleCache = mockRuleCache(); + + String xml = getFileContent("shouldImportXML_with_deprecated_linear_with_threshold.xml"); + + ValidationMessages messages = ValidationMessages.create(); + Model sqale = new TechnicalDebtXMLImporter().importXML(xml, messages, technicalDebtRuleCache); + + checkXmlCorrectlyImported(sqale, 0.0, messages); + assertThat(messages.getWarnings()).hasSize(1); + } + + @Test + public void ignore_deprecated_constant_per_file_function() { + TechnicalDebtRuleCache technicalDebtRuleCache = mockRuleCache(); + + String xml = getFileContent("shouldImportXML_with_deprecated_constant_per_file.xml"); + + ValidationMessages messages = ValidationMessages.create(); + Model sqale = new TechnicalDebtXMLImporter().importXML(xml, messages, technicalDebtRuleCache); + + assertThat(messages.getWarnings()).hasSize(1); + + // characteristics + assertThat(sqale.getRootCharacteristics()).hasSize(1); + Characteristic efficiency = sqale.getCharacteristicByKey("EFFICIENCY"); + assertThat(efficiency.getChildren()).isEmpty(); + } + + @Test public void shouldBadlyFormattedImportXML() { TechnicalDebtRuleCache technicalDebtRuleCache = mockRuleCache(); String xml = getFileContent("shouldImportXML_badly-formatted.xml"); @@ -68,13 +111,13 @@ public class TechnicalDebtXMLImporterTest { Model sqale = new TechnicalDebtXMLImporter().importXML(xml, messages, technicalDebtRuleCache); - Assertions.assertThat(messages.getWarnings()).hasSize(1); + assertThat(messages.getWarnings()).hasSize(1); // characteristics - Assertions.assertThat(sqale.getRootCharacteristics()).hasSize(1); + assertThat(sqale.getRootCharacteristics()).hasSize(1); Characteristic efficiency = sqale.getCharacteristicByKey("EFFICIENCY"); - Assertions.assertThat(efficiency.getChildren()).isEmpty(); - Assertions.assertThat(messages.getWarnings().get(0)).contains("findbugs"); + assertThat(efficiency.getChildren()).isEmpty(); + assertThat(messages.getWarnings().get(0)).contains("findbugs"); } @Test @@ -87,8 +130,8 @@ public class TechnicalDebtXMLImporterTest { new TechnicalDebtXMLImporter().importXML(xml, messages, technicalDebtRuleCache); - Assertions.assertThat(messages.getErrors()).hasSize(1); - Assertions.assertThat(messages.getErrors().get(0)).isEqualTo("Cannot import value 'abc' for field factor - Expected a numeric value instead"); + assertThat(messages.getErrors()).hasSize(1); + assertThat(messages.getErrors().get(0)).isEqualTo("Cannot import value 'abc' for field factor - Expected a numeric value instead"); } private TechnicalDebtRuleCache mockRuleCache() { @@ -98,23 +141,28 @@ public class TechnicalDebtXMLImporterTest { } private void checkXmlCorrectlyImported(Model sqale, ValidationMessages messages) { + checkXmlCorrectlyImported(sqale, null, messages); + } + + private void checkXmlCorrectlyImported(Model sqale, Double offset, ValidationMessages messages) { - Assertions.assertThat(messages.getErrors()).isEmpty(); - Assertions.assertThat(sqale.getName()).isEqualTo(TechnicalDebtModel.MODEL_NAME); + assertThat(messages.getErrors()).isEmpty(); + assertThat(sqale.getName()).isEqualTo(TechnicalDebtModel.MODEL_NAME); // characteristics - Assertions.assertThat(sqale.getRootCharacteristics()).hasSize(2); - Assertions.assertThat(sqale.getCharacteristicByKey("USABILITY").getDescription()).isEqualTo("Estimate usability"); + assertThat(sqale.getRootCharacteristics()).hasSize(2); + assertThat(sqale.getCharacteristicByKey("USABILITY").getDescription()).isEqualTo("Estimate usability"); Characteristic efficiency = sqale.getCharacteristicByKey("EFFICIENCY"); - Assertions.assertThat(efficiency.getName()).isEqualTo("Efficiency"); + assertThat(efficiency.getName()).isEqualTo("Efficiency"); // sub-characteristics - Assertions.assertThat(efficiency.getChildren()).hasSize(1); + assertThat(efficiency.getChildren()).hasSize(1); Characteristic requirement = efficiency.getChildren().get(0); - Assertions.assertThat(requirement.getRule().getRepositoryKey()).isEqualTo("checkstyle"); - Assertions.assertThat(requirement.getRule().getKey()).isEqualTo("Regexp"); - Assertions.assertThat(requirement.getPropertyTextValue("function", null)).isEqualTo("linear"); - Assertions.assertThat(requirement.getPropertyValue("factor", null)).isEqualTo(3.2); + assertThat(requirement.getRule().getRepositoryKey()).isEqualTo("checkstyle"); + assertThat(requirement.getRule().getKey()).isEqualTo("Regexp"); + assertThat(requirement.getPropertyTextValue("remediationFunction", null)).isEqualTo("linear"); + assertThat(requirement.getPropertyValue("remediationFactor", null)).isEqualTo(3.2); + assertThat(requirement.getPropertyValue("offset", null)).isEqualTo(offset); } private String getFileContent(String file) { diff --git a/sonar-core/src/test/java/org/sonar/core/technicaldebt/functions/ConstantFunctionTest.java b/sonar-core/src/test/java/org/sonar/core/technicaldebt/functions/ConstantFunctionTest.java deleted file mode 100644 index 1a377123164..00000000000 --- a/sonar-core/src/test/java/org/sonar/core/technicaldebt/functions/ConstantFunctionTest.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * SonarQube, open source software quality management tool. - * Copyright (C) 2008-2013 SonarSource - * mailto:contact AT sonarsource DOT com - * - * SonarQube 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. - * - * SonarQube 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.core.technicaldebt.functions; - -import com.google.common.collect.Lists; -import org.hamcrest.core.Is; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mockito; -import org.sonar.api.config.Settings; -import org.sonar.api.issue.internal.DefaultIssue; -import org.sonar.api.rules.Rule; -import org.sonar.api.rules.Violation; -import org.sonar.core.technicaldebt.TechnicalDebtConverter; -import org.sonar.core.technicaldebt.TechnicalDebtRequirement; -import org.sonar.core.technicaldebt.WorkUnit; - -import java.util.Collection; -import java.util.Collections; - -import static org.fest.assertions.Assertions.assertThat; -import static org.mockito.Mockito.when; - -public class ConstantFunctionTest { - - private TechnicalDebtRequirement requirement; - private Function function; - - @Before - public void before() { - function = new ConstantFunction(new TechnicalDebtConverter(new Settings())); - requirement = Mockito.mock(TechnicalDebtRequirement.class); - Mockito.when(requirement.getRemediationFactor()).thenReturn(WorkUnit.createInDays(3.14)); - } - - @Test - public void zero_if_no_violations() { - Assert.assertThat(function.costInHours(requirement, Collections.<Violation>emptyList()), Is.is(0.0)); - } - - @Test - public void count_as_if_single_violation() { - Collection<Violation> violations = Lists.newArrayList(); - - Rule rule = Rule.create("checkstyle", "foo", "Foo"); - violations.add(new Violation(rule)); - Assert.assertThat(function.costInHours(requirement, violations), Is.is(3.14)); - - violations.add(new Violation(rule)); - Assert.assertThat(function.costInHours(requirement, violations), Is.is(3.14)); - } - - @Test - public void cost_in_minutes() { - when(requirement.getRemediationFactor()).thenReturn(WorkUnit.create(10d, WorkUnit.MINUTES)); - DefaultIssue issue = new DefaultIssue().setKey("ABCDE"); - assertThat(function.costInMinutes(requirement, issue)).isEqualTo(10L); - } -} diff --git a/sonar-core/src/test/java/org/sonar/core/technicaldebt/functions/FunctionsTest.java b/sonar-core/src/test/java/org/sonar/core/technicaldebt/functions/FunctionsTest.java deleted file mode 100644 index e829e8e15e8..00000000000 --- a/sonar-core/src/test/java/org/sonar/core/technicaldebt/functions/FunctionsTest.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * SonarQube, open source software quality management tool. - * Copyright (C) 2008-2013 SonarSource - * mailto:contact AT sonarsource DOT com - * - * SonarQube 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. - * - * SonarQube 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.core.technicaldebt.functions; - -import org.junit.Test; - -import static org.fest.assertions.Assertions.assertThat; - -public class FunctionsTest { - - @Test - public void register_functions() { - Functions functions = new Functions(new Function[]{new LinearFunction(null), new LinearWithOffsetFunction(null), - new ConstantFunction(null)}); - assertThat(functions.getFunction(LinearFunction.FUNCTION_LINEAR)).isInstanceOf(LinearFunction.class); - assertThat(functions.getFunction(LinearWithOffsetFunction.FUNCTION_LINEAR_WITH_OFFSET)).isInstanceOf(LinearWithOffsetFunction.class); - assertThat(functions.getFunction(ConstantFunction.FUNCTION_CONSTANT_RESOURCE)).isInstanceOf(ConstantFunction.class); - assertThat(functions.getFunction("foo")).isNull(); - } -} diff --git a/sonar-core/src/test/java/org/sonar/core/technicaldebt/functions/LinearFunctionTest.java b/sonar-core/src/test/java/org/sonar/core/technicaldebt/functions/LinearFunctionTest.java deleted file mode 100644 index 1b2193298ac..00000000000 --- a/sonar-core/src/test/java/org/sonar/core/technicaldebt/functions/LinearFunctionTest.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * SonarQube, open source software quality management tool. - * Copyright (C) 2008-2013 SonarSource - * mailto:contact AT sonarsource DOT com - * - * SonarQube 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. - * - * SonarQube 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.core.technicaldebt.functions; - -import com.google.common.collect.Lists; -import org.junit.Before; -import org.junit.Test; -import org.sonar.api.config.Settings; -import org.sonar.api.issue.internal.DefaultIssue; -import org.sonar.api.rules.Rule; -import org.sonar.api.rules.Violation; -import org.sonar.core.technicaldebt.TechnicalDebtConverter; -import org.sonar.core.technicaldebt.TechnicalDebtRequirement; -import org.sonar.core.technicaldebt.WorkUnit; - -import java.util.Collection; -import java.util.Collections; - -import static org.fest.assertions.Assertions.assertThat; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -public class LinearFunctionTest { - - private TechnicalDebtRequirement requirement; - private Function function; - - @Before - public void before() { - Settings settings = new Settings(); - settings.setProperty(TechnicalDebtConverter.PROPERTY_HOURS_IN_DAY, 8); - function = new LinearFunction(new TechnicalDebtConverter(settings)); - - requirement = mock(TechnicalDebtRequirement.class); - when(requirement.getRemediationFactor()).thenReturn(WorkUnit.createInDays(3.14)); - } - - @Test - public void zero_if_no_violations() { - assertThat(function.costInHours(requirement, Collections.<Violation>emptyList())).isEqualTo(0.0); - } - - @Test - public void count_every_violation() { - Collection<Violation> violations = Lists.newArrayList(); - - Rule rule = Rule.create("checkstyle", "foo", "Foo"); - violations.add(new Violation(rule)); - assertThat(function.costInHours(requirement, violations)).isEqualTo(3.14); - - violations.add(new Violation(rule)); - assertThat(function.costInHours(requirement, violations)).isEqualTo(3.14 * 2); - } - - @Test - public void use_points_when_available() { - Collection<Violation> violations = Lists.newArrayList(); - - Rule rule = Rule.create("checkstyle", "foo", "Foo"); - violations.add(new Violation(rule).setCost(20.5)); - violations.add(new Violation(rule).setCost(3.8)); - violations.add(new Violation(rule)); - assertThat(function.costInHours(requirement, violations)).isEqualTo(3.14 * (20.5 + 3.8 + 1)); - } - - @Test - public void cost_in_minutes() { - when(requirement.getRemediationFactor()).thenReturn(WorkUnit.create(10d, WorkUnit.MINUTES)); - DefaultIssue issue = new DefaultIssue().setKey("ABCDE").setEffortToFix(2.0); - assertThat(function.costInMinutes(requirement, issue)).isEqualTo(20L); - } - - @Test - public void cost_in_minutes_use_default_cost_when_no_effort_to_fix_on_issue() { - when(requirement.getRemediationFactor()).thenReturn(WorkUnit.create(10d, WorkUnit.MINUTES)); - DefaultIssue issue = new DefaultIssue().setKey("ABCDE").setEffortToFix(null); - assertThat(function.costInMinutes(requirement, issue)).isEqualTo(10L); - } -} diff --git a/sonar-core/src/test/java/org/sonar/core/technicaldebt/functions/LinearWithOffsetFunctionTest.java b/sonar-core/src/test/java/org/sonar/core/technicaldebt/functions/LinearWithOffsetFunctionTest.java deleted file mode 100644 index 1a0b6c03521..00000000000 --- a/sonar-core/src/test/java/org/sonar/core/technicaldebt/functions/LinearWithOffsetFunctionTest.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * SonarQube, open source software quality management tool. - * Copyright (C) 2008-2013 SonarSource - * mailto:contact AT sonarsource DOT com - * - * SonarQube 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. - * - * SonarQube 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.core.technicaldebt.functions; - -import com.google.common.collect.Lists; -import org.hamcrest.core.Is; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mockito; -import org.sonar.api.config.Settings; -import org.sonar.api.rules.Rule; -import org.sonar.api.rules.Violation; -import org.sonar.core.technicaldebt.TechnicalDebtConverter; -import org.sonar.core.technicaldebt.TechnicalDebtRequirement; -import org.sonar.core.technicaldebt.WorkUnit; - -import java.util.Collection; -import java.util.Collections; - -public class LinearWithOffsetFunctionTest { - - private TechnicalDebtRequirement requirement; - private Function function = new LinearWithOffsetFunction(new TechnicalDebtConverter(new Settings())); - - @Before - public void before() { - requirement = Mockito.mock(TechnicalDebtRequirement.class); - Mockito.when(requirement.getRemediationFactor()).thenReturn(WorkUnit.createInDays(3.14)); - Mockito.when(requirement.getOffset()).thenReturn(WorkUnit.createInDays(2.12)); - } - - @Test - public void zeroIfNoViolations() { - Assert.assertThat(function.costInHours(requirement, Collections.<Violation>emptyList()), Is.is(0.0)); - } - - @Test - public void countEveryViolation() { - Collection<Violation> violations = Lists.newArrayList(); - - Rule rule = Rule.create("checkstyle", "foo", "Foo"); - violations.add(new Violation(rule)); - Assert.assertThat(function.costInHours(requirement, violations), Is.is(2.12 + 3.14)); - - violations.add(new Violation(rule)); - Assert.assertThat(function.costInHours(requirement, violations), Is.is(2.12 + 3.14 * 2)); - } -} diff --git a/sonar-core/src/test/java/org/sonar/core/technicaldebt/functions/LinearWithThresholdFunctionTest.java b/sonar-core/src/test/java/org/sonar/core/technicaldebt/functions/LinearWithThresholdFunctionTest.java deleted file mode 100644 index 86c71479c05..00000000000 --- a/sonar-core/src/test/java/org/sonar/core/technicaldebt/functions/LinearWithThresholdFunctionTest.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * SonarQube, open source software quality management tool. - * Copyright (C) 2008-2013 SonarSource - * mailto:contact AT sonarsource DOT com - * - * SonarQube 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. - * - * SonarQube 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.core.technicaldebt.functions; - -import com.google.common.collect.Lists; -import org.hamcrest.core.Is; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mockito; -import org.sonar.api.config.Settings; -import org.sonar.api.rules.Rule; -import org.sonar.api.rules.Violation; -import org.sonar.core.technicaldebt.TechnicalDebtConverter; -import org.sonar.core.technicaldebt.TechnicalDebtRequirement; -import org.sonar.core.technicaldebt.WorkUnit; - -import java.util.Collection; -import java.util.Collections; - -public class LinearWithThresholdFunctionTest { - - private TechnicalDebtRequirement requirement; - private Function function = new LinearWithThresholdFunction(new TechnicalDebtConverter(new Settings())); - - @Before - public void before() { - requirement = Mockito.mock(TechnicalDebtRequirement.class); - Mockito.when(requirement.getRemediationFactor()).thenReturn(WorkUnit.createInDays(2.0)); - Mockito.when(requirement.getOffset()).thenReturn(WorkUnit.createInDays(5.0)); - } - - @Test - public void zeroIfNoViolations() { - Assert.assertThat(function.costInHours(requirement, Collections.<Violation>emptyList()), Is.is(0.0)); - } - - @Test - public void countEveryViolationAndCheckThreshold() { - Collection<Violation> violations = Lists.newArrayList(); - - Rule rule = Rule.create("checkstyle", "foo", "Foo"); - violations.add(new Violation(rule)); - Assert.assertThat(function.costInHours(requirement, violations), Is.is(5.0)); - - violations.add(new Violation(rule)); - Assert.assertThat(function.costInHours(requirement, violations), Is.is(5.0)); - - violations.add(new Violation(rule)); - Assert.assertThat(function.costInHours(requirement, violations), Is.is(6.0)); - } -} diff --git a/sonar-core/src/test/resources/org/sonar/core/technicaldebt/TechnicalDebtXMLImporterTest/shouldImportXML_badly-formatted.xml b/sonar-core/src/test/resources/org/sonar/core/technicaldebt/TechnicalDebtXMLImporterTest/shouldImportXML_badly-formatted.xml index 373959f1a72..e55fa2d003b 100644 --- a/sonar-core/src/test/resources/org/sonar/core/technicaldebt/TechnicalDebtXMLImporterTest/shouldImportXML_badly-formatted.xml +++ b/sonar-core/src/test/resources/org/sonar/core/technicaldebt/TechnicalDebtXMLImporterTest/shouldImportXML_badly-formatted.xml @@ -19,13 +19,13 @@ <rule-key>Regexp </rule-key> <prop> - <key>factor + <key>remediationFactor </key> <val>3.2 </val> </prop> <prop> - <key>function + <key>remediationFunction </key> <txt>linear </txt> @@ -33,4 +33,4 @@ </chc> </chc> -</sqale>
\ No newline at end of file +</sqale> diff --git a/sonar-core/src/test/resources/org/sonar/core/technicaldebt/TechnicalDebtXMLImporterTest/shouldImportXML_with_deprecated_constant_per_file.xml b/sonar-core/src/test/resources/org/sonar/core/technicaldebt/TechnicalDebtXMLImporterTest/shouldImportXML_with_deprecated_constant_per_file.xml new file mode 100644 index 00000000000..2e13e2bd2a4 --- /dev/null +++ b/sonar-core/src/test/resources/org/sonar/core/technicaldebt/TechnicalDebtXMLImporterTest/shouldImportXML_with_deprecated_constant_per_file.xml @@ -0,0 +1,20 @@ +<sqale> + <chc> + <key>EFFICIENCY</key> + <name>Efficiency</name> + <!-- Should be ignored --> + <chc> + <rule-repo>checkstyle</rule-repo> + <rule-key>Regexp</rule-key> + <prop> + <key>remediationFactor</key> + <val>3.2</val> + </prop> + <prop> + <key>remediationFunction</key> + <txt>constant_resource</txt> + </prop> + </chc> + </chc> + +</sqale> diff --git a/sonar-core/src/test/resources/org/sonar/core/technicaldebt/TechnicalDebtXMLImporterTest/shouldImportXML_with_deprecated_linear_with_threshold.xml b/sonar-core/src/test/resources/org/sonar/core/technicaldebt/TechnicalDebtXMLImporterTest/shouldImportXML_with_deprecated_linear_with_threshold.xml new file mode 100644 index 00000000000..f46aea6e872 --- /dev/null +++ b/sonar-core/src/test/resources/org/sonar/core/technicaldebt/TechnicalDebtXMLImporterTest/shouldImportXML_with_deprecated_linear_with_threshold.xml @@ -0,0 +1,32 @@ +<sqale> + <chc> + <key>USABILITY</key> + <name>Usability</name> + <desc>Estimate usability</desc> + </chc> + <chc> + <key>EFFICIENCY</key> + <name>Efficiency</name> + <chc> + <rule-repo>checkstyle</rule-repo> + <rule-key>Regexp</rule-key> + <prop> + <key>remediationFunction</key> + <!-- Should be replaced by linear --> + <txt>linear_threshold</txt> + </prop> + <prop> + <key>remediationFactor</key> + <val>3.2</val> + <txt>h</txt> + </prop> + <!-- Should be ignored --> + <prop> + <key>offset</key> + <val>1.0</val> + <txt>h</txt> + </prop> + </chc> + </chc> + +</sqale> diff --git a/sonar-core/src/test/resources/org/sonar/core/technicaldebt/TechnicalDebtXMLImporterTest/shouldImportXML.xml b/sonar-core/src/test/resources/org/sonar/core/technicaldebt/TechnicalDebtXMLImporterTest/shouldImportXML_with_linear.xml index e4051894cb0..480df8f2d94 100644 --- a/sonar-core/src/test/resources/org/sonar/core/technicaldebt/TechnicalDebtXMLImporterTest/shouldImportXML.xml +++ b/sonar-core/src/test/resources/org/sonar/core/technicaldebt/TechnicalDebtXMLImporterTest/shouldImportXML_with_linear.xml @@ -12,14 +12,14 @@ <rule-repo>checkstyle</rule-repo> <rule-key>Regexp</rule-key> <prop> - <key>factor</key> + <key>remediationFactor</key> <val>3.2</val> </prop> <prop> - <key>function</key> + <key>remediationFunction</key> <txt>linear</txt> </prop> </chc> </chc> -</sqale>
\ No newline at end of file +</sqale> diff --git a/sonar-core/src/test/resources/org/sonar/core/technicaldebt/TechnicalDebtXMLImporterTest/shouldImportXML_with_linear_with_offset.xml b/sonar-core/src/test/resources/org/sonar/core/technicaldebt/TechnicalDebtXMLImporterTest/shouldImportXML_with_linear_with_offset.xml new file mode 100644 index 00000000000..768b43b8242 --- /dev/null +++ b/sonar-core/src/test/resources/org/sonar/core/technicaldebt/TechnicalDebtXMLImporterTest/shouldImportXML_with_linear_with_offset.xml @@ -0,0 +1,30 @@ +<sqale> + <chc> + <key>USABILITY</key> + <name>Usability</name> + <desc>Estimate usability</desc> + </chc> + <chc> + <key>EFFICIENCY</key> + <name>Efficiency</name> + + <chc> + <rule-repo>checkstyle</rule-repo> + <rule-key>Regexp</rule-key> + <prop> + <key>remediationFactor</key> + <val>3.2</val> + </prop> + <prop> + <key>remediationFunction</key> + <txt>linear</txt> + </prop> + <prop> + <key>offset</key> + <val>1.0</val> + <txt>h</txt> + </prop> + </chc> + </chc> + +</sqale> |