Package org.sonar.plugins.core.timemachine

Source Code of org.sonar.plugins.core.timemachine.AbstractNewCoverageFileAnalyzer$PeriodStruct

/*
* SonarQube, open source software quality management tool.
* Copyright (C) 2008-2014 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.plugins.core.timemachine;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.apache.commons.lang.ObjectUtils;
import org.sonar.api.batch.*;
import org.sonar.api.measures.CoreMetrics;
import org.sonar.api.measures.Measure;
import org.sonar.api.measures.Metric;
import org.sonar.api.resources.Project;
import org.sonar.api.resources.Qualifiers;
import org.sonar.api.resources.Resource;
import org.sonar.api.resources.Scopes;
import org.sonar.api.utils.KeyValueFormat;
import org.sonar.batch.components.Period;
import org.sonar.batch.components.TimeMachineConfiguration;
import org.sonar.core.DryRunIncompatible;

import javax.annotation.Nullable;

import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
* @since 2.7
*/
@DryRunIncompatible
@DependedUpon(DecoratorBarriers.END_OF_TIME_MACHINE)
public abstract class AbstractNewCoverageFileAnalyzer implements Decorator {

  private List<PeriodStruct> structs;

  public AbstractNewCoverageFileAnalyzer(TimeMachineConfiguration timeMachineConfiguration) {
    structs = Lists.newArrayList();
    for (Period period : timeMachineConfiguration.periods()) {
      structs.add(new PeriodStruct(period.getIndex(), period.getDate()));
    }
  }

  AbstractNewCoverageFileAnalyzer(List<PeriodStruct> structs) {
    this.structs = structs;
  }

  public abstract Metric getCoverageLineHitsDataMetric();

  public abstract Metric getConditionsByLineMetric();

  public abstract Metric getCoveredConditionsByLineMetric();

  public abstract Metric getNewLinesToCoverMetric();

  public abstract Metric getNewUncoveredLinesMetric();

  public abstract Metric getNewConditionsToCoverMetric();

  public abstract Metric getNewUncoveredConditionsMetric();

  @Override
  public boolean shouldExecuteOnProject(Project project) {
    return !structs.isEmpty();
  }

  private boolean shouldDecorate(Resource resource) {
    return Scopes.isFile(resource) && !Qualifiers.UNIT_TEST_FILE.equals(resource.getQualifier());
  }

  @DependsUpon
  public List<Metric> dependsOnMetrics() {

    return Arrays.asList(CoreMetrics.SCM_LAST_COMMIT_DATETIMES_BY_LINE,
      getCoverageLineHitsDataMetric(), getConditionsByLineMetric(), getCoveredConditionsByLineMetric());
  }

  @DependedUpon
  public List<Metric> generatesNewCoverageMetrics() {
    return Arrays.asList(getNewLinesToCoverMetric(), getNewUncoveredLinesMetric(), getNewConditionsToCoverMetric(), getNewUncoveredConditionsMetric());
  }

  @Override
  public void decorate(Resource resource, DecoratorContext context) {
    if (shouldDecorate(resource)) {
      doDecorate(context);
    }
  }

  void doDecorate(DecoratorContext context) {
    if (parse(context)) {
      compute(context);
    }
  }

  private boolean parse(DecoratorContext context) {
    Measure lastCommits = context.getMeasure(CoreMetrics.SCM_LAST_COMMIT_DATETIMES_BY_LINE);
    Measure hitsByLineMeasure = context.getMeasure(getCoverageLineHitsDataMetric());

    if (lastCommits != null && lastCommits.hasData() && hitsByLineMeasure != null && hitsByLineMeasure.hasData()) {
      Map<Integer, Date> datesByLine = KeyValueFormat.parseIntDateTime(lastCommits.getData());
      Map<Integer, Integer> hitsByLine = parseCountByLine(hitsByLineMeasure);
      Map<Integer, Integer> conditionsByLine = parseCountByLine(context.getMeasure(getConditionsByLineMetric()));
      Map<Integer, Integer> coveredConditionsByLine = parseCountByLine(context.getMeasure(getCoveredConditionsByLineMetric()));

      reset();

      for (Map.Entry<Integer, Integer> entry : hitsByLine.entrySet()) {
        int lineId = entry.getKey();
        int hits = entry.getValue();
        int conditions = (Integer) ObjectUtils.defaultIfNull(conditionsByLine.get(lineId), 0);
        int coveredConditions = (Integer) ObjectUtils.defaultIfNull(coveredConditionsByLine.get(lineId), 0);
        Date date = datesByLine.get(lineId);
        for (PeriodStruct struct : structs) {
          struct.analyze(date, hits, conditions, coveredConditions);
        }
      }

      return true;
    }
    return false;
  }

  private void reset() {
    for (PeriodStruct struct : structs) {
      struct.reset();
    }
  }

  private void compute(DecoratorContext context) {
    Measure newLines = new Measure(getNewLinesToCoverMetric());
    Measure newUncoveredLines = new Measure(getNewUncoveredLinesMetric());
    Measure newConditions = new Measure(getNewConditionsToCoverMetric());
    Measure newUncoveredConditions = new Measure(getNewUncoveredConditionsMetric());

    for (PeriodStruct struct : structs) {
      if (struct.hasNewCode()) {
        newLines.setVariation(struct.index, (double) struct.getNewLines());
        newUncoveredLines.setVariation(struct.index, (double) (struct.getNewLines() - struct.getNewCoveredLines()));
        newConditions.setVariation(struct.index, (double) struct.getNewConditions());
        newUncoveredConditions.setVariation(struct.index, (double) struct.getNewConditions() - struct.getNewCoveredConditions());
      }
    }

    context.saveMeasure(newLines);
    context.saveMeasure(newUncoveredLines);
    context.saveMeasure(newConditions);
    context.saveMeasure(newUncoveredConditions);
  }

  private Map<Integer, Integer> parseCountByLine(@Nullable Measure measure) {
    if (measure != null && measure.hasData()) {
      return KeyValueFormat.parseIntInt(measure.getData());
    }
    return Maps.newHashMap();
  }

  public static final class PeriodStruct {
    int index;
    Date date;
    Integer newLines;
    Integer newCoveredLines;
    Integer newConditions;
    Integer newCoveredConditions;

    PeriodStruct(int index, @Nullable Date date) {
      this.index = index;
      this.date = date;
    }

    void reset() {
      newLines = null;
      newCoveredLines = null;
      newConditions = null;
      newCoveredConditions = null;
    }

    void analyze(@Nullable Date lineDate, int hits, int conditions, int coveredConditions) {
      if (lineDate == null) {
        // TODO warning

      } else if (date == null || lineDate.after(date)) {
        // TODO test if string comparison is faster or not
        addLine(hits > 0);
        addConditions(conditions, coveredConditions);
      }
    }

    void addLine(boolean covered) {
      if (newLines == null) {
        newLines = 0;
      }
      newLines += 1;
      if (covered) {
        if (newCoveredLines == null) {
          newCoveredLines = 0;
        }
        newCoveredLines += 1;
      }
    }

    void addConditions(int count, int countCovered) {
      if (newConditions == null) {
        newConditions = 0;
      }
      newConditions += count;
      if (count > 0) {
        if (newCoveredConditions == null) {
          newCoveredConditions = 0;
        }
        newCoveredConditions += countCovered;
      }
    }

    boolean hasNewCode() {
      return newLines != null;
    }

    public int getNewLines() {
      return newLines != null ? newLines : 0;
    }

    public int getNewCoveredLines() {
      return newCoveredLines != null ? newCoveredLines : 0;
    }

    public int getNewConditions() {
      return newConditions != null ? newConditions : 0;
    }

    public int getNewCoveredConditions() {
      return newCoveredConditions != null ? newCoveredConditions : 0;
    }
  }
}
TOP

Related Classes of org.sonar.plugins.core.timemachine.AbstractNewCoverageFileAnalyzer$PeriodStruct

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.