This is an automated email from the ASF dual-hosted git repository.

gnodet pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/maven.git


The following commit(s) were added to refs/heads/master by this push:
     new e91cee9a2d [MNG-7820] Get rid of plexus-utils DAG class (#1250)
e91cee9a2d is described below

commit e91cee9a2d704f4b5f5429a67ccccd5675e4df6a
Author: Guillaume Nodet <gno...@gmail.com>
AuthorDate: Fri Sep 22 08:02:04 2023 +0200

    [MNG-7820] Get rid of plexus-utils DAG class (#1250)
---
 maven-core/pom.xml                                 |   2 +
 .../org/apache/maven/ProjectCycleException.java    |   2 +-
 .../org/apache/maven/execution/ReactorManager.java |   2 +-
 .../apache/maven/graph/DefaultGraphBuilder.java    |   2 +-
 .../maven/graph/DefaultProjectDependencyGraph.java |   2 +-
 .../CycleDetectedException.java}                   |  22 +-
 .../main/java/org/apache/maven/project/Graph.java  | 125 +++++++++++
 .../org/apache/maven/project/ProjectSorter.java    |  27 +--
 .../graph/DefaultProjectDependencyGraphTest.java   |   2 +-
 .../PluginParameterExpressionEvaluatorTest.java    |   2 +-
 .../PluginParameterExpressionEvaluatorV4Test.java  |   2 +-
 .../java/org/apache/maven/project/GraphTest.java   | 233 +++++++++++++++++++++
 12 files changed, 391 insertions(+), 32 deletions(-)

diff --git a/maven-core/pom.xml b/maven-core/pom.xml
index 50c87aaf77..f62bb41bc3 100644
--- a/maven-core/pom.xml
+++ b/maven-core/pom.xml
@@ -327,6 +327,8 @@ under the License.
               
<exclude>org.apache.maven.toolchain.DefaultToolchain#DefaultToolchain(org.apache.maven.toolchain.model.ToolchainModel,org.codehaus.plexus.logging.Logger):CONSTRUCTOR_REMOVED</exclude>
               
<exclude>org.apache.maven.toolchain.DefaultToolchain#DefaultToolchain(org.apache.maven.toolchain.model.ToolchainModel,java.lang.String,org.codehaus.plexus.logging.Logger):CONSTRUCTOR_REMOVED</exclude>
               
<exclude>org.apache.maven.toolchain.DefaultToolchainManager#logger</exclude>
+              <!-- Remove plexus utils -->
+              
<exclude>org.apache.maven.project.ProjectSorter#getDAG():METHOD_REMOVED</exclude>
               <!-- classes moved to maven-compat -->
               <exclude>org.apache.maven.plugin.PluginManager</exclude>
               
<exclude>org.apache.maven.repository.ArtifactDoesNotExistException</exclude>
diff --git 
a/maven-core/src/main/java/org/apache/maven/ProjectCycleException.java 
b/maven-core/src/main/java/org/apache/maven/ProjectCycleException.java
index 0157f2ebd3..ad004a7a76 100644
--- a/maven-core/src/main/java/org/apache/maven/ProjectCycleException.java
+++ b/maven-core/src/main/java/org/apache/maven/ProjectCycleException.java
@@ -18,7 +18,7 @@
  */
 package org.apache.maven;
 
-import org.codehaus.plexus.util.dag.CycleDetectedException;
+import org.apache.maven.project.CycleDetectedException;
 
 /**
  */
diff --git 
a/maven-core/src/main/java/org/apache/maven/execution/ReactorManager.java 
b/maven-core/src/main/java/org/apache/maven/execution/ReactorManager.java
index e1f21c3066..2ac0643135 100644
--- a/maven-core/src/main/java/org/apache/maven/execution/ReactorManager.java
+++ b/maven-core/src/main/java/org/apache/maven/execution/ReactorManager.java
@@ -25,10 +25,10 @@ import java.util.Map;
 
 import org.apache.maven.artifact.ArtifactUtils;
 import org.apache.maven.plugin.descriptor.PluginDescriptor;
+import org.apache.maven.project.CycleDetectedException;
 import org.apache.maven.project.DuplicateProjectException;
 import org.apache.maven.project.MavenProject;
 import org.apache.maven.project.ProjectSorter;
-import org.codehaus.plexus.util.dag.CycleDetectedException;
 
 /**
  * ReactorManager - unused
diff --git 
a/maven-core/src/main/java/org/apache/maven/graph/DefaultGraphBuilder.java 
b/maven-core/src/main/java/org/apache/maven/graph/DefaultGraphBuilder.java
index 6e617eace8..ca2334e894 100644
--- a/maven-core/src/main/java/org/apache/maven/graph/DefaultGraphBuilder.java
+++ b/maven-core/src/main/java/org/apache/maven/graph/DefaultGraphBuilder.java
@@ -43,13 +43,13 @@ import org.apache.maven.execution.ProjectDependencyGraph;
 import org.apache.maven.model.Plugin;
 import org.apache.maven.model.building.DefaultModelProblem;
 import org.apache.maven.model.building.Result;
+import org.apache.maven.project.CycleDetectedException;
 import org.apache.maven.project.DuplicateProjectException;
 import org.apache.maven.project.MavenProject;
 import org.apache.maven.project.ProjectBuildingException;
 import org.apache.maven.project.collector.MultiModuleCollectionStrategy;
 import org.apache.maven.project.collector.PomlessCollectionStrategy;
 import org.apache.maven.project.collector.RequestPomCollectionStrategy;
-import org.codehaus.plexus.util.dag.CycleDetectedException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
diff --git 
a/maven-core/src/main/java/org/apache/maven/graph/DefaultProjectDependencyGraph.java
 
b/maven-core/src/main/java/org/apache/maven/graph/DefaultProjectDependencyGraph.java
index fed6eb62a6..d49670b438 100644
--- 
a/maven-core/src/main/java/org/apache/maven/graph/DefaultProjectDependencyGraph.java
+++ 
b/maven-core/src/main/java/org/apache/maven/graph/DefaultProjectDependencyGraph.java
@@ -31,10 +31,10 @@ import java.util.Set;
 import java.util.stream.Collectors;
 
 import org.apache.maven.execution.ProjectDependencyGraph;
+import org.apache.maven.project.CycleDetectedException;
 import org.apache.maven.project.DuplicateProjectException;
 import org.apache.maven.project.MavenProject;
 import org.apache.maven.project.ProjectSorter;
-import org.codehaus.plexus.util.dag.CycleDetectedException;
 
 /**
  * Describes the interdependencies between projects in the reactor.
diff --git 
a/maven-core/src/main/java/org/apache/maven/ProjectCycleException.java 
b/maven-core/src/main/java/org/apache/maven/project/CycleDetectedException.java
similarity index 66%
copy from maven-core/src/main/java/org/apache/maven/ProjectCycleException.java
copy to 
maven-core/src/main/java/org/apache/maven/project/CycleDetectedException.java
index 0157f2ebd3..334034228d 100644
--- a/maven-core/src/main/java/org/apache/maven/ProjectCycleException.java
+++ 
b/maven-core/src/main/java/org/apache/maven/project/CycleDetectedException.java
@@ -16,18 +16,24 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.maven;
+package org.apache.maven.project;
 
-import org.codehaus.plexus.util.dag.CycleDetectedException;
+import java.util.List;
 
-/**
- */
-public class ProjectCycleException extends BuildFailureException {
-    public ProjectCycleException(String message) {
+public class CycleDetectedException extends Exception {
+    private final List<String> cycle;
+
+    public CycleDetectedException(String message, List<String> cycle) {
         super(message);
+        this.cycle = cycle;
+    }
+
+    public List<String> getCycle() {
+        return cycle;
     }
 
-    public ProjectCycleException(String message, CycleDetectedException cause) 
{
-        super(message, cause);
+    @Override
+    public String getMessage() {
+        return super.getMessage() + " " + String.join(" --> ", cycle);
     }
 }
diff --git a/maven-core/src/main/java/org/apache/maven/project/Graph.java 
b/maven-core/src/main/java/org/apache/maven/project/Graph.java
new file mode 100644
index 0000000000..a0c75cb1b2
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/project/Graph.java
@@ -0,0 +1,125 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.project;
+
+import java.util.*;
+
+class Graph {
+    private enum DfsState {
+        VISITING,
+        VISITED
+    }
+
+    final Map<String, Vertex> vertices = new LinkedHashMap<>();
+
+    public Vertex getVertex(String id) {
+        return vertices.get(id);
+    }
+
+    public Collection<Vertex> getVertices() {
+        return vertices.values();
+    }
+
+    Vertex addVertex(String label) {
+        return vertices.computeIfAbsent(label, Vertex::new);
+    }
+
+    void addEdge(Vertex from, Vertex to) throws CycleDetectedException {
+        from.children.add(to);
+        to.parents.add(from);
+        List<String> cycle = findCycle(to);
+        if (cycle != null) {
+            // remove edge which introduced cycle
+            removeEdge(from, to);
+            throw new CycleDetectedException(
+                    "Edge between '" + from.label + "' and '" + to.label + "' 
introduces to cycle in the graph", cycle);
+        }
+    }
+
+    void removeEdge(Vertex from, Vertex to) {
+        from.children.remove(to);
+        to.parents.remove(from);
+    }
+
+    List<String> visitAll() {
+        return visitAll(vertices.values(), new HashMap<>(), new ArrayList<>());
+    }
+
+    List<String> findCycle(Vertex vertex) {
+        return visitCycle(Collections.singleton(vertex), new HashMap<>(), new 
LinkedList<>());
+    }
+
+    private static List<String> visitAll(
+            Collection<Vertex> children, Map<Vertex, DfsState> stateMap, 
List<String> list) {
+        for (Vertex v : children) {
+            DfsState state = stateMap.putIfAbsent(v, DfsState.VISITING);
+            if (state == null) {
+                visitAll(v.children, stateMap, list);
+                stateMap.put(v, DfsState.VISITED);
+                list.add(v.label);
+            }
+        }
+        return list;
+    }
+
+    private static List<String> visitCycle(
+            Collection<Vertex> children, Map<Vertex, DfsState> stateMap, 
LinkedList<String> cycle) {
+        for (Vertex v : children) {
+            DfsState state = stateMap.putIfAbsent(v, DfsState.VISITING);
+            if (state == null) {
+                cycle.addLast(v.label);
+                List<String> ret = visitCycle(v.children, stateMap, cycle);
+                if (ret != null) {
+                    return ret;
+                }
+                cycle.removeLast();
+                stateMap.put(v, DfsState.VISITED);
+            } else if (state == DfsState.VISITING) {
+                // we are already visiting this vertex, this mean we have a 
cycle
+                int pos = cycle.lastIndexOf(v.label);
+                List<String> ret = cycle.subList(pos, cycle.size());
+                ret.add(v.label);
+                return ret;
+            }
+        }
+        return null;
+    }
+
+    static class Vertex {
+        final String label;
+        final List<Vertex> children = new ArrayList<>();
+        final List<Vertex> parents = new ArrayList<>();
+
+        Vertex(String label) {
+            this.label = label;
+        }
+
+        String getLabel() {
+            return label;
+        }
+
+        List<Vertex> getChildren() {
+            return children;
+        }
+
+        List<Vertex> getParents() {
+            return parents;
+        }
+    }
+}
diff --git 
a/maven-core/src/main/java/org/apache/maven/project/ProjectSorter.java 
b/maven-core/src/main/java/org/apache/maven/project/ProjectSorter.java
index 560c94eae5..32be1fee59 100644
--- a/maven-core/src/main/java/org/apache/maven/project/ProjectSorter.java
+++ b/maven-core/src/main/java/org/apache/maven/project/ProjectSorter.java
@@ -31,16 +31,13 @@ import org.apache.maven.api.model.Extension;
 import org.apache.maven.api.model.Parent;
 import org.apache.maven.api.model.Plugin;
 import org.apache.maven.artifact.ArtifactUtils;
-import org.codehaus.plexus.util.dag.CycleDetectedException;
-import org.codehaus.plexus.util.dag.DAG;
-import org.codehaus.plexus.util.dag.TopologicalSorter;
-import org.codehaus.plexus.util.dag.Vertex;
+import org.apache.maven.project.Graph.Vertex;
 
 /**
  * ProjectSorter
  */
 public class ProjectSorter {
-    private DAG dag;
+    private Graph graph;
 
     private List<MavenProject> sortedProjects;
 
@@ -70,7 +67,7 @@ public class ProjectSorter {
     // in a different lifecycle. Though the compiler-plugin has a valid use 
case, although
     // that seems to work fine. We need to take versions and lifecycle into 
account.
     public ProjectSorter(Collection<MavenProject> projects) throws 
CycleDetectedException, DuplicateProjectException {
-        dag = new DAG();
+        graph = new Graph();
 
         // groupId:artifactId:version -> project
         projectMap = new HashMap<>(projects.size() * 2);
@@ -95,10 +92,10 @@ public class ProjectSorter {
 
             Map<String, Vertex> vertices = 
vertexMap.computeIfAbsent(projectKey, k -> new HashMap<>(2, 1));
 
-            vertices.put(project.getVersion(), dag.addVertex(projectId));
+            vertices.put(project.getVersion(), graph.addVertex(projectId));
         }
 
-        for (Vertex projectVertex : dag.getVertices()) {
+        for (Vertex projectVertex : graph.getVertices()) {
             String projectId = projectVertex.getLabel();
 
             MavenProject project = projectMap.get(projectId);
@@ -176,7 +173,7 @@ public class ProjectSorter {
             }
         }
 
-        List<String> sortedProjectLabels = TopologicalSorter.sort(dag);
+        List<String> sortedProjectLabels = graph.visitAll();
 
         this.sortedProjects = sortedProjectLabels.stream()
                 .map(id -> projectMap.get(id))
@@ -231,11 +228,11 @@ public class ProjectSorter {
         }
 
         if (force && toVertex.getChildren().contains(fromVertex)) {
-            dag.removeEdge(toVertex, fromVertex);
+            graph.removeEdge(toVertex, fromVertex);
         }
 
         try {
-            dag.addEdge(fromVertex, toVertex);
+            graph.addEdge(fromVertex, toVertex);
         } catch (CycleDetectedException e) {
             if (!safe) {
                 throw e;
@@ -265,21 +262,17 @@ public class ProjectSorter {
     }
 
     public List<String> getDependents(String id) {
-        return dag.getParentLabels(id);
+        return 
graph.getVertex(id).getParents().stream().map(Vertex::getLabel).collect(Collectors.toList());
     }
 
     public List<String> getDependencies(String id) {
-        return dag.getChildLabels(id);
+        return 
graph.getVertex(id).getChildren().stream().map(Vertex::getLabel).collect(Collectors.toList());
     }
 
     public static String getId(MavenProject project) {
         return ArtifactUtils.key(project.getGroupId(), 
project.getArtifactId(), project.getVersion());
     }
 
-    public DAG getDAG() {
-        return dag;
-    }
-
     public Map<String, MavenProject> getProjectMap() {
         return projectMap;
     }
diff --git 
a/maven-core/src/test/java/org/apache/maven/graph/DefaultProjectDependencyGraphTest.java
 
b/maven-core/src/test/java/org/apache/maven/graph/DefaultProjectDependencyGraphTest.java
index 67a722a53a..9d68de0190 100644
--- 
a/maven-core/src/test/java/org/apache/maven/graph/DefaultProjectDependencyGraphTest.java
+++ 
b/maven-core/src/test/java/org/apache/maven/graph/DefaultProjectDependencyGraphTest.java
@@ -23,9 +23,9 @@ import java.util.List;
 
 import org.apache.maven.execution.ProjectDependencyGraph;
 import org.apache.maven.model.Dependency;
+import org.apache.maven.project.CycleDetectedException;
 import org.apache.maven.project.DuplicateProjectException;
 import org.apache.maven.project.MavenProject;
-import org.codehaus.plexus.util.dag.CycleDetectedException;
 import org.junit.jupiter.api.Test;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
diff --git 
a/maven-core/src/test/java/org/apache/maven/plugin/PluginParameterExpressionEvaluatorTest.java
 
b/maven-core/src/test/java/org/apache/maven/plugin/PluginParameterExpressionEvaluatorTest.java
index 3e3ba0a1a6..4090be80bf 100644
--- 
a/maven-core/src/test/java/org/apache/maven/plugin/PluginParameterExpressionEvaluatorTest.java
+++ 
b/maven-core/src/test/java/org/apache/maven/plugin/PluginParameterExpressionEvaluatorTest.java
@@ -45,12 +45,12 @@ import org.apache.maven.model.Model;
 import org.apache.maven.model.root.RootLocator;
 import org.apache.maven.plugin.descriptor.MojoDescriptor;
 import org.apache.maven.plugin.descriptor.PluginDescriptor;
+import org.apache.maven.project.CycleDetectedException;
 import org.apache.maven.project.DuplicateProjectException;
 import org.apache.maven.project.MavenProject;
 import org.codehaus.plexus.MutablePlexusContainer;
 import org.codehaus.plexus.PlexusContainer;
 import 
org.codehaus.plexus.component.configurator.expression.ExpressionEvaluator;
-import org.codehaus.plexus.util.dag.CycleDetectedException;
 import org.junit.jupiter.api.Test;
 
 import static org.codehaus.plexus.testing.PlexusExtension.getTestFile;
diff --git 
a/maven-core/src/test/java/org/apache/maven/plugin/PluginParameterExpressionEvaluatorV4Test.java
 
b/maven-core/src/test/java/org/apache/maven/plugin/PluginParameterExpressionEvaluatorV4Test.java
index dc03adf8b9..bcb247dade 100644
--- 
a/maven-core/src/test/java/org/apache/maven/plugin/PluginParameterExpressionEvaluatorV4Test.java
+++ 
b/maven-core/src/test/java/org/apache/maven/plugin/PluginParameterExpressionEvaluatorV4Test.java
@@ -48,12 +48,12 @@ import org.apache.maven.model.Model;
 import org.apache.maven.model.root.RootLocator;
 import org.apache.maven.plugin.descriptor.MojoDescriptor;
 import org.apache.maven.plugin.descriptor.PluginDescriptor;
+import org.apache.maven.project.CycleDetectedException;
 import org.apache.maven.project.DuplicateProjectException;
 import org.apache.maven.project.MavenProject;
 import org.codehaus.plexus.MutablePlexusContainer;
 import org.codehaus.plexus.PlexusContainer;
 import 
org.codehaus.plexus.component.configurator.expression.ExpressionEvaluator;
-import org.codehaus.plexus.util.dag.CycleDetectedException;
 import org.eclipse.aether.DefaultRepositorySystemSession;
 import org.eclipse.aether.internal.impl.DefaultRepositorySystem;
 import org.eclipse.aether.internal.impl.SimpleLocalRepositoryManagerFactory;
diff --git a/maven-core/src/test/java/org/apache/maven/project/GraphTest.java 
b/maven-core/src/test/java/org/apache/maven/project/GraphTest.java
new file mode 100644
index 0000000000..ef2b83278d
--- /dev/null
+++ b/maven-core/src/test/java/org/apache/maven/project/GraphTest.java
@@ -0,0 +1,233 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.project;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import org.apache.maven.project.Graph.Vertex;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+public class GraphTest {
+
+    @Test
+    public void testGraph() throws CycleDetectedException {
+        Graph graph = new Graph();
+        graph.addVertex("a");
+        assertEquals(1, graph.getVertices().size());
+        assertEquals("a", graph.getVertex("a").getLabel());
+        graph.addVertex("a");
+        assertEquals(1, graph.getVertices().size());
+        assertEquals("a", graph.getVertex("a").getLabel());
+
+        graph.addVertex("b");
+        assertEquals(2, graph.getVertices().size());
+        assertFalse(hasEdge(graph, "a", "b"));
+        assertFalse(hasEdge(graph, "b", "a"));
+
+        Vertex a = graph.getVertex("a");
+        Vertex b = graph.getVertex("b");
+        assertEquals("a", a.getLabel());
+        assertEquals("b", b.getLabel());
+
+        addEdge(graph, "a", "b");
+        assertTrue(a.getChildren().contains(b));
+        assertTrue(b.getParents().contains(a));
+        assertTrue(hasEdge(graph, "a", "b"));
+        assertFalse(hasEdge(graph, "b", "a"));
+
+        addEdge(graph, "c", "d");
+        assertEquals(4, graph.getVertices().size());
+
+        Vertex c = graph.getVertex("c");
+        Vertex d = graph.getVertex("d");
+        assertEquals("a", a.getLabel());
+        assertEquals("b", b.getLabel());
+        assertEquals("c", c.getLabel());
+        assertEquals("d", d.getLabel());
+        assertFalse(hasEdge(graph, "b", "a"));
+        assertFalse(hasEdge(graph, "a", "c"));
+        assertFalse(hasEdge(graph, "a", "d"));
+        assertTrue(hasEdge(graph, "c", "d"));
+        assertFalse(hasEdge(graph, "d", "c"));
+
+        Set<String> labels = 
graph.getVertices().stream().map(Vertex::getLabel).collect(Collectors.toSet());
+        assertEquals(4, labels.size());
+        assertTrue(labels.contains("a"));
+        assertTrue(labels.contains("b"));
+        assertTrue(labels.contains("c"));
+        assertTrue(labels.contains("d"));
+
+        addEdge(graph, "a", "d");
+        assertEquals(2, a.getChildren().size());
+        assertTrue(a.getChildren().contains(b));
+        assertTrue(a.getChildren().contains(d));
+        assertEquals(2, d.getParents().size());
+        assertTrue(d.getParents().contains(a));
+        assertTrue(d.getParents().contains(c));
+    }
+
+    @Test
+    public void testCycleDetection() throws Exception {
+        Graph graph1 = new Graph();
+        addEdge(graph1, "a", "b");
+        addEdge(graph1, "b", "c");
+
+        Graph graph2 = new Graph();
+        addEdge(graph2, "a", "b");
+        addEdge(graph2, "b", "c");
+        CycleDetectedException cde = 
assertThrows(CycleDetectedException.class, () -> addEdge(graph2, "c", "a"));
+        List<String> cycle = cde.getCycle();
+        assertNotNull(cycle, "Cycle should be not null");
+        assertTrue(cycle.contains("a"), "Cycle contains 'a'");
+        assertTrue(cycle.contains("b"), "Cycle contains 'b'");
+        assertTrue(cycle.contains("c"), "Cycle contains 'c'");
+
+        Graph graph3 = new Graph();
+        addEdge(graph3, "a", "b");
+        addEdge(graph3, "b", "c");
+        addEdge(graph3, "b", "d");
+        addEdge(graph3, "a", "d");
+
+        Graph graph4 = new Graph();
+        addEdge(graph4, "a", "b");
+        addEdge(graph4, "b", "c");
+        addEdge(graph4, "b", "d");
+        addEdge(graph4, "a", "d");
+        cde = assertThrows(CycleDetectedException.class, () -> addEdge(graph4, 
"c", "a"));
+        assertEquals(Arrays.asList("a", "b", "c", "a"), cde.getCycle());
+
+        Graph graph5 = new Graph();
+        addEdge(graph5, "a", "b");
+        addEdge(graph5, "b", "c");
+        addEdge(graph5, "b", "f");
+        addEdge(graph5, "f", "g");
+        addEdge(graph5, "g", "h");
+        addEdge(graph5, "c", "d");
+        addEdge(graph5, "d", "e");
+        cde = assertThrows(CycleDetectedException.class, () -> addEdge(graph5, 
"e", "b"));
+        assertEquals(Arrays.asList("b", "c", "d", "e", "b"), cde.getCycle());
+        assertTrue(hasEdge(graph5, "a", "b"));
+        assertTrue(hasEdge(graph5, "b", "c"));
+        assertTrue(hasEdge(graph5, "b", "f"));
+        assertTrue(hasEdge(graph5, "f", "g"));
+        assertTrue(hasEdge(graph5, "g", "h"));
+        assertTrue(hasEdge(graph5, "c", "d"));
+        assertTrue(hasEdge(graph5, "d", "e"));
+        assertFalse(hasEdge(graph5, "e", "b"));
+    }
+
+    @Test
+    public void testDfs() throws CycleDetectedException {
+        Graph graph1 = new Graph();
+        addEdge(graph1, "a", "b");
+        addEdge(graph1, "b", "c");
+        List<String> expected1 = new ArrayList<>();
+        expected1.add("c");
+        expected1.add("b");
+        expected1.add("a");
+        List<String> actual1 = graph1.visitAll();
+        assertEquals(expected1, actual1);
+
+        Graph graph2 = new Graph();
+        graph2.addVertex("a");
+        graph2.addVertex("b");
+        graph2.addVertex("c");
+        addEdge(graph2, "b", "a");
+        addEdge(graph2, "c", "b");
+        List<String> expected2 = new ArrayList<>();
+        expected2.add("a");
+        expected2.add("b");
+        expected2.add("c");
+        List<String> actual2 = graph2.visitAll();
+        assertEquals(expected2, actual2);
+
+        Graph graph3 = new Graph();
+        graph3.addVertex("a");
+        graph3.addVertex("b");
+        graph3.addVertex("c");
+        graph3.addVertex("d");
+        graph3.addVertex("e");
+        graph3.addVertex("f");
+        addEdge(graph3, "a", "b");
+        addEdge(graph3, "b", "c");
+        addEdge(graph3, "b", "d");
+        addEdge(graph3, "c", "d");
+        addEdge(graph3, "c", "e");
+        addEdge(graph3, "f", "d");
+        addEdge(graph3, "e", "f");
+        addEdge(graph3, "f", "g");
+        List<String> expected3 = new ArrayList<>();
+        expected3.add("d");
+        expected3.add("g");
+        expected3.add("f");
+        expected3.add("e");
+        expected3.add("c");
+        expected3.add("b");
+        expected3.add("a");
+        List<String> actual3 = graph3.visitAll();
+        assertEquals(expected3, actual3);
+
+        Graph graph4 = new Graph();
+        graph4.addVertex("f");
+        graph4.addVertex("e");
+        graph4.addVertex("d");
+        graph4.addVertex("c");
+        graph4.addVertex("a");
+        graph4.addVertex("b");
+        addEdge(graph4, "a", "b");
+        addEdge(graph4, "b", "c");
+        addEdge(graph4, "b", "d");
+        addEdge(graph4, "c", "d");
+        addEdge(graph4, "c", "e");
+        addEdge(graph4, "f", "d");
+        addEdge(graph4, "e", "f");
+
+        List<String> expected4 = new ArrayList<>();
+        expected4.add("d");
+        expected4.add("f");
+        expected4.add("e");
+        expected4.add("c");
+        expected4.add("b");
+        expected4.add("a");
+        List<String> actual4 = graph4.visitAll();
+        assertEquals(expected4, actual4);
+    }
+
+    static void addEdge(Graph graph, String v1, String v2) throws 
CycleDetectedException {
+        Vertex vx1 = graph.addVertex(v1);
+        Vertex vx2 = graph.addVertex(v2);
+        graph.addEdge(vx1, vx2);
+    }
+
+    static boolean hasEdge(Graph graph, String v1, String v2) {
+        Vertex vx1 = graph.getVertex(v1);
+        Vertex vx2 = graph.getVertex(v2);
+        return vx1 != null && vx2 != null && vx1.children.contains(vx2);
+    }
+}

Reply via email to