]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-7861 support unset name of project in scanner report 1183/head
authorSébastien Lesaint <sebastien.lesaint@sonarsource.com>
Thu, 25 Aug 2016 16:43:57 +0000 (18:43 +0200)
committerSébastien Lesaint <sebastien.lesaint@sonarsource.com>
Tue, 30 Aug 2016 13:42:00 +0000 (15:42 +0200)
server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/component/ComponentImpl.java
server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/component/ComponentRootBuilder.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/BuildComponentTreeStep.java
server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/component/ComponentImplTest.java
server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/component/ComponentRootBuilderTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/BuildComponentTreeStepTest.java

index 8339fa1e5a28808b89826dc951aec9d30241b5f6..8179270bc0c4bdba016d10d59b0da21fcb14e54a 100644 (file)
  */
 package org.sonar.server.computation.task.projectanalysis.component;
 
-import com.google.common.annotations.VisibleForTesting;
 import com.google.common.collect.ImmutableList;
 import java.util.ArrayList;
 import java.util.List;
 import javax.annotation.CheckForNull;
 import javax.annotation.Nullable;
 import javax.annotation.concurrent.Immutable;
-import org.sonar.scanner.protocol.output.ScannerReport;
-import org.sonar.scanner.protocol.output.ScannerReport.Component.ComponentType;
 
 import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkNotNull;
 import static com.google.common.base.Preconditions.checkState;
 import static java.util.Arrays.asList;
+import static java.util.Objects.requireNonNull;
 import static org.apache.commons.lang.StringUtils.trimToNull;
 
 @Immutable
@@ -53,7 +50,7 @@ public class ComponentImpl implements Component {
   private ComponentImpl(Builder builder) {
     this.type = builder.type;
     this.key = builder.key;
-    this.name = builder.name == null ? String.valueOf(builder.key) : builder.name;
+    this.name = builder.name;
     this.description = builder.description;
     this.uuid = builder.uuid;
     this.reportAttributes = builder.reportAttributes;
@@ -108,14 +105,19 @@ public class ComponentImpl implements Component {
     throw new IllegalStateException("Only component of type PROJECT_VIEW have a FileAttributes object");
   }
 
-  public static Builder builder(ScannerReport.Component component) {
-    return new Builder(component);
+  public static Builder builder(Type type) {
+    return new Builder(type);
   }
 
   public static final class Builder {
 
+    private static final String KEY_CANNOT_BE_NULL = "key can't be null";
+    private static final String UUID_CANNOT_BE_NULL = "uuid can't be null";
+    private static final String REPORT_ATTRIBUTES_CANNOT_BE_NULL = "reportAttributes can't be null";
+    private static final String NAME_CANNOT_BE_NULL = "name can't be null";
+
     private final Type type;
-    private final ReportAttributes reportAttributes;
+    private ReportAttributes reportAttributes;
     private String uuid;
     private String key;
     private String name;
@@ -123,71 +125,54 @@ public class ComponentImpl implements Component {
     private FileAttributes fileAttributes;
     private final List<Component> children = new ArrayList<>();
 
-    private Builder(ScannerReport.Component component) {
-      checkNotNull(component);
-      this.type = convertType(component.getType());
-      this.name = component.getName();
-      this.description = trimToNull(component.getDescription());
-      this.reportAttributes = createBatchAttributes(component);
-      this.fileAttributes = createFileAttributes(component);
+    private Builder(Type type){
+      this.type = requireNonNull(type, "type can't be null");
+    }
+
+    public Builder setReportAttributes(ReportAttributes reportAttributes) {
+      this.reportAttributes = requireNonNull(reportAttributes, REPORT_ATTRIBUTES_CANNOT_BE_NULL);
+      return this;
     }
 
     public Builder setUuid(String s) {
-      this.uuid = checkNotNull(s);
+      this.uuid = requireNonNull(s, UUID_CANNOT_BE_NULL);
       return this;
     }
 
     public Builder setKey(String s) {
-      this.key = checkNotNull(s);
+      this.key = requireNonNull(s, KEY_CANNOT_BE_NULL);
       return this;
     }
 
-    public Builder addChildren(Component... c) {
-      for (Component component : c) {
-        checkArgument(component.getType().isReportType());
-      }
-      this.children.addAll(asList(c));
+    public Builder setName(String name) {
+      this.name = requireNonNull(name, NAME_CANNOT_BE_NULL);
       return this;
     }
 
-    public ComponentImpl build() {
-      checkNotNull(key);
-      checkNotNull(uuid);
-      return new ComponentImpl(this);
+    public Builder setDescription(@Nullable String description) {
+      this.description = trimToNull(description);
+      return this;
     }
 
-    private static ReportAttributes createBatchAttributes(ScannerReport.Component component) {
-      return ReportAttributes.newBuilder(component.getRef())
-        .setVersion(trimToNull(component.getVersion()))
-        .setPath(trimToNull(component.getPath()))
-        .build();
+    public Builder setFileAttributes(@Nullable  FileAttributes fileAttributes) {
+      this.fileAttributes = fileAttributes;
+      return this;
     }
 
-    @CheckForNull
-    private static FileAttributes createFileAttributes(ScannerReport.Component component) {
-      if (component.getType() != ComponentType.FILE) {
-        return null;
+    public Builder addChildren(Component... c) {
+      for (Component component : c) {
+        checkArgument(component.getType().isReportType());
       }
-
-      return new FileAttributes(
-        component.getIsTest(),
-        trimToNull(component.getLanguage()));
+      this.children.addAll(asList(c));
+      return this;
     }
 
-    @VisibleForTesting
-    static Type convertType(ComponentType type) {
-      switch (type) {
-        case PROJECT:
-          return Type.PROJECT;
-        case MODULE:
-          return Type.MODULE;
-        case DIRECTORY:
-          return Type.DIRECTORY;
-        case FILE:
-          return Type.FILE;
-        default:
-          throw new IllegalArgumentException("Unsupported ComponentType value " + type);
-      }
+    public ComponentImpl build() {
+      requireNonNull(reportAttributes, REPORT_ATTRIBUTES_CANNOT_BE_NULL);
+      requireNonNull(uuid, UUID_CANNOT_BE_NULL);
+      requireNonNull(key, KEY_CANNOT_BE_NULL);
+      requireNonNull(name, NAME_CANNOT_BE_NULL);
+      return new ComponentImpl(this);
     }
   }
 
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/component/ComponentRootBuilder.java b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/component/ComponentRootBuilder.java
new file mode 100644 (file)
index 0000000..e072e3e
--- /dev/null
@@ -0,0 +1,147 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonar.server.computation.task.projectanalysis.component;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Optional;
+import com.google.common.base.Supplier;
+import java.util.function.Function;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+import org.sonar.db.component.ComponentDto;
+import org.sonar.scanner.protocol.output.ScannerReport;
+
+import static com.google.common.collect.Iterables.toArray;
+import static java.lang.String.format;
+import static org.apache.commons.lang.StringUtils.trimToNull;
+import static org.sonar.core.component.ComponentKeys.createEffectiveKey;
+import static org.sonar.core.component.ComponentKeys.createKey;
+import static org.sonar.core.util.stream.Collectors.toList;
+
+public class ComponentRootBuilder {
+  private final Function<String, String> uuidSupplier;
+  private final Function<Integer, ScannerReport.Component> scannerComponentSupplier;
+  private final Supplier<Optional<ComponentDto>> projectDtoSupplier;
+  @CheckForNull
+  private final String branch;
+
+  public ComponentRootBuilder(@Nullable String branch,
+    Function<String, String> uuidSupplier,
+    Function<Integer, ScannerReport.Component> scannerComponentSupplier,
+    Supplier<Optional<ComponentDto>> projectDtoSupplier) {
+    this.uuidSupplier = uuidSupplier;
+    this.scannerComponentSupplier = scannerComponentSupplier;
+    this.projectDtoSupplier = projectDtoSupplier;
+    this.branch = branch;
+  }
+
+  public Component build(ScannerReport.Component reportProject, String projectKey) {
+    return buildComponent(reportProject, projectKey);
+  }
+
+  private ComponentImpl buildComponent(ScannerReport.Component reportComponent, String latestModuleKey) {
+    switch (reportComponent.getType()) {
+      case PROJECT:
+        return createCommonBuilder(reportComponent, latestModuleKey, latestModuleKey)
+          .setName(nameOfProject(reportComponent, latestModuleKey, projectDtoSupplier))
+          .build();
+      case MODULE:
+        String moduleKey = createKey(reportComponent.getKey(), branch);
+        return buildOtherComponent(reportComponent, moduleKey, moduleKey);
+      case DIRECTORY:
+      case FILE:
+        return buildOtherComponent(reportComponent, createEffectiveKey(latestModuleKey, reportComponent.getPath()), latestModuleKey);
+      default:
+        throw new IllegalArgumentException(format("Unsupported component type '%s'", reportComponent.getType()));
+    }
+  }
+
+  private ComponentImpl buildOtherComponent(ScannerReport.Component reportComponent, String componentKey, String latestModuleKey) {
+    return createCommonBuilder(reportComponent, componentKey, latestModuleKey)
+      .setName(nameOfOthers(reportComponent, componentKey))
+      .build();
+  }
+
+  private ComponentImpl.Builder createCommonBuilder(ScannerReport.Component reportComponent, String componentKey, String latestModuleKey) {
+    return ComponentImpl.builder(convertType(reportComponent.getType()))
+      .setUuid(uuidSupplier.apply(componentKey))
+      .setKey(componentKey)
+      .setDescription(trimToNull(reportComponent.getDescription()))
+      .setFileAttributes(createFileAttributes(reportComponent))
+      .setReportAttributes(createReportAttributes(reportComponent))
+      .addChildren(toArray(buildChildren(reportComponent, latestModuleKey), Component.class));
+  }
+
+  private Iterable<Component> buildChildren(ScannerReport.Component component, String latestModuleKey) {
+    return component.getChildRefList()
+      .stream()
+      .map(componentRef -> buildComponent(scannerComponentSupplier.apply(componentRef), latestModuleKey))
+      .collect(toList(component.getChildRefList().size()));
+  }
+
+  private static String nameOfProject(ScannerReport.Component project, String projectKey, Supplier<Optional<ComponentDto>> projectDtoSupplier) {
+    String name = trimToNull(project.getName());
+    if (name == null) {
+      return projectDtoSupplier.get().transform(ComponentDto::name).or(projectKey);
+    }
+    return name;
+  }
+
+  private static String nameOfOthers(ScannerReport.Component reportComponent, String componentKey) {
+    String name = trimToNull(reportComponent.getName());
+    return name == null ? componentKey : name;
+  }
+
+  @VisibleForTesting
+  static ReportAttributes createReportAttributes(ScannerReport.Component component) {
+    return ReportAttributes.newBuilder(component.getRef())
+      .setPath(trimToNull(component.getPath()))
+      .setVersion(trimToNull(component.getVersion()))
+      .build();
+  }
+
+  @VisibleForTesting
+  @CheckForNull
+  static FileAttributes createFileAttributes(ScannerReport.Component component) {
+    if (component.getType() != ScannerReport.Component.ComponentType.FILE) {
+      return null;
+    }
+
+    return new FileAttributes(
+      component.getIsTest(),
+      trimToNull(component.getLanguage()));
+  }
+
+  @VisibleForTesting
+  static Component.Type convertType(ScannerReport.Component.ComponentType type) {
+    switch (type) {
+      case PROJECT:
+        return Component.Type.PROJECT;
+      case MODULE:
+        return Component.Type.MODULE;
+      case DIRECTORY:
+        return Component.Type.DIRECTORY;
+      case FILE:
+        return Component.Type.FILE;
+      default:
+        throw new IllegalArgumentException("Unsupported ComponentType value " + type);
+    }
+  }
+}
index 0b322adf7491f33cad88aad65c3a5af36276b40f..c97670c2f1ddd934439339e5d71d9dab3d440648 100644 (file)
  */
 package org.sonar.server.computation.task.projectanalysis.step;
 
-import com.google.common.collect.Iterables;
 import javax.annotation.CheckForNull;
 import javax.annotation.Nullable;
-import org.sonar.core.component.ComponentKeys;
 import org.sonar.db.DbClient;
 import org.sonar.db.DbSession;
 import org.sonar.db.component.SnapshotDto;
 import org.sonar.db.component.SnapshotQuery;
 import org.sonar.scanner.protocol.output.ScannerReport;
+import org.sonar.server.computation.task.projectanalysis.analysis.Analysis;
 import org.sonar.server.computation.task.projectanalysis.analysis.MutableAnalysisMetadataHolder;
 import org.sonar.server.computation.task.projectanalysis.batch.BatchReportReader;
 import org.sonar.server.computation.task.projectanalysis.component.Component;
-import org.sonar.server.computation.task.projectanalysis.component.ComponentImpl;
+import org.sonar.server.computation.task.projectanalysis.component.ComponentRootBuilder;
 import org.sonar.server.computation.task.projectanalysis.component.MutableTreeRootHolder;
 import org.sonar.server.computation.task.projectanalysis.component.UuidFactory;
-import org.sonar.server.computation.task.projectanalysis.analysis.Analysis;
 import org.sonar.server.computation.task.step.ComputationStep;
 
-import static com.google.common.collect.Iterables.toArray;
-import static org.sonar.server.computation.task.projectanalysis.component.ComponentImpl.builder;
+import static org.sonar.core.component.ComponentKeys.createKey;
 
 /**
  * Populates the {@link MutableTreeRootHolder} and {@link MutableAnalysisMetadataHolder} from the {@link BatchReportReader}
@@ -57,92 +54,47 @@ public class BuildComponentTreeStep implements ComputationStep {
     this.analysisMetadataHolder = analysisMetadataHolder;
   }
 
+  @Override
+  public String getDescription() {
+    return "Build tree of components";
+  }
+
   @Override
   public void execute() {
     String branch = analysisMetadataHolder.getBranch();
     ScannerReport.Component reportProject = reportReader.readComponent(analysisMetadataHolder.getRootComponentRef());
-    UuidFactory uuidFactory = new UuidFactory(dbClient, moduleKey(reportProject, branch));
-    Component project = new ComponentRootBuilder(reportProject, uuidFactory, branch).build();
-    treeRootHolder.setRoot(project);
-    setBaseAnalysis(project.getUuid());
+    String projectKey = createKey(reportProject.getKey(), branch);
+    UuidFactory uuidFactory = new UuidFactory(dbClient, projectKey);
+
+    try (DbSession dbSession = dbClient.openSession(false)) {
+      ComponentRootBuilder rootBuilder = new ComponentRootBuilder(branch,
+        uuidFactory::getOrCreateForKey,
+        reportReader::readComponent,
+        () -> dbClient.componentDao().selectByKey(dbSession, projectKey));
+      Component project = rootBuilder.build(reportProject, projectKey);
+      treeRootHolder.setRoot(project);
+      setBaseAnalysis(dbSession, project.getUuid());
+    }
   }
 
-  private void setBaseAnalysis(String projectUuid) {
-    DbSession dbSession = dbClient.openSession(false);
-    try {
-      SnapshotDto snapshotDto = dbClient.snapshotDao().selectAnalysisByQuery(dbSession,
-        new SnapshotQuery()
-          .setComponentUuid(projectUuid)
-          .setIsLast(true));
-      analysisMetadataHolder.setBaseAnalysis(toAnalysis(snapshotDto));
-    } finally {
-      dbClient.closeSession(dbSession);
-    }
+  private void setBaseAnalysis(DbSession dbSession, String projectUuid) {
+    SnapshotDto snapshotDto = dbClient.snapshotDao().selectAnalysisByQuery(dbSession,
+      new SnapshotQuery()
+        .setComponentUuid(projectUuid)
+        .setIsLast(true));
+    analysisMetadataHolder.setBaseAnalysis(toAnalysis(snapshotDto));
   }
 
   @CheckForNull
   private static Analysis toAnalysis(@Nullable SnapshotDto snapshotDto) {
-    return snapshotDto == null ? null : new Analysis.Builder()
+    if (snapshotDto == null) {
+      return null;
+    }
+    return new Analysis.Builder()
       .setId(snapshotDto.getId())
       .setUuid(snapshotDto.getUuid())
       .setCreatedAt(snapshotDto.getCreatedAt())
       .build();
   }
 
-  private class ComponentRootBuilder {
-
-    private final ScannerReport.Component reportProject;
-
-    private final UuidFactory uuidFactory;
-
-    @CheckForNull
-    private final String branch;
-
-    public ComponentRootBuilder(ScannerReport.Component reportProject, UuidFactory uuidFactory, @Nullable String branch) {
-      this.reportProject = reportProject;
-      this.uuidFactory = uuidFactory;
-      this.branch = branch;
-    }
-
-    private Component build() {
-      return buildComponent(reportProject, moduleKey(reportProject, branch));
-    }
-
-    private ComponentImpl buildComponent(ScannerReport.Component reportComponent, String latestModuleKey) {
-      switch (reportComponent.getType()) {
-        case PROJECT:
-        case MODULE:
-          String moduleKey = moduleKey(reportComponent, branch);
-          return buildComponent(reportComponent, moduleKey, moduleKey);
-        case DIRECTORY:
-        case FILE:
-          return buildComponent(reportComponent, ComponentKeys.createEffectiveKey(latestModuleKey, reportComponent.getPath()), latestModuleKey);
-        default:
-          throw new IllegalStateException(String.format("Unsupported component type '%s'", reportComponent.getType()));
-      }
-    }
-
-    private ComponentImpl buildComponent(ScannerReport.Component reportComponent, String componentKey, String latestModuleKey) {
-      return builder(reportComponent)
-        .addChildren(toArray(buildChildren(reportComponent, latestModuleKey), Component.class))
-        .setKey(componentKey)
-        .setUuid(uuidFactory.getOrCreateForKey(componentKey))
-        .build();
-    }
-
-    private Iterable<Component> buildChildren(ScannerReport.Component component, final String latestModuleKey) {
-      return Iterables.transform(
-        component.getChildRefList(),
-        componentRef -> buildComponent(reportReader.readComponent(componentRef), latestModuleKey));
-    }
-  }
-
-  private static String moduleKey(ScannerReport.Component reportComponent, @Nullable String branch) {
-    return ComponentKeys.createKey(reportComponent.getKey(), branch);
-  }
-
-  @Override
-  public String getDescription() {
-    return "Build tree of components";
-  }
 }
index 90ffa33a9e31cda581477630b79e491c01573deb..1d8c006551955bc895900caa6b334000accdf630 100644 (file)
  */
 package org.sonar.server.computation.task.projectanalysis.component;
 
+import java.util.Arrays;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.ExpectedException;
-import org.sonar.scanner.protocol.output.ScannerReport;
-import org.sonar.scanner.protocol.output.ScannerReport.Component.ComponentType;
 
-import static com.google.common.base.Predicates.in;
-import static com.google.common.base.Predicates.not;
-import static com.google.common.collect.FluentIterable.from;
-import static java.util.Arrays.asList;
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.fail;
-import static org.sonar.scanner.protocol.output.ScannerReport.Component.ComponentType.DIRECTORY;
-import static org.sonar.scanner.protocol.output.ScannerReport.Component.ComponentType.FILE;
-import static org.sonar.scanner.protocol.output.ScannerReport.Component.ComponentType.UNRECOGNIZED;
-import static org.sonar.scanner.protocol.output.ScannerReport.Component.ComponentType.UNSET;
+import static org.sonar.server.computation.task.projectanalysis.component.Component.Type.FILE;
 import static org.sonar.server.computation.task.projectanalysis.component.ComponentImpl.builder;
 
 public class ComponentImplTest {
@@ -46,11 +38,12 @@ public class ComponentImplTest {
   public ExpectedException thrown = ExpectedException.none();
 
   @Test
-  public void verify_key_and_uuid() throws Exception {
-    ComponentImpl component = builder(ScannerReport.Component.newBuilder().setType(FILE).build()).setKey(KEY).setUuid(UUID).build();
+  public void verify_key_uuid_and_name() throws Exception {
+    ComponentImpl component = buildSimpleComponent(FILE, KEY).setUuid(UUID).setName("name").build();
 
     assertThat(component.getKey()).isEqualTo(KEY);
     assertThat(component.getUuid()).isEqualTo(UUID);
+    assertThat(component.getName()).isEqualTo("name");
   }
 
   @Test
@@ -64,60 +57,55 @@ public class ComponentImplTest {
   public void set_key_throws_NPE_if_component_arg_is_Null() {
     thrown.expect(NullPointerException.class);
 
-    builder(ScannerReport.Component.newBuilder().setType(FILE).build()).setUuid(null);
+    builder(FILE).setUuid(null);
   }
 
   @Test
   public void set_uuid_throws_NPE_if_component_arg_is_Null() {
     thrown.expect(NullPointerException.class);
 
-    builder(ScannerReport.Component.newBuilder().setType(FILE).build()).setKey(null);
+    builder(FILE).setKey(null);
   }
 
   @Test
   public void build_without_key_throws_NPE_if_component_arg_is_Null() {
     thrown.expect(NullPointerException.class);
 
-    builder(ScannerReport.Component.newBuilder().setType(FILE).build()).setUuid("ABCD").build();
+    builder(FILE).setUuid("ABCD").build();
   }
 
   @Test
   public void build_without_uuid_throws_NPE_if_component_arg_is_Null() {
     thrown.expect(NullPointerException.class);
 
-    builder(ScannerReport.Component.newBuilder().setType(FILE).build()).setKey(KEY).build();
+    builder(FILE).setKey(KEY).build();
   }
 
   @Test
   public void get_name_from_batch_component() {
     String name = "project";
-    ComponentImpl component = buildSimpleComponent(ScannerReport.Component.newBuilder().setType(FILE).setName(name).build());
+    ComponentImpl component = buildSimpleComponent(FILE, "file").setName(name).build();
     assertThat(component.getName()).isEqualTo(name);
   }
 
-  @Test
-  public void get_version_from_batch_component() {
-    String version = "1.0";
-    ComponentImpl component = buildSimpleComponent(ScannerReport.Component.newBuilder().setType(FILE).setVersion(version).build());
-    assertThat(component.getReportAttributes().getVersion()).isEqualTo(version);
-  }
-
   @Test
   public void getFileAttributes_throws_ISE_if_BatchComponent_does_not_have_type_FILE() {
-    for (ComponentType componentType : from(asList(ComponentType.values())).filter(not(in(asList(FILE, UNSET, UNRECOGNIZED))))) {
-      ComponentImpl component = buildSimpleComponent(ScannerReport.Component.newBuilder().setType(componentType).build());
-      try {
-        component.getFileAttributes();
-        fail("A IllegalStateException should have been raised");
-      } catch (IllegalStateException e) {
-        assertThat(e).hasMessage("Only component of type FILE have a FileAttributes object");
-      }
-    }
+    Arrays.stream(Component.Type.values())
+      .filter(type -> type != FILE)
+      .forEach((componentType) -> {
+        ComponentImpl component = buildSimpleComponent(componentType, componentType.name()).build();
+        try {
+          component.getFileAttributes();
+          fail("A IllegalStateException should have been raised");
+        } catch (IllegalStateException e) {
+          assertThat(e).hasMessage("Only component of type FILE have a FileAttributes object");
+        }
+      });
   }
 
   @Test
   public void isUnitTest_returns_true_if_IsTest_is_set_in_BatchComponent() {
-    ComponentImpl component = buildSimpleComponent(ScannerReport.Component.newBuilder().setType(FILE).setIsTest(true).build());
+    ComponentImpl component = buildSimpleComponent(FILE, "file").setFileAttributes(new FileAttributes(true, null)).build();
 
     assertThat(component.getFileAttributes().isUnitTest()).isTrue();
   }
@@ -125,20 +113,24 @@ public class ComponentImplTest {
   @Test
   public void isUnitTest_returns_value_of_language_of_BatchComponent() {
     String languageKey = "some language key";
-    ComponentImpl component = buildSimpleComponent(ScannerReport.Component.newBuilder().setType(FILE).setLanguage(languageKey).build());
+    ComponentImpl component = buildSimpleComponent(FILE, "file").setFileAttributes(new FileAttributes(false, languageKey)).build();
 
     assertThat(component.getFileAttributes().getLanguageKey()).isEqualTo(languageKey);
   }
 
   @Test
   public void build_with_child() throws Exception {
-    ComponentImpl child = builder(ScannerReport.Component.newBuilder().setType(FILE).build())
+    ComponentImpl child = builder(FILE)
+      .setName("CHILD_NAME")
       .setKey("CHILD_KEY")
       .setUuid("CHILD_UUID")
+      .setReportAttributes(ReportAttributes.newBuilder(2).build())
       .build();
-    ComponentImpl componentImpl = builder(ScannerReport.Component.newBuilder().setType(DIRECTORY).build())
+    ComponentImpl componentImpl = builder(Component.Type.DIRECTORY)
+      .setName("DIR")
       .setKey(KEY)
       .setUuid(UUID)
+      .setReportAttributes(ReportAttributes.newBuilder(1).build())
       .addChildren(child)
       .build();
 
@@ -146,34 +138,33 @@ public class ComponentImplTest {
     Component childReloaded = componentImpl.getChildren().iterator().next();
     assertThat(childReloaded.getKey()).isEqualTo("CHILD_KEY");
     assertThat(childReloaded.getUuid()).isEqualTo("CHILD_UUID");
-    assertThat(childReloaded.getType()).isEqualTo(Component.Type.FILE);
-  }
-
-  @Test
-  public void convertType() {
-    for (ComponentType componentType : from(asList(ComponentType.values())).filter(not(in(asList(UNSET, UNRECOGNIZED))))) {
-      assertThat(ComponentImpl.Builder.convertType(componentType)).isEqualTo(Component.Type.valueOf(componentType.name()));
-    }
-  }
-
-  private static ComponentImpl buildSimpleComponent(ScannerReport.Component reportComponent) {
-    return builder(reportComponent).setKey(KEY).setUuid(UUID).build();
+    assertThat(childReloaded.getType()).isEqualTo(FILE);
   }
 
   @Test
   public void equals_compares_on_uuid_only() {
-    ComponentImpl.Builder builder = builder(ScannerReport.Component.newBuilder().setType(FILE).build()).setUuid(UUID);
+    ComponentImpl.Builder builder = buildSimpleComponent(FILE, "1").setUuid(UUID);
 
-    assertThat(builder.setKey("1").build()).isEqualTo(builder.setKey("1").build());
-    assertThat(builder.setKey("1").build()).isEqualTo(builder.setKey("2").build());
+    assertThat(builder.build()).isEqualTo(builder.build());
+    assertThat(builder.build()).isEqualTo(buildSimpleComponent(FILE, "2").setUuid(UUID).build());
+    assertThat(builder.build()).isNotEqualTo(buildSimpleComponent(FILE, "1").setUuid("otherUUid").build());
   }
 
   @Test
   public void hashCode_is_hashcode_of_uuid() {
-    ComponentImpl.Builder builder = builder(ScannerReport.Component.newBuilder().setType(FILE).build()).setUuid(UUID);
+    ComponentImpl.Builder builder = buildSimpleComponent(FILE, "1").setUuid(UUID);
+
+    assertThat(builder.build().hashCode()).isEqualTo(builder.build().hashCode());
+    assertThat(builder.build().hashCode()).isEqualTo(buildSimpleComponent(FILE, "2").setUuid(UUID).build().hashCode());
+    assertThat(builder.build().hashCode()).isEqualTo(UUID.hashCode());
+  }
 
-    assertThat(builder.setKey("1").build().hashCode()).isEqualTo(builder.setKey("1").build().hashCode());
-    assertThat(builder.setKey("1").build().hashCode()).isEqualTo(builder.setKey("2").build().hashCode());
-    assertThat(builder.setKey("1").build().hashCode()).isEqualTo(UUID.hashCode());
+  private static ComponentImpl.Builder buildSimpleComponent(Component.Type type, String key) {
+    return builder(type)
+      .setName("name_" + key)
+      .setKey(key)
+      .setUuid("uuid_" + key)
+      .setReportAttributes(ReportAttributes.newBuilder(key.hashCode())
+        .build());
   }
 }
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/component/ComponentRootBuilderTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/component/ComponentRootBuilderTest.java
new file mode 100644 (file)
index 0000000..3fa1c14
--- /dev/null
@@ -0,0 +1,396 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonar.server.computation.task.projectanalysis.component;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Supplier;
+import java.util.Arrays;
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.function.Function;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExternalResource;
+import org.sonar.db.component.ComponentDto;
+import org.sonar.scanner.protocol.output.ScannerReport;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.fail;
+import static org.sonar.scanner.protocol.output.ScannerReport.Component.newBuilder;
+import static org.sonar.scanner.protocol.output.ScannerReport.Component.ComponentType.DIRECTORY;
+import static org.sonar.scanner.protocol.output.ScannerReport.Component.ComponentType.FILE;
+import static org.sonar.scanner.protocol.output.ScannerReport.Component.ComponentType.MODULE;
+import static org.sonar.scanner.protocol.output.ScannerReport.Component.ComponentType.PROJECT;
+import static org.sonar.scanner.protocol.output.ScannerReport.Component.ComponentType.UNRECOGNIZED;
+import static org.sonar.scanner.protocol.output.ScannerReport.Component.ComponentType.UNSET;
+import static org.sonar.server.computation.task.projectanalysis.component.ComponentRootBuilder.createFileAttributes;
+import static org.sonar.server.computation.task.projectanalysis.component.ComponentRootBuilder.createReportAttributes;
+import static org.sonar.server.computation.task.projectanalysis.component.ComponentVisitor.Order.PRE_ORDER;
+
+public class ComponentRootBuilderTest {
+
+  private static final Function<String, String> SIMPLE_UUID_GENERATOR = (componentKey) -> componentKey + "_uuid";
+  private static final String NO_BRANCH = null;
+  private static final String PROJECT_KEY = "this is the key";
+  private static final String MODULE_KEY = "module key";
+  private static final String DIRECTORY_PATH = "directory path";
+  private static final String DIRECTORY_KEY = MODULE_KEY + ":" + DIRECTORY_PATH;
+  private static final String FILE_PATH = "file path";
+  private static final String FILE_KEY = MODULE_KEY + ":" + FILE_PATH;
+  private static final ComponentDto PROJECT_DTO = new ComponentDto().setName("name in db");
+  private static final Supplier<Optional<ComponentDto>> NO_COMPONENT_DTO_FOR_PROJECT = Optional::absent;
+  private static final Supplier<Optional<ComponentDto>> COMPONENT_DTO_FOR_PROJECT = () -> Optional.of(PROJECT_DTO);
+  private static final EnumSet<ScannerReport.Component.ComponentType> REPORT_TYPES = EnumSet.of(
+    PROJECT, MODULE, DIRECTORY, FILE);
+
+  @Rule
+  public ScannerComponentProvider scannerComponentProvider = new ScannerComponentProvider();
+
+  private ComponentRootBuilder underTest = new ComponentRootBuilder(NO_BRANCH, SIMPLE_UUID_GENERATOR, scannerComponentProvider, NO_COMPONENT_DTO_FOR_PROJECT);
+
+  @Test
+  public void build_throws_IAE_for_all_types_but_PROJECT_MODULE_DIRECTORY_FILE() {
+    Arrays.stream(ScannerReport.Component.ComponentType.values())
+      .filter((type) -> type != UNRECOGNIZED)
+      .filter((type) -> !REPORT_TYPES.contains(type))
+      .forEach(
+        (type) -> {
+          ScannerReport.Component component = newBuilder().setType(type).build();
+          try {
+            underTest.build(component, "don't care");
+            fail("Should have thrown a IllegalArgumentException");
+          } catch (IllegalArgumentException e) {
+            assertThat(e).hasMessage("Unsupported component type '" + type + "'");
+          }
+        });
+  }
+
+  @Test
+  public void name_of_project_is_name_in_Scanner_Component_when_set() {
+    String expected = "the name";
+    Component root = underTest.build(newBuilder().setType(PROJECT).setName(expected).build(), PROJECT_KEY);
+    assertThat(root.getName()).isEqualTo(expected);
+  }
+
+  @Test
+  public void name_of_project_is_name_in_Scanner_Component_when_set_even_if_there_is_a_ComponentDto() {
+    String expected = "the name";
+    Component root = new ComponentRootBuilder(NO_BRANCH, SIMPLE_UUID_GENERATOR, scannerComponentProvider, COMPONENT_DTO_FOR_PROJECT)
+      .build(newBuilder().setType(PROJECT).setName(expected).build(), PROJECT_KEY);
+    assertThat(root.getName()).isEqualTo(expected);
+  }
+
+  @Test
+  public void name_of_project_is_specified_key_when_name_is_unset_in_Scanner_Component_and_there_is_no_ComponentDto() {
+    Component root = underTest.build(newBuilder().setType(PROJECT).build(), PROJECT_KEY);
+    assertThat(root.getName()).isEqualTo(PROJECT_KEY);
+  }
+
+  @Test
+  public void name_of_project_is_specified_key_when_name_is_empty_in_Scanner_Component_and_there_is_no_ComponentDto() {
+    Component root = underTest.build(newBuilder().setType(PROJECT).setName("").build(), PROJECT_KEY);
+
+    assertThat(root.getName()).isEqualTo(PROJECT_KEY);
+  }
+
+  @Test
+  public void name_of_project_is_name_of_ComponentDto_when_name_is_unset_in_Scanner_Component_and_there_is_a_ComponentDto() {
+    Component root = new ComponentRootBuilder(NO_BRANCH, SIMPLE_UUID_GENERATOR, scannerComponentProvider, COMPONENT_DTO_FOR_PROJECT)
+      .build(newBuilder().setType(PROJECT).build(), PROJECT_KEY);
+
+    assertThat(root.getName()).isEqualTo(PROJECT_DTO.name());
+  }
+
+  @Test
+  public void name_of_project_is_name_of_ComponentDto_when_name_is_empty_in_Scanner_Component_and_there_is_a_ComponentDto() {
+    Component root = new ComponentRootBuilder(NO_BRANCH, SIMPLE_UUID_GENERATOR, scannerComponentProvider, COMPONENT_DTO_FOR_PROJECT)
+      .build(newBuilder().setType(PROJECT).setName("").build(), PROJECT_KEY);
+
+    assertThat(root.getName()).isEqualTo(PROJECT_DTO.name());
+  }
+
+  @Test
+  public void name_of_module_directory_and_file_contains_branch_when_non_empty() {
+    ScannerReport.Component project = newBuilder().setType(PROJECT).setRef(1).addChildRef(2).build();
+    scannerComponentProvider.add(newBuilder().setRef(2).setType(MODULE).setKey(MODULE_KEY).addChildRef(3));
+    scannerComponentProvider.add(newBuilder().setRef(3).setType(DIRECTORY).setPath(DIRECTORY_PATH).addChildRef(4));
+    scannerComponentProvider.add(newBuilder().setRef(4).setType(FILE).setPath(FILE_PATH));
+
+    String branch = "BRANCH";
+    ComponentRootBuilder builder = new ComponentRootBuilder(branch, SIMPLE_UUID_GENERATOR, scannerComponentProvider, NO_COMPONENT_DTO_FOR_PROJECT);
+
+    Component root = builder.build(project, PROJECT_KEY);
+    assertThat(root.getKey()).isEqualTo(PROJECT_KEY);
+    assertThat(root.getChildren()).hasSize(1);
+    Component module = root.getChildren().iterator().next();
+    assertThat(module.getKey()).isEqualTo(MODULE_KEY + ":" + branch);
+    assertThat(module.getChildren()).hasSize(1);
+    Component directory = module.getChildren().iterator().next();
+    assertThat(directory.getKey()).isEqualTo(module.getKey() + ":" + DIRECTORY_PATH);
+    assertThat(directory.getChildren()).hasSize(1);
+    Component file = directory.getChildren().iterator().next();
+    assertThat(file.getKey()).isEqualTo(module.getKey() + ":" + FILE_PATH);
+    assertThat(file.getChildren()).isEmpty();
+  }
+
+  @Test
+  public void name_of_module_directory_and_file_is_key_of_Scanner_Component_when_name_is_unset() {
+    ScannerReport.Component project = newBuilder().setType(PROJECT).setRef(1).addChildRef(2).build();
+    scannerComponentProvider.add(newBuilder().setRef(2).setType(MODULE).setKey(MODULE_KEY).addChildRef(3));
+    scannerComponentProvider.add(newBuilder().setRef(3).setType(DIRECTORY).setPath(DIRECTORY_PATH).addChildRef(4));
+    scannerComponentProvider.add(newBuilder().setRef(4).setType(FILE).setPath(FILE_PATH));
+
+    Component root = underTest.build(project, PROJECT_KEY);
+    assertThat(root.getKey()).isEqualTo(PROJECT_KEY);
+    Component module = root.getChildren().iterator().next();
+    assertThat(module.getName()).isEqualTo(MODULE_KEY);
+    Component directory = module.getChildren().iterator().next();
+    assertThat(directory.getName()).isEqualTo(module.getKey() + ":" + DIRECTORY_PATH);
+    Component file = directory.getChildren().iterator().next();
+    assertThat(file.getName()).isEqualTo(module.getKey() + ":" + FILE_PATH);
+  }
+
+  @Test
+  public void name_of_module_directory_and_file_is_key_of_Scanner_Component_when_name_is_empty() {
+    ScannerReport.Component project = newBuilder().setType(PROJECT).setRef(1).setName("").addChildRef(2).build();
+    scannerComponentProvider.add(newBuilder().setRef(2).setType(MODULE).setKey(MODULE_KEY).setName("").addChildRef(3));
+    scannerComponentProvider.add(newBuilder().setRef(3).setType(DIRECTORY).setPath(DIRECTORY_PATH).setName("").addChildRef(4));
+    scannerComponentProvider.add(newBuilder().setRef(4).setType(FILE).setPath(FILE_PATH).setName(""));
+
+    Component root = underTest.build(project, PROJECT_KEY);
+    assertThat(root.getKey()).isEqualTo(PROJECT_KEY);
+    Component module = root.getChildren().iterator().next();
+    assertThat(module.getName()).isEqualTo(MODULE_KEY);
+    Component directory = module.getChildren().iterator().next();
+    assertThat(directory.getName()).isEqualTo(module.getKey() + ":" + DIRECTORY_PATH);
+    Component file = directory.getChildren().iterator().next();
+    assertThat(file.getName()).isEqualTo(module.getKey() + ":" + FILE_PATH);
+  }
+
+  @Test
+  public void name_of_module_directory_and_files_includes_name_of_closest_module() {
+    ScannerReport.Component project = newBuilder().setType(PROJECT).setRef(1).addChildRef(11).addChildRef(21).addChildRef(31).build();
+    scannerComponentProvider.add(newBuilder().setRef(11).setType(MODULE).setKey("module 1").addChildRef(12).addChildRef(22).addChildRef(32));
+    scannerComponentProvider.add(newBuilder().setRef(12).setType(MODULE).setKey("module 2").addChildRef(13).addChildRef(23).addChildRef(33));
+    scannerComponentProvider.add(newBuilder().setRef(13).setType(MODULE).setKey("module 3").addChildRef(24).addChildRef(34));
+    scannerComponentProvider.add(newBuilder().setRef(21).setType(DIRECTORY).setPath("directory in project").addChildRef(35));
+    scannerComponentProvider.add(newBuilder().setRef(22).setType(DIRECTORY).setPath("directory in module 1").addChildRef(36));
+    scannerComponentProvider.add(newBuilder().setRef(23).setType(DIRECTORY).setPath("directory in module 2").addChildRef(37));
+    scannerComponentProvider.add(newBuilder().setRef(24).setType(DIRECTORY).setPath("directory in module 3").addChildRef(38));
+    scannerComponentProvider.add(newBuilder().setRef(31).setType(FILE).setPath("file in project"));
+    scannerComponentProvider.add(newBuilder().setRef(32).setType(FILE).setPath("file in module 1"));
+    scannerComponentProvider.add(newBuilder().setRef(33).setType(FILE).setPath("file in module 2"));
+    scannerComponentProvider.add(newBuilder().setRef(34).setType(FILE).setPath("file in module 3"));
+    scannerComponentProvider.add(newBuilder().setRef(35).setType(FILE).setPath("file in directory in project"));
+    scannerComponentProvider.add(newBuilder().setRef(36).setType(FILE).setPath("file in directory in module 1"));
+    scannerComponentProvider.add(newBuilder().setRef(37).setType(FILE).setPath("file in directory in module 2"));
+    scannerComponentProvider.add(newBuilder().setRef(38).setType(FILE).setPath("file in directory in module 3"));
+
+    Component root = underTest.build(project, PROJECT_KEY);
+    Map<Integer, Component> componentsByRef = indexComponentByRef(root);
+    assertThat(componentsByRef.get(11).getKey()).isEqualTo("module 1");
+    assertThat(componentsByRef.get(12).getKey()).isEqualTo("module 2");
+    assertThat(componentsByRef.get(13).getKey()).isEqualTo("module 3");
+    assertThat(componentsByRef.get(21).getKey()).startsWith(PROJECT_KEY + ":");
+    assertThat(componentsByRef.get(22).getKey()).startsWith("module 1" + ":");
+    assertThat(componentsByRef.get(23).getKey()).startsWith("module 2" + ":");
+    assertThat(componentsByRef.get(24).getKey()).startsWith("module 3" + ":");
+    assertThat(componentsByRef.get(31).getKey()).startsWith(PROJECT_KEY + ":");
+    assertThat(componentsByRef.get(32).getKey()).startsWith("module 1" + ":");
+    assertThat(componentsByRef.get(33).getKey()).startsWith("module 2" + ":");
+    assertThat(componentsByRef.get(34).getKey()).startsWith("module 3" + ":");
+    assertThat(componentsByRef.get(35).getKey()).startsWith(PROJECT_KEY + ":");
+    assertThat(componentsByRef.get(36).getKey()).startsWith("module 1" + ":");
+    assertThat(componentsByRef.get(37).getKey()).startsWith("module 2" + ":");
+    assertThat(componentsByRef.get(38).getKey()).startsWith("module 3" + ":");
+  }
+
+  @Test
+  public void uuid_is_value_from_uuid_supplier_for_project_module_directory_and_file() {
+    ScannerReport.Component project = newBuilder().setType(PROJECT).setRef(1).addChildRef(2).build();
+    scannerComponentProvider.add(newBuilder().setRef(2).setType(MODULE).setKey(MODULE_KEY).addChildRef(3));
+    scannerComponentProvider.add(newBuilder().setRef(3).setType(DIRECTORY).setPath(DIRECTORY_PATH).addChildRef(4));
+    scannerComponentProvider.add(newBuilder().setRef(4).setType(FILE).setPath(FILE_PATH));
+
+    Component root = underTest.build(project, PROJECT_KEY);
+    Map<Integer, Component> componentByRef = indexComponentByRef(root);
+    assertThat(componentByRef.get(1).getUuid()).isEqualTo(SIMPLE_UUID_GENERATOR.apply(PROJECT_KEY));
+    assertThat(componentByRef.get(2).getUuid()).isEqualTo(SIMPLE_UUID_GENERATOR.apply(MODULE_KEY));
+    assertThat(componentByRef.get(3).getUuid()).isEqualTo(SIMPLE_UUID_GENERATOR.apply(DIRECTORY_KEY));
+    assertThat(componentByRef.get(4).getUuid()).isEqualTo(SIMPLE_UUID_GENERATOR.apply(FILE_KEY));
+
+  }
+
+  @Test
+  public void description_of_project_module_directory_and_file_is_null_when_unset_in_Scanner_Component() {
+    ScannerReport.Component project = newBuilder().setType(PROJECT).setRef(1).addChildRef(2).build();
+    scannerComponentProvider.add(newBuilder().setRef(2).setType(MODULE).addChildRef(3));
+    scannerComponentProvider.add(newBuilder().setRef(3).setType(DIRECTORY).addChildRef(4));
+    scannerComponentProvider.add(newBuilder().setRef(4).setType(FILE));
+
+    Component root = underTest.build(project, PROJECT_KEY);
+    Map<Integer, Component> componentByRef = indexComponentByRef(root);
+    assertThat(componentByRef.get(1).getDescription()).isNull();
+    assertThat(componentByRef.get(2).getDescription()).isNull();
+    assertThat(componentByRef.get(3).getDescription()).isNull();
+    assertThat(componentByRef.get(4).getDescription()).isNull();
+  }
+
+  @Test
+  public void description_of_project_module_directory_and_file_is_null_when_empty_in_Scanner_Component() {
+    ScannerReport.Component project = newBuilder().setType(PROJECT).setRef(1).setDescription("").addChildRef(2).build();
+    scannerComponentProvider.add(newBuilder().setRef(2).setType(MODULE).setDescription("").addChildRef(3));
+    scannerComponentProvider.add(newBuilder().setRef(3).setType(DIRECTORY).setDescription("").addChildRef(4));
+    scannerComponentProvider.add(newBuilder().setRef(4).setType(FILE).setDescription(""));
+
+    Component root = underTest.build(project, PROJECT_KEY);
+    Map<Integer, Component> componentByRef = indexComponentByRef(root);
+    assertThat(componentByRef.get(1).getDescription()).isNull();
+    assertThat(componentByRef.get(2).getDescription()).isNull();
+    assertThat(componentByRef.get(3).getDescription()).isNull();
+    assertThat(componentByRef.get(4).getDescription()).isNull();
+  }
+
+  @Test
+  public void description_of_project_module_directory_and_file_is_description_of_Scanner_Component_when_set() {
+    ScannerReport.Component project = newBuilder().setType(PROJECT).setRef(1).setDescription("desc of project").addChildRef(2).build();
+    scannerComponentProvider.add(newBuilder().setRef(2).setType(MODULE).setDescription("desc of module").addChildRef(3));
+    scannerComponentProvider.add(newBuilder().setRef(3).setType(DIRECTORY).setDescription("desc of directory").addChildRef(4));
+    scannerComponentProvider.add(newBuilder().setRef(4).setType(FILE).setDescription("desc of file"));
+
+    Component root = underTest.build(project, PROJECT_KEY);
+    Map<Integer, Component> componentByRef = indexComponentByRef(root);
+    assertThat(componentByRef.get(1).getDescription()).isEqualTo("desc of project");
+    assertThat(componentByRef.get(2).getDescription()).isEqualTo("desc of module");
+    assertThat(componentByRef.get(3).getDescription()).isEqualTo("desc of directory");
+    assertThat(componentByRef.get(4).getDescription()).isEqualTo("desc of file");
+  }
+
+  @Test
+  public void all_types_but_UNSET_and_UNRECOGNIZED_are_converted() {
+    Arrays.stream(ScannerReport.Component.ComponentType.values())
+      .filter((type) -> type != UNRECOGNIZED)
+      .filter((type) -> type != UNSET)
+      .forEach((type) -> assertThat(ComponentRootBuilder.convertType(type)).isEqualTo(Component.Type.valueOf(type.name())));
+  }
+
+  @Test
+  public void createReportAttributes_takes_ref_version_and_path_from_Scanner_Component() {
+    int ref = 123;
+    String version = "1.0";
+    String path = "some path";
+
+    ReportAttributes reportAttributes = createReportAttributes(newBuilder()
+      .setRef(ref)
+      .setVersion(version)
+      .setPath(path)
+      .build());
+    assertThat(reportAttributes.getRef()).isEqualTo(ref);
+    assertThat(reportAttributes.getPath()).isEqualTo(path);
+    assertThat(reportAttributes.getVersion()).isEqualTo(version);
+  }
+
+  @Test
+  public void createReportAttributes_sets_null_version_when_unset_in_Scanner_Component() {
+    ReportAttributes reportAttributes = createReportAttributes(newBuilder().build());
+    assertThat(reportAttributes.getVersion()).isNull();
+  }
+
+  @Test
+  public void createReportAttributes_sets_null_path_when_unset_in_Scanner_Component() {
+    ReportAttributes reportAttributes = createReportAttributes(newBuilder().build());
+    assertThat(reportAttributes.getPath()).isNull();
+  }
+
+  @Test
+  public void createReportAttributes_sets_null_version_when_empty_in_Scanner_Component() {
+    ReportAttributes reportAttributes = createReportAttributes(newBuilder().setVersion("").build());
+    assertThat(reportAttributes.getVersion()).isNull();
+  }
+
+  @Test
+  public void createReportAttributes_sets_null_path_when_empty_in_Scanner_Component() {
+    ReportAttributes reportAttributes = createReportAttributes(newBuilder().setPath("").build());
+    assertThat(reportAttributes.getPath()).isNull();
+  }
+
+  @Test
+  public void createFileAttributes_returns_null_when_type_is_not_FILE() {
+    Arrays.stream(ScannerReport.Component.ComponentType.values())
+      .filter((type) -> type != UNRECOGNIZED)
+      .filter((type) -> type != FILE)
+      .map(
+        (type) -> newBuilder().setType(type).build())
+      .forEach(
+        (component) -> assertThat(createFileAttributes(component)).isNull());
+  }
+
+  @Test
+  public void createFileAttributes_sets_language_to_null_when_unset_in_Scanner_Component() {
+    assertThat(createFileAttributes(newBuilder().setType(FILE).build()).getLanguageKey()).isNull();
+  }
+
+  @Test
+  public void createFileAttributes_sets_language_to_null_when_empty_in_Scanner_Component() {
+    assertThat(createFileAttributes(newBuilder().setType(FILE).setLanguage("").build()).getLanguageKey()).isNull();
+  }
+
+  @Test
+  public void createFileAttributes_sets_unitTest_from_Scanner_Component() {
+    assertThat(createFileAttributes(newBuilder().setType(FILE).build()).isUnitTest()).isFalse();
+    assertThat(createFileAttributes(newBuilder().setType(FILE).setIsTest(true).build()).isUnitTest()).isTrue();
+  }
+
+  private static class ScannerComponentProvider extends ExternalResource implements Function<Integer, ScannerReport.Component> {
+    private final Map<Integer, ScannerReport.Component> components = new HashMap<>();
+
+    @Override
+    protected void before() throws Throwable {
+      components.clear();
+    }
+
+    @Override
+    public ScannerReport.Component apply(Integer componentRef) {
+      return checkNotNull(components.get(componentRef), "No Component for componentRef %s", componentRef);
+    }
+
+    public ScannerReport.Component add(ScannerReport.Component.Builder builder) {
+      ScannerReport.Component component = builder.build();
+      ScannerReport.Component existing = components.put(component.getRef(), component);
+      checkArgument(existing == null, "Component %s already set for ref %s", existing, component.getRef());
+      return component;
+    }
+  }
+
+  private static Map<Integer, Component> indexComponentByRef(Component root) {
+    Map<Integer, Component> componentsByRef = new HashMap<>();
+    new DepthTraversalTypeAwareCrawler(
+        new TypeAwareVisitorAdapter(CrawlerDepthLimit.FILE, PRE_ORDER) {
+          @Override
+          public void visitAny(Component any) {
+            componentsByRef.put(any.getReportAttributes().getRef(), any);
+          }
+        }).visit(root);
+    return componentsByRef;
+  }
+}
index 4f67ac3b60c42bb8924d76a58715e6ca67393363..9f681bc0a10faa80517970c3006f2397000f562d 100644 (file)
@@ -254,7 +254,7 @@ public class BuildComponentTreeStepTest {
     ComponentDto project = insertComponent(newProjectDto("ABCD").setKey(REPORT_PROJECT_KEY));
     ComponentDto removedModule = insertComponent(newModuleDto("BCDE", project).setKey(REPORT_MODULE_KEY).setEnabled(false));
     ComponentDto removedDirectory = insertComponent(newDirectory(removedModule, "CDEF", REPORT_DIR_KEY_1).setKey(REPORT_MODULE_KEY + ":" + REPORT_DIR_KEY_1).setEnabled(false));
-    insertComponent(newFileDto(removedModule, removedModule, "DEFG").setKey(REPORT_MODULE_KEY + ":" + REPORT_FILE_KEY_1).setEnabled(false));
+    insertComponent(newFileDto(removedModule, removedDirectory, "DEFG").setKey(REPORT_MODULE_KEY + ":" + REPORT_FILE_KEY_1).setEnabled(false));
 
     reportReader.putComponent(componentWithKey(ROOT_REF, PROJECT, REPORT_PROJECT_KEY, MODULE_REF));
     reportReader.putComponent(componentWithKey(MODULE_REF, MODULE, REPORT_MODULE_KEY, DIR_REF_1));