// 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 { final Map> graph; TestGraph(this.graph); Iterable get vertices => graph.keys; Iterable neighborsOf(String vertex) => graph[vertex]; } void test(String expected, Map> graph) { List> result = computeStrongComponents(new TestGraph(graph)); Expect.stringEquals(expected, "$result"); } void checkGraph(Map> graph, String startingNodeName, List> expectedEvaluations, List expectedSccFlags) { List> result = computeStrongComponents(new TestGraph(graph)); List> expectedReversed = >[]; for (List 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]); }