]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-6589 Support both pre-order and post-order in typeAwareVisitor
authorJulien Lancelot <julien.lancelot@sonarsource.com>
Wed, 27 May 2015 07:44:56 +0000 (09:44 +0200)
committerJulien Lancelot <julien.lancelot@sonarsource.com>
Wed, 27 May 2015 09:49:38 +0000 (11:49 +0200)
server/sonar-server/src/main/java/org/sonar/server/computation/component/ChildFirstTypeAwareVisitor.java [deleted file]
server/sonar-server/src/main/java/org/sonar/server/computation/component/DepthTraversalTypeAwareVisitor.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/computation/step/QualityProfileEventsStep.java
server/sonar-server/src/test/java/org/sonar/server/computation/component/ChildFirstTypeAwareVisitorTest.java [deleted file]
server/sonar-server/src/test/java/org/sonar/server/computation/component/PostOrderDepthTraversalTypeAwareVisitorTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/computation/component/PreOrderDepthTraversalTypeAwareVisitorTest.java [new file with mode: 0644]

diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/component/ChildFirstTypeAwareVisitor.java b/server/sonar-server/src/main/java/org/sonar/server/computation/component/ChildFirstTypeAwareVisitor.java
deleted file mode 100644 (file)
index 70e0d37..0000000
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2014 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * SonarQube is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-package org.sonar.server.computation.component;
-
-import java.util.Objects;
-
-/**
- * Implementation of {@link TypeAwareVisitor} that implements a depth first crawling of the
- * {@link ComponentImpl} tree. It supports a max depth for crawling (component strictly deeper than the specified
- * type will be ignored).
- */
-public abstract class ChildFirstTypeAwareVisitor implements TypeAwareVisitor {
-  private final Component.Type maxDepth;
-
-  protected ChildFirstTypeAwareVisitor(Component.Type maxDepth) {
-    this.maxDepth = Objects.requireNonNull(maxDepth);
-  }
-
-  @Override
-  public void visit(Component component) {
-    if (component.getType().isDeeperThan(maxDepth)) {
-      return;
-    }
-
-    if (component.getType() != maxDepth) {
-      for (Component child : component.getChildren()) {
-        visit(child);
-      }
-    }
-
-    switch (component.getType()) {
-      case PROJECT:
-        visitProject(component);
-        break;
-      case MODULE:
-        visitModule(component);
-        break;
-      case DIRECTORY:
-        visitDirectory(component);
-        break;
-      case FILE:
-        visitFile(component);
-        break;
-      default:
-        visitUnknown(component);
-    }
-  }
-
-  @Override
-  public void visitProject(Component tree) {
-    // empty implementation, meant to be override at will by subclasses
-  }
-
-  @Override
-  public void visitModule(Component tree) {
-    // empty implementation, meant to be override at will by subclasses
-  }
-
-  @Override
-  public void visitDirectory(Component tree) {
-    // empty implementation, meant to be override at will by subclasses
-  }
-
-  @Override
-  public void visitFile(Component tree) {
-    // empty implementation, meant to be override at will by subclasses
-  }
-
-  @Override
-  public void visitUnknown(Component tree) {
-    // empty implementation, meant to be override at will by subclasses
-  }
-
-}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/component/DepthTraversalTypeAwareVisitor.java b/server/sonar-server/src/main/java/org/sonar/server/computation/component/DepthTraversalTypeAwareVisitor.java
new file mode 100644 (file)
index 0000000..c368b15
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package org.sonar.server.computation.component;
+
+import static java.util.Objects.requireNonNull;
+
+/**
+ * Implementation of {@link TypeAwareVisitor} that implements a depth traversal of a {@link Component} tree.
+ * <p>It supports visiting traversal in either pre-order or post-order</p>
+ * It supports a max depth for crawling (component strictly deeper than the specified type will be ignored).
+ */
+public abstract class DepthTraversalTypeAwareVisitor implements TypeAwareVisitor {
+  private final Component.Type maxDepth;
+  private final Order order;
+
+  protected DepthTraversalTypeAwareVisitor(Component.Type maxDepth, Order order) {
+    this.maxDepth = requireNonNull(maxDepth);
+    this.order = requireNonNull(order);
+  }
+
+  @Override
+  public void visit(Component component) {
+    if (component.getType().isDeeperThan(maxDepth)) {
+      return;
+    }
+
+    if (order == Order.PRE_ORDER) {
+      visitNode(component);
+    }
+
+    visitChildren(component);
+
+    if (order == Order.POST_ORDER) {
+      visitNode(component);
+    }
+  }
+
+  private void visitNode(Component component) {
+    switch (component.getType()) {
+      case PROJECT:
+        visitProject(component);
+        break;
+      case MODULE:
+        visitModule(component);
+        break;
+      case DIRECTORY:
+        visitDirectory(component);
+        break;
+      case FILE:
+        visitFile(component);
+        break;
+      default:
+        visitUnknown(component);
+    }
+  }
+
+  private void visitChildren(Component component) {
+    if (component.getType() != maxDepth) {
+      for (Component child : component.getChildren()) {
+        visit(child);
+      }
+    }
+  }
+
+  @Override
+  public void visitProject(Component project) {
+    // empty implementation, meant to be override at will by subclasses
+  }
+
+  @Override
+  public void visitModule(Component module) {
+    // empty implementation, meant to be override at will by subclasses
+  }
+
+  @Override
+  public void visitDirectory(Component directory) {
+    // empty implementation, meant to be override at will by subclasses
+  }
+
+  @Override
+  public void visitFile(Component file) {
+    // empty implementation, meant to be override at will by subclasses
+  }
+
+  @Override
+  public void visitUnknown(Component unknownComponent) {
+    // empty implementation, meant to be override at will by subclasses
+  }
+
+  public enum Order {
+    PRE_ORDER, POST_ORDER
+  }
+}
index 4bb1e5f019ed76afde3a12e17d05cdd11fa53c84..3846599a0f27643380a28111eae5010d7b1645ab 100644 (file)
@@ -21,9 +21,6 @@ package org.sonar.server.computation.step;
 
 import com.google.common.base.Optional;
 import com.google.common.collect.ImmutableSortedMap;
-import java.util.Date;
-import java.util.Map;
-import javax.annotation.Nullable;
 import org.apache.commons.lang.time.DateUtils;
 import org.sonar.api.measures.CoreMetrics;
 import org.sonar.api.resources.Language;
@@ -32,17 +29,24 @@ import org.sonar.batch.protocol.output.BatchReport;
 import org.sonar.core.UtcDateUtils;
 import org.sonar.core.measure.db.MeasureDto;
 import org.sonar.server.computation.ComputationContext;
-import org.sonar.server.computation.component.ChildFirstTypeAwareVisitor;
 import org.sonar.server.computation.component.Component;
+import org.sonar.server.computation.component.DepthTraversalTypeAwareVisitor;
 import org.sonar.server.computation.event.Event;
-import org.sonar.server.computation.qualityprofile.QualityProfile;
 import org.sonar.server.computation.qualityprofile.QPMeasureData;
+import org.sonar.server.computation.qualityprofile.QualityProfile;
+
+import javax.annotation.Nullable;
+
+import java.util.Date;
+import java.util.Map;
+
+import static org.sonar.server.computation.component.DepthTraversalTypeAwareVisitor.Order.POST_ORDER;
 
 public class QualityProfileEventsStep implements ComputationStep {
 
   @Override
   public void execute(ComputationContext context) {
-    new ChildFirstTypeAwareVisitor(Component.Type.PROJECT) {
+    new DepthTraversalTypeAwareVisitor(Component.Type.PROJECT, POST_ORDER) {
       @Override
       public void visitProject(Component tree) {
         executeForProject(tree);
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/component/ChildFirstTypeAwareVisitorTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/component/ChildFirstTypeAwareVisitorTest.java
deleted file mode 100644 (file)
index 6f76339..0000000
+++ /dev/null
@@ -1,265 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2014 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * SonarQube is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-package org.sonar.server.computation.component;
-
-import org.junit.Test;
-import org.mockito.InOrder;
-
-import static org.mockito.Mockito.inOrder;
-import static org.mockito.Mockito.spy;
-import static org.sonar.server.computation.component.Component.Type.DIRECTORY;
-import static org.sonar.server.computation.component.Component.Type.FILE;
-import static org.sonar.server.computation.component.Component.Type.MODULE;
-import static org.sonar.server.computation.component.Component.Type.PROJECT;
-
-public class ChildFirstTypeAwareVisitorTest {
-
-  private static final Component FILE_4 = component(FILE, 4);
-  private static final Component FILE_5 = component(FILE, 5);
-  private static final Component DIRECTORY_3 = component(DIRECTORY, 3, FILE_4, FILE_5);
-  private static final Component MODULE_2 = component(MODULE, 2, DIRECTORY_3);
-  private static final Component COMPONENT_TREE = component(PROJECT, 1, MODULE_2);
-
-  private final ChildFirstTypeAwareVisitor spyProjectVisitor = spy(new ChildFirstTypeAwareVisitor(PROJECT) {});
-  private final ChildFirstTypeAwareVisitor spyModuleVisitor = spy(new ChildFirstTypeAwareVisitor(MODULE) {});
-  private final ChildFirstTypeAwareVisitor spyDirectoryVisitor = spy(new ChildFirstTypeAwareVisitor(DIRECTORY) {});
-  private final ChildFirstTypeAwareVisitor spyFileVisitor = spy(new ChildFirstTypeAwareVisitor(FILE) {});
-  private final InOrder inOrder = inOrder(spyProjectVisitor, spyModuleVisitor, spyDirectoryVisitor, spyFileVisitor);
-
-  @Test(expected = NullPointerException.class)
-  public void non_null_max_depth_fast_fail() {
-    new ChildFirstTypeAwareVisitor(null) {
-    };
-  }
-
-  @Test(expected = NullPointerException.class)
-  public void visit_null_Component_throws_NPE() {
-    spyFileVisitor.visit(null);
-  }
-
-  @Test
-  public void visit_file_with_depth_FILE_calls_visit_file() {
-    Component component = component(FILE, 1);
-    spyFileVisitor.visit(component);
-
-    inOrder.verify(spyFileVisitor).visit(component);
-    inOrder.verify(spyFileVisitor).visitFile(component);
-    inOrder.verifyNoMoreInteractions();
-  }
-
-  @Test
-  public void visit_module_with_depth_FILE_calls_visit_module() {
-    Component component = component(MODULE, 1);
-    spyFileVisitor.visit(component);
-
-    inOrder.verify(spyFileVisitor).visit(component);
-    inOrder.verify(spyFileVisitor).visitModule(component);
-    inOrder.verifyNoMoreInteractions();
-  }
-
-  @Test
-  public void visit_directory_with_depth_FILE_calls_visit_directory() {
-    Component component = component(DIRECTORY, 1);
-    spyFileVisitor.visit(component);
-
-    inOrder.verify(spyFileVisitor).visit(component);
-    inOrder.verify(spyFileVisitor).visitDirectory(component);
-    inOrder.verifyNoMoreInteractions();
-  }
-
-  @Test
-  public void visit_project_with_depth_FILE_calls_visit_project() {
-    Component component = component(PROJECT, 1);
-    spyFileVisitor.visit(component);
-
-    inOrder.verify(spyFileVisitor).visit(component);
-    inOrder.verify(spyFileVisitor).visitProject(component);
-    inOrder.verifyNoMoreInteractions();
-  }
-
-  @Test
-  public void visit_file_with_depth_DIRECTORY_does_not_call_visit_file() {
-    Component component = component(FILE, 1);
-    spyDirectoryVisitor.visit(component);
-
-    inOrder.verify(spyDirectoryVisitor).visit(component);
-    inOrder.verifyNoMoreInteractions();
-  }
-
-  @Test
-  public void visit_directory_with_depth_DIRECTORY_calls_visit_directory() {
-    Component component = component(DIRECTORY, 1);
-    spyDirectoryVisitor.visit(component);
-
-    inOrder.verify(spyDirectoryVisitor).visit(component);
-    inOrder.verify(spyDirectoryVisitor).visitDirectory(component);
-    inOrder.verifyNoMoreInteractions();
-  }
-
-  @Test
-  public void visit_module_with_depth_DIRECTORY_calls_visit_module() {
-    Component component = component(MODULE, 1);
-    spyDirectoryVisitor.visit(component);
-
-    inOrder.verify(spyDirectoryVisitor).visit(component);
-    inOrder.verify(spyDirectoryVisitor).visitModule(component);
-    inOrder.verifyNoMoreInteractions();
-  }
-
-  @Test
-  public void visit_project_with_depth_DIRECTORY_calls_visit_project() {
-    Component component = component(PROJECT, 1);
-    spyDirectoryVisitor.visit(component);
-
-    inOrder.verify(spyDirectoryVisitor).visit(component);
-    inOrder.verify(spyDirectoryVisitor).visitProject(component);
-    inOrder.verifyNoMoreInteractions();
-  }
-
-  @Test
-  public void visit_file_with_depth_MODULE_does_not_call_visit_file() {
-    Component component = component(FILE, 1);
-    spyModuleVisitor.visit(component);
-
-    inOrder.verify(spyModuleVisitor).visit(component);
-    inOrder.verifyNoMoreInteractions();
-  }
-
-  @Test
-  public void visit_directory_with_depth_MODULE_does_not_call_visit_directory() {
-    Component component = component(DIRECTORY, 1);
-    spyModuleVisitor.visit(component);
-
-    inOrder.verify(spyModuleVisitor).visit(component);
-    inOrder.verifyNoMoreInteractions();
-  }
-
-  @Test
-  public void visit_module_with_depth_MODULE_calls_visit_module() {
-    Component component = component(MODULE, 1);
-    spyModuleVisitor.visit(component);
-
-    inOrder.verify(spyModuleVisitor).visit(component);
-    inOrder.verify(spyModuleVisitor).visitModule(component);
-    inOrder.verifyNoMoreInteractions();
-  }
-
-  @Test
-  public void visit_project_with_depth_MODULE_calls_visit_project() {
-    Component component = component(MODULE, 1);
-    spyModuleVisitor.visit(component);
-
-    inOrder.verify(spyModuleVisitor).visit(component);
-    inOrder.verify(spyModuleVisitor).visitModule(component);
-    inOrder.verifyNoMoreInteractions();
-  }
-
-  @Test
-  public void visit_file_with_depth_PROJECT_does_not_call_visit_file() {
-    Component component = component(FILE, 1);
-    spyProjectVisitor.visit(component);
-
-    inOrder.verify(spyProjectVisitor).visit(component);
-    inOrder.verifyNoMoreInteractions();
-  }
-
-  @Test
-  public void visit_directory_with_depth_PROJECT_does_not_call_visit_directory() {
-    Component component = component(DIRECTORY, 1);
-    spyProjectVisitor.visit(component);
-
-    inOrder.verify(spyProjectVisitor).visit(component);
-    inOrder.verifyNoMoreInteractions();
-  }
-
-  @Test
-  public void visit_module_with_depth_PROJECT_does_not_call_visit_module() {
-    Component component = component(MODULE, 1);
-    spyProjectVisitor.visit(component);
-
-    inOrder.verify(spyProjectVisitor).visit(component);
-    inOrder.verifyNoMoreInteractions();
-  }
-
-  @Test
-  public void visit_project_with_depth_PROJECT_calls_visit_project() {
-    Component component = component(PROJECT, 1);
-    spyProjectVisitor.visit(component);
-
-    inOrder.verify(spyProjectVisitor).visit(component);
-    inOrder.verify(spyProjectVisitor).visitProject(component);
-    inOrder.verifyNoMoreInteractions();
-  }
-
-  @Test
-  public void verify_visit_call_when_visit_tree_with_depth_FILE() {
-    spyFileVisitor.visit(COMPONENT_TREE);
-
-    inOrder.verify(spyFileVisitor).visit(COMPONENT_TREE);
-    inOrder.verify(spyFileVisitor).visit(MODULE_2);
-    inOrder.verify(spyFileVisitor).visit(DIRECTORY_3);
-    inOrder.verify(spyFileVisitor).visit(FILE_4);
-    inOrder.verify(spyFileVisitor).visitFile(FILE_4);
-    inOrder.verify(spyFileVisitor).visit(FILE_5);
-    inOrder.verify(spyFileVisitor).visitFile(FILE_5);
-    inOrder.verify(spyFileVisitor).visitDirectory(DIRECTORY_3);
-    inOrder.verify(spyFileVisitor).visitModule(MODULE_2);
-    inOrder.verify(spyFileVisitor).visitProject(COMPONENT_TREE);
-    inOrder.verifyNoMoreInteractions();
-  }
-
-  @Test
-  public void verify_visit_call_when_visit_tree_with_depth_DIRECTORY() {
-    spyDirectoryVisitor.visit(COMPONENT_TREE);
-
-    inOrder.verify(spyDirectoryVisitor).visit(COMPONENT_TREE);
-    inOrder.verify(spyDirectoryVisitor).visit(MODULE_2);
-    inOrder.verify(spyDirectoryVisitor).visit(DIRECTORY_3);
-    inOrder.verify(spyDirectoryVisitor).visitDirectory(DIRECTORY_3);
-    inOrder.verify(spyDirectoryVisitor).visitModule(MODULE_2);
-    inOrder.verify(spyDirectoryVisitor).visitProject(COMPONENT_TREE);
-    inOrder.verifyNoMoreInteractions();
-  }
-
-  @Test
-  public void verify_visit_call_when_visit_tree_with_depth_MODULE() {
-    spyModuleVisitor.visit(COMPONENT_TREE);
-
-    inOrder.verify(spyModuleVisitor).visit(COMPONENT_TREE);
-    inOrder.verify(spyModuleVisitor).visit(MODULE_2);
-    inOrder.verify(spyModuleVisitor).visitModule(MODULE_2);
-    inOrder.verify(spyModuleVisitor).visitProject(COMPONENT_TREE);
-    inOrder.verifyNoMoreInteractions();
-  }
-
-  @Test
-  public void verify_visit_call_when_visit_tree_with_depth_PROJECT() {
-    spyProjectVisitor.visit(COMPONENT_TREE);
-
-    inOrder.verify(spyProjectVisitor).visit(COMPONENT_TREE);
-    inOrder.verify(spyProjectVisitor).visitProject(COMPONENT_TREE);
-    inOrder.verifyNoMoreInteractions();
-  }
-
-  private static Component component(final Component.Type type, final int ref, final Component... children) {
-    return new DumbComponent(type, ref, children);
-  }
-
-}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/component/PostOrderDepthTraversalTypeAwareVisitorTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/component/PostOrderDepthTraversalTypeAwareVisitorTest.java
new file mode 100644 (file)
index 0000000..50bd739
--- /dev/null
@@ -0,0 +1,266 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package org.sonar.server.computation.component;
+
+import org.junit.Test;
+import org.mockito.InOrder;
+
+import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.spy;
+import static org.sonar.server.computation.component.Component.Type.DIRECTORY;
+import static org.sonar.server.computation.component.Component.Type.FILE;
+import static org.sonar.server.computation.component.Component.Type.MODULE;
+import static org.sonar.server.computation.component.Component.Type.PROJECT;
+import static org.sonar.server.computation.component.DepthTraversalTypeAwareVisitor.Order.POST_ORDER;
+
+public class PostOrderDepthTraversalTypeAwareVisitorTest {
+
+  private static final Component FILE_4 = component(FILE, 4);
+  private static final Component FILE_5 = component(FILE, 5);
+  private static final Component DIRECTORY_3 = component(DIRECTORY, 3, FILE_4, FILE_5);
+  private static final Component MODULE_2 = component(MODULE, 2, DIRECTORY_3);
+  private static final Component COMPONENT_TREE = component(PROJECT, 1, MODULE_2);
+
+  private final DepthTraversalTypeAwareVisitor spyProjectVisitor = spy(new DepthTraversalTypeAwareVisitor(PROJECT, POST_ORDER) {});
+  private final DepthTraversalTypeAwareVisitor spyModuleVisitor = spy(new DepthTraversalTypeAwareVisitor(MODULE, POST_ORDER) {});
+  private final DepthTraversalTypeAwareVisitor spyDirectoryVisitor = spy(new DepthTraversalTypeAwareVisitor(DIRECTORY, POST_ORDER) {});
+  private final DepthTraversalTypeAwareVisitor spyFileVisitor = spy(new DepthTraversalTypeAwareVisitor(FILE, POST_ORDER) {});
+  private final InOrder inOrder = inOrder(spyProjectVisitor, spyModuleVisitor, spyDirectoryVisitor, spyFileVisitor);
+
+  @Test(expected = NullPointerException.class)
+  public void non_null_max_depth_fast_fail() {
+    new DepthTraversalTypeAwareVisitor(null, POST_ORDER) {};
+  }
+
+  @Test(expected = NullPointerException.class)
+  public void visit_null_Component_throws_NPE() {
+    spyFileVisitor.visit(null);
+  }
+
+  @Test
+  public void visit_file_with_depth_FILE_calls_visit_file() {
+    Component component = component(FILE, 1);
+    spyFileVisitor.visit(component);
+
+    inOrder.verify(spyFileVisitor).visit(component);
+    inOrder.verify(spyFileVisitor).visitFile(component);
+    inOrder.verifyNoMoreInteractions();
+  }
+
+  @Test
+  public void visit_module_with_depth_FILE_calls_visit_module() {
+    Component component = component(MODULE, 1);
+    spyFileVisitor.visit(component);
+
+    inOrder.verify(spyFileVisitor).visit(component);
+    inOrder.verify(spyFileVisitor).visitModule(component);
+    inOrder.verifyNoMoreInteractions();
+  }
+
+  @Test
+  public void visit_directory_with_depth_FILE_calls_visit_directory() {
+    Component component = component(DIRECTORY, 1);
+    spyFileVisitor.visit(component);
+
+    inOrder.verify(spyFileVisitor).visit(component);
+    inOrder.verify(spyFileVisitor).visitDirectory(component);
+    inOrder.verifyNoMoreInteractions();
+  }
+
+  @Test
+  public void visit_project_with_depth_FILE_calls_visit_project() {
+    Component component = component(PROJECT, 1);
+    spyFileVisitor.visit(component);
+
+    inOrder.verify(spyFileVisitor).visit(component);
+    inOrder.verify(spyFileVisitor).visitProject(component);
+    inOrder.verifyNoMoreInteractions();
+  }
+
+  @Test
+  public void visit_file_with_depth_DIRECTORY_does_not_call_visit_file() {
+    Component component = component(FILE, 1);
+    spyDirectoryVisitor.visit(component);
+
+    inOrder.verify(spyDirectoryVisitor).visit(component);
+    inOrder.verifyNoMoreInteractions();
+  }
+
+  @Test
+  public void visit_directory_with_depth_DIRECTORY_calls_visit_directory() {
+    Component component = component(DIRECTORY, 1);
+    spyDirectoryVisitor.visit(component);
+
+    inOrder.verify(spyDirectoryVisitor).visit(component);
+    inOrder.verify(spyDirectoryVisitor).visitDirectory(component);
+    inOrder.verifyNoMoreInteractions();
+  }
+
+  @Test
+  public void visit_module_with_depth_DIRECTORY_calls_visit_module() {
+    Component component = component(MODULE, 1);
+    spyDirectoryVisitor.visit(component);
+
+    inOrder.verify(spyDirectoryVisitor).visit(component);
+    inOrder.verify(spyDirectoryVisitor).visitModule(component);
+    inOrder.verifyNoMoreInteractions();
+  }
+
+  @Test
+  public void visit_project_with_depth_DIRECTORY_calls_visit_project() {
+    Component component = component(PROJECT, 1);
+    spyDirectoryVisitor.visit(component);
+
+    inOrder.verify(spyDirectoryVisitor).visit(component);
+    inOrder.verify(spyDirectoryVisitor).visitProject(component);
+    inOrder.verifyNoMoreInteractions();
+  }
+
+  @Test
+  public void visit_file_with_depth_MODULE_does_not_call_visit_file() {
+    Component component = component(FILE, 1);
+    spyModuleVisitor.visit(component);
+
+    inOrder.verify(spyModuleVisitor).visit(component);
+    inOrder.verifyNoMoreInteractions();
+  }
+
+  @Test
+  public void visit_directory_with_depth_MODULE_does_not_call_visit_directory() {
+    Component component = component(DIRECTORY, 1);
+    spyModuleVisitor.visit(component);
+
+    inOrder.verify(spyModuleVisitor).visit(component);
+    inOrder.verifyNoMoreInteractions();
+  }
+
+  @Test
+  public void visit_module_with_depth_MODULE_calls_visit_module() {
+    Component component = component(MODULE, 1);
+    spyModuleVisitor.visit(component);
+
+    inOrder.verify(spyModuleVisitor).visit(component);
+    inOrder.verify(spyModuleVisitor).visitModule(component);
+    inOrder.verifyNoMoreInteractions();
+  }
+
+  @Test
+  public void visit_project_with_depth_MODULE_calls_visit_project() {
+    Component component = component(MODULE, 1);
+    spyModuleVisitor.visit(component);
+
+    inOrder.verify(spyModuleVisitor).visit(component);
+    inOrder.verify(spyModuleVisitor).visitModule(component);
+    inOrder.verifyNoMoreInteractions();
+  }
+
+  @Test
+  public void visit_file_with_depth_PROJECT_does_not_call_visit_file() {
+    Component component = component(FILE, 1);
+    spyProjectVisitor.visit(component);
+
+    inOrder.verify(spyProjectVisitor).visit(component);
+    inOrder.verifyNoMoreInteractions();
+  }
+
+  @Test
+  public void visit_directory_with_depth_PROJECT_does_not_call_visit_directory() {
+    Component component = component(DIRECTORY, 1);
+    spyProjectVisitor.visit(component);
+
+    inOrder.verify(spyProjectVisitor).visit(component);
+    inOrder.verifyNoMoreInteractions();
+  }
+
+  @Test
+  public void visit_module_with_depth_PROJECT_does_not_call_visit_module() {
+    Component component = component(MODULE, 1);
+    spyProjectVisitor.visit(component);
+
+    inOrder.verify(spyProjectVisitor).visit(component);
+    inOrder.verifyNoMoreInteractions();
+  }
+
+  @Test
+  public void visit_project_with_depth_PROJECT_calls_visit_project() {
+    Component component = component(PROJECT, 1);
+    spyProjectVisitor.visit(component);
+
+    inOrder.verify(spyProjectVisitor).visit(component);
+    inOrder.verify(spyProjectVisitor).visitProject(component);
+    inOrder.verifyNoMoreInteractions();
+  }
+
+  @Test
+  public void verify_visit_call_when_visit_tree_with_depth_FILE() {
+    spyFileVisitor.visit(COMPONENT_TREE);
+
+    inOrder.verify(spyFileVisitor).visit(COMPONENT_TREE);
+    inOrder.verify(spyFileVisitor).visit(MODULE_2);
+    inOrder.verify(spyFileVisitor).visit(DIRECTORY_3);
+    inOrder.verify(spyFileVisitor).visit(FILE_4);
+    inOrder.verify(spyFileVisitor).visitFile(FILE_4);
+    inOrder.verify(spyFileVisitor).visit(FILE_5);
+    inOrder.verify(spyFileVisitor).visitFile(FILE_5);
+    inOrder.verify(spyFileVisitor).visitDirectory(DIRECTORY_3);
+    inOrder.verify(spyFileVisitor).visitModule(MODULE_2);
+    inOrder.verify(spyFileVisitor).visitProject(COMPONENT_TREE);
+    inOrder.verifyNoMoreInteractions();
+  }
+
+  @Test
+  public void verify_visit_call_when_visit_tree_with_depth_DIRECTORY() {
+    spyDirectoryVisitor.visit(COMPONENT_TREE);
+
+    inOrder.verify(spyDirectoryVisitor).visit(COMPONENT_TREE);
+    inOrder.verify(spyDirectoryVisitor).visit(MODULE_2);
+    inOrder.verify(spyDirectoryVisitor).visit(DIRECTORY_3);
+    inOrder.verify(spyDirectoryVisitor).visitDirectory(DIRECTORY_3);
+    inOrder.verify(spyDirectoryVisitor).visitModule(MODULE_2);
+    inOrder.verify(spyDirectoryVisitor).visitProject(COMPONENT_TREE);
+    inOrder.verifyNoMoreInteractions();
+  }
+
+  @Test
+  public void verify_visit_call_when_visit_tree_with_depth_MODULE() {
+    spyModuleVisitor.visit(COMPONENT_TREE);
+
+    inOrder.verify(spyModuleVisitor).visit(COMPONENT_TREE);
+    inOrder.verify(spyModuleVisitor).visit(MODULE_2);
+    inOrder.verify(spyModuleVisitor).visitModule(MODULE_2);
+    inOrder.verify(spyModuleVisitor).visitProject(COMPONENT_TREE);
+    inOrder.verifyNoMoreInteractions();
+  }
+
+  @Test
+  public void verify_visit_call_when_visit_tree_with_depth_PROJECT() {
+    spyProjectVisitor.visit(COMPONENT_TREE);
+
+    inOrder.verify(spyProjectVisitor).visit(COMPONENT_TREE);
+    inOrder.verify(spyProjectVisitor).visitProject(COMPONENT_TREE);
+    inOrder.verifyNoMoreInteractions();
+  }
+
+  private static Component component(final Component.Type type, final int ref, final Component... children) {
+    return new DumbComponent(type, ref, null, null, children);
+  }
+
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/component/PreOrderDepthTraversalTypeAwareVisitorTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/component/PreOrderDepthTraversalTypeAwareVisitorTest.java
new file mode 100644 (file)
index 0000000..fffa395
--- /dev/null
@@ -0,0 +1,266 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package org.sonar.server.computation.component;
+
+import org.junit.Test;
+import org.mockito.InOrder;
+
+import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.spy;
+import static org.sonar.server.computation.component.Component.Type.DIRECTORY;
+import static org.sonar.server.computation.component.Component.Type.FILE;
+import static org.sonar.server.computation.component.Component.Type.MODULE;
+import static org.sonar.server.computation.component.Component.Type.PROJECT;
+import static org.sonar.server.computation.component.DepthTraversalTypeAwareVisitor.Order.PRE_ORDER;
+
+public class PreOrderDepthTraversalTypeAwareVisitorTest {
+
+  private static final Component FILE_4 = component(FILE, 4);
+  private static final Component FILE_5 = component(FILE, 5);
+  private static final Component DIRECTORY_3 = component(DIRECTORY, 3, FILE_4, FILE_5);
+  private static final Component MODULE_2 = component(MODULE, 2, DIRECTORY_3);
+  private static final Component COMPONENT_TREE = component(PROJECT, 1, MODULE_2);
+
+  private final DepthTraversalTypeAwareVisitor spyProjectVisitor = spy(new DepthTraversalTypeAwareVisitor(PROJECT, PRE_ORDER) {});
+  private final DepthTraversalTypeAwareVisitor spyModuleVisitor = spy(new DepthTraversalTypeAwareVisitor(MODULE, PRE_ORDER) {});
+  private final DepthTraversalTypeAwareVisitor spyDirectoryVisitor = spy(new DepthTraversalTypeAwareVisitor(DIRECTORY, PRE_ORDER) {});
+  private final DepthTraversalTypeAwareVisitor spyFileVisitor = spy(new DepthTraversalTypeAwareVisitor(FILE, PRE_ORDER) {});
+  private final InOrder inOrder = inOrder(spyProjectVisitor, spyModuleVisitor, spyDirectoryVisitor, spyFileVisitor);
+
+  @Test(expected = NullPointerException.class)
+  public void non_null_max_depth_fast_fail() {
+    new DepthTraversalTypeAwareVisitor(null, PRE_ORDER) {};
+  }
+
+  @Test(expected = NullPointerException.class)
+  public void visit_null_Component_throws_NPE() {
+    spyFileVisitor.visit(null);
+  }
+
+  @Test
+  public void visit_file_with_depth_FILE_calls_visit_file() {
+    Component component = component(FILE, 1);
+    spyFileVisitor.visit(component);
+
+    inOrder.verify(spyFileVisitor).visit(component);
+    inOrder.verify(spyFileVisitor).visitFile(component);
+    inOrder.verifyNoMoreInteractions();
+  }
+
+  @Test
+  public void visit_module_with_depth_FILE_calls_visit_module() {
+    Component component = component(MODULE, 1);
+    spyFileVisitor.visit(component);
+
+    inOrder.verify(spyFileVisitor).visit(component);
+    inOrder.verify(spyFileVisitor).visitModule(component);
+    inOrder.verifyNoMoreInteractions();
+  }
+
+  @Test
+  public void visit_directory_with_depth_FILE_calls_visit_directory() {
+    Component component = component(DIRECTORY, 1);
+    spyFileVisitor.visit(component);
+
+    inOrder.verify(spyFileVisitor).visit(component);
+    inOrder.verify(spyFileVisitor).visitDirectory(component);
+    inOrder.verifyNoMoreInteractions();
+  }
+
+  @Test
+  public void visit_project_with_depth_FILE_calls_visit_project() {
+    Component component = component(PROJECT, 1);
+    spyFileVisitor.visit(component);
+
+    inOrder.verify(spyFileVisitor).visit(component);
+    inOrder.verify(spyFileVisitor).visitProject(component);
+    inOrder.verifyNoMoreInteractions();
+  }
+
+  @Test
+  public void visit_file_with_depth_DIRECTORY_does_not_call_visit_file() {
+    Component component = component(FILE, 1);
+    spyDirectoryVisitor.visit(component);
+
+    inOrder.verify(spyDirectoryVisitor).visit(component);
+    inOrder.verifyNoMoreInteractions();
+  }
+
+  @Test
+  public void visit_directory_with_depth_DIRECTORY_calls_visit_directory() {
+    Component component = component(DIRECTORY, 1);
+    spyDirectoryVisitor.visit(component);
+
+    inOrder.verify(spyDirectoryVisitor).visit(component);
+    inOrder.verify(spyDirectoryVisitor).visitDirectory(component);
+    inOrder.verifyNoMoreInteractions();
+  }
+
+  @Test
+  public void visit_module_with_depth_DIRECTORY_calls_visit_module() {
+    Component component = component(MODULE, 1);
+    spyDirectoryVisitor.visit(component);
+
+    inOrder.verify(spyDirectoryVisitor).visit(component);
+    inOrder.verify(spyDirectoryVisitor).visitModule(component);
+    inOrder.verifyNoMoreInteractions();
+  }
+
+  @Test
+  public void visit_project_with_depth_DIRECTORY_calls_visit_project() {
+    Component component = component(PROJECT, 1);
+    spyDirectoryVisitor.visit(component);
+
+    inOrder.verify(spyDirectoryVisitor).visit(component);
+    inOrder.verify(spyDirectoryVisitor).visitProject(component);
+    inOrder.verifyNoMoreInteractions();
+  }
+
+  @Test
+  public void visit_file_with_depth_MODULE_does_not_call_visit_file() {
+    Component component = component(FILE, 1);
+    spyModuleVisitor.visit(component);
+
+    inOrder.verify(spyModuleVisitor).visit(component);
+    inOrder.verifyNoMoreInteractions();
+  }
+
+  @Test
+  public void visit_directory_with_depth_MODULE_does_not_call_visit_directory() {
+    Component component = component(DIRECTORY, 1);
+    spyModuleVisitor.visit(component);
+
+    inOrder.verify(spyModuleVisitor).visit(component);
+    inOrder.verifyNoMoreInteractions();
+  }
+
+  @Test
+  public void visit_module_with_depth_MODULE_calls_visit_module() {
+    Component component = component(MODULE, 1);
+    spyModuleVisitor.visit(component);
+
+    inOrder.verify(spyModuleVisitor).visit(component);
+    inOrder.verify(spyModuleVisitor).visitModule(component);
+    inOrder.verifyNoMoreInteractions();
+  }
+
+  @Test
+  public void visit_project_with_depth_MODULE_calls_visit_project() {
+    Component component = component(MODULE, 1);
+    spyModuleVisitor.visit(component);
+
+    inOrder.verify(spyModuleVisitor).visit(component);
+    inOrder.verify(spyModuleVisitor).visitModule(component);
+    inOrder.verifyNoMoreInteractions();
+  }
+
+  @Test
+  public void visit_file_with_depth_PROJECT_does_not_call_visit_file() {
+    Component component = component(FILE, 1);
+    spyProjectVisitor.visit(component);
+
+    inOrder.verify(spyProjectVisitor).visit(component);
+    inOrder.verifyNoMoreInteractions();
+  }
+
+  @Test
+  public void visit_directory_with_depth_PROJECT_does_not_call_visit_directory() {
+    Component component = component(DIRECTORY, 1);
+    spyProjectVisitor.visit(component);
+
+    inOrder.verify(spyProjectVisitor).visit(component);
+    inOrder.verifyNoMoreInteractions();
+  }
+
+  @Test
+  public void visit_module_with_depth_PROJECT_does_not_call_visit_module() {
+    Component component = component(MODULE, 1);
+    spyProjectVisitor.visit(component);
+
+    inOrder.verify(spyProjectVisitor).visit(component);
+    inOrder.verifyNoMoreInteractions();
+  }
+
+  @Test
+  public void visit_project_with_depth_PROJECT_calls_visit_project() {
+    Component component = component(PROJECT, 1);
+    spyProjectVisitor.visit(component);
+
+    inOrder.verify(spyProjectVisitor).visit(component);
+    inOrder.verify(spyProjectVisitor).visitProject(component);
+    inOrder.verifyNoMoreInteractions();
+  }
+
+  @Test
+  public void verify_visit_call_when_visit_tree_with_depth_FILE() {
+    spyFileVisitor.visit(COMPONENT_TREE);
+
+    inOrder.verify(spyFileVisitor).visit(COMPONENT_TREE);
+    inOrder.verify(spyFileVisitor).visitProject(COMPONENT_TREE);
+    inOrder.verify(spyFileVisitor).visit(MODULE_2);
+    inOrder.verify(spyFileVisitor).visitModule(MODULE_2);
+    inOrder.verify(spyFileVisitor).visit(DIRECTORY_3);
+    inOrder.verify(spyFileVisitor).visitDirectory(DIRECTORY_3);
+    inOrder.verify(spyFileVisitor).visit(FILE_4);
+    inOrder.verify(spyFileVisitor).visitFile(FILE_4);
+    inOrder.verify(spyFileVisitor).visit(FILE_5);
+    inOrder.verify(spyFileVisitor).visitFile(FILE_5);
+    inOrder.verifyNoMoreInteractions();
+  }
+
+  @Test
+  public void verify_visit_call_when_visit_tree_with_depth_DIRECTORY() {
+    spyDirectoryVisitor.visit(COMPONENT_TREE);
+
+    inOrder.verify(spyDirectoryVisitor).visit(COMPONENT_TREE);
+    inOrder.verify(spyDirectoryVisitor).visitProject(COMPONENT_TREE);
+    inOrder.verify(spyDirectoryVisitor).visit(MODULE_2);
+    inOrder.verify(spyDirectoryVisitor).visitModule(MODULE_2);
+    inOrder.verify(spyDirectoryVisitor).visit(DIRECTORY_3);
+    inOrder.verify(spyDirectoryVisitor).visitDirectory(DIRECTORY_3);
+    inOrder.verifyNoMoreInteractions();
+  }
+
+  @Test
+  public void verify_visit_call_when_visit_tree_with_depth_MODULE() {
+    spyModuleVisitor.visit(COMPONENT_TREE);
+
+    inOrder.verify(spyModuleVisitor).visit(COMPONENT_TREE);
+    inOrder.verify(spyModuleVisitor).visitProject(COMPONENT_TREE);
+    inOrder.verify(spyModuleVisitor).visit(MODULE_2);
+    inOrder.verify(spyModuleVisitor).visitModule(MODULE_2);
+    inOrder.verifyNoMoreInteractions();
+  }
+
+  @Test
+  public void verify_visit_call_when_visit_tree_with_depth_PROJECT() {
+    spyProjectVisitor.visit(COMPONENT_TREE);
+
+    inOrder.verify(spyProjectVisitor).visit(COMPONENT_TREE);
+    inOrder.verify(spyProjectVisitor).visitProject(COMPONENT_TREE);
+    inOrder.verifyNoMoreInteractions();
+  }
+
+  private static Component component(final Component.Type type, final int ref, final Component... children) {
+    return new DumbComponent(type, ref, null, null, children);
+  }
+
+}