aboutsummaryrefslogtreecommitdiffstats
path: root/sonar-plugin-api
diff options
context:
space:
mode:
authorsimonbrandhof <simon.brandhof@gmail.com>2011-02-25 00:16:09 +0100
committersimonbrandhof <simon.brandhof@gmail.com>2011-02-25 07:44:16 +0100
commitd4beaec49895945d23d509d1502790794b008d56 (patch)
treee10aef01542a6de8a4b00b985870dfdcdbc3a700 /sonar-plugin-api
parent2dc09dd0800e0fca575133775e4b97dc5f711104 (diff)
downloadsonarqube-d4beaec49895945d23d509d1502790794b008d56.tar.gz
sonarqube-d4beaec49895945d23d509d1502790794b008d56.zip
SONAR-2218 Add CoverageMeasuresBuilder to API + add Metric.Builder, first step to get an immutable Metric class
Diffstat (limited to 'sonar-plugin-api')
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/measures/CoreMetrics.java107
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/measures/CoverageMeasuresBuilder.java161
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/measures/Measure.java72
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/measures/Metric.java97
-rw-r--r--sonar-plugin-api/src/test/java/org/sonar/api/measures/CoverageMeasuresBuilderTest.java128
-rw-r--r--sonar-plugin-api/src/test/java/org/sonar/api/measures/MetricTest.java59
6 files changed, 573 insertions, 51 deletions
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/measures/CoreMetrics.java b/sonar-plugin-api/src/main/java/org/sonar/api/measures/CoreMetrics.java
index 0b5c68efb46..d7c94b4853b 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/measures/CoreMetrics.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/measures/CoreMetrics.java
@@ -19,15 +19,13 @@
*/
package org.sonar.api.measures;
+import com.google.common.collect.Lists;
import org.apache.commons.lang.StringUtils;
import org.sonar.api.resources.Scopes;
import org.sonar.api.utils.SonarException;
import java.lang.reflect.Field;
-import java.util.ArrayList;
-import java.util.HashSet;
import java.util.List;
-import java.util.Set;
/**
* @since 1.10
@@ -43,6 +41,7 @@ public final class CoreMetrics {
public static final String DOMAIN_COMPLEXITY = "Complexity";
public static final String DOMAIN_DOCUMENTATION = "Documentation";
public static final String DOMAIN_RULES = "Rules";
+ public static final String DOMAIN_SCM = "SCM";
/**
* @deprecated since 2.5 See http://jira.codehaus.org/browse/SONAR-2007
@@ -180,7 +179,12 @@ public final class CoreMetrics {
"Commented lines of code", Metric.ValueType.INT, Metric.DIRECTION_WORST, true, DOMAIN_DOCUMENTATION).setFormula(
new SumChildValuesFormula(false)).setBestValue(0.0).setOptimizedBestValue(true);
- /* unit tests */
+
+
+
+
+ // UNIT TESTS
+
public static final String TESTS_KEY = "tests";
public static final Metric TESTS = new Metric(TESTS_KEY, "Unit tests", "Number of unit tests", Metric.ValueType.INT,
Metric.DIRECTION_WORST, false, DOMAIN_TESTS);
@@ -214,33 +218,83 @@ public final class CoreMetrics {
public static final Metric LINES_TO_COVER = new Metric(LINES_TO_COVER_KEY, "Lines to cover", "Lines to cover", Metric.ValueType.INT,
Metric.DIRECTION_BETTER, false, DOMAIN_TESTS).setFormula(new SumChildValuesFormula(false)).setHidden(true);
+
public static final String UNCOVERED_LINES_KEY = "uncovered_lines";
- public static final Metric UNCOVERED_LINES = new Metric(UNCOVERED_LINES_KEY, "Uncovered lines", "Uncovered lines", Metric.ValueType.INT,
- Metric.DIRECTION_WORST, false, DOMAIN_TESTS).setFormula(new SumChildValuesFormula(false));
+ public static final Metric UNCOVERED_LINES = new Metric.Builder(UNCOVERED_LINES_KEY, Metric.ValueType.INT)
+ .setName("Uncovered lines")
+ .setDescription("Uncovered lines")
+ .setDirection(Metric.DIRECTION_WORST)
+ .setDomain(DOMAIN_TESTS)
+ .setFormula(new SumChildValuesFormula(false))
+ .create();
+
+ public static final String NEW_UNCOVERED_LINES_KEY = "new_uncovered_lines";
+ public static final Metric NEW_UNCOVERED_LINES = new Metric.Builder(NEW_UNCOVERED_LINES_KEY, Metric.ValueType.INT)
+ .setName("New uncovered lines")
+ .setDescription("New uncovered lines")
+ .setDirection(Metric.DIRECTION_WORST)
+ .setDomain(DOMAIN_TESTS)
+ .setFormula(new SumChildValuesFormula(false))
+ .create();
public static final String LINE_COVERAGE_KEY = "line_coverage";
public static final Metric LINE_COVERAGE = new Metric(LINE_COVERAGE_KEY, "Line coverage", "Line coverage", Metric.ValueType.PERCENT,
Metric.DIRECTION_BETTER, true, DOMAIN_TESTS);
public static final String COVERAGE_LINE_HITS_DATA_KEY = "coverage_line_hits_data";
- public static final Metric COVERAGE_LINE_HITS_DATA = new Metric(COVERAGE_LINE_HITS_DATA_KEY, "Coverage hits data",
- "Code coverage line hits data", Metric.ValueType.DATA, Metric.DIRECTION_NONE, false, DOMAIN_TESTS);
+ public static final Metric COVERAGE_LINE_HITS_DATA = new Metric.Builder(COVERAGE_LINE_HITS_DATA_KEY, Metric.ValueType.DATA)
+ .setDomain(DOMAIN_TESTS)
+ .create();
public static final String CONDITIONS_TO_COVER_KEY = "conditions_to_cover";
public static final Metric CONDITIONS_TO_COVER = new Metric(CONDITIONS_TO_COVER_KEY, "Conditions to cover", "Conditions to cover",
Metric.ValueType.INT, Metric.DIRECTION_BETTER, false, DOMAIN_TESTS).setFormula(new SumChildValuesFormula(false)).setHidden(true);
public static final String UNCOVERED_CONDITIONS_KEY = "uncovered_conditions";
- public static final Metric UNCOVERED_CONDITIONS = new Metric(UNCOVERED_CONDITIONS_KEY, "Uncovered conditions", "Uncovered conditions",
- Metric.ValueType.INT, Metric.DIRECTION_WORST, false, DOMAIN_TESTS).setFormula(new SumChildValuesFormula(false));
+ public static final Metric UNCOVERED_CONDITIONS = new Metric.Builder(UNCOVERED_CONDITIONS_KEY, Metric.ValueType.INT)
+ .setName("Uncovered conditions")
+ .setDescription("Uncovered conditions")
+ .setDirection(Metric.DIRECTION_WORST)
+ .setDomain(DOMAIN_TESTS)
+ .setFormula(new SumChildValuesFormula(false))
+ .create();
+
+ public static final String NEW_UNCOVERED_CONDITIONS_KEY = "new_uncovered_conditions";
+ public static final Metric NEW_UNCOVERED_CONDITIONS = new Metric.Builder(NEW_UNCOVERED_CONDITIONS_KEY, Metric.ValueType.INT)
+ .setName("New uncovered conditions")
+ .setDescription("New uncovered conditions")
+ .setDirection(Metric.DIRECTION_WORST)
+ .setDomain(DOMAIN_TESTS)
+ .setFormula(new SumChildValuesFormula(false))
+ .create();
public static final String BRANCH_COVERAGE_KEY = "branch_coverage";
public static final Metric BRANCH_COVERAGE = new Metric(BRANCH_COVERAGE_KEY, "Branch coverage", "Branch coverage",
Metric.ValueType.PERCENT, Metric.DIRECTION_BETTER, true, DOMAIN_TESTS).setWorstValue(0.0).setBestValue(100.0);
public static final String BRANCH_COVERAGE_HITS_DATA_KEY = "branch_coverage_hits_data";
- public static final Metric BRANCH_COVERAGE_HITS_DATA = new Metric(BRANCH_COVERAGE_HITS_DATA_KEY, "Branch coverage hits",
- "Branch coverage hits", Metric.ValueType.DATA, Metric.DIRECTION_NONE, false, DOMAIN_TESTS);
+ public static final Metric BRANCH_COVERAGE_HITS_DATA = new Metric.Builder(BRANCH_COVERAGE_HITS_DATA_KEY, Metric.ValueType.DATA)
+ .setName("Branch coverage hits")
+ .setDomain(DOMAIN_TESTS)
+ .create();
+
+ public static final String CONDITIONS_BY_LINE_DATA_KEY = "conditions_by_line_data";
+
+ /**
+ * @since 2.7
+ */
+ public static final Metric CONDITIONS_BY_LINE_DATA = new Metric.Builder(CONDITIONS_BY_LINE_DATA_KEY, Metric.ValueType.DATA)
+ .setDomain(DOMAIN_TESTS)
+ .create();
+
+ public static final String COVERED_CONDITIONS_BY_LINE_DATA_KEY = "covered_conditions_by_line_data";
+
+ /**
+ * @since 2.7
+ */
+ public static final Metric COVERED_CONDITIONS_BY_LINE_DATA = new Metric.Builder(COVERED_CONDITIONS_BY_LINE_DATA_KEY, Metric.ValueType.DATA)
+ .setDomain(DOMAIN_TESTS)
+ .create();
/**
* @deprecated replaced since 1.11 by UNCOVERED_LINES and UNCOVERED_CONDITIONS
@@ -398,7 +452,11 @@ public final class CoreMetrics {
public static final Metric NEW_INFO_VIOLATIONS = new Metric(NEW_INFO_VIOLATIONS_KEY, "New Info violations", "New Info violations",
Metric.ValueType.INT, Metric.DIRECTION_WORST, true, DOMAIN_RULES).setHidden(true).setBestValue(0.0).setOptimizedBestValue(true);
- /* Design */
+
+
+
+
+ // DESIGN
public static final String ABSTRACTNESS_KEY = "abstractness";
public static final Metric ABSTRACTNESS = new Metric(ABSTRACTNESS_KEY, "Abstractness", "Abstractness", Metric.ValueType.PERCENT,
@@ -506,9 +564,28 @@ public final class CoreMetrics {
public static final Metric PROFILE = new Metric(PROFILE_KEY, "Profile", "Selected quality profile", Metric.ValueType.DATA,
Metric.DIRECTION_NONE, false, DOMAIN_GENERAL);
- public static List<Metric> metrics = new ArrayList<Metric>();
- public static Set<String> metricKeys = new HashSet<String>();
+
+
+
+ // SCM
+
+ public static final String SCM_AUTHORS_BY_LINE_KEY = "blame_authors_data";//"scm_authors_by_line";
+ public static final Metric SCM_AUTHORS_BY_LINE = new Metric.Builder(SCM_AUTHORS_BY_LINE_KEY, Metric.ValueType.DATA)
+ .setDomain(DOMAIN_SCM)
+ .create();
+
+ public static final String SCM_REVISIONS_BY_LINE_KEY = "blame_revision_data";//"scm_revisions_by_line";
+ public static final Metric SCM_REVISIONS_BY_LINE = new Metric.Builder(SCM_REVISIONS_BY_LINE_KEY, Metric.ValueType.DATA)
+ .setDomain(DOMAIN_SCM)
+ .create();
+
+ public static final String SCM_LAST_UPDATE_DATETIME_BY_LINE_KEY = "blame_date_data";//"scm_last_update_datetime_by_line";
+ public static final Metric SCM_LAST_UPDATE_DATETIME_BY_LINE = new Metric.Builder(SCM_LAST_UPDATE_DATETIME_BY_LINE_KEY, Metric.ValueType.DATA)
+ .setDomain(DOMAIN_SCM)
+ .create();
+
+ public static List<Metric> metrics = Lists.newLinkedList();
public static List<Metric> getMetrics() {
if (metrics.isEmpty()) {
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/measures/CoverageMeasuresBuilder.java b/sonar-plugin-api/src/main/java/org/sonar/api/measures/CoverageMeasuresBuilder.java
new file mode 100644
index 00000000000..dfc37496a54
--- /dev/null
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/measures/CoverageMeasuresBuilder.java
@@ -0,0 +1,161 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2011 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * Sonar 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.
+ *
+ * Sonar 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 Sonar; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
+ */
+package org.sonar.api.measures;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import org.sonar.api.utils.KeyValueFormat;
+
+import java.util.*;
+
+/**
+ * @since 2.7
+ */
+public final class CoverageMeasuresBuilder {
+
+ /**
+ * Metrics of generated measures
+ */
+ public static final List<Metric> METRICS = Arrays.asList(
+ CoreMetrics.LINES_TO_COVER, CoreMetrics.UNCOVERED_LINES, CoreMetrics.COVERAGE_LINE_HITS_DATA,
+ CoreMetrics.CONDITIONS_TO_COVER, CoreMetrics.UNCOVERED_CONDITIONS, CoreMetrics.CONDITIONS_BY_LINE_DATA,
+ CoreMetrics.COVERED_CONDITIONS_BY_LINE_DATA, CoreMetrics.BRANCH_COVERAGE_HITS_DATA);
+
+
+ private int totalCoveredLines = 0, totalConditions = 0, totalCoveredConditions = 0;
+ private SortedMap<Integer, Integer> hitsByLine = Maps.newTreeMap();
+ private SortedMap<Integer, Integer> conditionsByLine = Maps.newTreeMap();
+ private SortedMap<Integer, Integer> coveredConditionsByLine = Maps.newTreeMap();
+
+ private CoverageMeasuresBuilder() {
+ // use the factory
+ }
+
+ public CoverageMeasuresBuilder reset() {
+ totalCoveredLines = 0;
+ totalConditions = 0;
+ totalCoveredConditions = 0;
+ hitsByLine.clear();
+ conditionsByLine.clear();
+ coveredConditionsByLine.clear();
+ return this;
+ }
+
+ public CoverageMeasuresBuilder setHits(int lineId, int hits) {
+ if (hitsByLine.containsKey(lineId)) {
+ throw new IllegalArgumentException("Line " + lineId + " is count twice (hits=" + hits + ")");
+ }
+ hitsByLine.put(lineId, hits);
+ if (hits > 0) {
+ totalCoveredLines += 1;
+ }
+ return this;
+ }
+
+ public CoverageMeasuresBuilder setConditions(int lineId, int conditions, int coveredConditions) {
+ if (conditionsByLine.containsKey(lineId)) {
+ throw new IllegalArgumentException("Line " + lineId + " is count twice (conditions=" + conditions + ")");
+ }
+ if (conditions > 0) {
+ totalConditions += conditions;
+ totalCoveredConditions += coveredConditions;
+ conditionsByLine.put(lineId, conditions);
+ coveredConditionsByLine.put(lineId, coveredConditions);
+ }
+ return this;
+ }
+
+ public int getCoveredLines() {
+ return totalCoveredLines;
+ }
+
+ public int getLinesToCover() {
+ return hitsByLine.size();
+ }
+
+ public int getConditions() {
+ return totalConditions;
+ }
+
+ public int getCoveredConditions() {
+ return totalCoveredConditions;
+ }
+
+ public SortedMap<Integer, Integer> getHitsByLine() {
+ return Collections.unmodifiableSortedMap(hitsByLine);
+ }
+
+ public SortedMap<Integer, Integer> getConditionsByLine() {
+ return Collections.unmodifiableSortedMap(conditionsByLine);
+ }
+
+ public SortedMap<Integer, Integer> getCoveredConditionsByLine() {
+ return Collections.unmodifiableSortedMap(coveredConditionsByLine);
+ }
+
+ public Collection<Measure> createMeasures() {
+ Collection<Measure> measures = Lists.newArrayList();
+ if (getLinesToCover() > 0) {
+ measures.add(new Measure(CoreMetrics.LINES_TO_COVER, (double) getLinesToCover()));
+ measures.add(new Measure(CoreMetrics.UNCOVERED_LINES, (double) (getLinesToCover() - getCoveredLines())));
+ measures.add(new Measure(CoreMetrics.COVERAGE_LINE_HITS_DATA).setData(KeyValueFormat.format(hitsByLine)).setPersistenceMode(PersistenceMode.DATABASE));
+ }
+ if (getConditions() > 0) {
+ measures.add(new Measure(CoreMetrics.CONDITIONS_TO_COVER, (double) getConditions()));
+ measures.add(new Measure(CoreMetrics.UNCOVERED_CONDITIONS, (double) (getConditions() - getCoveredConditions())));
+ measures.add(createConditionsByLineData());
+ measures.add(createCoveredConditionsByLineData());
+ measures.add(createBranchCoverageByLine());
+ }
+ return measures;
+ }
+
+ private Measure createCoveredConditionsByLineData() {
+ return new Measure(CoreMetrics.COVERED_CONDITIONS_BY_LINE_DATA)
+ .setData(KeyValueFormat.format(coveredConditionsByLine))
+ .setPersistenceMode(PersistenceMode.DATABASE);
+ }
+
+ private Measure createConditionsByLineData() {
+ return new Measure(CoreMetrics.CONDITIONS_BY_LINE_DATA)
+ .setData(KeyValueFormat.format(conditionsByLine))
+ .setPersistenceMode(PersistenceMode.DATABASE);
+ }
+
+ private Measure createBranchCoverageByLine() {
+ PropertiesBuilder<Integer, String> builder = new PropertiesBuilder<Integer, String>(CoreMetrics.BRANCH_COVERAGE_HITS_DATA);
+ for (Map.Entry<Integer, Integer> entry : conditionsByLine.entrySet()) {
+ Integer lineId = entry.getKey();
+ int conditions = entry.getValue();
+ int coveredConditions = coveredConditionsByLine.get(lineId);
+ builder.add(lineId, formatBranchCoverage(conditions, coveredConditions));
+ }
+ return builder.build().setPersistenceMode(PersistenceMode.DATABASE);
+ }
+
+ static String formatBranchCoverage(int conditions, int coveredConditions) {
+ long branchCoverage = Math.round(100.0 * coveredConditions / conditions);
+ return branchCoverage + "%";
+ }
+
+ public static CoverageMeasuresBuilder create() {
+ return new CoverageMeasuresBuilder();
+ }
+}
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/measures/Measure.java b/sonar-plugin-api/src/main/java/org/sonar/api/measures/Measure.java
index e27d13cf69e..3b64b89da3f 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/measures/Measure.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/measures/Measure.java
@@ -28,7 +28,7 @@ import java.util.Date;
/**
* A class to handle measures.
- *
+ *
* @since 1.10
*/
public class Measure {
@@ -60,7 +60,7 @@ public class Measure {
/**
* Creates a measure with a metric
- *
+ *
* @param metric the metric
*/
public Measure(Metric metric) {
@@ -70,9 +70,9 @@ public class Measure {
/**
* Creates a measure with a metric and a value
- *
+ *
* @param metric the metric
- * @param value its value
+ * @param value its value
*/
public Measure(Metric metric, Double value) {
this.metric = metric;
@@ -82,9 +82,9 @@ public class Measure {
/**
* Creates a measure with a metric, a value and a precision for the value
- *
- * @param metric the metric
- * @param value its value
+ *
+ * @param metric the metric
+ * @param value its value
* @param precision the value precision
*/
public Measure(Metric metric, Double value, int precision) {
@@ -95,10 +95,10 @@ public class Measure {
/**
* Creates a measure with a metric, a value and a data field
- *
+ *
* @param metric the metric
- * @param value the value
- * @param data the data field
+ * @param value the value
+ * @param data the data field
*/
public Measure(Metric metric, Double value, String data) {
this.metric = metric;
@@ -109,9 +109,9 @@ public class Measure {
/**
* * Creates a measure with a metric and a data field
- *
+ *
* @param metric the metric
- * @param data the data field
+ * @param data the data field
*/
public Measure(Metric metric, String data) {
this.metric = metric;
@@ -121,9 +121,9 @@ public class Measure {
/**
* Creates a measure with a metric and an alert level
- *
+ *
* @param metric the metric
- * @param level the alert level
+ * @param level the alert level
*/
public Measure(Metric metric, Metric.Level level) {
this.metric = metric;
@@ -156,7 +156,7 @@ public class Measure {
* example, a measure save in memory at the module level will not be accessible by the root project. In that case, database should be
* used.
* </p>
- *
+ *
* @param mode the mode
* @return the measure object instance
*/
@@ -178,7 +178,7 @@ public class Measure {
/**
* Set the underlying metric
- *
+ *
* @param metric the metric
* @return the measure object instance
*/
@@ -198,6 +198,10 @@ public class Measure {
return null;
}
+ public boolean hasData() {
+ return data != null;
+ }
+
/**
* @return the date of the measure, i.e. the date the measure was taken. Used only in TimeMachine queries
*/
@@ -207,7 +211,7 @@ public class Measure {
/**
* Sets the date of the measure - Used only in TimeMachine queries
- *
+ *
* @param date the date
* @return the measure object instance
*/
@@ -235,7 +239,7 @@ public class Measure {
/**
* Sets the measure value with the default precision of 1
- *
+ *
* @param v the measure value
* @return the measure object instance
*/
@@ -245,7 +249,7 @@ public class Measure {
/**
* Sets the measure value as an int
- *
+ *
* @param i the value
* @return the measure object instance
*/
@@ -260,8 +264,8 @@ public class Measure {
/**
* Sets the measure value with a given precision
- *
- * @param v the measure value
+ *
+ * @param v the measure value
* @param precision the measure value precision
* @return the measure object instance
*/
@@ -291,7 +295,7 @@ public class Measure {
/**
* Sets the data field of the measure.
- *
+ *
* @param s the data
* @return the measure object instance
*/
@@ -305,7 +309,7 @@ public class Measure {
/**
* Sets an alert level as the data field
- *
+ *
* @param level the alert level
* @return the measure object instance
*/
@@ -327,7 +331,7 @@ public class Measure {
/**
* Sets the measure description
- *
+ *
* @param description the description
* @return the measure object instance
*/
@@ -345,7 +349,7 @@ public class Measure {
/**
* Set the alert status of the measure
- *
+ *
* @param status the status
* @return the measure object instance
*/
@@ -363,7 +367,7 @@ public class Measure {
/**
* Sets the text associated to the alert on the measure
- *
+ *
* @param alertText the text
* @return the measure object instance
*/
@@ -374,7 +378,7 @@ public class Measure {
/**
* Gets the measure tendency
- *
+ *
* @return the tendency
*/
public Integer getTendency() {
@@ -383,7 +387,7 @@ public class Measure {
/**
* Sets the tendency for the measure - Internal use only
- *
+ *
* @param tendency the tendency
* @return the measure object instance
*/
@@ -401,7 +405,7 @@ public class Measure {
/**
* Sets the measure id - Internal use only
- *
+ *
* @param id the id
* @return the measure object instance
*/
@@ -420,7 +424,7 @@ public class Measure {
/**
* Internal use only
- *
+ *
* @since 2.5
*/
public Measure setVariation1(Double d) {
@@ -438,7 +442,7 @@ public class Measure {
/**
* Internal use only
- *
+ *
* @since 2.5
*/
public Measure setVariation2(Double d) {
@@ -456,7 +460,7 @@ public class Measure {
/**
* Internal use only
- *
+ *
* @since 2.5
*/
public Measure setVariation3(Double d) {
@@ -522,7 +526,7 @@ public class Measure {
/**
* Internal use only
- *
+ *
* @since 2.5
*/
public Measure setVariation(int index, Double d) {
@@ -557,7 +561,7 @@ public class Measure {
/**
* Sets the URL of the measure
- *
+ *
* @param url the url
* @return the measure object instance
*/
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/measures/Metric.java b/sonar-plugin-api/src/main/java/org/sonar/api/measures/Metric.java
index 781b63eef13..92050c92d81 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/measures/Metric.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/measures/Metric.java
@@ -105,7 +105,7 @@ public class Metric implements ServerExtension, BatchExtension {
@Column(name = "origin", updatable = true, nullable = true, length = 3)
@Enumerated(EnumType.STRING)
- private Origin origin;
+ private Origin origin = Origin.JAV;
@Column(name = "worst_value", updatable = true, nullable = true, precision = 30, scale = 20)
private Double worstValue;
@@ -119,7 +119,6 @@ public class Metric implements ServerExtension, BatchExtension {
@Column(name = "hidden", updatable = true, nullable = true)
private Boolean hidden = Boolean.FALSE;
-
/**
* Creates an empty metric
*/
@@ -216,6 +215,23 @@ public class Metric implements ServerExtension, BatchExtension {
}
}
+ private Metric(String key, String name, ValueType type, String description, Integer direction, String domain, Boolean qualitative, Double worstValue, Double bestValue, Boolean optimizedBestValue, Boolean hidden, Formula formula) {
+ this.key = key;
+ this.name = name;
+ this.description = description;
+ this.type = type;
+ this.direction = direction;
+ this.domain = domain;
+ this.qualitative = qualitative;
+ this.userManaged = Boolean.FALSE;
+ this.enabled = Boolean.TRUE;
+ this.worstValue = worstValue;
+ this.optimizedBestValue = optimizedBestValue;
+ this.bestValue = bestValue;
+ this.hidden = hidden;
+ this.formula = formula;
+ }
+
/**
* For internal use only
*/
@@ -554,4 +570,81 @@ public class Metric implements ServerExtension, BatchExtension {
this.hidden = with.hidden;
return this;
}
+
+ public static final class Builder {
+ private String key;
+ private Metric.ValueType type;
+ private String name;
+ private String description;
+ private Integer direction = DIRECTION_NONE;
+ private Boolean qualitative = Boolean.FALSE;
+ private String domain = null;
+ private Formula formula;
+ private Double worstValue;
+ private Double bestValue;
+ private boolean optimizedBestValue = false;
+ private boolean hidden = false;
+
+ public Builder(String key, ValueType type) {
+ this.key = key;
+ this.type = type;
+ }
+
+ public Builder setName(String s) {
+ this.name = s;
+ return this;
+ }
+
+ public Builder setDescription(String s) {
+ this.description = s;
+ return this;
+ }
+
+ /**
+ * Used for numeric values only
+ */
+ public Builder setDirection(Integer i) {
+ this.direction = i;
+ return this;
+ }
+
+ public Builder setQualitative(Boolean b) {
+ this.qualitative = b;
+ return this;
+ }
+
+ public Builder setDomain(String s) {
+ this.domain = s;
+ return this;
+ }
+
+ public Builder setFormula(Formula f) {
+ this.formula = f;
+ return this;
+ }
+
+ public Builder setWorstValue(Double d) {
+ this.worstValue = d;
+ return this;
+ }
+
+ public Builder setBestValue(Double d) {
+ this.bestValue = d;
+ return this;
+ }
+
+ public Builder setOptimizedBestValue(boolean b) {
+ this.optimizedBestValue = b;
+ return this;
+ }
+
+ public Builder setHidden(boolean b) {
+ this.hidden = b;
+ return this;
+ }
+
+ public Metric create() {
+ return new Metric(key, name, type, description, direction, domain, qualitative, worstValue, bestValue, optimizedBestValue, hidden, formula);
+ }
+ }
}
diff --git a/sonar-plugin-api/src/test/java/org/sonar/api/measures/CoverageMeasuresBuilderTest.java b/sonar-plugin-api/src/test/java/org/sonar/api/measures/CoverageMeasuresBuilderTest.java
new file mode 100644
index 00000000000..12c43709c37
--- /dev/null
+++ b/sonar-plugin-api/src/test/java/org/sonar/api/measures/CoverageMeasuresBuilderTest.java
@@ -0,0 +1,128 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2011 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * Sonar 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.
+ *
+ * Sonar 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 Sonar; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
+ */
+package org.sonar.api.measures;
+
+import org.junit.Test;
+
+import java.util.Collection;
+
+import static org.hamcrest.core.Is.is;
+import static org.junit.Assert.assertThat;
+
+public class CoverageMeasuresBuilderTest {
+
+ @Test
+ public void shouldNotCreateIfNoValues() {
+ CoverageMeasuresBuilder builder = CoverageMeasuresBuilder.create();
+ assertThat(builder.createMeasures().size(), is(0));
+ }
+
+ @Test
+ public void shouldCreateHitsByLineData() {
+ CoverageMeasuresBuilder builder = CoverageMeasuresBuilder.create();
+ builder.setHits(1, 0);
+ builder.setHits(2, 3);
+ builder.setHits(4, 2);
+ assertThat(find(builder.createMeasures(), CoreMetrics.COVERAGE_LINE_HITS_DATA_KEY).getData(), is("1=0;2=3;4=2"));
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void shouldFailIfDuplicatedLineHits() {
+ CoverageMeasuresBuilder builder = CoverageMeasuresBuilder.create();
+ builder.setHits(1, 0);
+ builder.setHits(1, 3);
+ }
+
+ @Test
+ public void shouldCreateUncoveredLines() {
+ CoverageMeasuresBuilder builder = CoverageMeasuresBuilder.create();
+ builder.setHits(1, 0);
+ builder.setHits(2, 3);
+ builder.setHits(3, 0);
+ assertThat(find(builder.createMeasures(), CoreMetrics.UNCOVERED_LINES_KEY).getIntValue(), is(2));
+ }
+
+ @Test
+ public void shouldCreateConditionsByLineData() {
+ CoverageMeasuresBuilder builder = CoverageMeasuresBuilder.create();
+ builder.setConditions(1, 2, 2);
+ builder.setConditions(2, 1, 0);
+ assertThat(find(builder.createMeasures(), CoreMetrics.CONDITIONS_BY_LINE_DATA_KEY).getData(), is("1=2;2=1"));
+ assertThat(find(builder.createMeasures(), CoreMetrics.COVERED_CONDITIONS_BY_LINE_DATA_KEY).getData(), is("1=2;2=0"));
+ assertThat(find(builder.createMeasures(), CoreMetrics.BRANCH_COVERAGE_HITS_DATA_KEY).getData(), is("1=100%;2=0%"));
+ }
+
+ @Test
+ public void shouldCreateNumberOfConditionsToCover() {
+ CoverageMeasuresBuilder builder = CoverageMeasuresBuilder.create();
+ builder.setConditions(1, 2, 2);
+ builder.setConditions(2, 1, 0);
+ assertThat(find(builder.createMeasures(), CoreMetrics.CONDITIONS_TO_COVER_KEY).getIntValue(), is(3));
+ }
+
+ @Test
+ public void shouldCreateNumberOfUncoveredConditions() {
+ CoverageMeasuresBuilder builder = CoverageMeasuresBuilder.create();
+ builder.setConditions(1, 2, 2);
+ builder.setConditions(2, 1, 0);
+ builder.setConditions(3, 3, 1);
+ assertThat(find(builder.createMeasures(), CoreMetrics.UNCOVERED_CONDITIONS_KEY).getIntValue(), is(3));
+ }
+
+ @Test
+ public void shouldSetOnlyPositiveConditions() {
+ CoverageMeasuresBuilder builder = CoverageMeasuresBuilder.create();
+ builder.setConditions(1, 0, 0);
+ builder.setConditions(2, 1, 0);
+ assertThat(find(builder.createMeasures(), CoreMetrics.CONDITIONS_BY_LINE_DATA_KEY).getData(), is("2=1"));
+ assertThat(find(builder.createMeasures(), CoreMetrics.COVERED_CONDITIONS_BY_LINE_DATA_KEY).getData(), is("2=0"));
+ assertThat(find(builder.createMeasures(), CoreMetrics.BRANCH_COVERAGE_HITS_DATA_KEY).getData(), is("2=0%"));
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void shouldFailIfDuplicatedLineConditions() {
+ CoverageMeasuresBuilder builder = CoverageMeasuresBuilder.create();
+ builder.setConditions(1, 3, 0);
+ builder.setConditions(1, 3, 1);
+ }
+
+ @Test
+ public void shouldResetFields() {
+ CoverageMeasuresBuilder builder = CoverageMeasuresBuilder.create();
+ builder.setHits(1, 4);
+ builder.setConditions(1, 3, 1);
+ builder.reset();
+ assertThat(builder.getConditions(), is(0));
+ assertThat(builder.getCoveredConditions(), is(0));
+ assertThat(builder.getCoveredLines(), is(0));
+ assertThat(builder.getHitsByLine().size(), is(0));
+ assertThat(builder.getConditionsByLine().size(), is(0));
+ assertThat(builder.getCoveredConditionsByLine().size(), is(0));
+ }
+
+ private Measure find(Collection<Measure> measures, String metricKey) {
+ for (Measure measure : measures) {
+ if (metricKey.equals(measure.getMetricKey())) {
+ return measure;
+ }
+ }
+ return null;
+ }
+}
diff --git a/sonar-plugin-api/src/test/java/org/sonar/api/measures/MetricTest.java b/sonar-plugin-api/src/test/java/org/sonar/api/measures/MetricTest.java
new file mode 100644
index 00000000000..84706bcc658
--- /dev/null
+++ b/sonar-plugin-api/src/test/java/org/sonar/api/measures/MetricTest.java
@@ -0,0 +1,59 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2011 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * Sonar 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.
+ *
+ * Sonar 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 Sonar; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
+ */
+package org.sonar.api.measures;
+
+import org.junit.Test;
+
+import static org.hamcrest.core.Is.is;
+import static org.hamcrest.core.IsNull.nullValue;
+import static org.junit.Assert.assertThat;
+
+public class MetricTest {
+
+ @Test
+ public void shouldCreateMetric() {
+ Metric metric = new Metric.Builder("foo", Metric.ValueType.INT)
+ .setDomain("my domain")
+ .setName("Foo")
+ .create();
+
+ assertThat(metric.getKey(), is("foo"));
+ assertThat(metric.getName(), is("Foo"));
+ assertThat(metric.getDomain(), is("my domain"));
+ }
+
+ @Test
+ public void shouldCreateMetricWithDefaultValues() {
+ Metric metric = new Metric.Builder("foo", Metric.ValueType.INT)
+ .create();
+
+ assertThat(metric.getBestValue(), nullValue());
+ assertThat(metric.getDescription(), nullValue());
+ assertThat(metric.getWorstValue(), nullValue());
+ assertThat(metric.getDirection(), is(Metric.DIRECTION_NONE));
+ assertThat(metric.getEnabled(), is(true));
+ assertThat(metric.getOrigin(), is(Metric.Origin.JAV));
+ assertThat(metric.getFormula(), nullValue());
+ assertThat(metric.getId(), nullValue());
+ assertThat(metric.getUserManaged(), is(false));
+ assertThat(metric.isHidden(), is(false));
+ assertThat(metric.isOptimizedBestValue(), is(false));
+ }
+}