| // Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file | |
| // for details. All rights reserved. Use of this source code is governed by a | |
| // BSD-style license that can be found in the LICENSE.md file. | |
| library kernel.test.graph_test; | |
| import 'package:expect/expect.dart' show Expect; | |
| import 'package:kernel/util/graph.dart'; | |
| class TestGraph implements Graph<String> { | |
| final Map<String, List<String>> graph; | |
| TestGraph(this.graph); | |
| Iterable<String> get vertices => graph.keys; | |
| Iterable<String> neighborsOf(String vertex) => graph[vertex]; | |
| } | |
| void test(String expected, Map<String, List<String>> graph) { | |
| List<List<String>> result = computeStrongComponents(new TestGraph(graph)); | |
| Expect.stringEquals(expected, "$result"); | |
| } | |
| void checkGraph(Map<String, List<String>> graph, String startingNodeName, | |
| List<List<String>> expectedEvaluations, List<bool> expectedSccFlags) { | |
| List<List<String>> result = computeStrongComponents(new TestGraph(graph)); | |
| List<List<String>> expectedReversed = <List<String>>[]; | |
| for (List<String> list in expectedEvaluations) { | |
| expectedReversed.add(list.reversed.toList()); | |
| } | |
| Expect.stringEquals(expectedReversed.join(", "), result.join(", ")); | |
| } | |
| main() { | |
| test("[[B, A], [C], [D]]", { | |
| "A": ["B"], | |
| "B": ["A"], | |
| "C": ["A"], | |
| "D": ["C"], | |
| }); | |
| test("[]", {}); | |
| test("[[A], [B], [C], [D]]", { | |
| "A": [], | |
| "B": [], | |
| "C": [], | |
| "D": [], | |
| }); | |
| test("[[B, A], [C], [D]]", { | |
| "D": ["C"], | |
| "C": ["A"], | |
| "B": ["A"], | |
| "A": ["B"], | |
| }); | |
| test("[[D], [C], [B], [A]]", { | |
| "A": ["B"], | |
| "B": ["C"], | |
| "C": ["D"], | |
| "D": [], | |
| }); | |
| test("[[D], [C], [B], [A]]", { | |
| "D": [], | |
| "C": ["D"], | |
| "B": ["C"], | |
| "A": ["B"], | |
| }); | |
| test("[[A], [B], [C], [D]]", { | |
| "A": [], | |
| "B": ["A"], | |
| "C": ["A"], | |
| "D": ["B", "C"], | |
| }); | |
| // Test a complex graph. | |
| checkGraph( | |
| { | |
| 'a': ['b', 'c'], | |
| 'b': ['c', 'd'], | |
| 'c': [], | |
| 'd': ['c', 'e'], | |
| 'e': ['b', 'f'], | |
| 'f': ['c', 'd'] | |
| }, | |
| 'a', | |
| [ | |
| ['c'], | |
| ['b', 'd', 'e', 'f'], | |
| ['a'] | |
| ], | |
| [false, true, false]); | |
| // Test a diamond-shaped graph. | |
| checkGraph( | |
| { | |
| 'a': ['b', 'c'], | |
| 'b': ['d'], | |
| 'c': ['d'], | |
| 'd': [] | |
| }, | |
| 'a', | |
| [ | |
| ['d'], | |
| ['b'], | |
| ['c'], | |
| ['a'] | |
| ], | |
| [false, false, false, false]); | |
| // Test a graph with a single node. | |
| checkGraph( | |
| {'a': []}, | |
| 'a', | |
| [ | |
| ['a'] | |
| ], | |
| [false]); | |
| // Test a graph with a single node and a trivial cycle. | |
| checkGraph( | |
| { | |
| 'a': ['a'] | |
| }, | |
| 'a', | |
| [ | |
| ['a'] | |
| ], | |
| [true]); | |
| // Test a graph with three nodes with circular dependencies. | |
| checkGraph( | |
| { | |
| 'a': ['b'], | |
| 'b': ['c'], | |
| 'c': ['a'], | |
| }, | |
| 'a', | |
| [ | |
| ['a', 'b', 'c'] | |
| ], | |
| [true]); | |
| // Test a graph A->B->C->D, where D points back to B and then C. | |
| checkGraph( | |
| { | |
| 'a': ['b'], | |
| 'b': ['c'], | |
| 'c': ['d'], | |
| 'd': ['b', 'c'] | |
| }, | |
| 'a', | |
| [ | |
| ['b', 'c', 'd'], | |
| ['a'] | |
| ], | |
| [true, false]); | |
| // Test a graph A->B->C->D, where D points back to C and then B. | |
| checkGraph( | |
| { | |
| 'a': ['b'], | |
| 'b': ['c'], | |
| 'c': ['d'], | |
| 'd': ['c', 'b'] | |
| }, | |
| 'a', | |
| [ | |
| ['b', 'c', 'd'], | |
| ['a'] | |
| ], | |
| [true, false]); | |
| // Test a graph with two nodes with circular dependencies. | |
| checkGraph( | |
| { | |
| 'a': ['b'], | |
| 'b': ['a'] | |
| }, | |
| 'a', | |
| [ | |
| ['a', 'b'] | |
| ], | |
| [true]); | |
| // Test a graph with two nodes and a single dependency. | |
| checkGraph( | |
| { | |
| 'a': ['b'], | |
| 'b': [] | |
| }, | |
| 'a', | |
| [ | |
| ['b'], | |
| ['a'] | |
| ], | |
| [false, false]); | |
| } |