blob: 8a84aaf109e6acdc7ccfd84b7f41e9f19699a681 [file] [log] [blame]
// 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]);
}