3 * Copyright (C) 2009-2024 SonarSource SA
4 * mailto:info AT sonarsource DOT com
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 3 of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 package org.sonar.ce.task.projectanalysis.component;
22 import java.util.Arrays;
23 import java.util.EnumSet;
24 import java.util.HashMap;
25 import java.util.List;
27 import java.util.Objects;
28 import java.util.Optional;
29 import java.util.Random;
30 import java.util.function.Function;
31 import java.util.function.UnaryOperator;
32 import org.junit.Rule;
33 import org.junit.Test;
34 import org.junit.rules.ExternalResource;
35 import org.sonar.ce.task.projectanalysis.analysis.Branch;
36 import org.sonar.core.component.ComponentKeys;
37 import org.sonar.scanner.protocol.output.ScannerReport;
38 import org.sonar.server.project.Project;
40 import static com.google.common.base.Preconditions.checkArgument;
41 import static org.apache.commons.lang.RandomStringUtils.randomAlphabetic;
42 import static org.assertj.core.api.Assertions.assertThat;
43 import static org.assertj.core.api.Assertions.assertThatThrownBy;
44 import static org.junit.Assert.fail;
45 import static org.mockito.Mockito.mock;
46 import static org.mockito.Mockito.when;
47 import static org.sonar.ce.task.projectanalysis.component.ComponentVisitor.Order.PRE_ORDER;
48 import static org.sonar.db.component.ComponentTesting.newPrivateProjectDto;
49 import static org.sonar.scanner.protocol.output.ScannerReport.Component.ComponentType.FILE;
50 import static org.sonar.scanner.protocol.output.ScannerReport.Component.ComponentType.PROJECT;
51 import static org.sonar.scanner.protocol.output.ScannerReport.Component.ComponentType.UNRECOGNIZED;
52 import static org.sonar.scanner.protocol.output.ScannerReport.Component.newBuilder;
54 public class ComponentTreeBuilderTest {
56 private static final ComponentKeyGenerator KEY_GENERATOR = (projectKey, path) -> "generated_" + ComponentKeys.createEffectiveKey(projectKey, path);
57 private static final UnaryOperator<String> UUID_SUPPLIER = (componentKey) -> componentKey + "_uuid";
58 private static final EnumSet<ScannerReport.Component.ComponentType> REPORT_TYPES = EnumSet.of(PROJECT, FILE);
59 private static final String NO_SCM_BASE_PATH = "";
60 // both no project as "" or null should be supported
61 private static final ProjectAttributes SOME_PROJECT_ATTRIBUTES = new ProjectAttributes(
62 randomAlphabetic(20), new Random().nextBoolean() ? null : randomAlphabetic(12), "1def5123");
65 public ScannerComponentProvider scannerComponentProvider = new ScannerComponentProvider();
67 private Project projectInDb = Project.from(newPrivateProjectDto(UUID_SUPPLIER.apply("K1")).setKey("K1").setDescription(null));
70 public void build_throws_IAE_for_all_types_except_PROJECT_and_FILE() {
71 Arrays.stream(ScannerReport.Component.ComponentType.values())
72 .filter((type) -> type != UNRECOGNIZED)
73 .filter((type) -> !REPORT_TYPES.contains(type))
76 scannerComponentProvider.clear();
77 ScannerReport.Component project = newBuilder()
79 .setKey(projectInDb.getKey())
82 .setProjectRelativePath("root")
84 scannerComponentProvider.add(newBuilder()
87 .setProjectRelativePath("src")
90 call(project, NO_SCM_BASE_PATH, SOME_PROJECT_ATTRIBUTES);
91 fail("Should have thrown a IllegalArgumentException");
92 } catch (IllegalArgumentException e) {
93 assertThat(e).hasMessage("Unsupported component type '" + type + "'");
99 public void build_throws_IAE_if_root_is_not_PROJECT() {
100 Arrays.stream(ScannerReport.Component.ComponentType.values())
101 .filter((type) -> type != UNRECOGNIZED)
102 .filter((type) -> !REPORT_TYPES.contains(type))
105 ScannerReport.Component component = newBuilder().setType(type).build();
108 fail("Should have thrown a IllegalArgumentException");
109 } catch (IllegalArgumentException e) {
110 assertThat(e).hasMessage("Expected root component of type 'PROJECT'");
116 public void by_default_project_fields_are_loaded_from_report() {
117 String nameInReport = "the name";
118 String descriptionInReport = "the desc";
119 String buildString = randomAlphabetic(21);
120 Component root = call(newBuilder()
122 .setKey(projectInDb.getKey())
124 .setName(nameInReport)
125 .setDescription(descriptionInReport)
126 .build(), NO_SCM_BASE_PATH, new ProjectAttributes("6.5", buildString, "4124af4"));
128 assertThat(root.getUuid()).isEqualTo("generated_K1_uuid");
129 assertThat(root.getKey()).isEqualTo("generated_K1");
130 assertThat(root.getType()).isEqualTo(Component.Type.PROJECT);
131 assertThat(root.getName()).isEqualTo(nameInReport);
132 assertThat(root.getShortName()).isEqualTo(nameInReport);
133 assertThat(root.getDescription()).isEqualTo(descriptionInReport);
134 assertThat(root.getReportAttributes().getRef()).isEqualTo(42);
135 assertThat(root.getProjectAttributes().getProjectVersion()).contains("6.5");
136 assertThat(root.getProjectAttributes().getBuildString()).isEqualTo(Optional.of(buildString));
137 assertThatFileAttributesAreNotSet(root);
141 public void project_name_is_loaded_from_db_if_absent_from_report() {
142 Component root = call(newBuilder()
144 .build(), NO_SCM_BASE_PATH, SOME_PROJECT_ATTRIBUTES);
146 assertThat(root.getName()).isEqualTo(projectInDb.getName());
150 public void project_name_is_loaded_from_report_if_present_and_on_main_branch() {
151 String reportName = randomAlphabetic(5);
152 ScannerReport.Component reportProject = newBuilder()
157 Component root = newUnderTest(SOME_PROJECT_ATTRIBUTES, true).buildProject(reportProject, NO_SCM_BASE_PATH);
159 assertThat(root.getName()).isEqualTo(reportName);
163 public void project_name_is_loaded_from_db_if_not_on_main_branch() {
164 String reportName = randomAlphabetic(5);
165 ScannerReport.Component reportProject = newBuilder()
170 Component root = newUnderTest(SOME_PROJECT_ATTRIBUTES, false)
171 .buildProject(reportProject, NO_SCM_BASE_PATH);
173 assertThat(root.getName()).isEqualTo(projectInDb.getName());
177 public void project_description_is_loaded_from_db_if_absent_from_report() {
178 Component root = call(newBuilder()
180 .build(), NO_SCM_BASE_PATH, SOME_PROJECT_ATTRIBUTES);
182 assertThat(root.getDescription()).isEqualTo(projectInDb.getDescription());
186 public void project_description_is_loaded_from_report_if_present_and_on_main_branch() {
187 String reportDescription = randomAlphabetic(5);
188 ScannerReport.Component reportProject = newBuilder()
190 .setDescription(reportDescription)
193 Component root = newUnderTest(SOME_PROJECT_ATTRIBUTES, true).buildProject(reportProject, NO_SCM_BASE_PATH);
195 assertThat(root.getDescription()).isEqualTo(reportDescription);
199 public void project_description_is_loaded_from_db_if_not_on_main_branch() {
200 String reportDescription = randomAlphabetic(5);
201 ScannerReport.Component reportProject = newBuilder()
203 .setDescription(reportDescription)
206 Component root = newUnderTest(SOME_PROJECT_ATTRIBUTES, false).buildProject(reportProject, NO_SCM_BASE_PATH);
208 assertThat(root.getDescription()).isEqualTo(projectInDb.getDescription());
212 public void project_scmPath_is_empty_if_scmBasePath_is_empty() {
213 Component root = call(newBuilder()
215 .build(), NO_SCM_BASE_PATH, SOME_PROJECT_ATTRIBUTES);
217 assertThat(root.getReportAttributes().getScmPath()).isEmpty();
221 public void projectAttributes_is_constructor_argument() {
222 Component root = call(newBuilder()
224 .build(), NO_SCM_BASE_PATH, SOME_PROJECT_ATTRIBUTES);
226 assertThat(root.getProjectAttributes()).isSameAs(SOME_PROJECT_ATTRIBUTES);
230 public void any_component_with_projectRelativePath_has_this_value_as_scmPath_if_scmBasePath_is_empty() {
231 ScannerReport.Component project = newBuilder()
233 .setKey(projectInDb.getKey())
236 .setProjectRelativePath("root")
238 scannerComponentProvider.add(newBuilder()
241 .setProjectRelativePath("src/js/Foo.js")
244 Component root = call(project, NO_SCM_BASE_PATH, SOME_PROJECT_ATTRIBUTES);
246 assertThat(root.getReportAttributes().getScmPath())
248 Component directory = root.getChildren().iterator().next();
249 assertThat(directory.getReportAttributes().getScmPath())
251 Component file = directory.getChildren().iterator().next();
252 assertThat(file.getReportAttributes().getScmPath())
253 .contains("src/js/Foo.js");
257 public void any_component_with_projectRelativePath_has_this_value_appended_to_scmBasePath_and_a_slash_as_scmPath_if_scmBasePath_is_not_empty() {
258 ScannerReport.Component project = createProject();
259 String scmBasePath = randomAlphabetic(10);
261 Component root = call(project, scmBasePath, SOME_PROJECT_ATTRIBUTES);
262 assertThat(root.getReportAttributes().getScmPath())
263 .contains(scmBasePath);
264 Component directory = root.getChildren().iterator().next();
265 assertThat(directory.getReportAttributes().getScmPath())
266 .contains(scmBasePath + "/src/js");
267 Component file = directory.getChildren().iterator().next();
268 assertThat(file.getReportAttributes().getScmPath())
269 .contains(scmBasePath + "/src/js/Foo.js");
272 private ScannerReport.Component createProject() {
273 ScannerReport.Component project = newBuilder()
275 .setKey(projectInDb.getKey())
279 scannerComponentProvider.add(newBuilder()
282 .setProjectRelativePath("src/js/Foo.js")
288 public void keys_of_directory_and_file_are_generated() {
289 ScannerReport.Component project = createProject();
291 Component root = call(project);
292 assertThat(root.getKey()).isEqualTo("generated_" + projectInDb.getKey());
293 assertThat(root.getChildren()).hasSize(1);
295 Component directory = root.getChildren().iterator().next();
296 assertThat(directory.getKey()).isEqualTo("generated_" + projectInDb.getKey() + ":src/js");
297 assertThat(directory.getChildren()).hasSize(1);
299 Component file = directory.getChildren().iterator().next();
300 assertThat(file.getKey()).isEqualTo("generated_" + projectInDb.getKey() + ":src/js/Foo.js");
301 assertThat(file.getChildren()).isEmpty();
305 public void modules_are_not_created() {
306 ScannerReport.Component project = newBuilder()
308 .setKey(projectInDb.getKey())
312 scannerComponentProvider.add(newBuilder()
315 .setProjectRelativePath("src/js/Foo.js")
318 Component root = call(project);
320 List<Component> components = root.getChildren();
321 assertThat(components).extracting("type").containsOnly(Component.Type.DIRECTORY);
325 public void folder_hierarchy_is_created() {
326 ScannerReport.Component project = newBuilder()
328 .setKey(projectInDb.getKey())
334 scannerComponentProvider.add(newBuilder()
337 .setProjectRelativePath("src/main/xoo/Foo1.js")
339 scannerComponentProvider.add(newBuilder()
342 .setProjectRelativePath("src/test/xoo/org/sonar/Foo2.js")
344 scannerComponentProvider.add(newBuilder()
347 .setProjectRelativePath("pom.xml")
350 Component root = call(project);
351 assertThat(root.getChildren()).hasSize(2);
353 Component pom = root.getChildren().get(1);
354 assertThat(pom.getKey()).isEqualTo("generated_K1:pom.xml");
355 assertThat(pom.getName()).isEqualTo("pom.xml");
357 Component directory = root.getChildren().get(0);
358 assertThat(directory.getKey()).isEqualTo("generated_K1:src");
359 assertThat(directory.getName()).isEqualTo("src");
361 // folders are collapsed and they only contain one directory
362 Component d1 = directory.getChildren().get(0);
363 assertThat(d1.getKey()).isEqualTo("generated_K1:src/main/xoo");
364 assertThat(d1.getName()).isEqualTo("src/main/xoo");
365 assertThat(d1.getShortName()).isEqualTo("main/xoo");
367 Component d2 = directory.getChildren().get(1);
368 assertThat(d2.getKey()).isEqualTo("generated_K1:src/test/xoo/org/sonar");
369 assertThat(d2.getName()).isEqualTo("src/test/xoo/org/sonar");
370 assertThat(d2.getShortName()).isEqualTo("test/xoo/org/sonar");
374 public void collapse_directories_from_root() {
375 ScannerReport.Component project = newBuilder()
377 .setKey(projectInDb.getKey())
381 scannerComponentProvider.add(newBuilder()
384 .setProjectRelativePath("src/test/xoo/org/sonar/Foo2.js")
387 Component root = call(project);
389 // folders are collapsed and they only contain one directory
390 Component dir = root.getChildren().get(0);
391 assertThat(dir.getKey()).isEqualTo("generated_K1:src/test/xoo/org/sonar");
392 assertThat(dir.getName()).isEqualTo("src/test/xoo/org/sonar");
393 assertThat(dir.getShortName()).isEqualTo("src/test/xoo/org/sonar");
395 Component file = dir.getChildren().get(0);
396 assertThat(file.getKey()).isEqualTo("generated_K1:src/test/xoo/org/sonar/Foo2.js");
397 assertThat(file.getName()).isEqualTo("src/test/xoo/org/sonar/Foo2.js");
398 assertThat(file.getShortName()).isEqualTo("Foo2.js");
402 public void directories_are_collapsed() {
403 ScannerReport.Component project = newBuilder()
405 .setKey(projectInDb.getKey())
409 scannerComponentProvider.add(newBuilder()
412 .setProjectRelativePath("src/js/Foo.js")
415 Component root = call(project);
417 Component directory = root.getChildren().iterator().next();
418 assertThat(directory.getKey()).isEqualTo("generated_K1:src/js");
419 assertThat(directory.getName()).isEqualTo("src/js");
420 assertThat(directory.getShortName()).isEqualTo("src/js");
422 Component file = directory.getChildren().iterator().next();
423 assertThat(file.getKey()).isEqualTo("generated_K1:src/js/Foo.js");
424 assertThat(file.getName()).isEqualTo("src/js/Foo.js");
425 assertThat(file.getShortName()).isEqualTo("Foo.js");
429 public void names_of_directory_and_file_are_based_on_the_path() {
430 ScannerReport.Component project = newBuilder()
432 .setKey(projectInDb.getKey())
436 scannerComponentProvider.add(newBuilder()
439 .setProjectRelativePath("src/js/Foo.js")
443 Component root = call(project);
445 Component directory = root.getChildren().iterator().next();
446 assertThat(directory.getName()).isEqualTo("src/js");
447 assertThat(directory.getShortName()).isEqualTo("src/js");
449 Component file = directory.getChildren().iterator().next();
450 assertThat(file.getName()).isEqualTo("src/js/Foo.js");
451 assertThat(file.getShortName()).isEqualTo("Foo.js");
455 public void create_full_hierarchy_of_directories() {
456 ScannerReport.Component project = newBuilder()
458 .setKey(projectInDb.getKey())
463 scannerComponentProvider.add(newBuilder()
466 .setProjectRelativePath("src/java/Bar.java")
469 scannerComponentProvider.add(newBuilder()
472 .setProjectRelativePath("src/js/Foo.js")
476 Component root = call(project);
478 Component directory = root.getChildren().iterator().next();
479 assertThat(directory.getKey()).isEqualTo("generated_K1:src");
480 assertThat(directory.getName()).isEqualTo("src");
481 assertThat(directory.getShortName()).isEqualTo("src");
483 Component directoryJava = directory.getChildren().get(0);
484 assertThat(directoryJava.getKey()).isEqualTo("generated_K1:src/java");
485 assertThat(directoryJava.getName()).isEqualTo("src/java");
486 assertThat(directoryJava.getShortName()).isEqualTo("java");
488 Component directoryJs = directory.getChildren().get(1);
489 assertThat(directoryJs.getKey()).isEqualTo("generated_K1:src/js");
490 assertThat(directoryJs.getName()).isEqualTo("src/js");
491 assertThat(directoryJs.getShortName()).isEqualTo("js");
493 Component file = directoryJs.getChildren().iterator().next();
494 assertThat(file.getKey()).isEqualTo("generated_K1:src/js/Foo.js");
495 assertThat(file.getName()).isEqualTo("src/js/Foo.js");
496 assertThat(file.getShortName()).isEqualTo("Foo.js");
499 private void assertThatFileAttributesAreNotSet(Component root) {
501 root.getFileAttributes();
503 } catch (IllegalStateException e) {
504 assertThat(e).hasMessage("Only component of type FILE have a FileAttributes object");
509 public void keys_of_directory_and_files_includes_always_root_project() {
510 ScannerReport.Component project = newBuilder()
514 .addChildRef(31).build();
515 scannerComponentProvider.add(newBuilder().setRef(31).setType(FILE).setProjectRelativePath("file in project").setLines(1));
516 Component root = call(project);
517 Map<String, Component> componentsByKey = indexComponentByKey(root);
519 assertThat(componentsByKey.values()).extracting("key").startsWith("generated_project 1");
523 public void uuids_are_provided_by_supplier() {
524 ScannerReport.Component project = newBuilder()
530 scannerComponentProvider.add(newBuilder()
533 .setProjectRelativePath("src/js/Foo.js")
536 Component root = call(project);
537 assertThat(root.getUuid()).isEqualTo("generated_c1_uuid");
539 Component directory = root.getChildren().iterator().next();
540 assertThat(directory.getUuid()).isEqualTo("generated_c1:src/js_uuid");
542 Component file = directory.getChildren().iterator().next();
543 assertThat(file.getUuid()).isEqualTo("generated_c1:src/js/Foo.js_uuid");
547 public void files_have_markedAsUnchanged_flag() {
548 ScannerReport.Component project = newBuilder()
554 scannerComponentProvider.add(newBuilder()
557 .setMarkedAsUnchanged(true)
558 .setProjectRelativePath("src/js/Foo.js")
561 Component root = call(project);
562 assertThat(root.getUuid()).isEqualTo("generated_c1_uuid");
564 Component directory = root.getChildren().iterator().next();
565 assertThat(directory.getUuid()).isEqualTo("generated_c1:src/js_uuid");
567 Component file = directory.getChildren().iterator().next();
568 assertThat(file.getFileAttributes().isMarkedAsUnchanged()).isTrue();
572 public void issues_are_relocated_from_directories_and_modules_to_root() {
573 ScannerReport.Component project = newBuilder()
579 ScannerReport.Component.Builder file = newBuilder()
582 .setProjectRelativePath("src/js/Foo.js")
584 scannerComponentProvider.add(file);
590 public void descriptions_of_module_directory_and_file_are_null_if_absent_from_report() {
591 ScannerReport.Component project = newBuilder()
596 scannerComponentProvider.add(newBuilder()
599 .setProjectRelativePath("src/js/Foo.js")
602 Component root = call(project);
604 Component directory = root.getChildren().iterator().next();
605 assertThat(directory.getDescription()).isNull();
607 Component file = directory.getChildren().iterator().next();
608 assertThat(file.getDescription()).isNull();
612 public void descriptions_of_module_directory_and_file_are_null_if_empty_in_report() {
613 ScannerReport.Component project = newBuilder()
619 scannerComponentProvider.add(newBuilder()
623 .setProjectRelativePath("src/js/Foo.js")
626 Component root = call(project);
628 Component directory = root.getChildren().iterator().next();
629 assertThat(directory.getDescription()).isNull();
631 Component file = directory.getChildren().iterator().next();
632 assertThat(file.getDescription()).isNull();
636 public void descriptions_of_module_directory_and_file_are_set_from_report_if_present() {
637 ScannerReport.Component project = newBuilder()
642 scannerComponentProvider.add(newBuilder()
646 .setProjectRelativePath("src/js/Foo.js")
649 Component root = call(project);
650 Component directory = root.getChildren().iterator().next();
651 assertThat(directory.getDescription()).isNull();
653 Component file = directory.getChildren().iterator().next();
654 assertThat(file.getDescription()).isEqualTo("d");
658 public void only_nb_of_lines_is_mandatory_on_file_attributes() {
659 ScannerReport.Component project = newBuilder()
664 scannerComponentProvider.add(newBuilder()
667 .setProjectRelativePath("src/js/Foo.js")
670 Component root = call(project);
671 Component dir = root.getChildren().iterator().next();
672 Component file = dir.getChildren().iterator().next();
673 assertThat(file.getFileAttributes().getLines()).isOne();
674 assertThat(file.getFileAttributes().getLanguageKey()).isNull();
675 assertThat(file.getFileAttributes().isUnitTest()).isFalse();
679 public void language_file_attributes_is_null_if_empty_in_report() {
680 ScannerReport.Component project = newBuilder()
685 scannerComponentProvider.add(newBuilder()
688 .setProjectRelativePath("src/js/Foo.js")
692 Component root = call(project);
693 Component dir2 = root.getChildren().iterator().next();
695 Component file = dir2.getChildren().iterator().next();
696 assertThat(file.getFileAttributes().getLanguageKey()).isNull();
700 public void file_attributes_are_fully_loaded_from_report() {
701 ScannerReport.Component project = newBuilder()
706 scannerComponentProvider.add(newBuilder()
709 .setProjectRelativePath("src/js/Foo.js")
714 Component root = call(project);
715 Component dir = root.getChildren().iterator().next();
716 Component file = dir.getChildren().iterator().next();
717 assertThat(file.getFileAttributes().getLines()).isOne();
718 assertThat(file.getFileAttributes().getLanguageKey()).isEqualTo("js");
719 assertThat(file.getFileAttributes().isUnitTest()).isTrue();
723 public void throw_IAE_if_lines_is_absent_from_report() {
724 ScannerReport.Component project = newBuilder()
729 scannerComponentProvider.add(newBuilder()
732 .setProjectRelativePath("src/js/Foo.js"));
734 assertThatThrownBy(() -> call(project))
735 .isInstanceOf(IllegalArgumentException.class)
736 .hasMessage("File 'src/js/Foo.js' has no line");
740 public void throw_IAE_if_lines_is_zero_in_report() {
741 ScannerReport.Component project = newBuilder()
746 scannerComponentProvider.add(newBuilder()
749 .setProjectRelativePath("src/js/Foo.js")
752 assertThatThrownBy(() -> call(project))
753 .isInstanceOf(IllegalArgumentException.class)
754 .hasMessage("File 'src/js/Foo.js' has no line");
758 public void throw_IAE_if_lines_is_negative_in_report() {
759 ScannerReport.Component project = newBuilder()
764 scannerComponentProvider.add(newBuilder()
767 .setProjectRelativePath("src/js/Foo.js")
770 assertThatThrownBy(() -> call(project))
771 .isInstanceOf(IllegalArgumentException.class)
772 .hasMessage("File 'src/js/Foo.js' has no line");
775 private static class ScannerComponentProvider extends ExternalResource implements Function<Integer, ScannerReport.Component> {
776 private final Map<Integer, ScannerReport.Component> components = new HashMap<>();
779 protected void before() {
783 public void clear() {
788 public ScannerReport.Component apply(Integer componentRef) {
789 return Objects.requireNonNull(components.get(componentRef), "No Component for componentRef " + componentRef);
792 public ScannerReport.Component add(ScannerReport.Component.Builder builder) {
793 ScannerReport.Component component = builder.build();
794 ScannerReport.Component existing = components.put(component.getRef(), component);
795 checkArgument(existing == null, "Component %s already set for ref %s", existing, component.getRef());
800 private Component call(ScannerReport.Component project) {
801 return call(project, NO_SCM_BASE_PATH, SOME_PROJECT_ATTRIBUTES);
804 private Component call(ScannerReport.Component project, String scmBasePath, ProjectAttributes projectAttributes) {
805 return newUnderTest(projectAttributes, true).buildProject(project, scmBasePath);
808 private ComponentTreeBuilder newUnderTest(ProjectAttributes projectAttributes, boolean mainBranch) {
809 Branch branch = mock(Branch.class);
810 when(branch.isMain()).thenReturn(mainBranch);
811 return new ComponentTreeBuilder(KEY_GENERATOR, UUID_SUPPLIER, scannerComponentProvider, projectInDb, branch, projectAttributes);
814 private static Map<String, Component> indexComponentByKey(Component root) {
815 Map<String, Component> componentsByKey = new HashMap<>();
816 new DepthTraversalTypeAwareCrawler(
817 new TypeAwareVisitorAdapter(CrawlerDepthLimit.FILE, PRE_ORDER) {
819 public void visitAny(Component any) {
820 componentsByKey.put(any.getKey(), any);
823 return componentsByKey;