diff --git a/core/includes/graph.inc b/core/includes/graph.inc
deleted file mode 100644
index 9ef86a1..0000000
--- a/core/includes/graph.inc
+++ /dev/null
@@ -1,145 +0,0 @@
-<?php
-
-/**
- * @file
- * Directed acyclic graph functions.
- */
-
-
-/**
- * Performs a depth-first sort on a directed acyclic graph.
- *
- * @param $graph
- *   A three dimensional associated array, with the first keys being the names
- *   of the vertices, these can be strings or numbers. The second key is
- *   'edges' and the third one are again vertices, each such key representing
- *   an edge. Values of array elements are copied over.
- *
- *   Example:
- *   @code
- *     $graph[1]['edges'][2] = 1;
- *     $graph[2]['edges'][3] = 1;
- *     $graph[2]['edges'][4] = 1;
- *     $graph[3]['edges'][4] = 1;
- *   @endcode
- *
- *   On return you will also have:
- *   @code
- *     $graph[1]['paths'][2] = 1;
- *     $graph[1]['paths'][3] = 1;
- *     $graph[2]['reverse_paths'][1] = 1;
- *     $graph[3]['reverse_paths'][1] = 1;
- *   @endcode
- *
- * @return
- *   The passed-in $graph with more secondary keys filled in:
- *   - 'paths': Contains a list of vertices than can be reached on a path from
- *     this vertex.
- *   - 'reverse_paths': Contains a list of vertices that has a path from them
- *     to this vertex.
- *   - 'weight': If there is a path from a vertex to another then the weight of
- *     the latter is higher.
- *   - 'component': Vertices in the same component have the same component
- *     identifier.
- *
- * @see _drupal_depth_first_search()
- */
-function drupal_depth_first_search(&$graph) {
-  $state = array(
-    // The order of last visit of the depth first search. This is the reverse
-    // of the topological order if the graph is acyclic.
-    'last_visit_order' => array(),
-    // The components of the graph.
-    'components' => array(),
-  );
-  // Perform the actual sort.
-  foreach ($graph as $start => $data) {
-    _drupal_depth_first_search($graph, $state, $start);
-  }
-
-  // We do such a numbering that every component starts with 0. This is useful
-  // for module installs as we can install every 0 weighted module in one
-  // request, and then every 1 weighted etc.
-  $component_weights = array();
-
-  foreach ($state['last_visit_order'] as $vertex) {
-    $component = $graph[$vertex]['component'];
-    if (!isset($component_weights[$component])) {
-      $component_weights[$component] = 0;
-    }
-    $graph[$vertex]['weight'] = $component_weights[$component]--;
-  }
-}
-
-/**
- * Performs a depth-first sort on a graph.
- *
- * @param $graph
- *   A three dimensional associated graph array.
- * @param $state
- *   An associative array. The key 'last_visit_order' stores a list of the
- *   vertices visited. The key components stores list of vertices belonging
- *   to the same the component.
- * @param $start
- *   An arbitrary vertex where we started traversing the graph.
- * @param $component
- *   The component of the last vertex.
- *
- * @see drupal_depth_first_search()
- */
-function _drupal_depth_first_search(&$graph, &$state, $start, &$component = NULL) {
-  // Assign new component for each new vertex, i.e. when not called recursively.
-  if (!isset($component)) {
-    $component = $start;
-  }
-  // Nothing to do, if we already visited this vertex.
-  if (isset($graph[$start]['paths'])) {
-    return;
-  }
-  // Mark $start as visited.
-  $graph[$start]['paths'] = array();
-
-  // Assign $start to the current component.
-  $graph[$start]['component'] = $component;
-  $state['components'][$component][] = $start;
-
-  // Visit edges of $start.
-  if (isset($graph[$start]['edges'])) {
-    foreach ($graph[$start]['edges'] as $end => $v) {
-      // Mark that $start can reach $end.
-      $graph[$start]['paths'][$end] = $v;
-
-      if (isset($graph[$end]['component']) && $component != $graph[$end]['component']) {
-        // This vertex already has a component, use that from now on and
-        // reassign all the previously explored vertices.
-        $new_component = $graph[$end]['component'];
-        foreach ($state['components'][$component] as $vertex) {
-          $graph[$vertex]['component'] = $new_component;
-          $state['components'][$new_component][] = $vertex;
-        }
-        unset($state['components'][$component]);
-        $component = $new_component;
-      }
-      // Only visit existing vertices.
-      if (isset($graph[$end])) {
-        // Visit the connected vertex.
-        _drupal_depth_first_search($graph, $state, $end, $component);
-
-        // All vertices reachable by $end are also reachable by $start.
-        $graph[$start]['paths'] += $graph[$end]['paths'];
-      }
-    }
-  }
-
-  // Now that any other subgraph has been explored, add $start to all reverse
-  // paths.
-  foreach ($graph[$start]['paths'] as $end => $v) {
-    if (isset($graph[$end])) {
-      $graph[$end]['reverse_paths'][$start] = $v;
-    }
-  }
-
-  // Record the order of the last visit. This is the reverse of the
-  // topological order if the graph is acyclic.
-  $state['last_visit_order'][] = $start;
-}
diff --git a/core/includes/module.inc b/core/includes/module.inc
index df9c138..0b357a1 100644
--- a/core/includes/module.inc
+++ b/core/includes/module.inc
@@ -5,6 +5,8 @@
  * API for loading and interacting with Drupal modules.
  */
 
+use Drupal\Component\Graph\Graph;
+
 /**
  * Load all the modules that have been enabled in the system table.
  *
@@ -240,7 +242,6 @@ function system_list_reset() {
  *     without this module.
  */
 function _module_build_dependencies($files) {
-  require_once DRUPAL_ROOT . '/core/includes/graph.inc';
   foreach ($files as $filename => $file) {
     $graph[$file->name]['edges'] = array();
     if (isset($file->info['dependencies']) && is_array($file->info['dependencies'])) {
@@ -250,7 +251,8 @@ function _module_build_dependencies($files) {
       }
     }
   }
-  drupal_depth_first_search($graph);
+  $graph_object = new Graph($graph);
+  $graph = $graph_object->searchAndSort();
   foreach ($graph as $module => $data) {
     $files[$module]->required_by = isset($data['reverse_paths']) ? $data['reverse_paths'] : array();
     $files[$module]->requires = isset($data['paths']) ? $data['paths'] : array();
diff --git a/core/includes/update.inc b/core/includes/update.inc
index 7a4a27d..863c994 100644
--- a/core/includes/update.inc
+++ b/core/includes/update.inc
@@ -8,6 +8,8 @@
  * installation. It is included and used extensively by update.php.
  */
 
+use Drupal\Component\Graph\Graph;
+
 /**
  * Minimum schema version of Drupal 7 required for upgrade to Drupal 8.
  *
@@ -562,7 +564,7 @@ function update_get_update_list() {
  *
  * In addition, the returned array also includes detailed information about the
  * dependency chain for each update, as provided by the depth-first search
- * algorithm in drupal_depth_first_search().
+ * algorithm in Drupal\Component\Graph\Graph::searchAndSort().
  *
  * @param $starting_updates
  *   An array whose keys contain the names of modules with updates to be run
@@ -575,10 +577,11 @@ function update_get_update_list() {
  *   request, arranged in the order in which the update functions should be
  *   run. (This includes the provided starting update for each module and all
  *   subsequent updates that are available.) The values are themselves arrays
- *   containing all the keys provided by the drupal_depth_first_search()
- *   algorithm, which encode detailed information about the dependency chain
- *   for this update function (for example: 'paths', 'reverse_paths', 'weight',
- *   and 'component'), as well as the following additional keys:
+ *   containing all the keys provided by the
+ *   Drupal\Component\Graph\Graph::searchAndSort() algorithm, which encode
+ *   detailed information about the dependency chain for this update function
+ *   (for example: 'paths', 'reverse_paths', 'weight', and 'component'), as well
+ *   as the following additional keys:
  *   - 'allowed': A boolean which is TRUE when the update function's
  *     dependencies are met, and FALSE otherwise. Calling functions should
  *     inspect this value before running the update.
@@ -588,16 +591,16 @@ function update_get_update_list() {
  *   - 'module': The name of the module that this update function belongs to.
  *   - 'number': The number of this update function within that module.
  *
- * @see drupal_depth_first_search()
+ * @see Drupal\Component\Graph\Graph::searchAndSort()
  */
 function update_resolve_dependencies($starting_updates) {
   // Obtain a dependency graph for the requested update functions.
   $update_functions = update_get_update_function_list($starting_updates);
   $graph = update_build_dependency_graph($update_functions);
 
-  // Perform the depth-first search and sort the results.
-  require_once DRUPAL_ROOT . '/core/includes/graph.inc';
-  drupal_depth_first_search($graph);
+  // Perform the depth-first search and sort on the results.
+  $graph_object = new Graph($graph);
+  $graph = $graph_object->searchAndSort();
   uasort($graph, 'drupal_sort_weight');
 
   foreach ($graph as $function => &$data) {
@@ -692,18 +695,19 @@ function update_get_update_function_list($starting_updates) {
  *
  * @return
  *   A multidimensional array representing the dependency graph, suitable for
- *   passing in to drupal_depth_first_search(), but with extra information
- *   about each update function also included. Each array key contains the name
- *   of an update function, including all update functions from the provided
- *   list as well as any outside update functions which they directly depend
- *   on. Each value is an associative array containing the following keys:
+ *   passing in to Drupal\Component\Graph\Graph::searchAndSort(), but with extra
+ *   information about each update function also included. Each array key
+ *   contains the name of an update function, including all update functions
+ *   from the provided list as well as any outside update functions which they
+ *   directly depend on. Each value is an associative array containing the
+ *   following keys:
  *   - 'edges': A representation of any other update functions that immediately
- *     depend on this one. See drupal_depth_first_search() for more details on
- *     the format.
+ *     depend on this one. See Drupal\Component\Graph\Graph::searchAndSort() for
+ *     more details on the format.
  *   - 'module': The name of the module that this update function belongs to.
  *   - 'number': The number of this update function within that module.
  *
- * @see drupal_depth_first_search()
+ * @see Drupal\Component\Graph\Graph::searchAndSort()
  * @see update_resolve_dependencies()
  */
 function update_build_dependency_graph($update_functions) {
diff --git a/core/lib/Drupal/Component/Graph/Graph.php b/core/lib/Drupal/Component/Graph/Graph.php
new file mode 100644
index 0000000..cc801e9
--- /dev/null
+++ b/core/lib/Drupal/Component/Graph/Graph.php
@@ -0,0 +1,162 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Component\Graph\Graph.
+ */
+
+namespace Drupal\Component\Graph;
+
+/**
+ * Directed acyclic graph manipulation.
+ */
+class Graph {
+
+  /**
+   * Holds the directed acyclic graph.
+   */
+  protected $graph;
+
+  /**
+   * Instantiates the depth first search object.
+   *
+   * @param $graph
+   *   A three dimensional associated array, with the first keys being the names
+   *   of the vertices, these can be strings or numbers. The second key is
+   *   'edges' and the third one are again vertices, each such key representing
+   *   an edge. Values of array elements are copied over.
+   *
+   *   Example:
+   *   @code
+   *     $graph[1]['edges'][2] = 1;
+   *     $graph[2]['edges'][3] = 1;
+   *     $graph[2]['edges'][4] = 1;
+   *     $graph[3]['edges'][4] = 1;
+   *   @endcode
+   *
+   *   On return you will also have:
+   *   @code
+   *     $graph[1]['paths'][2] = 1;
+   *     $graph[1]['paths'][3] = 1;
+   *     $graph[2]['reverse_paths'][1] = 1;
+   *     $graph[3]['reverse_paths'][1] = 1;
+   *   @endcode
+   */
+  public function __construct($graph) {
+    $this->graph = $graph;
+  }
+
+  /**
+   * Performs a depth-first search and sort on the directed acyclic graph.
+   *
+   * @return
+   *   The given $graph with more secondary keys filled in:
+   *   - 'paths': Contains a list of vertices than can be reached on a path from
+   *     this vertex.
+   *   - 'reverse_paths': Contains a list of vertices that has a path from them
+   *     to this vertex.
+   *   - 'weight': If there is a path from a vertex to another then the weight of
+   *     the latter is higher.
+   *   - 'component': Vertices in the same component have the same component
+   *     identifier.
+   */
+  public function searchAndSort() {
+    $state = array(
+      // The order of last visit of the depth first search. This is the reverse
+      // of the topological order if the graph is acyclic.
+      'last_visit_order' => array(),
+      // The components of the graph.
+      'components' => array(),
+    );
+    // Perform the actual search.
+    foreach ($this->graph as $start => $data) {
+      $this->depthFirstSearch($state, $start);
+    }
+
+    // We do such a numbering that every component starts with 0. This is useful
+    // for module installs as we can install every 0 weighted module in one
+    // request, and then every 1 weighted etc.
+    $component_weights = array();
+
+    foreach ($state['last_visit_order'] as $vertex) {
+      $component = $this->graph[$vertex]['component'];
+      if (!isset($component_weights[$component])) {
+        $component_weights[$component] = 0;
+      }
+      $this->graph[$vertex]['weight'] = $component_weights[$component]--;
+    }
+
+    return $this->graph;
+  }
+
+  /**
+   * Performs a depth-first search on a graph.
+   *
+   * @param $state
+   *   An associative array. The key 'last_visit_order' stores a list of the
+   *   vertices visited. The key components stores list of vertices belonging
+   *   to the same the component.
+   * @param $start
+   *   An arbitrary vertex where we started traversing the graph.
+   * @param $component
+   *   The component of the last vertex.
+   *
+   * @see Drupal\Component\Graph\Graph::searchAndSort()
+   */
+  protected function depthFirstSearch(&$state, $start, &$component = NULL) {
+    // Assign new component for each new vertex, i.e. when not called recursively.
+    if (!isset($component)) {
+      $component = $start;
+    }
+    // Nothing to do, if we already visited this vertex.
+    if (isset($this->graph[$start]['paths'])) {
+      return;
+    }
+    // Mark $start as visited.
+    $this->graph[$start]['paths'] = array();
+
+    // Assign $start to the current component.
+    $this->graph[$start]['component'] = $component;
+    $state['components'][$component][] = $start;
+
+    // Visit edges of $start.
+    if (isset($this->graph[$start]['edges'])) {
+      foreach ($this->graph[$start]['edges'] as $end => $v) {
+        // Mark that $start can reach $end.
+        $this->graph[$start]['paths'][$end] = $v;
+
+        if (isset($this->graph[$end]['component']) && $component != $this->graph[$end]['component']) {
+          // This vertex already has a component, use that from now on and
+          // reassign all the previously explored vertices.
+          $new_component = $this->graph[$end]['component'];
+          foreach ($state['components'][$component] as $vertex) {
+            $this->graph[$vertex]['component'] = $new_component;
+            $state['components'][$new_component][] = $vertex;
+          }
+          unset($state['components'][$component]);
+          $component = $new_component;
+        }
+        // Only visit existing vertices.
+        if (isset($this->graph[$end])) {
+          // Visit the connected vertex.
+          $this->depthFirstSearch($state, $end, $component);
+
+          // All vertices reachable by $end are also reachable by $start.
+          $this->graph[$start]['paths'] += $this->graph[$end]['paths'];
+        }
+      }
+    }
+
+    // Now that any other subgraph has been explored, add $start to all reverse
+    // paths.
+    foreach ($this->graph[$start]['paths'] as $end => $v) {
+      if (isset($this->graph[$end])) {
+        $this->graph[$end]['reverse_paths'][$start] = $v;
+      }
+    }
+
+    // Record the order of the last visit. This is the reverse of the
+    // topological order if the graph is acyclic.
+    $state['last_visit_order'][] = $start;
+  }
+}
diff --git a/core/modules/simpletest/tests/graph.test b/core/modules/simpletest/tests/graph.test
deleted file mode 100644
index e60cd39..0000000
--- a/core/modules/simpletest/tests/graph.test
+++ /dev/null
@@ -1,195 +0,0 @@
-<?php
-
-/**
- * @file
- * Provides unit tests for graph.inc.
- */
-
-/**
- * Unit tests for the graph handling features.
- */
-class GraphUnitTest extends DrupalUnitTestCase {
-  public static function getInfo() {
-    return array(
-      'name' => 'Graph',
-      'description' => 'Graph handling unit tests.',
-      'group' => 'System',
-    );
-  }
-
-  function setUp() {
-    require_once DRUPAL_ROOT . '/core/includes/graph.inc';
-    parent::setUp();
-  }
-
-  /**
-   * Test depth-first-search features.
-   */
-  function testDepthFirstSearch() {
-    // The sample graph used is:
-    // 1 --> 2 --> 3     5 ---> 6
-    //       |     ^     ^
-    //       |     |     |
-    //       |     |     |
-    //       +---> 4 <-- 7      8 ---> 9
-    $graph = $this->normalizeGraph(array(
-      1 => array(2),
-      2 => array(3, 4),
-      3 => array(),
-      4 => array(3),
-      5 => array(6),
-      7 => array(4, 5),
-      8 => array(9),
-      9 => array(),
-    ));
-    drupal_depth_first_search($graph);
-
-    $expected_paths = array(
-      1 => array(2, 3, 4),
-      2 => array(3, 4),
-      3 => array(),
-      4 => array(3),
-      5 => array(6),
-      7 => array(4, 3, 5, 6),
-      8 => array(9),
-      9 => array(),
-    );
-    $this->assertPaths($graph, $expected_paths);
-
-    $expected_reverse_paths = array(
-      1 => array(),
-      2 => array(1),
-      3 => array(2, 1, 4, 7),
-      4 => array(2, 1, 7),
-      5 => array(7),
-      7 => array(),
-      8 => array(),
-      9 => array(8),
-    );
-    $this->assertReversePaths($graph, $expected_reverse_paths);
-
-    // Assert that DFS didn't created "missing" vertexes automatically.
-    $this->assertFALSE(isset($graph[6]), t('Vertex 6 has not been created'));
-
-    $expected_components = array(
-      array(1, 2, 3, 4, 5, 7),
-      array(8, 9),
-    );
-    $this->assertComponents($graph, $expected_components);
-
-    $expected_weights = array(
-      array(1, 2, 3),
-      array(2, 4, 3),
-      array(7, 4, 3),
-      array(7, 5),
-      array(8, 9),
-    );
-    $this->assertWeights($graph, $expected_weights);
-  }
-
-  /**
-   * Return a normalized version of a graph.
-   */
-  function normalizeGraph($graph) {
-    $normalized_graph = array();
-    foreach ($graph as $vertex => $edges) {
-      // Create vertex even if it hasn't any edges.
-      $normalized_graph[$vertex] = array();
-      foreach ($edges as $edge) {
-        $normalized_graph[$vertex]['edges'][$edge] = TRUE;
-      }
-    }
-    return $normalized_graph;
-  }
-
-  /**
-   * Verify expected paths in a graph.
-   *
-   * @param $graph
-   *   A graph array processed by drupal_depth_first_search().
-   * @param $expected_paths
-   *   An associative array containing vertices with their expected paths.
-   */
-  function assertPaths($graph, $expected_paths) {
-    foreach ($expected_paths as $vertex => $paths) {
-      // Build an array with keys = $paths and values = TRUE.
-      $expected = array_fill_keys($paths, TRUE);
-      $result = isset($graph[$vertex]['paths']) ? $graph[$vertex]['paths'] : array();
-      $this->assertEqual($expected, $result, t('Expected paths for vertex @vertex: @expected-paths, got @paths', array('@vertex' => $vertex, '@expected-paths' => $this->displayArray($expected, TRUE), '@paths' => $this->displayArray($result, TRUE))));
-    }
-  }
-
-  /**
-   * Verify expected reverse paths in a graph.
-   *
-   * @param $graph
-   *   A graph array processed by drupal_depth_first_search().
-   * @param $expected_reverse_paths
-   *   An associative array containing vertices with their expected reverse
-   *   paths.
-   */
-  function assertReversePaths($graph, $expected_reverse_paths) {
-    foreach ($expected_reverse_paths as $vertex => $paths) {
-      // Build an array with keys = $paths and values = TRUE.
-      $expected = array_fill_keys($paths, TRUE);
-      $result = isset($graph[$vertex]['reverse_paths']) ? $graph[$vertex]['reverse_paths'] : array();
-      $this->assertEqual($expected, $result, t('Expected reverse paths for vertex @vertex: @expected-paths, got @paths', array('@vertex' => $vertex, '@expected-paths' => $this->displayArray($expected, TRUE), '@paths' => $this->displayArray($result, TRUE))));
-    }
-  }
-
-  /**
-   * Verify expected components in a graph.
-   *
-   * @param $graph
-   *   A graph array processed by drupal_depth_first_search().
-   * @param $expected_components
-   *   An array containing of components defined as a list of their vertices.
-   */
-  function assertComponents($graph, $expected_components) {
-    $unassigned_vertices = array_fill_keys(array_keys($graph), TRUE);
-    foreach ($expected_components as $component) {
-      $result_components = array();
-      foreach ($component as $vertex) {
-        $result_components[] = $graph[$vertex]['component'];
-        unset($unassigned_vertices[$vertex]);
-      }
-      $this->assertEqual(1, count(array_unique($result_components)), t('Expected one unique component for vertices @vertices, got @components', array('@vertices' => $this->displayArray($component), '@components' => $this->displayArray($result_components))));
-    }
-    $this->assertEqual(array(), $unassigned_vertices, t('Vertices not assigned to a component: @vertices', array('@vertices' => $this->displayArray($unassigned_vertices, TRUE))));
-  }
-
-  /**
-   * Verify expected order in a graph.
-   *
-   * @param $graph
-   *   A graph array processed by drupal_depth_first_search().
-   * @param $expected_orders
-   *   An array containing lists of vertices in their expected order.
-   */
-  function assertWeights($graph, $expected_orders) {
-    foreach ($expected_orders as $order) {
-      $previous_vertex = array_shift($order);
-      foreach ($order as $vertex) {
-        $this->assertTrue($graph[$previous_vertex]['weight'] < $graph[$vertex]['weight'], t('Weights of @previous-vertex and @vertex are correct relative to each other', array('@previous-vertex' => $previous_vertex, '@vertex' => $vertex)));
-      }
-    }
-  }
-
-  /**
-   * Helper function to output vertices as comma-separated list.
-   *
-   * @param $paths
-   *   An array containing a list of vertices.
-   * @param $keys
-   *   (optional) Whether to output the keys of $paths instead of the values.
-   */
-  function displayArray($paths, $keys = FALSE) {
-    if (!empty($paths)) {
-      return implode(', ', $keys ? array_keys($paths) : $paths);
-    }
-    else {
-      return '(empty)';
-    }
-  }
-}
-
diff --git a/core/modules/system/system.test b/core/modules/system/system.test
index 099c673..2aa1363 100644
--- a/core/modules/system/system.test
+++ b/core/modules/system/system.test
@@ -1,6 +1,7 @@
 <?php
 
 use Drupal\Core\Database\Database;
+use Drupal\Component\Graph\Graph;
 
 /**
  * @file
@@ -2590,6 +2591,193 @@ class SystemAdminTestCase extends DrupalWebTestCase {
 }
 
 /**
+ * Unit tests for the graph handling features.
+ *
+ * @see Drupal\Component\Graph\Graph
+ */
+class GraphUnitTest extends DrupalUnitTestCase {
+  public static function getInfo() {
+    return array(
+      'name' => 'Directed acyclic graph manipulation',
+      'description' => 'Depth first search and sort unit tests.',
+      'group' => 'System',
+    );
+  }
+
+  /**
+   * Test depth-first-search features.
+   */
+  function testDepthFirstSearch() {
+    // The sample graph used is:
+    // 1 --> 2 --> 3     5 ---> 6
+    //       |     ^     ^
+    //       |     |     |
+    //       |     |     |
+    //       +---> 4 <-- 7      8 ---> 9
+    $graph = $this->normalizeGraph(array(
+      1 => array(2),
+      2 => array(3, 4),
+      3 => array(),
+      4 => array(3),
+      5 => array(6),
+      7 => array(4, 5),
+      8 => array(9),
+      9 => array(),
+    ));
+    $graph_object = new Graph($graph);
+    $graph = $graph_object->searchAndSort();
+
+    $expected_paths = array(
+      1 => array(2, 3, 4),
+      2 => array(3, 4),
+      3 => array(),
+      4 => array(3),
+      5 => array(6),
+      7 => array(4, 3, 5, 6),
+      8 => array(9),
+      9 => array(),
+    );
+    $this->assertPaths($graph, $expected_paths);
+
+    $expected_reverse_paths = array(
+      1 => array(),
+      2 => array(1),
+      3 => array(2, 1, 4, 7),
+      4 => array(2, 1, 7),
+      5 => array(7),
+      7 => array(),
+      8 => array(),
+      9 => array(8),
+    );
+    $this->assertReversePaths($graph, $expected_reverse_paths);
+
+    // Assert that DFS didn't created "missing" vertexes automatically.
+    $this->assertFALSE(isset($graph[6]), t('Vertex 6 has not been created'));
+
+    $expected_components = array(
+      array(1, 2, 3, 4, 5, 7),
+      array(8, 9),
+    );
+    $this->assertComponents($graph, $expected_components);
+
+    $expected_weights = array(
+      array(1, 2, 3),
+      array(2, 4, 3),
+      array(7, 4, 3),
+      array(7, 5),
+      array(8, 9),
+    );
+    $this->assertWeights($graph, $expected_weights);
+  }
+
+  /**
+   * Return a normalized version of a graph.
+   */
+  function normalizeGraph($graph) {
+    $normalized_graph = array();
+    foreach ($graph as $vertex => $edges) {
+      // Create vertex even if it hasn't any edges.
+      $normalized_graph[$vertex] = array();
+      foreach ($edges as $edge) {
+        $normalized_graph[$vertex]['edges'][$edge] = TRUE;
+      }
+    }
+    return $normalized_graph;
+  }
+
+  /**
+   * Verify expected paths in a graph.
+   *
+   * @param $graph
+   *   A graph array processed by
+   *   Drupal\Component\Graph\Graph::searchAndSort().
+   * @param $expected_paths
+   *   An associative array containing vertices with their expected paths.
+   */
+  function assertPaths($graph, $expected_paths) {
+    foreach ($expected_paths as $vertex => $paths) {
+      // Build an array with keys = $paths and values = TRUE.
+      $expected = array_fill_keys($paths, TRUE);
+      $result = isset($graph[$vertex]['paths']) ? $graph[$vertex]['paths'] : array();
+      $this->assertEqual($expected, $result, t('Expected paths for vertex @vertex: @expected-paths, got @paths', array('@vertex' => $vertex, '@expected-paths' => $this->displayArray($expected, TRUE), '@paths' => $this->displayArray($result, TRUE))));
+    }
+  }
+
+  /**
+   * Verify expected reverse paths in a graph.
+   *
+   * @param $graph
+   *   A graph array processed by Drupal\Component\Graph\Graph::searchAndSort().
+   * @param $expected_reverse_paths
+   *   An associative array containing vertices with their expected reverse
+   *   paths.
+   */
+  function assertReversePaths($graph, $expected_reverse_paths) {
+    foreach ($expected_reverse_paths as $vertex => $paths) {
+      // Build an array with keys = $paths and values = TRUE.
+      $expected = array_fill_keys($paths, TRUE);
+      $result = isset($graph[$vertex]['reverse_paths']) ? $graph[$vertex]['reverse_paths'] : array();
+      $this->assertEqual($expected, $result, t('Expected reverse paths for vertex @vertex: @expected-paths, got @paths', array('@vertex' => $vertex, '@expected-paths' => $this->displayArray($expected, TRUE), '@paths' => $this->displayArray($result, TRUE))));
+    }
+  }
+
+  /**
+   * Verify expected components in a graph.
+   *
+   * @param $graph
+   *   A graph array processed by Drupal\Component\Graph\Graph::searchAndSort().
+   * @param $expected_components
+   *   An array containing of components defined as a list of their vertices.
+   */
+  function assertComponents($graph, $expected_components) {
+    $unassigned_vertices = array_fill_keys(array_keys($graph), TRUE);
+    foreach ($expected_components as $component) {
+      $result_components = array();
+      foreach ($component as $vertex) {
+        $result_components[] = $graph[$vertex]['component'];
+        unset($unassigned_vertices[$vertex]);
+      }
+      $this->assertEqual(1, count(array_unique($result_components)), t('Expected one unique component for vertices @vertices, got @components', array('@vertices' => $this->displayArray($component), '@components' => $this->displayArray($result_components))));
+    }
+    $this->assertEqual(array(), $unassigned_vertices, t('Vertices not assigned to a component: @vertices', array('@vertices' => $this->displayArray($unassigned_vertices, TRUE))));
+  }
+
+  /**
+   * Verify expected order in a graph.
+   *
+   * @param $graph
+   *   A graph array processed by Drupal\Component\Graph\Graph::searchAndSort().
+   * @param $expected_orders
+   *   An array containing lists of vertices in their expected order.
+   */
+  function assertWeights($graph, $expected_orders) {
+    foreach ($expected_orders as $order) {
+      $previous_vertex = array_shift($order);
+      foreach ($order as $vertex) {
+        $this->assertTrue($graph[$previous_vertex]['weight'] < $graph[$vertex]['weight'], t('Weights of @previous-vertex and @vertex are correct relative to each other', array('@previous-vertex' => $previous_vertex, '@vertex' => $vertex)));
+      }
+    }
+  }
+
+  /**
+   * Helper function to output vertices as comma-separated list.
+   *
+   * @param $paths
+   *   An array containing a list of vertices.
+   * @param $keys
+   *   (optional) Whether to output the keys of $paths instead of the values.
+   */
+  function displayArray($paths, $keys = FALSE) {
+    if (!empty($paths)) {
+      return implode(', ', $keys ? array_keys($paths) : $paths);
+    }
+    else {
+      return '(empty)';
+    }
+  }
+}
+
+/**
  * Tests authorize.php and related hooks.
  */
 class SystemAuthorizeCase extends DrupalWebTestCase {
