]> source.dussan.org Git - sonarqube.git/commitdiff
use testFixtures instead of test configuration of ce-task-projectanalysis
authorSébastien Lesaint <sebastien.lesaint@sonarsource.com>
Thu, 29 Aug 2019 13:27:53 +0000 (15:27 +0200)
committerSonarTech <sonartech@sonarsource.com>
Mon, 2 Sep 2019 18:21:05 +0000 (20:21 +0200)
33 files changed:
server/sonar-ce-task-projectanalysis/build.gradle
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/analysis/AnalysisMetadataHolderRule.java [deleted file]
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/analysis/MutableAnalysisMetadataHolderRule.java [deleted file]
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/component/AbstractComponentProvider.java [deleted file]
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/component/ComponentProvider.java [deleted file]
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/component/MutableTreeRootHolderRule.java [deleted file]
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/component/NoComponentProvider.java [deleted file]
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/component/ReportComponent.java [deleted file]
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/component/TreeComponentProvider.java [deleted file]
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/component/TreeRootHolderComponentProvider.java [deleted file]
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/component/TreeRootHolderRule.java [deleted file]
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/component/ViewsComponent.java [deleted file]
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/measure/MeasureAssert.java [deleted file]
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/measure/MeasureRepoEntry.java [deleted file]
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/measure/MeasureRepositoryRule.java [deleted file]
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/metric/MetricRepositoryRule.java [deleted file]
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/step/BaseStepTest.java [deleted file]
server/sonar-ce-task-projectanalysis/src/testFixtures/java/org/sonar/ce/task/projectanalysis/analysis/AnalysisMetadataHolderRule.java [new file with mode: 0644]
server/sonar-ce-task-projectanalysis/src/testFixtures/java/org/sonar/ce/task/projectanalysis/analysis/MutableAnalysisMetadataHolderRule.java [new file with mode: 0644]
server/sonar-ce-task-projectanalysis/src/testFixtures/java/org/sonar/ce/task/projectanalysis/component/AbstractComponentProvider.java [new file with mode: 0644]
server/sonar-ce-task-projectanalysis/src/testFixtures/java/org/sonar/ce/task/projectanalysis/component/ComponentProvider.java [new file with mode: 0644]
server/sonar-ce-task-projectanalysis/src/testFixtures/java/org/sonar/ce/task/projectanalysis/component/MutableTreeRootHolderRule.java [new file with mode: 0644]
server/sonar-ce-task-projectanalysis/src/testFixtures/java/org/sonar/ce/task/projectanalysis/component/NoComponentProvider.java [new file with mode: 0644]
server/sonar-ce-task-projectanalysis/src/testFixtures/java/org/sonar/ce/task/projectanalysis/component/ReportComponent.java [new file with mode: 0644]
server/sonar-ce-task-projectanalysis/src/testFixtures/java/org/sonar/ce/task/projectanalysis/component/TreeComponentProvider.java [new file with mode: 0644]
server/sonar-ce-task-projectanalysis/src/testFixtures/java/org/sonar/ce/task/projectanalysis/component/TreeRootHolderComponentProvider.java [new file with mode: 0644]
server/sonar-ce-task-projectanalysis/src/testFixtures/java/org/sonar/ce/task/projectanalysis/component/TreeRootHolderRule.java [new file with mode: 0644]
server/sonar-ce-task-projectanalysis/src/testFixtures/java/org/sonar/ce/task/projectanalysis/component/ViewsComponent.java [new file with mode: 0644]
server/sonar-ce-task-projectanalysis/src/testFixtures/java/org/sonar/ce/task/projectanalysis/measure/MeasureAssert.java [new file with mode: 0644]
server/sonar-ce-task-projectanalysis/src/testFixtures/java/org/sonar/ce/task/projectanalysis/measure/MeasureRepoEntry.java [new file with mode: 0644]
server/sonar-ce-task-projectanalysis/src/testFixtures/java/org/sonar/ce/task/projectanalysis/measure/MeasureRepositoryRule.java [new file with mode: 0644]
server/sonar-ce-task-projectanalysis/src/testFixtures/java/org/sonar/ce/task/projectanalysis/metric/MetricRepositoryRule.java [new file with mode: 0644]
server/sonar-ce-task-projectanalysis/src/testFixtures/java/org/sonar/ce/task/projectanalysis/step/BaseStepTest.java [new file with mode: 0644]

index 99971d84553c7631851dc1ca5610068eb27e3cd0..b801b25a6842d810f6a2ea694b2800072682fd3e 100644 (file)
@@ -14,11 +14,6 @@ sourceSets {
   }
 }
 
-configurations {
-  tests
-  testCompile.extendsFrom compileOnly
-}
-
 dependencies {
   // please keep the list grouped by configuration and ordered by name
 
@@ -54,18 +49,14 @@ dependencies {
   testCompile 'org.apache.logging.log4j:log4j-core'
   testCompile 'org.assertj:assertj-core'
   testCompile 'org.assertj:assertj-guava'
-  testCompile 'org.mockito:mockito-core'
   testCompile 'org.reflections:reflections'
   testCompile project(':sonar-testing-harness')
-  testCompile testFixtures(project(':server:sonar-ce-task'))
   testCompile testFixtures(project(':server:sonar-server-common'))
-}
 
-task testJar(type: Jar) {
-  classifier = 'tests'
-  from sourceSets.test.output
-}
+  testFixturesApi 'junit:junit'
+  testFixturesApi 'org.assertj:assertj-core'
+  testFixturesApi 'org.mockito:mockito-core'
+  testFixturesApi testFixtures(project(':server:sonar-ce-task'))
 
-artifacts {
- tests testJar
+  testFixturesCompileOnly 'com.google.code.findbugs:jsr305'
 }
diff --git a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/analysis/AnalysisMetadataHolderRule.java b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/analysis/AnalysisMetadataHolderRule.java
deleted file mode 100644 (file)
index 34a2e0f..0000000
+++ /dev/null
@@ -1,270 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info 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.ce.task.projectanalysis.analysis;
-
-import java.util.Date;
-import java.util.Map;
-import java.util.Optional;
-import javax.annotation.CheckForNull;
-import javax.annotation.Nullable;
-import org.junit.rules.ExternalResource;
-import org.sonar.ce.task.util.InitializedProperty;
-import org.sonar.db.component.BranchType;
-import org.sonar.db.organization.OrganizationDto;
-import org.sonar.server.project.Project;
-import org.sonar.server.qualityprofile.QualityProfile;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.base.Preconditions.checkState;
-import static java.util.Objects.requireNonNull;
-import static org.apache.commons.lang.StringUtils.defaultIfBlank;
-
-public class AnalysisMetadataHolderRule extends ExternalResource implements MutableAnalysisMetadataHolder {
-
-  private final InitializedProperty<Boolean> organizationsEnabled = new InitializedProperty<>();
-
-  private final InitializedProperty<Organization> organization = new InitializedProperty<>();
-
-  private final InitializedProperty<String> uuid = new InitializedProperty<>();
-
-  private final InitializedProperty<Long> analysisDate = new InitializedProperty<>();
-
-  private final InitializedProperty<Analysis> baseAnalysis = new InitializedProperty<>();
-
-  private final InitializedProperty<Boolean> crossProjectDuplicationEnabled = new InitializedProperty<>();
-
-  private final InitializedProperty<Branch> branch = new InitializedProperty<>();
-
-  private final InitializedProperty<String> pullRequestId = new InitializedProperty<>();
-
-  private final InitializedProperty<Project> project = new InitializedProperty<>();
-
-  private final InitializedProperty<Integer> rootComponentRef = new InitializedProperty<>();
-
-  private final InitializedProperty<Map<String, QualityProfile>> qProfilesPerLanguage = new InitializedProperty<>();
-
-  private final InitializedProperty<Map<String, ScannerPlugin>> pluginsByKey = new InitializedProperty<>();
-
-  private final InitializedProperty<String> scmRevision = new InitializedProperty<>();
-
-  @Override
-  public AnalysisMetadataHolderRule setOrganizationsEnabled(boolean isOrganizationsEnabled) {
-    this.organizationsEnabled.setProperty(isOrganizationsEnabled);
-    return this;
-  }
-
-  @Override
-  public boolean isOrganizationsEnabled() {
-    checkState(organizationsEnabled.isInitialized(), "Organizations enabled flag has not been set");
-    return organizationsEnabled.getProperty();
-  }
-
-  @Override
-  public AnalysisMetadataHolderRule setOrganization(Organization organization) {
-    requireNonNull(organization, "organization can't be null");
-    this.organization.setProperty(organization);
-    return this;
-  }
-
-  public AnalysisMetadataHolderRule setOrganizationUuid(String uuid, String defaultQualityGateUuid) {
-    requireNonNull(uuid, "organization uuid can't be null");
-    this.organization
-      .setProperty(Organization.from(new OrganizationDto().setUuid(uuid).setKey("key_" + uuid).setName("name_" + uuid).setDefaultQualityGateUuid(defaultQualityGateUuid)));
-    return this;
-  }
-
-  @Override
-  public Organization getOrganization() {
-    checkState(organization.isInitialized(), "Organization has not been set");
-    return this.organization.getProperty();
-  }
-
-  @Override
-  public AnalysisMetadataHolderRule setUuid(String s) {
-    checkNotNull(s, "UUID must not be null");
-    this.uuid.setProperty(s);
-    return this;
-  }
-
-  @Override
-  public String getUuid() {
-    checkState(uuid.isInitialized(), "Analysis UUID has not been set");
-    return this.uuid.getProperty();
-  }
-
-  public AnalysisMetadataHolderRule setAnalysisDate(Date date) {
-    checkNotNull(date, "Date must not be null");
-    this.analysisDate.setProperty(date.getTime());
-    return this;
-  }
-
-  @Override
-  public AnalysisMetadataHolderRule setAnalysisDate(long date) {
-    checkNotNull(date, "Date must not be null");
-    this.analysisDate.setProperty(date);
-    return this;
-  }
-
-  @Override
-  public long getAnalysisDate() {
-    checkState(analysisDate.isInitialized(), "Analysis date has not been set");
-    return this.analysisDate.getProperty();
-  }
-
-  @Override
-  public boolean hasAnalysisDateBeenSet() {
-    return analysisDate.isInitialized();
-  }
-
-  @Override
-  public boolean isFirstAnalysis() {
-    return getBaseAnalysis() == null;
-  }
-
-  @Override
-  public AnalysisMetadataHolderRule setBaseAnalysis(@Nullable Analysis baseAnalysis) {
-    this.baseAnalysis.setProperty(baseAnalysis);
-    return this;
-  }
-
-  @Override
-  @CheckForNull
-  public Analysis getBaseAnalysis() {
-    checkState(baseAnalysis.isInitialized(), "Base analysis has not been set");
-    return baseAnalysis.getProperty();
-  }
-
-  @Override
-  public AnalysisMetadataHolderRule setCrossProjectDuplicationEnabled(boolean isCrossProjectDuplicationEnabled) {
-    this.crossProjectDuplicationEnabled.setProperty(isCrossProjectDuplicationEnabled);
-    return this;
-  }
-
-  @Override
-  public boolean isCrossProjectDuplicationEnabled() {
-    checkState(crossProjectDuplicationEnabled.isInitialized(), "Cross project duplication flag has not been set");
-    return crossProjectDuplicationEnabled.getProperty();
-  }
-
-  @Override
-  public AnalysisMetadataHolderRule setBranch(Branch branch) {
-    this.branch.setProperty(branch);
-    return this;
-  }
-
-  @Override
-  public Branch getBranch() {
-    checkState(branch.isInitialized(), "Branch has not been set");
-    return branch.getProperty();
-  }
-
-  @Override
-  public MutableAnalysisMetadataHolder setPullRequestKey(String pullRequestKey) {
-    this.pullRequestId.setProperty(pullRequestKey);
-    return this;
-  }
-
-  @Override
-  public String getPullRequestKey() {
-    checkState(pullRequestId.isInitialized(), "Pull request id has not been set");
-    return pullRequestId.getProperty();
-  }
-
-  @Override
-  public AnalysisMetadataHolderRule setProject(Project p) {
-    this.project.setProperty(p);
-    return this;
-  }
-
-  @Override
-  public Project getProject() {
-    checkState(project.isInitialized(), "Project has not been set");
-    return project.getProperty();
-  }
-
-  @Override
-  public AnalysisMetadataHolderRule setRootComponentRef(int rootComponentRef) {
-    this.rootComponentRef.setProperty(rootComponentRef);
-    return this;
-  }
-
-  @Override
-  public int getRootComponentRef() {
-    checkState(rootComponentRef.isInitialized(), "Root component ref has not been set");
-    return rootComponentRef.getProperty();
-  }
-
-  @Override
-  public AnalysisMetadataHolderRule setQProfilesByLanguage(Map<String, QualityProfile> qProfilesPerLanguage) {
-    this.qProfilesPerLanguage.setProperty(qProfilesPerLanguage);
-    return this;
-  }
-
-  @Override
-  public Map<String, QualityProfile> getQProfilesByLanguage() {
-    checkState(qProfilesPerLanguage.isInitialized(), "QProfile per language has not been set");
-    return qProfilesPerLanguage.getProperty();
-  }
-
-  @Override
-  public AnalysisMetadataHolderRule setScannerPluginsByKey(Map<String, ScannerPlugin> plugins) {
-    this.pluginsByKey.setProperty(plugins);
-    return this;
-  }
-
-  @Override
-  public Map<String, ScannerPlugin> getScannerPluginsByKey() {
-    checkState(pluginsByKey.isInitialized(), "Plugins per key has not been set");
-    return pluginsByKey.getProperty();
-  }
-
-  @Override
-  public MutableAnalysisMetadataHolder setScmRevision(@Nullable String s) {
-    checkState(!this.scmRevision.isInitialized(), "ScmRevisionId has already been set");
-    this.scmRevision.setProperty(defaultIfBlank(s, null));
-    return this;
-  }
-
-  @Override
-  public Optional<String> getScmRevision() {
-    if (!scmRevision.isInitialized()) {
-      return Optional.empty();
-    }
-    return Optional.ofNullable(scmRevision.getProperty());
-  }
-
-  @Override
-  public boolean isShortLivingBranch() {
-    Branch property = this.branch.getProperty();
-    return property != null && property.getType() == BranchType.SHORT;
-  }
-
-  @Override
-  public boolean isLongLivingBranch() {
-    Branch property = this.branch.getProperty();
-    return property != null && property.getType() == BranchType.LONG;
-  }
-
-  @Override
-  public boolean isPullRequest() {
-    Branch property = this.branch.getProperty();
-    return property != null && property.getType() == BranchType.PULL_REQUEST;
-  }
-}
diff --git a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/analysis/MutableAnalysisMetadataHolderRule.java b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/analysis/MutableAnalysisMetadataHolderRule.java
deleted file mode 100644 (file)
index a622ff7..0000000
+++ /dev/null
@@ -1,211 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info 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.ce.task.projectanalysis.analysis;
-
-import java.util.Map;
-import java.util.Optional;
-import javax.annotation.CheckForNull;
-import javax.annotation.Nullable;
-import org.junit.rules.ExternalResource;
-import org.sonar.core.platform.PlatformEditionProvider;
-import org.sonar.server.project.Project;
-import org.sonar.server.qualityprofile.QualityProfile;
-
-import static org.mockito.Mockito.mock;
-
-public class MutableAnalysisMetadataHolderRule extends ExternalResource implements MutableAnalysisMetadataHolder {
-
-  private PlatformEditionProvider editionProvider = mock(PlatformEditionProvider.class);
-  private AnalysisMetadataHolderImpl delegate = new AnalysisMetadataHolderImpl(editionProvider);
-
-  @Override
-  protected void after() {
-    delegate = new AnalysisMetadataHolderImpl(editionProvider);
-  }
-
-  @Override
-  public boolean isOrganizationsEnabled() {
-    return delegate.isOrganizationsEnabled();
-  }
-
-  @Override
-  public MutableAnalysisMetadataHolderRule setOrganizationsEnabled(boolean isOrganizationsEnabled) {
-    delegate.setOrganizationsEnabled(isOrganizationsEnabled);
-    return this;
-  }
-
-  @Override
-  public MutableAnalysisMetadataHolderRule setOrganization(Organization organization) {
-    delegate.setOrganization(organization);
-    return this;
-  }
-
-  @Override
-  public Organization getOrganization() {
-    return delegate.getOrganization();
-  }
-
-  public MutableAnalysisMetadataHolderRule setUuid(String s) {
-    delegate.setUuid(s);
-    return this;
-  }
-
-  @Override
-  public String getUuid() {
-    return delegate.getUuid();
-  }
-
-  public MutableAnalysisMetadataHolderRule setAnalysisDate(long date) {
-    delegate.setAnalysisDate(date);
-    return this;
-  }
-
-  @Override
-  public long getAnalysisDate() {
-    return delegate.getAnalysisDate();
-  }
-
-  @Override
-  public boolean hasAnalysisDateBeenSet() {
-    return delegate.hasAnalysisDateBeenSet();
-  }
-
-  @Override
-  public boolean isFirstAnalysis() {
-    return delegate.isFirstAnalysis();
-  }
-
-  @Override
-  public MutableAnalysisMetadataHolderRule setBaseAnalysis(@Nullable Analysis baseAnalysis) {
-    delegate.setBaseAnalysis(baseAnalysis);
-    return this;
-  }
-
-  @Override
-  @CheckForNull
-  public Analysis getBaseAnalysis() {
-    return delegate.getBaseAnalysis();
-  }
-
-  @Override
-  public boolean isCrossProjectDuplicationEnabled() {
-    return delegate.isCrossProjectDuplicationEnabled();
-  }
-
-  @Override
-  public MutableAnalysisMetadataHolderRule setCrossProjectDuplicationEnabled(boolean isCrossProjectDuplicationEnabled) {
-    delegate.setCrossProjectDuplicationEnabled(isCrossProjectDuplicationEnabled);
-    return this;
-  }
-
-  @Override
-  public Branch getBranch() {
-    return delegate.getBranch();
-  }
-
-  @Override
-  public MutableAnalysisMetadataHolderRule setBranch(Branch branch) {
-    delegate.setBranch(branch);
-    return this;
-  }
-
-  @Override
-  public String getPullRequestKey() {
-    return delegate.getPullRequestKey();
-  }
-
-  @Override
-  public MutableAnalysisMetadataHolder setPullRequestKey(String pullRequestKey) {
-    delegate.setPullRequestKey(pullRequestKey);
-    return this;
-  }
-
-  @Override
-  public MutableAnalysisMetadataHolderRule setProject(@Nullable Project project) {
-    delegate.setProject(project);
-    return this;
-  }
-
-  @Override
-  public Project getProject() {
-    return delegate.getProject();
-  }
-
-  @Override
-  public MutableAnalysisMetadataHolderRule setRootComponentRef(int rootComponentRef) {
-    delegate.setRootComponentRef(rootComponentRef);
-    return this;
-  }
-
-  @Override
-  public int getRootComponentRef() {
-    return delegate.getRootComponentRef();
-  }
-
-  @Override
-  public MutableAnalysisMetadataHolder setQProfilesByLanguage(Map<String, QualityProfile> qprofilesByLanguage) {
-    delegate.setQProfilesByLanguage(qprofilesByLanguage);
-    return this;
-  }
-
-  @Override
-  public Map<String, QualityProfile> getQProfilesByLanguage() {
-    return delegate.getQProfilesByLanguage();
-  }
-
-  @Override
-  public MutableAnalysisMetadataHolder setScannerPluginsByKey(Map<String, ScannerPlugin> plugins) {
-    delegate.setScannerPluginsByKey(plugins);
-    return this;
-  }
-
-  @Override
-  public Map<String, ScannerPlugin> getScannerPluginsByKey() {
-    return delegate.getScannerPluginsByKey();
-  }
-
-
-
-  @Override
-  public MutableAnalysisMetadataHolder setScmRevision(String scmRevisionId) {
-    delegate.setScmRevision(scmRevisionId);
-    return this;
-  }
-
-  @Override
-  public Optional<String> getScmRevision() {
-    return delegate.getScmRevision();
-  }
-
-  @Override
-  public boolean isShortLivingBranch() {
-    return delegate.isShortLivingBranch();
-  }
-
-  @Override
-  public boolean isLongLivingBranch() {
-    return delegate.isLongLivingBranch();
-  }
-
-  @Override
-  public boolean isPullRequest() {
-    return delegate.isPullRequest();
-  }
-}
diff --git a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/component/AbstractComponentProvider.java b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/component/AbstractComponentProvider.java
deleted file mode 100644 (file)
index b45de74..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info 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.ce.task.projectanalysis.component;
-
-import static com.google.common.base.Preconditions.checkState;
-
-abstract class AbstractComponentProvider implements ComponentProvider {
-  private boolean initialized = false;
-
-  @Override
-  public void ensureInitialized() {
-    if (!this.initialized) {
-      ensureInitializedImpl();
-      this.initialized = true;
-    }
-  }
-
-  protected abstract void ensureInitializedImpl();
-
-  @Override
-  public void reset() {
-    resetImpl();
-    this.initialized = false;
-  }
-
-  protected abstract void resetImpl();
-
-  @Override
-  public Component getByRef(int componentRef) {
-    checkState(this.initialized, "%s has not been initialized", getClass().getSimpleName());
-    return getByRefImpl(componentRef);
-  }
-
-  protected abstract Component getByRefImpl(int componentRef);
-}
diff --git a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/component/ComponentProvider.java b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/component/ComponentProvider.java
deleted file mode 100644 (file)
index 7d04264..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info 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.ce.task.projectanalysis.component;
-
-public interface ComponentProvider {
-  /**
-   * does nothing if already initialized
-   */
-  void ensureInitialized();
-
-  void reset();
-
-  /**
-   * @throws IllegalStateException if no component is found for the specified ref
-   * @throws IllegalStateException if provider has not been initialized
-   */
-  Component getByRef(int componentRef);
-}
diff --git a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/component/MutableTreeRootHolderRule.java b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/component/MutableTreeRootHolderRule.java
deleted file mode 100644 (file)
index 506a4e2..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info 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.ce.task.projectanalysis.component;
-
-public class MutableTreeRootHolderRule extends TreeRootHolderRule implements MutableTreeRootHolder {
-  @Override
-  public MutableTreeRootHolderRule setRoots(Component root, Component reportRoot) {
-    delegate.setRoots(root, reportRoot);
-    return this;
-  }
-}
diff --git a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/component/NoComponentProvider.java b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/component/NoComponentProvider.java
deleted file mode 100644 (file)
index 670b57d..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info 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.ce.task.projectanalysis.component;
-
-public enum NoComponentProvider implements ComponentProvider {
-  INSTANCE;
-
-  private static final String ERROR_MSG = "Can not add a measure by Component ref if MeasureRepositoryRule has not been created for some Component provider";
-
-  @Override
-  public void ensureInitialized() {
-    throw new IllegalStateException(ERROR_MSG);
-  }
-
-  @Override
-  public void reset() {
-    // do nothing
-  }
-
-  @Override
-  public Component getByRef(int componentRef) {
-    throw new IllegalStateException(ERROR_MSG);
-  }
-}
diff --git a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/component/ReportComponent.java b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/component/ReportComponent.java
deleted file mode 100644 (file)
index 0b10c06..0000000
+++ /dev/null
@@ -1,304 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info 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.ce.task.projectanalysis.component;
-
-import com.google.common.collect.ImmutableList;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Optional;
-import javax.annotation.CheckForNull;
-import javax.annotation.Nullable;
-
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkState;
-import static java.util.Arrays.asList;
-import static java.util.Objects.requireNonNull;
-
-/**
- * Implementation of {@link Component} to unit test report components.
- */
-public class ReportComponent implements Component {
-
-  private static final FileAttributes DEFAULT_FILE_ATTRIBUTES = new FileAttributes(false, null, 1);
-
-  public static final Component DUMB_PROJECT = builder(Type.PROJECT, 1)
-    .setKey("PROJECT_KEY")
-    .setPublicKey("PUBLIC_PROJECT_KEY")
-    .setUuid("PROJECT_UUID")
-    .setName("Project Name")
-    .setProjectVersion("1.0-SNAPSHOT")
-    .build();
-
-  private final Type type;
-  private final Status status;
-  private final String name;
-  private final String shortName;
-  @CheckForNull
-  private final String description;
-  private final String key;
-  private final String publicKey;
-  private final String uuid;
-  private final ProjectAttributes projectAttributes;
-  private final ReportAttributes reportAttributes;
-  private final FileAttributes fileAttributes;
-  private final List<Component> children;
-
-  private ReportComponent(Builder builder) {
-    this.type = builder.type;
-    this.status = builder.status;
-    this.key = builder.key;
-    this.publicKey = builder.publicKey;
-    this.name = builder.name == null ? String.valueOf(builder.key) : builder.name;
-    this.shortName = builder.shortName == null ? this.name : builder.shortName;
-    this.description = builder.description;
-    this.uuid = builder.uuid;
-    this.projectAttributes = Optional.ofNullable(builder.projectVersion)
-      .map(v -> new ProjectAttributes(v, builder.buildString, builder.scmRevisionId))
-      .orElse(null);
-    this.reportAttributes = ReportAttributes.newBuilder(builder.ref)
-      .build();
-    this.fileAttributes = builder.fileAttributes == null ? DEFAULT_FILE_ATTRIBUTES : builder.fileAttributes;
-    this.children = ImmutableList.copyOf(builder.children);
-  }
-
-  @Override
-  public Type getType() {
-    return type;
-  }
-
-  @Override
-  public Status getStatus() {
-    return status;
-  }
-
-  @Override
-  public String getUuid() {
-    if (uuid == null) {
-      throw new UnsupportedOperationException(String.format("Component uuid of ref '%d' has not be fed yet", this.reportAttributes.getRef()));
-    }
-    return uuid;
-  }
-
-  @Override
-  public String getDbKey() {
-    if (key == null) {
-      throw new UnsupportedOperationException(String.format("Component key of ref '%d' has not be fed yet", this.reportAttributes.getRef()));
-    }
-    return key;
-  }
-
-  @Override
-  public String getKey() {
-    if (publicKey == null) {
-      throw new UnsupportedOperationException(String.format("Component key of ref '%d' has not be fed yet", this.reportAttributes.getRef()));
-    }
-    return publicKey;
-  }
-
-  @Override
-  public String getName() {
-    return this.name;
-  }
-
-  @Override
-  public String getShortName() {
-    return this.shortName;
-  }
-
-  @Override
-  @CheckForNull
-  public String getDescription() {
-    return this.description;
-  }
-
-  @Override
-  public List<Component> getChildren() {
-    return children;
-  }
-
-  @Override
-  public ProjectAttributes getProjectAttributes() {
-    checkState(this.type == Type.PROJECT);
-    return this.projectAttributes;
-  }
-
-  @Override
-  public ReportAttributes getReportAttributes() {
-    return this.reportAttributes;
-  }
-
-  @Override
-  public FileAttributes getFileAttributes() {
-    checkState(this.type == Type.FILE, "Only component of type FILE can have a FileAttributes object");
-    return this.fileAttributes;
-  }
-
-  @Override
-  public ProjectViewAttributes getProjectViewAttributes() {
-    throw new IllegalStateException("Only component of type PROJECT_VIEW can have a ProjectViewAttributes object");
-  }
-
-  @Override
-  public SubViewAttributes getSubViewAttributes() {
-    throw new IllegalStateException("Only component of type SUBVIEW have a SubViewAttributes object");
-  }
-
-  @Override
-  public ViewAttributes getViewAttributes() {
-    throw new IllegalStateException("Only component of type VIEW have a ViewAttributes object");
-  }
-
-  @Override
-  public boolean equals(@Nullable Object o) {
-    if (this == o) {
-      return true;
-    }
-    if (o == null || getClass() != o.getClass()) {
-      return false;
-    }
-    ReportComponent that = (ReportComponent) o;
-    return uuid.equals(that.uuid);
-  }
-
-  @Override
-  public int hashCode() {
-    return uuid.hashCode();
-  }
-
-  @Override
-  public String toString() {
-    return "ReportComponent{" +
-      "ref=" + this.reportAttributes.getRef() +
-      ", key='" + key + '\'' +
-      ", type=" + type +
-      '}';
-  }
-
-  public static Builder builder(Type type, int ref) {
-    String key = "key_" + ref;
-    return new Builder(type, ref).setKey(key).setPublicKey(key).setUuid("uuid_" + ref).setName("name_" + ref);
-  }
-
-  public static final class Builder {
-    private final Type type;
-    private final int ref;
-    private Status status;
-    private String uuid;
-    private String key;
-    private String publicKey;
-    private String name;
-    private String shortName;
-    private String projectVersion;
-    private String buildString;
-    private String scmRevisionId;
-    private String description;
-    private FileAttributes fileAttributes;
-    private final List<Component> children = new ArrayList<>();
-
-    private Builder(Type type, int ref) {
-      checkArgument(type.isReportType(), "Component type must be a report type");
-      this.type = type;
-      this.ref = ref;
-      if (type == Type.PROJECT) {
-        this.projectVersion = "toBeDefined";
-      }
-    }
-
-    public Builder setStatus(Status s) {
-      this.status = requireNonNull(s);
-      return this;
-    }
-
-    public Builder setUuid(String s) {
-      this.uuid = requireNonNull(s);
-      return this;
-    }
-
-    public Builder setName(@Nullable String s) {
-      this.name = s;
-      return this;
-    }
-
-    public Builder setShortName(@Nullable String s) {
-      this.shortName = s;
-      return this;
-    }
-
-    public Builder setKey(String s) {
-      this.key = requireNonNull(s);
-      return this;
-    }
-
-    public Builder setPublicKey(String publicKey) {
-      this.publicKey = requireNonNull(publicKey);
-      return this;
-    }
-
-    public Builder setProjectVersion(@Nullable String s) {
-      checkProjectVersion(s);
-      this.projectVersion = s;
-      return this;
-    }
-
-    public Builder setBuildString(@Nullable String buildString) {
-      checkBuildString(buildString);
-      this.buildString = buildString;
-      return this;
-    }
-
-    public Builder setScmRevisionId(@Nullable String scmRevisionId) {
-      this.scmRevisionId = scmRevisionId;
-      return this;
-    }
-
-    public Builder setFileAttributes(FileAttributes fileAttributes) {
-      checkState(type == Type.FILE, "Only Component of type File can have File attributes");
-      this.fileAttributes = fileAttributes;
-      return this;
-    }
-
-    public Builder setDescription(@Nullable String description) {
-      this.description = description;
-      return this;
-    }
-
-    public Builder addChildren(Component... c) {
-      for (Component component : c) {
-        checkArgument(component.getType().isReportType());
-      }
-      this.children.addAll(asList(c));
-      return this;
-    }
-
-    public ReportComponent build() {
-      checkProjectVersion(this.projectVersion);
-      checkBuildString(this.buildString);
-      return new ReportComponent(this);
-    }
-
-    private void checkProjectVersion(@Nullable String s) {
-      checkArgument(type != Type.PROJECT ^ s != null, "Project version must and can only be set on Project");
-    }
-
-    private void checkBuildString(@Nullable String s) {
-      checkArgument(type == Type.PROJECT || s == null, "BuildString can only be set on Project");
-    }
-  }
-}
diff --git a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/component/TreeComponentProvider.java b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/component/TreeComponentProvider.java
deleted file mode 100644 (file)
index 10ebd61..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info 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.ce.task.projectanalysis.component;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import static com.google.common.base.Preconditions.checkState;
-
-public final class TreeComponentProvider extends AbstractComponentProvider {
-  private final Component root;
-  private final Map<String, Component> componentsByRef = new HashMap<>();
-
-  public TreeComponentProvider(Component root) {
-    this.root = root;
-    ensureInitialized();
-  }
-
-  private static String getRef(Component component) {
-    return component.getType().isReportType() ? String.valueOf(component.getReportAttributes().getRef()) : component.getDbKey();
-  }
-
-  @Override
-  protected void ensureInitializedImpl() {
-    new DepthTraversalTypeAwareCrawler(
-      new TypeAwareVisitorAdapter(CrawlerDepthLimit.LEAVES, ComponentVisitor.Order.PRE_ORDER) {
-        @Override
-        public void visitAny(Component component) {
-          String ref = getRef(component);
-          checkState(!componentsByRef.containsKey(ref), "Tree contains more than one component with ref " + ref);
-          componentsByRef.put(ref, component);
-        }
-      }).visit(root);
-  }
-
-  @Override
-  protected void resetImpl() {
-    // we can not reset
-  }
-
-  @Override
-  protected Component getByRefImpl(int componentRef) {
-    Component component = componentsByRef.get(String.valueOf(componentRef));
-    checkState(component != null, "Can not find Component for ref " + componentRef);
-    return component;
-  }
-}
diff --git a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/component/TreeRootHolderComponentProvider.java b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/component/TreeRootHolderComponentProvider.java
deleted file mode 100644 (file)
index da7eae0..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info 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.ce.task.projectanalysis.component;
-
-public final class TreeRootHolderComponentProvider extends AbstractComponentProvider {
-  private final TreeRootHolder treeRootHolder;
-  private TreeComponentProvider delegate;
-
-  public TreeRootHolderComponentProvider(TreeRootHolder treeRootHolder) {
-    this.treeRootHolder = treeRootHolder;
-  }
-
-  @Override
-  protected void ensureInitializedImpl() {
-    if (this.delegate == null) {
-      this.delegate = new TreeComponentProvider(treeRootHolder.getRoot());
-      this.delegate.ensureInitialized();
-    }
-  }
-
-  @Override
-  protected void resetImpl() {
-    this.delegate = null;
-  }
-
-  @Override
-  protected Component getByRefImpl(int componentRef) {
-    return delegate.getByRef(componentRef);
-  }
-}
diff --git a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/component/TreeRootHolderRule.java b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/component/TreeRootHolderRule.java
deleted file mode 100644 (file)
index bfdaa2f..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info 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.ce.task.projectanalysis.component;
-
-import java.util.Optional;
-import org.junit.rules.ExternalResource;
-
-public class TreeRootHolderRule extends ExternalResource implements TreeRootHolder {
-  protected TreeRootHolderImpl delegate = new TreeRootHolderImpl();
-
-  @Override
-  protected void after() {
-    this.delegate = null;
-  }
-
-  public TreeRootHolderRule setRoot(Component root) {
-    return setRoots(root, root);
-  }
-
-  public TreeRootHolderRule setRoots(Component root, Component reportRoot) {
-    delegate = new TreeRootHolderImpl();
-    delegate.setRoots(root, reportRoot);
-    return this;
-  }
-
-  @Override
-  public boolean isEmpty() {
-    return delegate.isEmpty();
-  }
-
-  @Override
-  public Component getRoot() {
-    return delegate.getRoot();
-  }
-
-  @Override
-  public Component getReportTreeRoot() {
-    return delegate.getReportTreeRoot();
-  }
-
-  @Override
-  public Component getComponentByRef(int ref) {
-    return delegate.getComponentByRef(ref);
-  }
-
-  @Override
-  public Optional<Component> getOptionalComponentByRef(int ref) {
-    return delegate.getOptionalComponentByRef(ref);
-  }
-
-  @Override public Component getReportTreeComponentByRef(int ref) {
-    return delegate.getReportTreeComponentByRef(ref);
-  }
-
-  @Override
-  public int getSize() {
-    return delegate.getSize();
-  }
-
-}
diff --git a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/component/ViewsComponent.java b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/component/ViewsComponent.java
deleted file mode 100644 (file)
index a8f5afb..0000000
+++ /dev/null
@@ -1,253 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info 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.ce.task.projectanalysis.component;
-
-import com.google.common.collect.ImmutableList;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Objects;
-import javax.annotation.CheckForNull;
-import javax.annotation.Nullable;
-
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkState;
-import static java.util.Arrays.asList;
-import static java.util.Objects.requireNonNull;
-
-/**
- * Implementation of {@link Component} to unit test views components.
- */
-public class ViewsComponent implements Component {
-  private final Type type;
-  private final String key;
-  private final String uuid;
-  private final String name;
-  private final String description;
-  private final List<Component> children;
-  private final ProjectViewAttributes projectViewAttributes;
-  private final SubViewAttributes subViewAttributes;
-  private final ViewAttributes viewAttributes;
-
-  private ViewsComponent(Type type, String key, @Nullable String uuid, @Nullable String name, @Nullable String description,
-    List<Component> children, @Nullable ProjectViewAttributes projectViewAttributes, @Nullable SubViewAttributes subViewAttributes,
-    @Nullable ViewAttributes viewAttributes) {
-    checkArgument(type.isViewsType(), "Component type must be a Views type");
-    this.type = type;
-    this.key = requireNonNull(key);
-    this.uuid = uuid;
-    this.name = name;
-    this.description = description;
-    this.children = ImmutableList.copyOf(children);
-    this.projectViewAttributes = projectViewAttributes;
-    this.subViewAttributes = subViewAttributes;
-    this.viewAttributes = viewAttributes;
-  }
-
-  public static Builder builder(Type type, String key) {
-    return new Builder(type, key);
-  }
-
-  public static Builder builder(Type type, int key) {
-    return new Builder(type, String.valueOf(key));
-  }
-
-  public static final class Builder {
-    private final Type type;
-    private String key;
-    private String uuid;
-    private String name;
-    private String description;
-    private List<Component> children = new ArrayList<>();
-    private ProjectViewAttributes projectViewAttributes;
-    private SubViewAttributes subViewAttributes;
-    private ViewAttributes viewAttributes;
-
-    private Builder(Type type, String key) {
-      this.type = type;
-      this.key = key;
-    }
-
-    public Builder setUuid(@Nullable String uuid) {
-      this.uuid = uuid;
-      return this;
-    }
-
-    public Builder setKey(String key) {
-      this.key = key;
-      return this;
-    }
-
-    public Builder setName(@Nullable String name) {
-      this.name = name;
-      return this;
-    }
-
-    public Builder setDescription(String description) {
-      this.description = description;
-      return this;
-    }
-
-    public Builder setChildren(List<Component> children) {
-      this.children = children;
-      return this;
-    }
-
-    public Builder setProjectViewAttributes(@Nullable ProjectViewAttributes projectViewAttributes) {
-      this.projectViewAttributes = projectViewAttributes;
-      return this;
-    }
-
-    public Builder setSubViewAttributes(@Nullable SubViewAttributes subViewAttributes) {
-      this.subViewAttributes = subViewAttributes;
-      return this;
-    }
-
-    public Builder setViewAttributes(@Nullable ViewAttributes viewAttributes) {
-      this.viewAttributes = viewAttributes;
-      return this;
-    }
-
-    public Builder addChildren(Component... c) {
-      for (Component viewsComponent : c) {
-        checkArgument(viewsComponent.getType().isViewsType());
-      }
-      this.children.addAll(asList(c));
-      return this;
-    }
-
-    public ViewsComponent build() {
-      return new ViewsComponent(type, key, uuid, name, description, children, projectViewAttributes, subViewAttributes, viewAttributes);
-    }
-  }
-
-  @Override
-  public Type getType() {
-    return type;
-  }
-
-  @Override
-  public Status getStatus() {
-    return Status.UNAVAILABLE;
-  }
-
-  @Override
-  public String getUuid() {
-    return uuid;
-  }
-
-  @Override
-  public String getDbKey() {
-    return key;
-  }
-
-  /**
-   * Views has no branch feature, the public key is the same as the key
-   */
-  @Override
-  public String getKey() {
-    return getDbKey();
-  }
-
-  @Override
-  public String getName() {
-    checkState(this.name != null, "No name has been set");
-    return this.name;
-  }
-
-  @Override
-  public String getShortName() {
-    return getName();
-  }
-
-  @Override
-  @CheckForNull
-  public String getDescription() {
-    return this.description;
-  }
-
-  @Override
-  public List<Component> getChildren() {
-    return children;
-  }
-
-  @Override
-  public ProjectAttributes getProjectAttributes() {
-    throw new IllegalStateException("A component of type " + type + " does not have project attributes");
-  }
-
-  @Override
-  public ReportAttributes getReportAttributes() {
-    throw new IllegalStateException("A component of type " + type + " does not have report attributes");
-  }
-
-  @Override
-  public FileAttributes getFileAttributes() {
-    throw new IllegalStateException("A component of type " + type + " does not have file attributes");
-  }
-
-  @Override
-  public ProjectViewAttributes getProjectViewAttributes() {
-    checkState(this.type != Type.PROJECT_VIEW || this.projectViewAttributes != null, "A ProjectViewAttribute object should have been set");
-    return this.projectViewAttributes;
-  }
-
-  @Override
-  public SubViewAttributes getSubViewAttributes() {
-    checkState(this.type != Type.SUBVIEW || this.subViewAttributes != null, "A SubViewAttributes object should have been set");
-    return this.subViewAttributes;
-  }
-
-  @Override
-  public ViewAttributes getViewAttributes() {
-    checkState(this.type != Type.VIEW || this.viewAttributes != null, "A ViewAttributes object should have been set");
-    return viewAttributes;
-  }
-
-  @Override
-  public String toString() {
-    return "ViewsComponent{" +
-      "type=" + type +
-      ", key='" + key + '\'' +
-      ", uuid='" + uuid + '\'' +
-      ", name='" + name + '\'' +
-      ", children=" + children +
-      ", projectViewAttributes=" + projectViewAttributes +
-      ", subViewAttributes=" + subViewAttributes +
-      ", viewAttributes=" + viewAttributes +
-      '}';
-  }
-
-  @Override
-  public boolean equals(@Nullable Object o) {
-    if (this == o) {
-      return true;
-    }
-    if (o == null || getClass() != o.getClass()) {
-      return false;
-    }
-    ViewsComponent that = (ViewsComponent) o;
-    return key.equals(that.key);
-  }
-
-  @Override
-  public int hashCode() {
-    return Objects.hash(key);
-  }
-}
diff --git a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/measure/MeasureAssert.java b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/measure/MeasureAssert.java
deleted file mode 100644 (file)
index 7b8d2ea..0000000
+++ /dev/null
@@ -1,255 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info 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.ce.task.projectanalysis.measure;
-
-import java.util.Objects;
-import java.util.Optional;
-import javax.annotation.Nullable;
-import org.assertj.core.api.AbstractAssert;
-import org.assertj.core.data.Offset;
-
-import static java.lang.Math.abs;
-
-public class MeasureAssert extends AbstractAssert<MeasureAssert, Measure> {
-
-  protected MeasureAssert(@Nullable Measure actual) {
-    super(actual, MeasureAssert.class);
-  }
-
-  public static MeasureAssert assertThat(Measure actual) {
-    return new MeasureAssert(actual);
-  }
-
-  public static MeasureAssert assertThat(@Nullable Optional<Measure> actual) {
-    return new MeasureAssert(actual == null ? null : actual.orElse(null));
-  }
-
-  public MeasureAssert hasValueType(Measure.ValueType expected) {
-    isNotNull();
-
-    if (actual.getValueType() != expected) {
-      failWithMessage("Expected ValueType of Measure to be <%s> but was <%s>", expected, actual.getValueType());
-    }
-
-    return this;
-  }
-
-  public MeasureAssert hasValue(int expected) {
-    isNotNull();
-
-    if (actual.getValueType() != Measure.ValueType.INT) {
-      failWithMessage(
-        "Expected Measure to have an int value and therefore its ValueType to be <%s> but was <%s>",
-        Measure.ValueType.INT, actual.getValueType());
-    }
-
-    if (actual.getIntValue() != expected) {
-      failWithMessage("Expected value of Measure to be <%s> but was <%s>", expected, actual.getIntValue());
-    }
-
-    return this;
-  }
-
-  public MeasureAssert hasValue(long expected) {
-    isNotNull();
-
-    if (actual.getValueType() != Measure.ValueType.LONG) {
-      failWithMessage(
-        "Expected Measure to have a long value and therefore its ValueType to be <%s> but was <%s>",
-        Measure.ValueType.LONG, actual.getValueType());
-    }
-
-    if (actual.getLongValue() != expected) {
-      failWithMessage("Expected value of Measure to be <%s> but was <%s>", expected, actual.getLongValue());
-    }
-
-    return this;
-  }
-
-  public MeasureAssert hasValue(double expected) {
-    isNotNull();
-
-    if (actual.getValueType() != Measure.ValueType.DOUBLE) {
-      failWithMessage(
-        "Expected Measure to have a double value and therefore its ValueType to be <%s> but was <%s>",
-        Measure.ValueType.DOUBLE, actual.getValueType());
-    }
-
-    if (actual.getDoubleValue() != expected) {
-      failWithMessage("Expected value of Measure to be <%s> but was <%s>", expected, actual.getDoubleValue());
-    }
-
-    return this;
-  }
-
-  public MeasureAssert hasValue(boolean expected) {
-    isNotNull();
-
-    if (actual.getValueType() != Measure.ValueType.BOOLEAN) {
-      failWithMessage(
-        "Expected Measure to have a boolean value and therefore its ValueType to be <%s> but was <%s>",
-        Measure.ValueType.DOUBLE, actual.getValueType());
-    }
-
-    if (actual.getBooleanValue() != expected) {
-      failWithMessage("Expected value of Measure to be <%s> but was <%s>", expected, actual.getBooleanValue());
-    }
-
-    return this;
-  }
-
-  public MeasureAssert hasValue(String expected) {
-    isNotNull();
-
-    if (actual.getValueType() != Measure.ValueType.STRING) {
-      failWithMessage(
-        "Expected Measure to have a String value and therefore its ValueType to be <%s> but was <%s>",
-        Measure.ValueType.DOUBLE, actual.getValueType());
-    }
-
-    if (!Objects.equals(actual.getStringValue(), expected)) {
-      failWithMessage("Expected value of Measure to be <%s> but was <%s>", expected, actual.getStringValue());
-    }
-
-    return this;
-  }
-
-  public MeasureAssert hasValue(Measure.Level expected) {
-    isNotNull();
-
-    if (actual.getValueType() != Measure.ValueType.LEVEL) {
-      failWithMessage(
-        "Expected Measure to have a Level value and therefore its ValueType to be <%s> but was <%s>",
-        Measure.ValueType.DOUBLE, actual.getValueType());
-    }
-
-    if (actual.getLevelValue() != expected) {
-      failWithMessage("Expected value of Measure to be <%s> but was <%s>", expected, actual.getLevelValue());
-    }
-
-    return this;
-  }
-
-  public MeasureAssert hasNoValue() {
-    isNotNull();
-
-    if (actual.getValueType() != Measure.ValueType.NO_VALUE) {
-      failWithMessage(
-        "Expected Measure to have no value and therefore its ValueType to be <%s> but was <%s>",
-        Measure.ValueType.DOUBLE, actual.getValueType());
-    }
-
-    return this;
-  }
-
-  public MeasureAssert hasData(String expected) {
-    isNotNull();
-
-    if (!Objects.equals(actual.getData(), expected)) {
-      failWithMessage("Expected data of Measure to be <%s> but was <%s>", expected, actual.getData());
-    }
-
-    return this;
-  }
-
-  public MeasureAssert hasNoData() {
-    isNotNull();
-
-    if (actual.getData() == null) {
-      failWithMessage("Expected Measure to have no data but was <%s>", actual.getData());
-    }
-
-    return this;
-  }
-
-  public MeasureAssert hasQualityGateLevel(Measure.Level expected) {
-    isNotNull();
-    hasQualityGateStatus();
-
-    if (actual.getQualityGateStatus().getStatus() != expected) {
-      failWithMessage("Expected Level of QualityGateStatus of Measure to be <%s> but was <%s>", expected, actual.getQualityGateStatus().getStatus());
-    }
-
-    return this;
-  }
-
-  public MeasureAssert hasQualityGateText(String expected) {
-    isNotNull();
-    hasQualityGateStatus();
-
-    if (!Objects.equals(actual.getQualityGateStatus().getText(), expected)) {
-      failWithMessage("Expected text of QualityGateStatus of Measure to be \n<%s>\n but was \n<%s>", expected, actual.getQualityGateStatus().getText());
-    }
-
-    return this;
-  }
-
-  private void hasQualityGateStatus() {
-    if (!actual.hasQualityGateStatus()) {
-      failWithMessage("Expected Measure to have a QualityGateStatus but it did not");
-    }
-  }
-
-  public MeasureAssert hasVariation(double expected) {
-    isNotNull();
-    hasVariation();
-
-    if (!actual.hasVariation()) {
-      failWithMessage("Expected Measure to have a variation but it did not");
-    }
-
-    double variation = actual.getVariation();
-    if (variation != expected) {
-      failWithMessage("Expected variation of Measure to be <%s> but was <%s>", expected, variation);
-    }
-
-    return this;
-  }
-
-  public MeasureAssert hasVariation(double expected, Offset<Double> offset) {
-    isNotNull();
-    hasVariation();
-
-    if (!actual.hasVariation()) {
-      failWithMessage("Expected Measure to have a variation but it did not");
-    }
-
-    double variation = actual.getVariation();
-    if (abs(expected - variation) > offset.value) {
-      failWithMessage(
-        "Expected variation of Measure to be close to <%s> by less than <%s> but was <%s>",
-        expected, offset.value, variation);
-    }
-
-    return this;
-  }
-
-  private void hasVariation() {
-    if (!actual.hasVariation()) {
-      failWithMessage("Expected Measure to have a variation but it did not");
-    }
-  }
-
-  public void isAbsent() {
-    if (actual != null) {
-      failWithMessage("Expected measure to be absent");
-    }
-  }
-}
diff --git a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/measure/MeasureRepoEntry.java b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/measure/MeasureRepoEntry.java
deleted file mode 100644 (file)
index 2cf7fc1..0000000
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info 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.ce.task.projectanalysis.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.ce.task.projectanalysis.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 measure.getValueType() == measure1.getValueType()
-      && equalsByValue(measure, measure1)
-      && equalsByVariation(measure, measure1)
-      && equalsByQualityGateStatus(measure, measure1)
-      && 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) {
-    return measure.hasVariation() == measure1.hasVariation() && (!measure.hasVariation()
-      || Double.compare(scale(measure.getVariation()), scale(measure1.getVariation())) == 0);
-  }
-
-  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());
-    }
-  }
-}
diff --git a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/measure/MeasureRepositoryRule.java b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/measure/MeasureRepositoryRule.java
deleted file mode 100644 (file)
index 2c57915..0000000
+++ /dev/null
@@ -1,316 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info 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.ce.task.projectanalysis.measure;
-
-import com.google.common.base.Function;
-import com.google.common.base.Predicate;
-import com.google.common.collect.ImmutableSetMultimap;
-import com.google.common.collect.SetMultimap;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Optional;
-import java.util.Set;
-import javax.annotation.CheckForNull;
-import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
-import org.junit.rules.ExternalResource;
-import org.sonar.ce.task.projectanalysis.component.Component;
-import org.sonar.ce.task.projectanalysis.component.ComponentProvider;
-import org.sonar.ce.task.projectanalysis.component.NoComponentProvider;
-import org.sonar.ce.task.projectanalysis.component.TreeComponentProvider;
-import org.sonar.ce.task.projectanalysis.component.TreeRootHolder;
-import org.sonar.ce.task.projectanalysis.component.TreeRootHolderComponentProvider;
-import org.sonar.ce.task.projectanalysis.metric.Metric;
-import org.sonar.ce.task.projectanalysis.metric.MetricRepositoryRule;
-
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkState;
-import static com.google.common.collect.FluentIterable.from;
-import static com.google.common.collect.Maps.filterKeys;
-import static java.lang.String.format;
-import static java.util.Objects.requireNonNull;
-
-/**
- * An implementation of MeasureRepository as a JUnit rule which provides add methods for raw measures and extra add
- * methods that takes component ref and metric keys thanks to the integration with various Component and Metric
- * providers.
- */
-public class MeasureRepositoryRule extends ExternalResource implements MeasureRepository {
-  private final ComponentProvider componentProvider;
-  @CheckForNull
-  private final MetricRepositoryRule metricRepositoryRule;
-  private final Map<InternalKey, Measure> baseMeasures = new HashMap<>();
-  private final Map<InternalKey, Measure> rawMeasures = new HashMap<>();
-  private final Map<InternalKey, Measure> initialRawMeasures = new HashMap<>();
-  private final Predicate<Map.Entry<InternalKey, Measure>> isAddedMeasure = input -> !initialRawMeasures.containsKey(input.getKey())
-    || !MeasureRepoEntry.deepEquals(input.getValue(), initialRawMeasures.get(input.getKey()));
-
-  private MeasureRepositoryRule(ComponentProvider componentProvider, @Nullable MetricRepositoryRule metricRepositoryRule) {
-    this.componentProvider = componentProvider;
-    this.metricRepositoryRule = metricRepositoryRule;
-  }
-
-  @Override
-  protected void after() {
-    componentProvider.reset();
-    baseMeasures.clear();
-    rawMeasures.clear();
-  }
-
-  public static MeasureRepositoryRule create() {
-    return new MeasureRepositoryRule(NoComponentProvider.INSTANCE, null);
-  }
-
-  public static MeasureRepositoryRule create(TreeRootHolder treeRootHolder, MetricRepositoryRule metricRepositoryRule) {
-    return new MeasureRepositoryRule(new TreeRootHolderComponentProvider(treeRootHolder), requireNonNull(metricRepositoryRule));
-  }
-
-  public static MeasureRepositoryRule create(Component treeRoot, MetricRepositoryRule metricRepositoryRule) {
-    return new MeasureRepositoryRule(new TreeComponentProvider(treeRoot), requireNonNull(metricRepositoryRule));
-  }
-
-  public MeasureRepositoryRule addBaseMeasure(int componentRef, String metricKey, Measure measure) {
-    checkAndInitProvidersState();
-
-    InternalKey internalKey = new InternalKey(componentProvider.getByRef(componentRef), metricRepositoryRule.getByKey(metricKey));
-    checkState(!baseMeasures.containsKey(internalKey), format("Can not add a BaseMeasure twice for a Component (ref=%s) and Metric (key=%s)", componentRef, metricKey));
-
-    baseMeasures.put(internalKey, measure);
-
-    return this;
-  }
-
-  public SetMultimap<String, Measure> getRawMeasures(int componentRef) {
-    return getRawMeasures(componentProvider.getByRef(componentRef));
-  }
-
-  /**
-   * Return measures that were added by the step (using {@link #add(Component, Metric, Measure)}).
-   * It does not contain the one added in the test by {@link #addRawMeasure(int, String, Measure)}
-   */
-  public SetMultimap<String, Measure> getAddedRawMeasures(int componentRef) {
-    checkAndInitProvidersState();
-
-    return getAddedRawMeasures(componentProvider.getByRef(componentRef));
-  }
-
-  /**
-   * Return a measure that were added by the step (using {@link #add(Component, Metric, Measure)}).
-   * It does not contain the one added in the test by {@link #addRawMeasure(int, String, Measure)}
-   */
-  public Optional<Measure> getAddedRawMeasure(Component component, String metricKey) {
-    return getAddedRawMeasure(component.getReportAttributes().getRef(), metricKey);
-  }
-
-  /**
-   * Return a measure that were added by the step (using {@link #add(Component, Metric, Measure)}).
-   * It does not contain the one added in the test by {@link #addRawMeasure(int, String, Measure)}
-   */
-  public Optional<Measure> getAddedRawMeasure(int componentRef, String metricKey) {
-    checkAndInitProvidersState();
-
-    Set<Measure> measures = getAddedRawMeasures(componentProvider.getByRef(componentRef)).get(metricKey);
-    if (measures.isEmpty()) {
-      return Optional.empty();
-    }
-    checkArgument(measures.size() == 1, String.format("There is more than one measure on metric '%s' for component '%s'", metricKey, componentRef));
-    return Optional.of(measures.iterator().next());
-  }
-
-  /**
-   * Return measures that were added by the step (using {@link #add(Component, Metric, Measure)}).
-   * It does not contain the one added in the test by {@link #addRawMeasure(int, String, Measure)}
-   */
-  public SetMultimap<String, Measure> getAddedRawMeasures(Component component) {
-    checkAndInitProvidersState();
-
-    ImmutableSetMultimap.Builder<String, Measure> builder = ImmutableSetMultimap.builder();
-    for (Map.Entry<InternalKey, Measure> entry : from(filterKeys(rawMeasures, hasComponentRef(component)).entrySet()).filter(isAddedMeasure)) {
-      builder.put(entry.getKey().getMetricKey(), entry.getValue());
-    }
-    return builder.build();
-  }
-
-  public MeasureRepositoryRule addRawMeasure(int componentRef, String metricKey, Measure measure) {
-    checkAndInitProvidersState();
-
-    InternalKey internalKey = new InternalKey(componentProvider.getByRef(componentRef), metricRepositoryRule.getByKey(metricKey));
-    checkState(!rawMeasures.containsKey(internalKey), format(
-      "A measure can only be set once for Component (ref=%s), Metric (key=%s)",
-      componentRef, metricKey));
-
-    rawMeasures.put(internalKey, measure);
-    initialRawMeasures.put(internalKey, measure);
-
-    return this;
-  }
-
-  @Override
-  public Optional<Measure> getBaseMeasure(Component component, Metric metric) {
-    return Optional.ofNullable(baseMeasures.get(new InternalKey(component, metric)));
-  }
-
-  @Override
-  public Optional<Measure> getRawMeasure(Component component, Metric metric) {
-    return Optional.ofNullable(rawMeasures.get(new InternalKey(component, metric)));
-  }
-
-  @Override
-  public Set<Measure> getRawMeasures(Component component, Metric metric) {
-    return from(filterKeys(rawMeasures, hasComponentRef(component)).entrySet()).filter(new MatchMetric(metric)).transform(ToMeasure.INSTANCE).toSet();
-  }
-
-  @Override
-  public SetMultimap<String, Measure> getRawMeasures(Component component) {
-    ImmutableSetMultimap.Builder<String, Measure> builder = ImmutableSetMultimap.builder();
-    for (Map.Entry<InternalKey, Measure> entry : filterKeys(rawMeasures, hasComponentRef(component)).entrySet()) {
-      builder.put(entry.getKey().getMetricKey(), entry.getValue());
-    }
-    return builder.build();
-  }
-
-  private HasComponentRefPredicate hasComponentRef(Component component) {
-    return new HasComponentRefPredicate(component);
-  }
-
-  @Override
-  public void add(Component component, Metric metric, Measure measure) {
-    String ref = getRef(component);
-    InternalKey internalKey = new InternalKey(ref, metric.getKey());
-    if (rawMeasures.containsKey(internalKey)) {
-      throw new UnsupportedOperationException(format(
-        "A measure can only be set once for Component (ref=%s), Metric (key=%s)",
-        ref, metric.getKey()));
-    }
-    rawMeasures.put(internalKey, measure);
-  }
-
-  @Override
-  public void update(Component component, Metric metric, Measure measure) {
-    String componentRef = getRef(component);
-    InternalKey internalKey = new InternalKey(componentRef, metric.getKey());
-    if (!rawMeasures.containsKey(internalKey)) {
-      throw new UnsupportedOperationException(format(
-        "A measure can only be updated if it has been added first for Component (ref=%s), Metric (key=%s)",
-        componentRef, metric.getKey()));
-    }
-    rawMeasures.put(internalKey, measure);
-  }
-
-  private void checkAndInitProvidersState() {
-    checkState(metricRepositoryRule != null, "Can not add a measure by metric key if MeasureRepositoryRule has not been created for a MetricRepository");
-    componentProvider.ensureInitialized();
-  }
-
-  public boolean isEmpty() {
-    return rawMeasures.isEmpty();
-  }
-
-  private static final class InternalKey {
-    private final String componentRef;
-    private final String metricKey;
-
-    public InternalKey(Component component, Metric metric) {
-      this(getRef(component), metric.getKey());
-    }
-
-    private InternalKey(String componentRef, String metricKey) {
-      this.componentRef = componentRef;
-      this.metricKey = metricKey;
-    }
-
-    public String getComponentRef() {
-      return componentRef;
-    }
-
-    public String getMetricKey() {
-      return metricKey;
-    }
-
-    @Override
-    public boolean equals(@Nullable Object o) {
-      if (this == o) {
-        return true;
-      }
-      if (o == null || getClass() != o.getClass()) {
-        return false;
-      }
-      InternalKey that = (InternalKey) o;
-      return Objects.equals(componentRef, that.componentRef) &&
-        Objects.equals(metricKey, that.metricKey);
-    }
-
-    @Override
-    public int hashCode() {
-      return Objects.hash(componentRef, metricKey);
-    }
-
-    @Override
-    public String toString() {
-      return "InternalKey{" +
-        "component=" + componentRef +
-        ", metric='" + metricKey + '\'' +
-        '}';
-    }
-  }
-
-  private static class HasComponentRefPredicate implements Predicate<InternalKey> {
-
-    private final String componentRef;
-
-    public HasComponentRefPredicate(Component component) {
-      this.componentRef = getRef(component);
-    }
-
-    @Override
-    public boolean apply(@Nonnull InternalKey input) {
-      return input.getComponentRef().equals(this.componentRef);
-    }
-  }
-
-  private static String getRef(Component component) {
-    return component.getType().isReportType() ? String.valueOf(component.getReportAttributes().getRef()) : component.getDbKey();
-  }
-
-  private static class MatchMetric implements Predicate<Map.Entry<InternalKey, Measure>> {
-    private final Metric metric;
-
-    public MatchMetric(Metric metric) {
-      this.metric = metric;
-    }
-
-    @Override
-    public boolean apply(@Nonnull Map.Entry<InternalKey, Measure> input) {
-      return input.getKey().getMetricKey().equals(metric.getKey());
-    }
-  }
-
-  private enum ToMeasure implements Function<Map.Entry<InternalKey, Measure>, Measure> {
-    INSTANCE;
-
-    @Nullable
-    @Override
-    public Measure apply(@Nonnull Map.Entry<InternalKey, Measure> input) {
-      return input.getValue();
-    }
-  }
-
-}
diff --git a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/metric/MetricRepositoryRule.java b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/metric/MetricRepositoryRule.java
deleted file mode 100644 (file)
index 7f781ff..0000000
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info 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.ce.task.projectanalysis.metric;
-
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Optional;
-import org.junit.rules.ExternalResource;
-
-import static com.google.common.base.Preconditions.checkState;
-import static java.lang.String.format;
-import static java.util.Objects.requireNonNull;
-
-public class MetricRepositoryRule extends ExternalResource implements MetricRepository {
-  private final Map<String, Metric> metricsByKey = new HashMap<>();
-  private final Map<Long, Metric> metricsById = new HashMap<>();
-
-  /**
-   * Convenience method to add a {@link Metric} to the repository created from a {@link org.sonar.api.measures.Metric},
-   * most of the time it will be a constant of the {@link org.sonar.api.measures.CoreMetrics} class.
-   * <p>
-   * For the id of the created metric, this method uses the hashCode of the metric's key. If you want to specify
-   * the id of the create {@link Metric}, use {@link #add(int, org.sonar.api.measures.Metric)}
-   * </p>
-   */
-  public MetricRepositoryRule add(org.sonar.api.measures.Metric<?> coreMetric) {
-    add(from(coreMetric));
-    return this;
-  }
-
-  /**
-   * Convenience method to add a {@link Metric} to the repository created from a {@link org.sonar.api.measures.Metric}
-   * and with the specified id, most of the time it will be a constant of the {@link org.sonar.api.measures.CoreMetrics}
-   * class.
-   */
-  public MetricRepositoryRule add(int id, org.sonar.api.measures.Metric<?> coreMetric) {
-    add(from(id, coreMetric));
-    return this;
-  }
-
-  private static Metric from(org.sonar.api.measures.Metric<?> coreMetric) {
-    return from(coreMetric.getKey().hashCode(), coreMetric);
-  }
-
-  private static Metric from(int id, org.sonar.api.measures.Metric<?> coreMetric) {
-    return new MetricImpl(
-      id, coreMetric.getKey(), coreMetric.getName(),
-      convert(coreMetric.getType()),
-      coreMetric.getDecimalScale(),
-      coreMetric.getBestValue(), coreMetric.isOptimizedBestValue());
-  }
-
-  private static Metric.MetricType convert(org.sonar.api.measures.Metric.ValueType coreMetricType) {
-    return Metric.MetricType.valueOf(coreMetricType.name());
-  }
-
-  public MetricRepositoryRule add(Metric metric) {
-    requireNonNull(metric.getKey(), "key can not be null");
-    requireNonNull(metric.getId(), "id can not be null");
-
-    checkState(!metricsByKey.containsKey(metric.getKey()), format("Repository already contains a metric for key %s", metric.getKey()));
-    checkState(!metricsById.containsKey((long) metric.getId()), format("Repository already contains a metric for id %s", metric.getId()));
-
-    metricsByKey.put(metric.getKey(), metric);
-    metricsById.put((long) metric.getId(), metric);
-
-    return this;
-  }
-
-  @Override
-  protected void after() {
-    this.metricsById.clear();
-    this.metricsById.clear();
-  }
-
-  @Override
-  public Metric getByKey(String key) {
-    Metric res = metricsByKey.get(key);
-    checkState(res != null, format("No Metric can be found for key %s", key));
-    return res;
-  }
-
-  @Override
-  public Metric getById(long id) {
-    Metric res = metricsById.get(id);
-    checkState(res != null, format("No Metric can be found for id %s", id));
-    return res;
-  }
-
-  @Override
-  public Optional<Metric> getOptionalById(long id) {
-    return Optional.of(metricsById.get(id));
-  }
-
-  @Override
-  public Iterable<Metric> getAll() {
-    return metricsByKey.values();
-  }
-}
diff --git a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/step/BaseStepTest.java b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/step/BaseStepTest.java
deleted file mode 100644 (file)
index 16aed80..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info 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.ce.task.projectanalysis.step;
-
-import org.junit.Test;
-import org.sonar.ce.task.step.ComputationStep;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-/**
- * Temporary solution to test metadata. Should be replaced by a medium test of
- * all computation stack
- */
-public abstract class BaseStepTest {
-
-  protected abstract ComputationStep step();
-
-  @Test
-  public void test_metadata() {
-    assertThat(step().toString()).isNotEmpty();
-    assertThat(step().getDescription()).isNotEmpty();
-  }
-}
diff --git a/server/sonar-ce-task-projectanalysis/src/testFixtures/java/org/sonar/ce/task/projectanalysis/analysis/AnalysisMetadataHolderRule.java b/server/sonar-ce-task-projectanalysis/src/testFixtures/java/org/sonar/ce/task/projectanalysis/analysis/AnalysisMetadataHolderRule.java
new file mode 100644 (file)
index 0000000..34a2e0f
--- /dev/null
@@ -0,0 +1,270 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info 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.ce.task.projectanalysis.analysis;
+
+import java.util.Date;
+import java.util.Map;
+import java.util.Optional;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+import org.junit.rules.ExternalResource;
+import org.sonar.ce.task.util.InitializedProperty;
+import org.sonar.db.component.BranchType;
+import org.sonar.db.organization.OrganizationDto;
+import org.sonar.server.project.Project;
+import org.sonar.server.qualityprofile.QualityProfile;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+import static java.util.Objects.requireNonNull;
+import static org.apache.commons.lang.StringUtils.defaultIfBlank;
+
+public class AnalysisMetadataHolderRule extends ExternalResource implements MutableAnalysisMetadataHolder {
+
+  private final InitializedProperty<Boolean> organizationsEnabled = new InitializedProperty<>();
+
+  private final InitializedProperty<Organization> organization = new InitializedProperty<>();
+
+  private final InitializedProperty<String> uuid = new InitializedProperty<>();
+
+  private final InitializedProperty<Long> analysisDate = new InitializedProperty<>();
+
+  private final InitializedProperty<Analysis> baseAnalysis = new InitializedProperty<>();
+
+  private final InitializedProperty<Boolean> crossProjectDuplicationEnabled = new InitializedProperty<>();
+
+  private final InitializedProperty<Branch> branch = new InitializedProperty<>();
+
+  private final InitializedProperty<String> pullRequestId = new InitializedProperty<>();
+
+  private final InitializedProperty<Project> project = new InitializedProperty<>();
+
+  private final InitializedProperty<Integer> rootComponentRef = new InitializedProperty<>();
+
+  private final InitializedProperty<Map<String, QualityProfile>> qProfilesPerLanguage = new InitializedProperty<>();
+
+  private final InitializedProperty<Map<String, ScannerPlugin>> pluginsByKey = new InitializedProperty<>();
+
+  private final InitializedProperty<String> scmRevision = new InitializedProperty<>();
+
+  @Override
+  public AnalysisMetadataHolderRule setOrganizationsEnabled(boolean isOrganizationsEnabled) {
+    this.organizationsEnabled.setProperty(isOrganizationsEnabled);
+    return this;
+  }
+
+  @Override
+  public boolean isOrganizationsEnabled() {
+    checkState(organizationsEnabled.isInitialized(), "Organizations enabled flag has not been set");
+    return organizationsEnabled.getProperty();
+  }
+
+  @Override
+  public AnalysisMetadataHolderRule setOrganization(Organization organization) {
+    requireNonNull(organization, "organization can't be null");
+    this.organization.setProperty(organization);
+    return this;
+  }
+
+  public AnalysisMetadataHolderRule setOrganizationUuid(String uuid, String defaultQualityGateUuid) {
+    requireNonNull(uuid, "organization uuid can't be null");
+    this.organization
+      .setProperty(Organization.from(new OrganizationDto().setUuid(uuid).setKey("key_" + uuid).setName("name_" + uuid).setDefaultQualityGateUuid(defaultQualityGateUuid)));
+    return this;
+  }
+
+  @Override
+  public Organization getOrganization() {
+    checkState(organization.isInitialized(), "Organization has not been set");
+    return this.organization.getProperty();
+  }
+
+  @Override
+  public AnalysisMetadataHolderRule setUuid(String s) {
+    checkNotNull(s, "UUID must not be null");
+    this.uuid.setProperty(s);
+    return this;
+  }
+
+  @Override
+  public String getUuid() {
+    checkState(uuid.isInitialized(), "Analysis UUID has not been set");
+    return this.uuid.getProperty();
+  }
+
+  public AnalysisMetadataHolderRule setAnalysisDate(Date date) {
+    checkNotNull(date, "Date must not be null");
+    this.analysisDate.setProperty(date.getTime());
+    return this;
+  }
+
+  @Override
+  public AnalysisMetadataHolderRule setAnalysisDate(long date) {
+    checkNotNull(date, "Date must not be null");
+    this.analysisDate.setProperty(date);
+    return this;
+  }
+
+  @Override
+  public long getAnalysisDate() {
+    checkState(analysisDate.isInitialized(), "Analysis date has not been set");
+    return this.analysisDate.getProperty();
+  }
+
+  @Override
+  public boolean hasAnalysisDateBeenSet() {
+    return analysisDate.isInitialized();
+  }
+
+  @Override
+  public boolean isFirstAnalysis() {
+    return getBaseAnalysis() == null;
+  }
+
+  @Override
+  public AnalysisMetadataHolderRule setBaseAnalysis(@Nullable Analysis baseAnalysis) {
+    this.baseAnalysis.setProperty(baseAnalysis);
+    return this;
+  }
+
+  @Override
+  @CheckForNull
+  public Analysis getBaseAnalysis() {
+    checkState(baseAnalysis.isInitialized(), "Base analysis has not been set");
+    return baseAnalysis.getProperty();
+  }
+
+  @Override
+  public AnalysisMetadataHolderRule setCrossProjectDuplicationEnabled(boolean isCrossProjectDuplicationEnabled) {
+    this.crossProjectDuplicationEnabled.setProperty(isCrossProjectDuplicationEnabled);
+    return this;
+  }
+
+  @Override
+  public boolean isCrossProjectDuplicationEnabled() {
+    checkState(crossProjectDuplicationEnabled.isInitialized(), "Cross project duplication flag has not been set");
+    return crossProjectDuplicationEnabled.getProperty();
+  }
+
+  @Override
+  public AnalysisMetadataHolderRule setBranch(Branch branch) {
+    this.branch.setProperty(branch);
+    return this;
+  }
+
+  @Override
+  public Branch getBranch() {
+    checkState(branch.isInitialized(), "Branch has not been set");
+    return branch.getProperty();
+  }
+
+  @Override
+  public MutableAnalysisMetadataHolder setPullRequestKey(String pullRequestKey) {
+    this.pullRequestId.setProperty(pullRequestKey);
+    return this;
+  }
+
+  @Override
+  public String getPullRequestKey() {
+    checkState(pullRequestId.isInitialized(), "Pull request id has not been set");
+    return pullRequestId.getProperty();
+  }
+
+  @Override
+  public AnalysisMetadataHolderRule setProject(Project p) {
+    this.project.setProperty(p);
+    return this;
+  }
+
+  @Override
+  public Project getProject() {
+    checkState(project.isInitialized(), "Project has not been set");
+    return project.getProperty();
+  }
+
+  @Override
+  public AnalysisMetadataHolderRule setRootComponentRef(int rootComponentRef) {
+    this.rootComponentRef.setProperty(rootComponentRef);
+    return this;
+  }
+
+  @Override
+  public int getRootComponentRef() {
+    checkState(rootComponentRef.isInitialized(), "Root component ref has not been set");
+    return rootComponentRef.getProperty();
+  }
+
+  @Override
+  public AnalysisMetadataHolderRule setQProfilesByLanguage(Map<String, QualityProfile> qProfilesPerLanguage) {
+    this.qProfilesPerLanguage.setProperty(qProfilesPerLanguage);
+    return this;
+  }
+
+  @Override
+  public Map<String, QualityProfile> getQProfilesByLanguage() {
+    checkState(qProfilesPerLanguage.isInitialized(), "QProfile per language has not been set");
+    return qProfilesPerLanguage.getProperty();
+  }
+
+  @Override
+  public AnalysisMetadataHolderRule setScannerPluginsByKey(Map<String, ScannerPlugin> plugins) {
+    this.pluginsByKey.setProperty(plugins);
+    return this;
+  }
+
+  @Override
+  public Map<String, ScannerPlugin> getScannerPluginsByKey() {
+    checkState(pluginsByKey.isInitialized(), "Plugins per key has not been set");
+    return pluginsByKey.getProperty();
+  }
+
+  @Override
+  public MutableAnalysisMetadataHolder setScmRevision(@Nullable String s) {
+    checkState(!this.scmRevision.isInitialized(), "ScmRevisionId has already been set");
+    this.scmRevision.setProperty(defaultIfBlank(s, null));
+    return this;
+  }
+
+  @Override
+  public Optional<String> getScmRevision() {
+    if (!scmRevision.isInitialized()) {
+      return Optional.empty();
+    }
+    return Optional.ofNullable(scmRevision.getProperty());
+  }
+
+  @Override
+  public boolean isShortLivingBranch() {
+    Branch property = this.branch.getProperty();
+    return property != null && property.getType() == BranchType.SHORT;
+  }
+
+  @Override
+  public boolean isLongLivingBranch() {
+    Branch property = this.branch.getProperty();
+    return property != null && property.getType() == BranchType.LONG;
+  }
+
+  @Override
+  public boolean isPullRequest() {
+    Branch property = this.branch.getProperty();
+    return property != null && property.getType() == BranchType.PULL_REQUEST;
+  }
+}
diff --git a/server/sonar-ce-task-projectanalysis/src/testFixtures/java/org/sonar/ce/task/projectanalysis/analysis/MutableAnalysisMetadataHolderRule.java b/server/sonar-ce-task-projectanalysis/src/testFixtures/java/org/sonar/ce/task/projectanalysis/analysis/MutableAnalysisMetadataHolderRule.java
new file mode 100644 (file)
index 0000000..a622ff7
--- /dev/null
@@ -0,0 +1,211 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info 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.ce.task.projectanalysis.analysis;
+
+import java.util.Map;
+import java.util.Optional;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+import org.junit.rules.ExternalResource;
+import org.sonar.core.platform.PlatformEditionProvider;
+import org.sonar.server.project.Project;
+import org.sonar.server.qualityprofile.QualityProfile;
+
+import static org.mockito.Mockito.mock;
+
+public class MutableAnalysisMetadataHolderRule extends ExternalResource implements MutableAnalysisMetadataHolder {
+
+  private PlatformEditionProvider editionProvider = mock(PlatformEditionProvider.class);
+  private AnalysisMetadataHolderImpl delegate = new AnalysisMetadataHolderImpl(editionProvider);
+
+  @Override
+  protected void after() {
+    delegate = new AnalysisMetadataHolderImpl(editionProvider);
+  }
+
+  @Override
+  public boolean isOrganizationsEnabled() {
+    return delegate.isOrganizationsEnabled();
+  }
+
+  @Override
+  public MutableAnalysisMetadataHolderRule setOrganizationsEnabled(boolean isOrganizationsEnabled) {
+    delegate.setOrganizationsEnabled(isOrganizationsEnabled);
+    return this;
+  }
+
+  @Override
+  public MutableAnalysisMetadataHolderRule setOrganization(Organization organization) {
+    delegate.setOrganization(organization);
+    return this;
+  }
+
+  @Override
+  public Organization getOrganization() {
+    return delegate.getOrganization();
+  }
+
+  public MutableAnalysisMetadataHolderRule setUuid(String s) {
+    delegate.setUuid(s);
+    return this;
+  }
+
+  @Override
+  public String getUuid() {
+    return delegate.getUuid();
+  }
+
+  public MutableAnalysisMetadataHolderRule setAnalysisDate(long date) {
+    delegate.setAnalysisDate(date);
+    return this;
+  }
+
+  @Override
+  public long getAnalysisDate() {
+    return delegate.getAnalysisDate();
+  }
+
+  @Override
+  public boolean hasAnalysisDateBeenSet() {
+    return delegate.hasAnalysisDateBeenSet();
+  }
+
+  @Override
+  public boolean isFirstAnalysis() {
+    return delegate.isFirstAnalysis();
+  }
+
+  @Override
+  public MutableAnalysisMetadataHolderRule setBaseAnalysis(@Nullable Analysis baseAnalysis) {
+    delegate.setBaseAnalysis(baseAnalysis);
+    return this;
+  }
+
+  @Override
+  @CheckForNull
+  public Analysis getBaseAnalysis() {
+    return delegate.getBaseAnalysis();
+  }
+
+  @Override
+  public boolean isCrossProjectDuplicationEnabled() {
+    return delegate.isCrossProjectDuplicationEnabled();
+  }
+
+  @Override
+  public MutableAnalysisMetadataHolderRule setCrossProjectDuplicationEnabled(boolean isCrossProjectDuplicationEnabled) {
+    delegate.setCrossProjectDuplicationEnabled(isCrossProjectDuplicationEnabled);
+    return this;
+  }
+
+  @Override
+  public Branch getBranch() {
+    return delegate.getBranch();
+  }
+
+  @Override
+  public MutableAnalysisMetadataHolderRule setBranch(Branch branch) {
+    delegate.setBranch(branch);
+    return this;
+  }
+
+  @Override
+  public String getPullRequestKey() {
+    return delegate.getPullRequestKey();
+  }
+
+  @Override
+  public MutableAnalysisMetadataHolder setPullRequestKey(String pullRequestKey) {
+    delegate.setPullRequestKey(pullRequestKey);
+    return this;
+  }
+
+  @Override
+  public MutableAnalysisMetadataHolderRule setProject(@Nullable Project project) {
+    delegate.setProject(project);
+    return this;
+  }
+
+  @Override
+  public Project getProject() {
+    return delegate.getProject();
+  }
+
+  @Override
+  public MutableAnalysisMetadataHolderRule setRootComponentRef(int rootComponentRef) {
+    delegate.setRootComponentRef(rootComponentRef);
+    return this;
+  }
+
+  @Override
+  public int getRootComponentRef() {
+    return delegate.getRootComponentRef();
+  }
+
+  @Override
+  public MutableAnalysisMetadataHolder setQProfilesByLanguage(Map<String, QualityProfile> qprofilesByLanguage) {
+    delegate.setQProfilesByLanguage(qprofilesByLanguage);
+    return this;
+  }
+
+  @Override
+  public Map<String, QualityProfile> getQProfilesByLanguage() {
+    return delegate.getQProfilesByLanguage();
+  }
+
+  @Override
+  public MutableAnalysisMetadataHolder setScannerPluginsByKey(Map<String, ScannerPlugin> plugins) {
+    delegate.setScannerPluginsByKey(plugins);
+    return this;
+  }
+
+  @Override
+  public Map<String, ScannerPlugin> getScannerPluginsByKey() {
+    return delegate.getScannerPluginsByKey();
+  }
+
+
+
+  @Override
+  public MutableAnalysisMetadataHolder setScmRevision(String scmRevisionId) {
+    delegate.setScmRevision(scmRevisionId);
+    return this;
+  }
+
+  @Override
+  public Optional<String> getScmRevision() {
+    return delegate.getScmRevision();
+  }
+
+  @Override
+  public boolean isShortLivingBranch() {
+    return delegate.isShortLivingBranch();
+  }
+
+  @Override
+  public boolean isLongLivingBranch() {
+    return delegate.isLongLivingBranch();
+  }
+
+  @Override
+  public boolean isPullRequest() {
+    return delegate.isPullRequest();
+  }
+}
diff --git a/server/sonar-ce-task-projectanalysis/src/testFixtures/java/org/sonar/ce/task/projectanalysis/component/AbstractComponentProvider.java b/server/sonar-ce-task-projectanalysis/src/testFixtures/java/org/sonar/ce/task/projectanalysis/component/AbstractComponentProvider.java
new file mode 100644 (file)
index 0000000..b45de74
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info 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.ce.task.projectanalysis.component;
+
+import static com.google.common.base.Preconditions.checkState;
+
+abstract class AbstractComponentProvider implements ComponentProvider {
+  private boolean initialized = false;
+
+  @Override
+  public void ensureInitialized() {
+    if (!this.initialized) {
+      ensureInitializedImpl();
+      this.initialized = true;
+    }
+  }
+
+  protected abstract void ensureInitializedImpl();
+
+  @Override
+  public void reset() {
+    resetImpl();
+    this.initialized = false;
+  }
+
+  protected abstract void resetImpl();
+
+  @Override
+  public Component getByRef(int componentRef) {
+    checkState(this.initialized, "%s has not been initialized", getClass().getSimpleName());
+    return getByRefImpl(componentRef);
+  }
+
+  protected abstract Component getByRefImpl(int componentRef);
+}
diff --git a/server/sonar-ce-task-projectanalysis/src/testFixtures/java/org/sonar/ce/task/projectanalysis/component/ComponentProvider.java b/server/sonar-ce-task-projectanalysis/src/testFixtures/java/org/sonar/ce/task/projectanalysis/component/ComponentProvider.java
new file mode 100644 (file)
index 0000000..7d04264
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info 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.ce.task.projectanalysis.component;
+
+public interface ComponentProvider {
+  /**
+   * does nothing if already initialized
+   */
+  void ensureInitialized();
+
+  void reset();
+
+  /**
+   * @throws IllegalStateException if no component is found for the specified ref
+   * @throws IllegalStateException if provider has not been initialized
+   */
+  Component getByRef(int componentRef);
+}
diff --git a/server/sonar-ce-task-projectanalysis/src/testFixtures/java/org/sonar/ce/task/projectanalysis/component/MutableTreeRootHolderRule.java b/server/sonar-ce-task-projectanalysis/src/testFixtures/java/org/sonar/ce/task/projectanalysis/component/MutableTreeRootHolderRule.java
new file mode 100644 (file)
index 0000000..506a4e2
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info 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.ce.task.projectanalysis.component;
+
+public class MutableTreeRootHolderRule extends TreeRootHolderRule implements MutableTreeRootHolder {
+  @Override
+  public MutableTreeRootHolderRule setRoots(Component root, Component reportRoot) {
+    delegate.setRoots(root, reportRoot);
+    return this;
+  }
+}
diff --git a/server/sonar-ce-task-projectanalysis/src/testFixtures/java/org/sonar/ce/task/projectanalysis/component/NoComponentProvider.java b/server/sonar-ce-task-projectanalysis/src/testFixtures/java/org/sonar/ce/task/projectanalysis/component/NoComponentProvider.java
new file mode 100644 (file)
index 0000000..670b57d
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info 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.ce.task.projectanalysis.component;
+
+public enum NoComponentProvider implements ComponentProvider {
+  INSTANCE;
+
+  private static final String ERROR_MSG = "Can not add a measure by Component ref if MeasureRepositoryRule has not been created for some Component provider";
+
+  @Override
+  public void ensureInitialized() {
+    throw new IllegalStateException(ERROR_MSG);
+  }
+
+  @Override
+  public void reset() {
+    // do nothing
+  }
+
+  @Override
+  public Component getByRef(int componentRef) {
+    throw new IllegalStateException(ERROR_MSG);
+  }
+}
diff --git a/server/sonar-ce-task-projectanalysis/src/testFixtures/java/org/sonar/ce/task/projectanalysis/component/ReportComponent.java b/server/sonar-ce-task-projectanalysis/src/testFixtures/java/org/sonar/ce/task/projectanalysis/component/ReportComponent.java
new file mode 100644 (file)
index 0000000..0b10c06
--- /dev/null
@@ -0,0 +1,304 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info 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.ce.task.projectanalysis.component;
+
+import com.google.common.collect.ImmutableList;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkState;
+import static java.util.Arrays.asList;
+import static java.util.Objects.requireNonNull;
+
+/**
+ * Implementation of {@link Component} to unit test report components.
+ */
+public class ReportComponent implements Component {
+
+  private static final FileAttributes DEFAULT_FILE_ATTRIBUTES = new FileAttributes(false, null, 1);
+
+  public static final Component DUMB_PROJECT = builder(Type.PROJECT, 1)
+    .setKey("PROJECT_KEY")
+    .setPublicKey("PUBLIC_PROJECT_KEY")
+    .setUuid("PROJECT_UUID")
+    .setName("Project Name")
+    .setProjectVersion("1.0-SNAPSHOT")
+    .build();
+
+  private final Type type;
+  private final Status status;
+  private final String name;
+  private final String shortName;
+  @CheckForNull
+  private final String description;
+  private final String key;
+  private final String publicKey;
+  private final String uuid;
+  private final ProjectAttributes projectAttributes;
+  private final ReportAttributes reportAttributes;
+  private final FileAttributes fileAttributes;
+  private final List<Component> children;
+
+  private ReportComponent(Builder builder) {
+    this.type = builder.type;
+    this.status = builder.status;
+    this.key = builder.key;
+    this.publicKey = builder.publicKey;
+    this.name = builder.name == null ? String.valueOf(builder.key) : builder.name;
+    this.shortName = builder.shortName == null ? this.name : builder.shortName;
+    this.description = builder.description;
+    this.uuid = builder.uuid;
+    this.projectAttributes = Optional.ofNullable(builder.projectVersion)
+      .map(v -> new ProjectAttributes(v, builder.buildString, builder.scmRevisionId))
+      .orElse(null);
+    this.reportAttributes = ReportAttributes.newBuilder(builder.ref)
+      .build();
+    this.fileAttributes = builder.fileAttributes == null ? DEFAULT_FILE_ATTRIBUTES : builder.fileAttributes;
+    this.children = ImmutableList.copyOf(builder.children);
+  }
+
+  @Override
+  public Type getType() {
+    return type;
+  }
+
+  @Override
+  public Status getStatus() {
+    return status;
+  }
+
+  @Override
+  public String getUuid() {
+    if (uuid == null) {
+      throw new UnsupportedOperationException(String.format("Component uuid of ref '%d' has not be fed yet", this.reportAttributes.getRef()));
+    }
+    return uuid;
+  }
+
+  @Override
+  public String getDbKey() {
+    if (key == null) {
+      throw new UnsupportedOperationException(String.format("Component key of ref '%d' has not be fed yet", this.reportAttributes.getRef()));
+    }
+    return key;
+  }
+
+  @Override
+  public String getKey() {
+    if (publicKey == null) {
+      throw new UnsupportedOperationException(String.format("Component key of ref '%d' has not be fed yet", this.reportAttributes.getRef()));
+    }
+    return publicKey;
+  }
+
+  @Override
+  public String getName() {
+    return this.name;
+  }
+
+  @Override
+  public String getShortName() {
+    return this.shortName;
+  }
+
+  @Override
+  @CheckForNull
+  public String getDescription() {
+    return this.description;
+  }
+
+  @Override
+  public List<Component> getChildren() {
+    return children;
+  }
+
+  @Override
+  public ProjectAttributes getProjectAttributes() {
+    checkState(this.type == Type.PROJECT);
+    return this.projectAttributes;
+  }
+
+  @Override
+  public ReportAttributes getReportAttributes() {
+    return this.reportAttributes;
+  }
+
+  @Override
+  public FileAttributes getFileAttributes() {
+    checkState(this.type == Type.FILE, "Only component of type FILE can have a FileAttributes object");
+    return this.fileAttributes;
+  }
+
+  @Override
+  public ProjectViewAttributes getProjectViewAttributes() {
+    throw new IllegalStateException("Only component of type PROJECT_VIEW can have a ProjectViewAttributes object");
+  }
+
+  @Override
+  public SubViewAttributes getSubViewAttributes() {
+    throw new IllegalStateException("Only component of type SUBVIEW have a SubViewAttributes object");
+  }
+
+  @Override
+  public ViewAttributes getViewAttributes() {
+    throw new IllegalStateException("Only component of type VIEW have a ViewAttributes object");
+  }
+
+  @Override
+  public boolean equals(@Nullable Object o) {
+    if (this == o) {
+      return true;
+    }
+    if (o == null || getClass() != o.getClass()) {
+      return false;
+    }
+    ReportComponent that = (ReportComponent) o;
+    return uuid.equals(that.uuid);
+  }
+
+  @Override
+  public int hashCode() {
+    return uuid.hashCode();
+  }
+
+  @Override
+  public String toString() {
+    return "ReportComponent{" +
+      "ref=" + this.reportAttributes.getRef() +
+      ", key='" + key + '\'' +
+      ", type=" + type +
+      '}';
+  }
+
+  public static Builder builder(Type type, int ref) {
+    String key = "key_" + ref;
+    return new Builder(type, ref).setKey(key).setPublicKey(key).setUuid("uuid_" + ref).setName("name_" + ref);
+  }
+
+  public static final class Builder {
+    private final Type type;
+    private final int ref;
+    private Status status;
+    private String uuid;
+    private String key;
+    private String publicKey;
+    private String name;
+    private String shortName;
+    private String projectVersion;
+    private String buildString;
+    private String scmRevisionId;
+    private String description;
+    private FileAttributes fileAttributes;
+    private final List<Component> children = new ArrayList<>();
+
+    private Builder(Type type, int ref) {
+      checkArgument(type.isReportType(), "Component type must be a report type");
+      this.type = type;
+      this.ref = ref;
+      if (type == Type.PROJECT) {
+        this.projectVersion = "toBeDefined";
+      }
+    }
+
+    public Builder setStatus(Status s) {
+      this.status = requireNonNull(s);
+      return this;
+    }
+
+    public Builder setUuid(String s) {
+      this.uuid = requireNonNull(s);
+      return this;
+    }
+
+    public Builder setName(@Nullable String s) {
+      this.name = s;
+      return this;
+    }
+
+    public Builder setShortName(@Nullable String s) {
+      this.shortName = s;
+      return this;
+    }
+
+    public Builder setKey(String s) {
+      this.key = requireNonNull(s);
+      return this;
+    }
+
+    public Builder setPublicKey(String publicKey) {
+      this.publicKey = requireNonNull(publicKey);
+      return this;
+    }
+
+    public Builder setProjectVersion(@Nullable String s) {
+      checkProjectVersion(s);
+      this.projectVersion = s;
+      return this;
+    }
+
+    public Builder setBuildString(@Nullable String buildString) {
+      checkBuildString(buildString);
+      this.buildString = buildString;
+      return this;
+    }
+
+    public Builder setScmRevisionId(@Nullable String scmRevisionId) {
+      this.scmRevisionId = scmRevisionId;
+      return this;
+    }
+
+    public Builder setFileAttributes(FileAttributes fileAttributes) {
+      checkState(type == Type.FILE, "Only Component of type File can have File attributes");
+      this.fileAttributes = fileAttributes;
+      return this;
+    }
+
+    public Builder setDescription(@Nullable String description) {
+      this.description = description;
+      return this;
+    }
+
+    public Builder addChildren(Component... c) {
+      for (Component component : c) {
+        checkArgument(component.getType().isReportType());
+      }
+      this.children.addAll(asList(c));
+      return this;
+    }
+
+    public ReportComponent build() {
+      checkProjectVersion(this.projectVersion);
+      checkBuildString(this.buildString);
+      return new ReportComponent(this);
+    }
+
+    private void checkProjectVersion(@Nullable String s) {
+      checkArgument(type != Type.PROJECT ^ s != null, "Project version must and can only be set on Project");
+    }
+
+    private void checkBuildString(@Nullable String s) {
+      checkArgument(type == Type.PROJECT || s == null, "BuildString can only be set on Project");
+    }
+  }
+}
diff --git a/server/sonar-ce-task-projectanalysis/src/testFixtures/java/org/sonar/ce/task/projectanalysis/component/TreeComponentProvider.java b/server/sonar-ce-task-projectanalysis/src/testFixtures/java/org/sonar/ce/task/projectanalysis/component/TreeComponentProvider.java
new file mode 100644 (file)
index 0000000..10ebd61
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info 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.ce.task.projectanalysis.component;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import static com.google.common.base.Preconditions.checkState;
+
+public final class TreeComponentProvider extends AbstractComponentProvider {
+  private final Component root;
+  private final Map<String, Component> componentsByRef = new HashMap<>();
+
+  public TreeComponentProvider(Component root) {
+    this.root = root;
+    ensureInitialized();
+  }
+
+  private static String getRef(Component component) {
+    return component.getType().isReportType() ? String.valueOf(component.getReportAttributes().getRef()) : component.getDbKey();
+  }
+
+  @Override
+  protected void ensureInitializedImpl() {
+    new DepthTraversalTypeAwareCrawler(
+      new TypeAwareVisitorAdapter(CrawlerDepthLimit.LEAVES, ComponentVisitor.Order.PRE_ORDER) {
+        @Override
+        public void visitAny(Component component) {
+          String ref = getRef(component);
+          checkState(!componentsByRef.containsKey(ref), "Tree contains more than one component with ref " + ref);
+          componentsByRef.put(ref, component);
+        }
+      }).visit(root);
+  }
+
+  @Override
+  protected void resetImpl() {
+    // we can not reset
+  }
+
+  @Override
+  protected Component getByRefImpl(int componentRef) {
+    Component component = componentsByRef.get(String.valueOf(componentRef));
+    checkState(component != null, "Can not find Component for ref " + componentRef);
+    return component;
+  }
+}
diff --git a/server/sonar-ce-task-projectanalysis/src/testFixtures/java/org/sonar/ce/task/projectanalysis/component/TreeRootHolderComponentProvider.java b/server/sonar-ce-task-projectanalysis/src/testFixtures/java/org/sonar/ce/task/projectanalysis/component/TreeRootHolderComponentProvider.java
new file mode 100644 (file)
index 0000000..da7eae0
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info 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.ce.task.projectanalysis.component;
+
+public final class TreeRootHolderComponentProvider extends AbstractComponentProvider {
+  private final TreeRootHolder treeRootHolder;
+  private TreeComponentProvider delegate;
+
+  public TreeRootHolderComponentProvider(TreeRootHolder treeRootHolder) {
+    this.treeRootHolder = treeRootHolder;
+  }
+
+  @Override
+  protected void ensureInitializedImpl() {
+    if (this.delegate == null) {
+      this.delegate = new TreeComponentProvider(treeRootHolder.getRoot());
+      this.delegate.ensureInitialized();
+    }
+  }
+
+  @Override
+  protected void resetImpl() {
+    this.delegate = null;
+  }
+
+  @Override
+  protected Component getByRefImpl(int componentRef) {
+    return delegate.getByRef(componentRef);
+  }
+}
diff --git a/server/sonar-ce-task-projectanalysis/src/testFixtures/java/org/sonar/ce/task/projectanalysis/component/TreeRootHolderRule.java b/server/sonar-ce-task-projectanalysis/src/testFixtures/java/org/sonar/ce/task/projectanalysis/component/TreeRootHolderRule.java
new file mode 100644 (file)
index 0000000..bfdaa2f
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info 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.ce.task.projectanalysis.component;
+
+import java.util.Optional;
+import org.junit.rules.ExternalResource;
+
+public class TreeRootHolderRule extends ExternalResource implements TreeRootHolder {
+  protected TreeRootHolderImpl delegate = new TreeRootHolderImpl();
+
+  @Override
+  protected void after() {
+    this.delegate = null;
+  }
+
+  public TreeRootHolderRule setRoot(Component root) {
+    return setRoots(root, root);
+  }
+
+  public TreeRootHolderRule setRoots(Component root, Component reportRoot) {
+    delegate = new TreeRootHolderImpl();
+    delegate.setRoots(root, reportRoot);
+    return this;
+  }
+
+  @Override
+  public boolean isEmpty() {
+    return delegate.isEmpty();
+  }
+
+  @Override
+  public Component getRoot() {
+    return delegate.getRoot();
+  }
+
+  @Override
+  public Component getReportTreeRoot() {
+    return delegate.getReportTreeRoot();
+  }
+
+  @Override
+  public Component getComponentByRef(int ref) {
+    return delegate.getComponentByRef(ref);
+  }
+
+  @Override
+  public Optional<Component> getOptionalComponentByRef(int ref) {
+    return delegate.getOptionalComponentByRef(ref);
+  }
+
+  @Override public Component getReportTreeComponentByRef(int ref) {
+    return delegate.getReportTreeComponentByRef(ref);
+  }
+
+  @Override
+  public int getSize() {
+    return delegate.getSize();
+  }
+
+}
diff --git a/server/sonar-ce-task-projectanalysis/src/testFixtures/java/org/sonar/ce/task/projectanalysis/component/ViewsComponent.java b/server/sonar-ce-task-projectanalysis/src/testFixtures/java/org/sonar/ce/task/projectanalysis/component/ViewsComponent.java
new file mode 100644 (file)
index 0000000..a8f5afb
--- /dev/null
@@ -0,0 +1,253 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info 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.ce.task.projectanalysis.component;
+
+import com.google.common.collect.ImmutableList;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkState;
+import static java.util.Arrays.asList;
+import static java.util.Objects.requireNonNull;
+
+/**
+ * Implementation of {@link Component} to unit test views components.
+ */
+public class ViewsComponent implements Component {
+  private final Type type;
+  private final String key;
+  private final String uuid;
+  private final String name;
+  private final String description;
+  private final List<Component> children;
+  private final ProjectViewAttributes projectViewAttributes;
+  private final SubViewAttributes subViewAttributes;
+  private final ViewAttributes viewAttributes;
+
+  private ViewsComponent(Type type, String key, @Nullable String uuid, @Nullable String name, @Nullable String description,
+    List<Component> children, @Nullable ProjectViewAttributes projectViewAttributes, @Nullable SubViewAttributes subViewAttributes,
+    @Nullable ViewAttributes viewAttributes) {
+    checkArgument(type.isViewsType(), "Component type must be a Views type");
+    this.type = type;
+    this.key = requireNonNull(key);
+    this.uuid = uuid;
+    this.name = name;
+    this.description = description;
+    this.children = ImmutableList.copyOf(children);
+    this.projectViewAttributes = projectViewAttributes;
+    this.subViewAttributes = subViewAttributes;
+    this.viewAttributes = viewAttributes;
+  }
+
+  public static Builder builder(Type type, String key) {
+    return new Builder(type, key);
+  }
+
+  public static Builder builder(Type type, int key) {
+    return new Builder(type, String.valueOf(key));
+  }
+
+  public static final class Builder {
+    private final Type type;
+    private String key;
+    private String uuid;
+    private String name;
+    private String description;
+    private List<Component> children = new ArrayList<>();
+    private ProjectViewAttributes projectViewAttributes;
+    private SubViewAttributes subViewAttributes;
+    private ViewAttributes viewAttributes;
+
+    private Builder(Type type, String key) {
+      this.type = type;
+      this.key = key;
+    }
+
+    public Builder setUuid(@Nullable String uuid) {
+      this.uuid = uuid;
+      return this;
+    }
+
+    public Builder setKey(String key) {
+      this.key = key;
+      return this;
+    }
+
+    public Builder setName(@Nullable String name) {
+      this.name = name;
+      return this;
+    }
+
+    public Builder setDescription(String description) {
+      this.description = description;
+      return this;
+    }
+
+    public Builder setChildren(List<Component> children) {
+      this.children = children;
+      return this;
+    }
+
+    public Builder setProjectViewAttributes(@Nullable ProjectViewAttributes projectViewAttributes) {
+      this.projectViewAttributes = projectViewAttributes;
+      return this;
+    }
+
+    public Builder setSubViewAttributes(@Nullable SubViewAttributes subViewAttributes) {
+      this.subViewAttributes = subViewAttributes;
+      return this;
+    }
+
+    public Builder setViewAttributes(@Nullable ViewAttributes viewAttributes) {
+      this.viewAttributes = viewAttributes;
+      return this;
+    }
+
+    public Builder addChildren(Component... c) {
+      for (Component viewsComponent : c) {
+        checkArgument(viewsComponent.getType().isViewsType());
+      }
+      this.children.addAll(asList(c));
+      return this;
+    }
+
+    public ViewsComponent build() {
+      return new ViewsComponent(type, key, uuid, name, description, children, projectViewAttributes, subViewAttributes, viewAttributes);
+    }
+  }
+
+  @Override
+  public Type getType() {
+    return type;
+  }
+
+  @Override
+  public Status getStatus() {
+    return Status.UNAVAILABLE;
+  }
+
+  @Override
+  public String getUuid() {
+    return uuid;
+  }
+
+  @Override
+  public String getDbKey() {
+    return key;
+  }
+
+  /**
+   * Views has no branch feature, the public key is the same as the key
+   */
+  @Override
+  public String getKey() {
+    return getDbKey();
+  }
+
+  @Override
+  public String getName() {
+    checkState(this.name != null, "No name has been set");
+    return this.name;
+  }
+
+  @Override
+  public String getShortName() {
+    return getName();
+  }
+
+  @Override
+  @CheckForNull
+  public String getDescription() {
+    return this.description;
+  }
+
+  @Override
+  public List<Component> getChildren() {
+    return children;
+  }
+
+  @Override
+  public ProjectAttributes getProjectAttributes() {
+    throw new IllegalStateException("A component of type " + type + " does not have project attributes");
+  }
+
+  @Override
+  public ReportAttributes getReportAttributes() {
+    throw new IllegalStateException("A component of type " + type + " does not have report attributes");
+  }
+
+  @Override
+  public FileAttributes getFileAttributes() {
+    throw new IllegalStateException("A component of type " + type + " does not have file attributes");
+  }
+
+  @Override
+  public ProjectViewAttributes getProjectViewAttributes() {
+    checkState(this.type != Type.PROJECT_VIEW || this.projectViewAttributes != null, "A ProjectViewAttribute object should have been set");
+    return this.projectViewAttributes;
+  }
+
+  @Override
+  public SubViewAttributes getSubViewAttributes() {
+    checkState(this.type != Type.SUBVIEW || this.subViewAttributes != null, "A SubViewAttributes object should have been set");
+    return this.subViewAttributes;
+  }
+
+  @Override
+  public ViewAttributes getViewAttributes() {
+    checkState(this.type != Type.VIEW || this.viewAttributes != null, "A ViewAttributes object should have been set");
+    return viewAttributes;
+  }
+
+  @Override
+  public String toString() {
+    return "ViewsComponent{" +
+      "type=" + type +
+      ", key='" + key + '\'' +
+      ", uuid='" + uuid + '\'' +
+      ", name='" + name + '\'' +
+      ", children=" + children +
+      ", projectViewAttributes=" + projectViewAttributes +
+      ", subViewAttributes=" + subViewAttributes +
+      ", viewAttributes=" + viewAttributes +
+      '}';
+  }
+
+  @Override
+  public boolean equals(@Nullable Object o) {
+    if (this == o) {
+      return true;
+    }
+    if (o == null || getClass() != o.getClass()) {
+      return false;
+    }
+    ViewsComponent that = (ViewsComponent) o;
+    return key.equals(that.key);
+  }
+
+  @Override
+  public int hashCode() {
+    return Objects.hash(key);
+  }
+}
diff --git a/server/sonar-ce-task-projectanalysis/src/testFixtures/java/org/sonar/ce/task/projectanalysis/measure/MeasureAssert.java b/server/sonar-ce-task-projectanalysis/src/testFixtures/java/org/sonar/ce/task/projectanalysis/measure/MeasureAssert.java
new file mode 100644 (file)
index 0000000..7b8d2ea
--- /dev/null
@@ -0,0 +1,255 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info 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.ce.task.projectanalysis.measure;
+
+import java.util.Objects;
+import java.util.Optional;
+import javax.annotation.Nullable;
+import org.assertj.core.api.AbstractAssert;
+import org.assertj.core.data.Offset;
+
+import static java.lang.Math.abs;
+
+public class MeasureAssert extends AbstractAssert<MeasureAssert, Measure> {
+
+  protected MeasureAssert(@Nullable Measure actual) {
+    super(actual, MeasureAssert.class);
+  }
+
+  public static MeasureAssert assertThat(Measure actual) {
+    return new MeasureAssert(actual);
+  }
+
+  public static MeasureAssert assertThat(@Nullable Optional<Measure> actual) {
+    return new MeasureAssert(actual == null ? null : actual.orElse(null));
+  }
+
+  public MeasureAssert hasValueType(Measure.ValueType expected) {
+    isNotNull();
+
+    if (actual.getValueType() != expected) {
+      failWithMessage("Expected ValueType of Measure to be <%s> but was <%s>", expected, actual.getValueType());
+    }
+
+    return this;
+  }
+
+  public MeasureAssert hasValue(int expected) {
+    isNotNull();
+
+    if (actual.getValueType() != Measure.ValueType.INT) {
+      failWithMessage(
+        "Expected Measure to have an int value and therefore its ValueType to be <%s> but was <%s>",
+        Measure.ValueType.INT, actual.getValueType());
+    }
+
+    if (actual.getIntValue() != expected) {
+      failWithMessage("Expected value of Measure to be <%s> but was <%s>", expected, actual.getIntValue());
+    }
+
+    return this;
+  }
+
+  public MeasureAssert hasValue(long expected) {
+    isNotNull();
+
+    if (actual.getValueType() != Measure.ValueType.LONG) {
+      failWithMessage(
+        "Expected Measure to have a long value and therefore its ValueType to be <%s> but was <%s>",
+        Measure.ValueType.LONG, actual.getValueType());
+    }
+
+    if (actual.getLongValue() != expected) {
+      failWithMessage("Expected value of Measure to be <%s> but was <%s>", expected, actual.getLongValue());
+    }
+
+    return this;
+  }
+
+  public MeasureAssert hasValue(double expected) {
+    isNotNull();
+
+    if (actual.getValueType() != Measure.ValueType.DOUBLE) {
+      failWithMessage(
+        "Expected Measure to have a double value and therefore its ValueType to be <%s> but was <%s>",
+        Measure.ValueType.DOUBLE, actual.getValueType());
+    }
+
+    if (actual.getDoubleValue() != expected) {
+      failWithMessage("Expected value of Measure to be <%s> but was <%s>", expected, actual.getDoubleValue());
+    }
+
+    return this;
+  }
+
+  public MeasureAssert hasValue(boolean expected) {
+    isNotNull();
+
+    if (actual.getValueType() != Measure.ValueType.BOOLEAN) {
+      failWithMessage(
+        "Expected Measure to have a boolean value and therefore its ValueType to be <%s> but was <%s>",
+        Measure.ValueType.DOUBLE, actual.getValueType());
+    }
+
+    if (actual.getBooleanValue() != expected) {
+      failWithMessage("Expected value of Measure to be <%s> but was <%s>", expected, actual.getBooleanValue());
+    }
+
+    return this;
+  }
+
+  public MeasureAssert hasValue(String expected) {
+    isNotNull();
+
+    if (actual.getValueType() != Measure.ValueType.STRING) {
+      failWithMessage(
+        "Expected Measure to have a String value and therefore its ValueType to be <%s> but was <%s>",
+        Measure.ValueType.DOUBLE, actual.getValueType());
+    }
+
+    if (!Objects.equals(actual.getStringValue(), expected)) {
+      failWithMessage("Expected value of Measure to be <%s> but was <%s>", expected, actual.getStringValue());
+    }
+
+    return this;
+  }
+
+  public MeasureAssert hasValue(Measure.Level expected) {
+    isNotNull();
+
+    if (actual.getValueType() != Measure.ValueType.LEVEL) {
+      failWithMessage(
+        "Expected Measure to have a Level value and therefore its ValueType to be <%s> but was <%s>",
+        Measure.ValueType.DOUBLE, actual.getValueType());
+    }
+
+    if (actual.getLevelValue() != expected) {
+      failWithMessage("Expected value of Measure to be <%s> but was <%s>", expected, actual.getLevelValue());
+    }
+
+    return this;
+  }
+
+  public MeasureAssert hasNoValue() {
+    isNotNull();
+
+    if (actual.getValueType() != Measure.ValueType.NO_VALUE) {
+      failWithMessage(
+        "Expected Measure to have no value and therefore its ValueType to be <%s> but was <%s>",
+        Measure.ValueType.DOUBLE, actual.getValueType());
+    }
+
+    return this;
+  }
+
+  public MeasureAssert hasData(String expected) {
+    isNotNull();
+
+    if (!Objects.equals(actual.getData(), expected)) {
+      failWithMessage("Expected data of Measure to be <%s> but was <%s>", expected, actual.getData());
+    }
+
+    return this;
+  }
+
+  public MeasureAssert hasNoData() {
+    isNotNull();
+
+    if (actual.getData() == null) {
+      failWithMessage("Expected Measure to have no data but was <%s>", actual.getData());
+    }
+
+    return this;
+  }
+
+  public MeasureAssert hasQualityGateLevel(Measure.Level expected) {
+    isNotNull();
+    hasQualityGateStatus();
+
+    if (actual.getQualityGateStatus().getStatus() != expected) {
+      failWithMessage("Expected Level of QualityGateStatus of Measure to be <%s> but was <%s>", expected, actual.getQualityGateStatus().getStatus());
+    }
+
+    return this;
+  }
+
+  public MeasureAssert hasQualityGateText(String expected) {
+    isNotNull();
+    hasQualityGateStatus();
+
+    if (!Objects.equals(actual.getQualityGateStatus().getText(), expected)) {
+      failWithMessage("Expected text of QualityGateStatus of Measure to be \n<%s>\n but was \n<%s>", expected, actual.getQualityGateStatus().getText());
+    }
+
+    return this;
+  }
+
+  private void hasQualityGateStatus() {
+    if (!actual.hasQualityGateStatus()) {
+      failWithMessage("Expected Measure to have a QualityGateStatus but it did not");
+    }
+  }
+
+  public MeasureAssert hasVariation(double expected) {
+    isNotNull();
+    hasVariation();
+
+    if (!actual.hasVariation()) {
+      failWithMessage("Expected Measure to have a variation but it did not");
+    }
+
+    double variation = actual.getVariation();
+    if (variation != expected) {
+      failWithMessage("Expected variation of Measure to be <%s> but was <%s>", expected, variation);
+    }
+
+    return this;
+  }
+
+  public MeasureAssert hasVariation(double expected, Offset<Double> offset) {
+    isNotNull();
+    hasVariation();
+
+    if (!actual.hasVariation()) {
+      failWithMessage("Expected Measure to have a variation but it did not");
+    }
+
+    double variation = actual.getVariation();
+    if (abs(expected - variation) > offset.value) {
+      failWithMessage(
+        "Expected variation of Measure to be close to <%s> by less than <%s> but was <%s>",
+        expected, offset.value, variation);
+    }
+
+    return this;
+  }
+
+  private void hasVariation() {
+    if (!actual.hasVariation()) {
+      failWithMessage("Expected Measure to have a variation but it did not");
+    }
+  }
+
+  public void isAbsent() {
+    if (actual != null) {
+      failWithMessage("Expected measure to be absent");
+    }
+  }
+}
diff --git a/server/sonar-ce-task-projectanalysis/src/testFixtures/java/org/sonar/ce/task/projectanalysis/measure/MeasureRepoEntry.java b/server/sonar-ce-task-projectanalysis/src/testFixtures/java/org/sonar/ce/task/projectanalysis/measure/MeasureRepoEntry.java
new file mode 100644 (file)
index 0000000..2cf7fc1
--- /dev/null
@@ -0,0 +1,157 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info 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.ce.task.projectanalysis.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.ce.task.projectanalysis.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 measure.getValueType() == measure1.getValueType()
+      && equalsByValue(measure, measure1)
+      && equalsByVariation(measure, measure1)
+      && equalsByQualityGateStatus(measure, measure1)
+      && 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) {
+    return measure.hasVariation() == measure1.hasVariation() && (!measure.hasVariation()
+      || Double.compare(scale(measure.getVariation()), scale(measure1.getVariation())) == 0);
+  }
+
+  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());
+    }
+  }
+}
diff --git a/server/sonar-ce-task-projectanalysis/src/testFixtures/java/org/sonar/ce/task/projectanalysis/measure/MeasureRepositoryRule.java b/server/sonar-ce-task-projectanalysis/src/testFixtures/java/org/sonar/ce/task/projectanalysis/measure/MeasureRepositoryRule.java
new file mode 100644 (file)
index 0000000..2c57915
--- /dev/null
@@ -0,0 +1,316 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info 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.ce.task.projectanalysis.measure;
+
+import com.google.common.base.Function;
+import com.google.common.base.Predicate;
+import com.google.common.collect.ImmutableSetMultimap;
+import com.google.common.collect.SetMultimap;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Set;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import org.junit.rules.ExternalResource;
+import org.sonar.ce.task.projectanalysis.component.Component;
+import org.sonar.ce.task.projectanalysis.component.ComponentProvider;
+import org.sonar.ce.task.projectanalysis.component.NoComponentProvider;
+import org.sonar.ce.task.projectanalysis.component.TreeComponentProvider;
+import org.sonar.ce.task.projectanalysis.component.TreeRootHolder;
+import org.sonar.ce.task.projectanalysis.component.TreeRootHolderComponentProvider;
+import org.sonar.ce.task.projectanalysis.metric.Metric;
+import org.sonar.ce.task.projectanalysis.metric.MetricRepositoryRule;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkState;
+import static com.google.common.collect.FluentIterable.from;
+import static com.google.common.collect.Maps.filterKeys;
+import static java.lang.String.format;
+import static java.util.Objects.requireNonNull;
+
+/**
+ * An implementation of MeasureRepository as a JUnit rule which provides add methods for raw measures and extra add
+ * methods that takes component ref and metric keys thanks to the integration with various Component and Metric
+ * providers.
+ */
+public class MeasureRepositoryRule extends ExternalResource implements MeasureRepository {
+  private final ComponentProvider componentProvider;
+  @CheckForNull
+  private final MetricRepositoryRule metricRepositoryRule;
+  private final Map<InternalKey, Measure> baseMeasures = new HashMap<>();
+  private final Map<InternalKey, Measure> rawMeasures = new HashMap<>();
+  private final Map<InternalKey, Measure> initialRawMeasures = new HashMap<>();
+  private final Predicate<Map.Entry<InternalKey, Measure>> isAddedMeasure = input -> !initialRawMeasures.containsKey(input.getKey())
+    || !MeasureRepoEntry.deepEquals(input.getValue(), initialRawMeasures.get(input.getKey()));
+
+  private MeasureRepositoryRule(ComponentProvider componentProvider, @Nullable MetricRepositoryRule metricRepositoryRule) {
+    this.componentProvider = componentProvider;
+    this.metricRepositoryRule = metricRepositoryRule;
+  }
+
+  @Override
+  protected void after() {
+    componentProvider.reset();
+    baseMeasures.clear();
+    rawMeasures.clear();
+  }
+
+  public static MeasureRepositoryRule create() {
+    return new MeasureRepositoryRule(NoComponentProvider.INSTANCE, null);
+  }
+
+  public static MeasureRepositoryRule create(TreeRootHolder treeRootHolder, MetricRepositoryRule metricRepositoryRule) {
+    return new MeasureRepositoryRule(new TreeRootHolderComponentProvider(treeRootHolder), requireNonNull(metricRepositoryRule));
+  }
+
+  public static MeasureRepositoryRule create(Component treeRoot, MetricRepositoryRule metricRepositoryRule) {
+    return new MeasureRepositoryRule(new TreeComponentProvider(treeRoot), requireNonNull(metricRepositoryRule));
+  }
+
+  public MeasureRepositoryRule addBaseMeasure(int componentRef, String metricKey, Measure measure) {
+    checkAndInitProvidersState();
+
+    InternalKey internalKey = new InternalKey(componentProvider.getByRef(componentRef), metricRepositoryRule.getByKey(metricKey));
+    checkState(!baseMeasures.containsKey(internalKey), format("Can not add a BaseMeasure twice for a Component (ref=%s) and Metric (key=%s)", componentRef, metricKey));
+
+    baseMeasures.put(internalKey, measure);
+
+    return this;
+  }
+
+  public SetMultimap<String, Measure> getRawMeasures(int componentRef) {
+    return getRawMeasures(componentProvider.getByRef(componentRef));
+  }
+
+  /**
+   * Return measures that were added by the step (using {@link #add(Component, Metric, Measure)}).
+   * It does not contain the one added in the test by {@link #addRawMeasure(int, String, Measure)}
+   */
+  public SetMultimap<String, Measure> getAddedRawMeasures(int componentRef) {
+    checkAndInitProvidersState();
+
+    return getAddedRawMeasures(componentProvider.getByRef(componentRef));
+  }
+
+  /**
+   * Return a measure that were added by the step (using {@link #add(Component, Metric, Measure)}).
+   * It does not contain the one added in the test by {@link #addRawMeasure(int, String, Measure)}
+   */
+  public Optional<Measure> getAddedRawMeasure(Component component, String metricKey) {
+    return getAddedRawMeasure(component.getReportAttributes().getRef(), metricKey);
+  }
+
+  /**
+   * Return a measure that were added by the step (using {@link #add(Component, Metric, Measure)}).
+   * It does not contain the one added in the test by {@link #addRawMeasure(int, String, Measure)}
+   */
+  public Optional<Measure> getAddedRawMeasure(int componentRef, String metricKey) {
+    checkAndInitProvidersState();
+
+    Set<Measure> measures = getAddedRawMeasures(componentProvider.getByRef(componentRef)).get(metricKey);
+    if (measures.isEmpty()) {
+      return Optional.empty();
+    }
+    checkArgument(measures.size() == 1, String.format("There is more than one measure on metric '%s' for component '%s'", metricKey, componentRef));
+    return Optional.of(measures.iterator().next());
+  }
+
+  /**
+   * Return measures that were added by the step (using {@link #add(Component, Metric, Measure)}).
+   * It does not contain the one added in the test by {@link #addRawMeasure(int, String, Measure)}
+   */
+  public SetMultimap<String, Measure> getAddedRawMeasures(Component component) {
+    checkAndInitProvidersState();
+
+    ImmutableSetMultimap.Builder<String, Measure> builder = ImmutableSetMultimap.builder();
+    for (Map.Entry<InternalKey, Measure> entry : from(filterKeys(rawMeasures, hasComponentRef(component)).entrySet()).filter(isAddedMeasure)) {
+      builder.put(entry.getKey().getMetricKey(), entry.getValue());
+    }
+    return builder.build();
+  }
+
+  public MeasureRepositoryRule addRawMeasure(int componentRef, String metricKey, Measure measure) {
+    checkAndInitProvidersState();
+
+    InternalKey internalKey = new InternalKey(componentProvider.getByRef(componentRef), metricRepositoryRule.getByKey(metricKey));
+    checkState(!rawMeasures.containsKey(internalKey), format(
+      "A measure can only be set once for Component (ref=%s), Metric (key=%s)",
+      componentRef, metricKey));
+
+    rawMeasures.put(internalKey, measure);
+    initialRawMeasures.put(internalKey, measure);
+
+    return this;
+  }
+
+  @Override
+  public Optional<Measure> getBaseMeasure(Component component, Metric metric) {
+    return Optional.ofNullable(baseMeasures.get(new InternalKey(component, metric)));
+  }
+
+  @Override
+  public Optional<Measure> getRawMeasure(Component component, Metric metric) {
+    return Optional.ofNullable(rawMeasures.get(new InternalKey(component, metric)));
+  }
+
+  @Override
+  public Set<Measure> getRawMeasures(Component component, Metric metric) {
+    return from(filterKeys(rawMeasures, hasComponentRef(component)).entrySet()).filter(new MatchMetric(metric)).transform(ToMeasure.INSTANCE).toSet();
+  }
+
+  @Override
+  public SetMultimap<String, Measure> getRawMeasures(Component component) {
+    ImmutableSetMultimap.Builder<String, Measure> builder = ImmutableSetMultimap.builder();
+    for (Map.Entry<InternalKey, Measure> entry : filterKeys(rawMeasures, hasComponentRef(component)).entrySet()) {
+      builder.put(entry.getKey().getMetricKey(), entry.getValue());
+    }
+    return builder.build();
+  }
+
+  private HasComponentRefPredicate hasComponentRef(Component component) {
+    return new HasComponentRefPredicate(component);
+  }
+
+  @Override
+  public void add(Component component, Metric metric, Measure measure) {
+    String ref = getRef(component);
+    InternalKey internalKey = new InternalKey(ref, metric.getKey());
+    if (rawMeasures.containsKey(internalKey)) {
+      throw new UnsupportedOperationException(format(
+        "A measure can only be set once for Component (ref=%s), Metric (key=%s)",
+        ref, metric.getKey()));
+    }
+    rawMeasures.put(internalKey, measure);
+  }
+
+  @Override
+  public void update(Component component, Metric metric, Measure measure) {
+    String componentRef = getRef(component);
+    InternalKey internalKey = new InternalKey(componentRef, metric.getKey());
+    if (!rawMeasures.containsKey(internalKey)) {
+      throw new UnsupportedOperationException(format(
+        "A measure can only be updated if it has been added first for Component (ref=%s), Metric (key=%s)",
+        componentRef, metric.getKey()));
+    }
+    rawMeasures.put(internalKey, measure);
+  }
+
+  private void checkAndInitProvidersState() {
+    checkState(metricRepositoryRule != null, "Can not add a measure by metric key if MeasureRepositoryRule has not been created for a MetricRepository");
+    componentProvider.ensureInitialized();
+  }
+
+  public boolean isEmpty() {
+    return rawMeasures.isEmpty();
+  }
+
+  private static final class InternalKey {
+    private final String componentRef;
+    private final String metricKey;
+
+    public InternalKey(Component component, Metric metric) {
+      this(getRef(component), metric.getKey());
+    }
+
+    private InternalKey(String componentRef, String metricKey) {
+      this.componentRef = componentRef;
+      this.metricKey = metricKey;
+    }
+
+    public String getComponentRef() {
+      return componentRef;
+    }
+
+    public String getMetricKey() {
+      return metricKey;
+    }
+
+    @Override
+    public boolean equals(@Nullable Object o) {
+      if (this == o) {
+        return true;
+      }
+      if (o == null || getClass() != o.getClass()) {
+        return false;
+      }
+      InternalKey that = (InternalKey) o;
+      return Objects.equals(componentRef, that.componentRef) &&
+        Objects.equals(metricKey, that.metricKey);
+    }
+
+    @Override
+    public int hashCode() {
+      return Objects.hash(componentRef, metricKey);
+    }
+
+    @Override
+    public String toString() {
+      return "InternalKey{" +
+        "component=" + componentRef +
+        ", metric='" + metricKey + '\'' +
+        '}';
+    }
+  }
+
+  private static class HasComponentRefPredicate implements Predicate<InternalKey> {
+
+    private final String componentRef;
+
+    public HasComponentRefPredicate(Component component) {
+      this.componentRef = getRef(component);
+    }
+
+    @Override
+    public boolean apply(@Nonnull InternalKey input) {
+      return input.getComponentRef().equals(this.componentRef);
+    }
+  }
+
+  private static String getRef(Component component) {
+    return component.getType().isReportType() ? String.valueOf(component.getReportAttributes().getRef()) : component.getDbKey();
+  }
+
+  private static class MatchMetric implements Predicate<Map.Entry<InternalKey, Measure>> {
+    private final Metric metric;
+
+    public MatchMetric(Metric metric) {
+      this.metric = metric;
+    }
+
+    @Override
+    public boolean apply(@Nonnull Map.Entry<InternalKey, Measure> input) {
+      return input.getKey().getMetricKey().equals(metric.getKey());
+    }
+  }
+
+  private enum ToMeasure implements Function<Map.Entry<InternalKey, Measure>, Measure> {
+    INSTANCE;
+
+    @Nullable
+    @Override
+    public Measure apply(@Nonnull Map.Entry<InternalKey, Measure> input) {
+      return input.getValue();
+    }
+  }
+
+}
diff --git a/server/sonar-ce-task-projectanalysis/src/testFixtures/java/org/sonar/ce/task/projectanalysis/metric/MetricRepositoryRule.java b/server/sonar-ce-task-projectanalysis/src/testFixtures/java/org/sonar/ce/task/projectanalysis/metric/MetricRepositoryRule.java
new file mode 100644 (file)
index 0000000..7f781ff
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info 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.ce.task.projectanalysis.metric;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Optional;
+import org.junit.rules.ExternalResource;
+
+import static com.google.common.base.Preconditions.checkState;
+import static java.lang.String.format;
+import static java.util.Objects.requireNonNull;
+
+public class MetricRepositoryRule extends ExternalResource implements MetricRepository {
+  private final Map<String, Metric> metricsByKey = new HashMap<>();
+  private final Map<Long, Metric> metricsById = new HashMap<>();
+
+  /**
+   * Convenience method to add a {@link Metric} to the repository created from a {@link org.sonar.api.measures.Metric},
+   * most of the time it will be a constant of the {@link org.sonar.api.measures.CoreMetrics} class.
+   * <p>
+   * For the id of the created metric, this method uses the hashCode of the metric's key. If you want to specify
+   * the id of the create {@link Metric}, use {@link #add(int, org.sonar.api.measures.Metric)}
+   * </p>
+   */
+  public MetricRepositoryRule add(org.sonar.api.measures.Metric<?> coreMetric) {
+    add(from(coreMetric));
+    return this;
+  }
+
+  /**
+   * Convenience method to add a {@link Metric} to the repository created from a {@link org.sonar.api.measures.Metric}
+   * and with the specified id, most of the time it will be a constant of the {@link org.sonar.api.measures.CoreMetrics}
+   * class.
+   */
+  public MetricRepositoryRule add(int id, org.sonar.api.measures.Metric<?> coreMetric) {
+    add(from(id, coreMetric));
+    return this;
+  }
+
+  private static Metric from(org.sonar.api.measures.Metric<?> coreMetric) {
+    return from(coreMetric.getKey().hashCode(), coreMetric);
+  }
+
+  private static Metric from(int id, org.sonar.api.measures.Metric<?> coreMetric) {
+    return new MetricImpl(
+      id, coreMetric.getKey(), coreMetric.getName(),
+      convert(coreMetric.getType()),
+      coreMetric.getDecimalScale(),
+      coreMetric.getBestValue(), coreMetric.isOptimizedBestValue());
+  }
+
+  private static Metric.MetricType convert(org.sonar.api.measures.Metric.ValueType coreMetricType) {
+    return Metric.MetricType.valueOf(coreMetricType.name());
+  }
+
+  public MetricRepositoryRule add(Metric metric) {
+    requireNonNull(metric.getKey(), "key can not be null");
+    requireNonNull(metric.getId(), "id can not be null");
+
+    checkState(!metricsByKey.containsKey(metric.getKey()), format("Repository already contains a metric for key %s", metric.getKey()));
+    checkState(!metricsById.containsKey((long) metric.getId()), format("Repository already contains a metric for id %s", metric.getId()));
+
+    metricsByKey.put(metric.getKey(), metric);
+    metricsById.put((long) metric.getId(), metric);
+
+    return this;
+  }
+
+  @Override
+  protected void after() {
+    this.metricsById.clear();
+    this.metricsById.clear();
+  }
+
+  @Override
+  public Metric getByKey(String key) {
+    Metric res = metricsByKey.get(key);
+    checkState(res != null, format("No Metric can be found for key %s", key));
+    return res;
+  }
+
+  @Override
+  public Metric getById(long id) {
+    Metric res = metricsById.get(id);
+    checkState(res != null, format("No Metric can be found for id %s", id));
+    return res;
+  }
+
+  @Override
+  public Optional<Metric> getOptionalById(long id) {
+    return Optional.of(metricsById.get(id));
+  }
+
+  @Override
+  public Iterable<Metric> getAll() {
+    return metricsByKey.values();
+  }
+}
diff --git a/server/sonar-ce-task-projectanalysis/src/testFixtures/java/org/sonar/ce/task/projectanalysis/step/BaseStepTest.java b/server/sonar-ce-task-projectanalysis/src/testFixtures/java/org/sonar/ce/task/projectanalysis/step/BaseStepTest.java
new file mode 100644 (file)
index 0000000..16aed80
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info 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.ce.task.projectanalysis.step;
+
+import org.junit.Test;
+import org.sonar.ce.task.step.ComputationStep;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * Temporary solution to test metadata. Should be replaced by a medium test of
+ * all computation stack
+ */
+public abstract class BaseStepTest {
+
+  protected abstract ComputationStep step();
+
+  @Test
+  public void test_metadata() {
+    assertThat(step().toString()).isNotEmpty();
+    assertThat(step().getDescription()).isNotEmpty();
+  }
+}