1 //===- llvm/unittest/ADT/DirectedGraphTest.cpp ------------------*- C++ -*-===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 // This file defines concrete derivations of the directed-graph base classes
10 // for testing purposes.
12 //===----------------------------------------------------------------------===//
14 #include "llvm/ADT/DirectedGraph.h"
15 #include "llvm/ADT/GraphTraits.h"
16 #include "llvm/ADT/SCCIterator.h"
17 #include "llvm/ADT/SmallPtrSet.h"
18 #include "gtest/gtest.h"
22 //===--------------------------------------------------------------------===//
23 // Derived nodes, edges and graph types based on DirectedGraph.
24 //===--------------------------------------------------------------------===//
28 using DGTestNodeBase
= DGNode
<DGTestNode
, DGTestEdge
>;
29 using DGTestEdgeBase
= DGEdge
<DGTestNode
, DGTestEdge
>;
30 using DGTestBase
= DirectedGraph
<DGTestNode
, DGTestEdge
>;
32 class DGTestNode
: public DGTestNodeBase
{
34 DGTestNode() = default;
37 class DGTestEdge
: public DGTestEdgeBase
{
39 DGTestEdge() = delete;
40 DGTestEdge(DGTestNode
&N
) : DGTestEdgeBase(N
) {}
43 class DGTestGraph
: public DGTestBase
{
45 DGTestGraph() = default;
49 using EdgeListTy
= SmallVector
<DGTestEdge
*, 2>;
51 //===--------------------------------------------------------------------===//
52 // GraphTraits specializations for the DGTest
53 //===--------------------------------------------------------------------===//
55 template <> struct GraphTraits
<DGTestNode
*> {
56 using NodeRef
= DGTestNode
*;
58 static DGTestNode
*DGTestGetTargetNode(DGEdge
<DGTestNode
, DGTestEdge
> *P
) {
59 return &P
->getTargetNode();
62 // Provide a mapped iterator so that the GraphTrait-based implementations can
63 // find the target nodes without having to explicitly go through the edges.
64 using ChildIteratorType
=
65 mapped_iterator
<DGTestNode::iterator
, decltype(&DGTestGetTargetNode
)>;
66 using ChildEdgeIteratorType
= DGTestNode::iterator
;
68 static NodeRef
getEntryNode(NodeRef N
) { return N
; }
69 static ChildIteratorType
child_begin(NodeRef N
) {
70 return ChildIteratorType(N
->begin(), &DGTestGetTargetNode
);
72 static ChildIteratorType
child_end(NodeRef N
) {
73 return ChildIteratorType(N
->end(), &DGTestGetTargetNode
);
76 static ChildEdgeIteratorType
child_edge_begin(NodeRef N
) {
79 static ChildEdgeIteratorType
child_edge_end(NodeRef N
) { return N
->end(); }
83 struct GraphTraits
<DGTestGraph
*> : public GraphTraits
<DGTestNode
*> {
84 using nodes_iterator
= DGTestGraph::iterator
;
85 static NodeRef
getEntryNode(DGTestGraph
*DG
) { return *DG
->begin(); }
86 static nodes_iterator
nodes_begin(DGTestGraph
*DG
) { return DG
->begin(); }
87 static nodes_iterator
nodes_end(DGTestGraph
*DG
) { return DG
->end(); }
90 //===--------------------------------------------------------------------===//
91 // Test various modification and query functions.
92 //===--------------------------------------------------------------------===//
94 TEST(DirectedGraphTest
, AddAndConnectNodes
) {
96 DGTestNode N1
, N2
, N3
;
97 DGTestEdge
E1(N1
), E2(N2
), E3(N3
);
99 // Check that new nodes can be added successfully.
100 EXPECT_TRUE(DG
.addNode(N1
));
101 EXPECT_TRUE(DG
.addNode(N2
));
102 EXPECT_TRUE(DG
.addNode(N3
));
104 // Check that duplicate nodes are not added to the graph.
105 EXPECT_FALSE(DG
.addNode(N1
));
107 // Check that nodes can be connected using valid edges with no errors.
108 EXPECT_TRUE(DG
.connect(N1
, N2
, E2
));
109 EXPECT_TRUE(DG
.connect(N2
, N3
, E3
));
110 EXPECT_TRUE(DG
.connect(N3
, N1
, E1
));
112 // The graph looks like this now:
118 // Check that already connected nodes with the given edge are not connected
119 // again (ie. edges are between nodes are not duplicated).
120 EXPECT_FALSE(DG
.connect(N3
, N1
, E1
));
122 // Check that there are 3 nodes in the graph.
123 EXPECT_TRUE(DG
.size() == 3);
125 // Check that the added nodes can be found in the graph.
126 EXPECT_NE(DG
.findNode(N3
), DG
.end());
128 // Check that nodes that are not part of the graph are not found.
130 EXPECT_EQ(DG
.findNode(N4
), DG
.end());
132 // Check that findIncommingEdgesToNode works correctly.
134 EXPECT_TRUE(DG
.findIncomingEdgesToNode(N1
, EL
));
135 EXPECT_TRUE(EL
.size() == 1);
136 EXPECT_EQ(*EL
[0], E1
);
139 TEST(DirectedGraphTest
, AddRemoveEdge
) {
141 DGTestNode N1
, N2
, N3
;
142 DGTestEdge
E1(N1
), E2(N2
), E3(N3
);
146 DG
.connect(N1
, N2
, E2
);
147 DG
.connect(N2
, N3
, E3
);
148 DG
.connect(N3
, N1
, E1
);
150 // The graph looks like this now:
156 // Check that there are 3 nodes in the graph.
157 EXPECT_TRUE(DG
.size() == 3);
159 // Check that the target nodes of the edges are correct.
160 EXPECT_EQ(E1
.getTargetNode(), N1
);
161 EXPECT_EQ(E2
.getTargetNode(), N2
);
162 EXPECT_EQ(E3
.getTargetNode(), N3
);
164 // Remove the edge from N1 to N2.
167 // The graph looks like this now:
171 // Check that there are no incoming edges to N2.
173 EXPECT_FALSE(DG
.findIncomingEdgesToNode(N2
, EL
));
174 EXPECT_TRUE(EL
.empty());
176 // Put the edge from N1 to N2 back in place.
179 // Check that E2 is the only incoming edge to N2.
181 EXPECT_TRUE(DG
.findIncomingEdgesToNode(N2
, EL
));
182 EXPECT_EQ(*EL
[0], E2
);
185 TEST(DirectedGraphTest
, hasEdgeTo
) {
187 DGTestNode N1
, N2
, N3
;
188 DGTestEdge
E1(N1
), E2(N2
), E3(N3
), E4(N1
);
192 DG
.connect(N1
, N2
, E2
);
193 DG
.connect(N2
, N3
, E3
);
194 DG
.connect(N3
, N1
, E1
);
195 DG
.connect(N2
, N1
, E4
);
197 // The graph looks like this now:
205 EXPECT_TRUE(N2
.hasEdgeTo(N1
));
206 EXPECT_TRUE(N3
.hasEdgeTo(N1
));
209 TEST(DirectedGraphTest
, AddRemoveNode
) {
211 DGTestNode N1
, N2
, N3
;
212 DGTestEdge
E1(N1
), E2(N2
), E3(N3
);
216 DG
.connect(N1
, N2
, E2
);
217 DG
.connect(N2
, N3
, E3
);
218 DG
.connect(N3
, N1
, E1
);
220 // The graph looks like this now:
226 // Check that there are 3 nodes in the graph.
227 EXPECT_TRUE(DG
.size() == 3);
229 // Check that a node in the graph can be removed, but not more than once.
230 EXPECT_TRUE(DG
.removeNode(N1
));
231 EXPECT_EQ(DG
.findNode(N1
), DG
.end());
232 EXPECT_FALSE(DG
.removeNode(N1
));
234 // The graph looks like this now:
238 // Check that there are 2 nodes in the graph and only N2 is connected to N3.
239 EXPECT_TRUE(DG
.size() == 2);
240 EXPECT_TRUE(N3
.getEdges().empty());
242 EXPECT_FALSE(DG
.findIncomingEdgesToNode(N2
, EL
));
243 EXPECT_TRUE(EL
.empty());
246 TEST(DirectedGraphTest
, SCC
) {
249 DGTestNode N1
, N2
, N3
, N4
;
250 DGTestEdge
E1(N1
), E2(N2
), E3(N3
), E4(N4
);
255 DG
.connect(N1
, N2
, E2
);
256 DG
.connect(N2
, N3
, E3
);
257 DG
.connect(N3
, N1
, E1
);
258 DG
.connect(N3
, N4
, E4
);
260 // The graph looks like this now:
264 // N1 -> N2 -> N3 -+ N4
268 // Test that there are two SCCs:
271 using NodeListTy
= SmallPtrSet
<DGTestNode
*, 3>;
272 SmallVector
<NodeListTy
, 4> ListOfSCCs
;
273 for (auto &SCC
: make_range(scc_begin(&DG
), scc_end(&DG
)))
274 ListOfSCCs
.push_back(NodeListTy(SCC
.begin(), SCC
.end()));
276 EXPECT_TRUE(ListOfSCCs
.size() == 2);
278 for (auto &SCC
: ListOfSCCs
) {
281 EXPECT_TRUE(SCC
.size() == 1);
282 EXPECT_TRUE(SCC
.count(&N4
) == 1);
284 for (auto &SCC
: ListOfSCCs
) {
287 EXPECT_TRUE(SCC
.size() == 3);
288 EXPECT_TRUE(SCC
.count(&N1
) == 1);
289 EXPECT_TRUE(SCC
.count(&N2
) == 1);
290 EXPECT_TRUE(SCC
.count(&N3
) == 1);
291 EXPECT_TRUE(SCC
.count(&N4
) == 0);