org.sonar.server.computation.measure.MeasureRepoEntry.java Source code

Java tutorial

Introduction

Here is the source code for org.sonar.server.computation.measure.MeasureRepoEntry.java

Source

/*
 * SonarQube
 * Copyright (C) 2009-2016 SonarSource SA
 * mailto:contact AT sonarsource DOT com
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 3 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */
package org.sonar.server.computation.measure;

import com.google.common.base.Function;
import com.google.common.collect.FluentIterable;
import com.google.common.collect.SetMultimap;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Map;
import java.util.Objects;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import org.sonar.server.computation.component.Component;

/**
 * This class represents a metric key and an associated measure.
 * It can be used to easily compare the content of the SetMultimap returned by {@link MeasureRepository#getRawMeasures(Component)}
 * or {@link MeasureRepositoryRule#getAddedRawMeasures(int)}.
 * <p>
 * This class is also highly useful to accurately make sure of the SetMultimap content since this
 * object implements a deep equals of Measure objects (see {@link #deepEquals(Measure, Measure)}), when
 * {@link Measure#equals(Object)} only care about the ruleId and characteristicId.
 * </p>
 * <p>
 * In order to explore the content of the SetMultimap, use {@link #toEntries(SetMultimap)} to convert it
 * to an Iterable of {@link MeasureRepoEntry} and then take benefit of AssertJ API, eg.:
 * <pre>
 * assertThat(MeasureRepoEntry.toEntries(measureRepository.getAddedRawMeasures(componentRef))).containsOnly(
 *   MeasureRepoEntry.entryOf(DEVELOPMENT_COST_KEY, newMeasureBuilder().create(Long.toString(expectedDevCost))),
 *   MeasureRepoEntry.entryOf(SQALE_DEBT_RATIO_KEY, newMeasureBuilder().create(expectedDebtRatio))
 * );
 * </pre>
 * </p>
 */
public final class MeasureRepoEntry {
    private final String metricKey;
    private final Measure measure;

    public MeasureRepoEntry(String metricKey, Measure measure) {
        this.metricKey = metricKey;
        this.measure = measure;
    }

    public static Function<Map.Entry<String, Measure>, MeasureRepoEntry> toMeasureRepoEntry() {
        return EntryToMeasureRepoEntry.INSTANCE;
    }

    public static Iterable<MeasureRepoEntry> toEntries(SetMultimap<String, Measure> data) {
        return FluentIterable.from(data.entries()).transform(toMeasureRepoEntry()).toList();
    }

    public static MeasureRepoEntry entryOf(String metricKey, Measure measure) {
        return new MeasureRepoEntry(metricKey, measure);
    }

    public static boolean deepEquals(Measure measure, Measure measure1) {
        return Objects.equals(measure, measure1) && measure.getValueType() == measure1.getValueType()
                && equalsByValue(measure, measure1) && equalsByVariation(measure, measure1)
                && equalsByQualityGateStatus(measure, measure1)
                && Objects.equals(measure.getDescription(), measure1.getDescription())
                && Objects.equals(measure.getData(), measure1.getData());
    }

    private static boolean equalsByValue(Measure measure, Measure measure1) {
        switch (measure.getValueType()) {
        case BOOLEAN:
            return measure.getBooleanValue() == measure1.getBooleanValue();
        case INT:
            return measure.getIntValue() == measure1.getIntValue();
        case LONG:
            return measure.getLongValue() == measure1.getLongValue();
        case DOUBLE:
            return Double.compare(measure.getDoubleValue(), measure1.getDoubleValue()) == 0;
        case STRING:
            return measure.getStringValue().equals(measure1.getStringValue());
        case LEVEL:
            return measure.getLevelValue() == measure1.getLevelValue();
        case NO_VALUE:
            return true;
        default:
            throw new IllegalArgumentException("Unsupported ValueType " + measure.getValueType());
        }
    }

    private static boolean equalsByVariation(Measure measure, Measure measure1) {
        if (measure.hasVariations() != measure1.hasVariations()) {
            return false;
        }
        if (!measure.hasVariations()) {
            return true;
        }
        MeasureVariations variations = measure.getVariations();
        MeasureVariations variations1 = measure1.getVariations();
        for (int i = 1; i <= 5; i++) {
            if (variations.hasVariation(i) != variations1.hasVariation(i)) {
                return false;
            }
            if (variations.hasVariation(i)
                    && Double.compare(scale(variations.getVariation(i)), scale(variations1.getVariation(i))) != 0) {
                return false;
            }
        }
        return true;
    }

    private static final int DOUBLE_PRECISION = 1;

    private static double scale(double value) {
        BigDecimal bd = BigDecimal.valueOf(value);
        return bd.setScale(DOUBLE_PRECISION, RoundingMode.HALF_UP).doubleValue();
    }

    private static boolean equalsByQualityGateStatus(Measure measure, Measure measure1) {
        if (measure.hasQualityGateStatus() != measure1.hasQualityGateStatus()) {
            return false;
        }
        if (!measure.hasQualityGateStatus()) {
            return true;
        }
        return Objects.equals(measure.getQualityGateStatus(), measure1.getQualityGateStatus());
    }

    @Override
    public boolean equals(@Nullable Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }
        MeasureRepoEntry that = (MeasureRepoEntry) o;
        return Objects.equals(metricKey, that.metricKey) && deepEquals(measure, that.measure);
    }

    @Override
    public int hashCode() {
        return Objects.hash(metricKey, measure);
    }

    @Override
    public String toString() {
        return "<" + metricKey + ", " + measure + '>';
    }

    private enum EntryToMeasureRepoEntry implements Function<Map.Entry<String, Measure>, MeasureRepoEntry> {
        INSTANCE;

        @Nullable
        @Override
        public MeasureRepoEntry apply(@Nonnull Map.Entry<String, Measure> input) {
            return new MeasureRepoEntry(input.getKey(), input.getValue());
        }
    }
}