3 * Copyright (C) 2009-2023 SonarSource SA
4 * mailto:info AT sonarsource DOT com
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 3 of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 package org.sonar.ce.task.projectanalysis.measure;
23 import java.util.Objects;
24 import java.util.function.Function;
25 import java.util.stream.Collectors;
26 import javax.annotation.Nonnull;
27 import javax.annotation.Nullable;
28 import org.sonar.ce.task.projectanalysis.component.Component;
31 * This class represents a metric key and an associated measure.
32 * It can be used to easily compare the content of the SetMultimap returned by {@link MeasureRepository#getRawMeasures(Component)}
33 * or {@link MeasureRepositoryRule#getAddedRawMeasures(int)}.
35 * This class is also highly useful to accurately make sure of the SetMultimap content since this
36 * object implements a deep equals of Measure objects (see {@link #deepEquals(Measure, Measure)}), when
37 * {@link Measure#equals(Object)} only care about the ruleId and characteristicId.
40 * In order to explore the content of the Map, use {@link #toEntries(Map)} to convert it
41 * to an Iterable of {@link MeasureRepoEntry} and then take benefit of AssertJ API, eg.:
43 * assertThat(MeasureRepoEntry.toEntries(measureRepository.getAddedRawMeasures(componentRef))).containsOnly(
44 * MeasureRepoEntry.entryOf(DEVELOPMENT_COST_KEY, newMeasureBuilder().create(Long.toString(expectedDevCost))),
45 * MeasureRepoEntry.entryOf(SQALE_DEBT_RATIO_KEY, newMeasureBuilder().create(expectedDebtRatio))
50 public final class MeasureRepoEntry {
51 private final String metricKey;
52 private final Measure measure;
54 public MeasureRepoEntry(String metricKey, Measure measure) {
55 this.metricKey = metricKey;
56 this.measure = measure;
59 public static Function<Map.Entry<String, Measure>, MeasureRepoEntry> toMeasureRepoEntry() {
60 return EntryToMeasureRepoEntry.INSTANCE;
63 public static Iterable<MeasureRepoEntry> toEntries(Map<String, Measure> data) {
64 return data.entrySet().stream().map(toMeasureRepoEntry()).collect(Collectors.toList());
67 public static MeasureRepoEntry entryOf(String metricKey, Measure measure) {
68 return new MeasureRepoEntry(metricKey, measure);
71 public static boolean deepEquals(Measure measure, Measure measure1) {
72 return measure.getValueType() == measure1.getValueType()
73 && equalsByValue(measure, measure1)
74 && equalsByQualityGateStatus(measure, measure1)
75 && Objects.equals(measure.getData(), measure1.getData());
78 private static boolean equalsByValue(Measure measure, Measure measure1) {
79 switch (measure.getValueType()) {
81 return measure.getBooleanValue() == measure1.getBooleanValue();
83 return measure.getIntValue() == measure1.getIntValue();
85 return measure.getLongValue() == measure1.getLongValue();
87 return Double.compare(measure.getDoubleValue(), measure1.getDoubleValue()) == 0;
89 return measure.getStringValue().equals(measure1.getStringValue());
91 return measure.getLevelValue() == measure1.getLevelValue();
95 throw new IllegalArgumentException("Unsupported ValueType " + measure.getValueType());
99 private static boolean equalsByQualityGateStatus(Measure measure, Measure measure1) {
100 if (measure.hasQualityGateStatus() != measure1.hasQualityGateStatus()) {
103 if (!measure.hasQualityGateStatus()) {
106 return Objects.equals(measure.getQualityGateStatus(), measure1.getQualityGateStatus());
110 public boolean equals(@Nullable Object o) {
114 if (o == null || getClass() != o.getClass()) {
117 MeasureRepoEntry that = (MeasureRepoEntry) o;
118 return Objects.equals(metricKey, that.metricKey) &&
119 deepEquals(measure, that.measure);
123 public int hashCode() {
124 return Objects.hash(metricKey, measure);
128 public String toString() {
129 return "<" + metricKey + ", " + measure + '>';
132 private enum EntryToMeasureRepoEntry implements Function<Map.Entry<String, Measure>, MeasureRepoEntry> {
137 public MeasureRepoEntry apply(@Nonnull Map.Entry<String, Measure> input) {
138 return new MeasureRepoEntry(input.getKey(), input.getValue());