golang.org/toolchain@v0.0.1-go1.9rc2.windows-amd64/src/cmd/vendor/github.com/google/pprof/internal/graph/graph_test.go (about) 1 package graph 2 3 import ( 4 "fmt" 5 "testing" 6 ) 7 8 func edgeDebugString(edge *Edge) string { 9 debug := "" 10 debug += fmt.Sprintf("\t\tSrc: %p\n", edge.Src) 11 debug += fmt.Sprintf("\t\tDest: %p\n", edge.Dest) 12 debug += fmt.Sprintf("\t\tWeight: %d\n", edge.Weight) 13 debug += fmt.Sprintf("\t\tResidual: %t\n", edge.Residual) 14 debug += fmt.Sprintf("\t\tInline: %t\n", edge.Inline) 15 return debug 16 } 17 18 func edgeMapsDebugString(in, out EdgeMap) string { 19 debug := "" 20 debug += "In Edges:\n" 21 for parent, edge := range in { 22 debug += fmt.Sprintf("\tParent: %p\n", parent) 23 debug += edgeDebugString(edge) 24 } 25 debug += "Out Edges:\n" 26 for child, edge := range out { 27 debug += fmt.Sprintf("\tChild: %p\n", child) 28 debug += edgeDebugString(edge) 29 } 30 return debug 31 } 32 33 func graphDebugString(graph *Graph) string { 34 debug := "" 35 for i, node := range graph.Nodes { 36 debug += fmt.Sprintf("Node %d: %p\n", i, node) 37 } 38 39 for i, node := range graph.Nodes { 40 debug += "\n" 41 debug += fmt.Sprintf("=== Node %d: %p ===\n", i, node) 42 debug += edgeMapsDebugString(node.In, node.Out) 43 } 44 return debug 45 } 46 47 func expectedNodesDebugString(expected []expectedNode) string { 48 debug := "" 49 for i, node := range expected { 50 debug += fmt.Sprintf("Node %d: %p\n", i, node.node) 51 } 52 53 for i, node := range expected { 54 debug += "\n" 55 debug += fmt.Sprintf("=== Node %d: %p ===\n", i, node.node) 56 debug += edgeMapsDebugString(node.in, node.out) 57 } 58 return debug 59 } 60 61 // edgeMapsEqual checks if all the edges in this equal all the edges in that. 62 func edgeMapsEqual(this, that EdgeMap) bool { 63 if len(this) != len(that) { 64 return false 65 } 66 for node, thisEdge := range this { 67 if *thisEdge != *that[node] { 68 return false 69 } 70 } 71 return true 72 } 73 74 // nodesEqual checks if node is equal to expected. 75 func nodesEqual(node *Node, expected expectedNode) bool { 76 return node == expected.node && edgeMapsEqual(node.In, expected.in) && 77 edgeMapsEqual(node.Out, expected.out) 78 } 79 80 // graphsEqual checks if graph is equivalent to the graph templated by expected. 81 func graphsEqual(graph *Graph, expected []expectedNode) bool { 82 if len(graph.Nodes) != len(expected) { 83 return false 84 } 85 expectedSet := make(map[*Node]expectedNode) 86 for i := range expected { 87 expectedSet[expected[i].node] = expected[i] 88 } 89 90 for _, node := range graph.Nodes { 91 expectedNode, found := expectedSet[node] 92 if !found || !nodesEqual(node, expectedNode) { 93 return false 94 } 95 } 96 return true 97 } 98 99 type expectedNode struct { 100 node *Node 101 in, out EdgeMap 102 } 103 104 type trimTreeTestcase struct { 105 initial *Graph 106 expected []expectedNode 107 keep NodePtrSet 108 } 109 110 // makeExpectedEdgeResidual makes the edge from parent to child residual. 111 func makeExpectedEdgeResidual(parent, child expectedNode) { 112 parent.out[child.node].Residual = true 113 child.in[parent.node].Residual = true 114 } 115 116 func makeEdgeInline(edgeMap EdgeMap, node *Node) { 117 edgeMap[node].Inline = true 118 } 119 120 func setEdgeWeight(edgeMap EdgeMap, node *Node, weight int64) { 121 edgeMap[node].Weight = weight 122 } 123 124 // createEdges creates directed edges from the parent to each of the children. 125 func createEdges(parent *Node, children ...*Node) { 126 for _, child := range children { 127 edge := &Edge{ 128 Src: parent, 129 Dest: child, 130 } 131 parent.Out[child] = edge 132 child.In[parent] = edge 133 } 134 } 135 136 // createEmptyNode creates a node without any edges. 137 func createEmptyNode() *Node { 138 return &Node{ 139 In: make(EdgeMap), 140 Out: make(EdgeMap), 141 } 142 } 143 144 // createExpectedNodes creates a slice of expectedNodes from nodes. 145 func createExpectedNodes(nodes ...*Node) ([]expectedNode, NodePtrSet) { 146 expected := make([]expectedNode, len(nodes)) 147 keep := make(NodePtrSet, len(nodes)) 148 149 for i, node := range nodes { 150 expected[i] = expectedNode{ 151 node: node, 152 in: make(EdgeMap), 153 out: make(EdgeMap), 154 } 155 keep[node] = true 156 } 157 158 return expected, keep 159 } 160 161 // createExpectedEdges creates directed edges from the parent to each of the 162 // children. 163 func createExpectedEdges(parent expectedNode, children ...expectedNode) { 164 for _, child := range children { 165 edge := &Edge{ 166 Src: parent.node, 167 Dest: child.node, 168 } 169 parent.out[child.node] = edge 170 child.in[parent.node] = edge 171 } 172 } 173 174 // createTestCase1 creates a test case that initally looks like: 175 // 0 176 // |(5) 177 // 1 178 // (3)/ \(4) 179 // 2 3. 180 // 181 // After keeping 0, 2, and 3, it expects the graph: 182 // 0 183 // (3)/ \(4) 184 // 2 3. 185 func createTestCase1() trimTreeTestcase { 186 // Create initial graph 187 graph := &Graph{make(Nodes, 4)} 188 nodes := graph.Nodes 189 for i := range nodes { 190 nodes[i] = createEmptyNode() 191 } 192 createEdges(nodes[0], nodes[1]) 193 createEdges(nodes[1], nodes[2], nodes[3]) 194 makeEdgeInline(nodes[0].Out, nodes[1]) 195 makeEdgeInline(nodes[1].Out, nodes[2]) 196 setEdgeWeight(nodes[0].Out, nodes[1], 5) 197 setEdgeWeight(nodes[1].Out, nodes[2], 3) 198 setEdgeWeight(nodes[1].Out, nodes[3], 4) 199 200 // Create expected graph 201 expected, keep := createExpectedNodes(nodes[0], nodes[2], nodes[3]) 202 createExpectedEdges(expected[0], expected[1], expected[2]) 203 makeEdgeInline(expected[0].out, expected[1].node) 204 makeExpectedEdgeResidual(expected[0], expected[1]) 205 makeExpectedEdgeResidual(expected[0], expected[2]) 206 setEdgeWeight(expected[0].out, expected[1].node, 3) 207 setEdgeWeight(expected[0].out, expected[2].node, 4) 208 return trimTreeTestcase{ 209 initial: graph, 210 expected: expected, 211 keep: keep, 212 } 213 } 214 215 // createTestCase2 creates a test case that initially looks like: 216 // 3 217 // | (12) 218 // 1 219 // | (8) 220 // 2 221 // | (15) 222 // 0 223 // | (10) 224 // 4. 225 // 226 // After keeping 3 and 4, it expects the graph: 227 // 3 228 // | (10) 229 // 4. 230 func createTestCase2() trimTreeTestcase { 231 // Create initial graph 232 graph := &Graph{make(Nodes, 5)} 233 nodes := graph.Nodes 234 for i := range nodes { 235 nodes[i] = createEmptyNode() 236 } 237 createEdges(nodes[3], nodes[1]) 238 createEdges(nodes[1], nodes[2]) 239 createEdges(nodes[2], nodes[0]) 240 createEdges(nodes[0], nodes[4]) 241 setEdgeWeight(nodes[3].Out, nodes[1], 12) 242 setEdgeWeight(nodes[1].Out, nodes[2], 8) 243 setEdgeWeight(nodes[2].Out, nodes[0], 15) 244 setEdgeWeight(nodes[0].Out, nodes[4], 10) 245 246 // Create expected graph 247 expected, keep := createExpectedNodes(nodes[3], nodes[4]) 248 createExpectedEdges(expected[0], expected[1]) 249 makeExpectedEdgeResidual(expected[0], expected[1]) 250 setEdgeWeight(expected[0].out, expected[1].node, 10) 251 return trimTreeTestcase{ 252 initial: graph, 253 expected: expected, 254 keep: keep, 255 } 256 } 257 258 // createTestCase3 creates an initally empty graph and expects an empty graph 259 // after trimming. 260 func createTestCase3() trimTreeTestcase { 261 graph := &Graph{make(Nodes, 0)} 262 expected, keep := createExpectedNodes() 263 return trimTreeTestcase{ 264 initial: graph, 265 expected: expected, 266 keep: keep, 267 } 268 } 269 270 // createTestCase4 creates a test case that initially looks like: 271 // 0. 272 // 273 // After keeping 0, it expects the graph: 274 // 0. 275 func createTestCase4() trimTreeTestcase { 276 graph := &Graph{make(Nodes, 1)} 277 nodes := graph.Nodes 278 for i := range nodes { 279 nodes[i] = createEmptyNode() 280 } 281 expected, keep := createExpectedNodes(nodes[0]) 282 return trimTreeTestcase{ 283 initial: graph, 284 expected: expected, 285 keep: keep, 286 } 287 } 288 289 func createTrimTreeTestCases() []trimTreeTestcase { 290 caseGenerators := []func() trimTreeTestcase{ 291 createTestCase1, 292 createTestCase2, 293 createTestCase3, 294 createTestCase4, 295 } 296 cases := make([]trimTreeTestcase, len(caseGenerators)) 297 for i, gen := range caseGenerators { 298 cases[i] = gen() 299 } 300 return cases 301 } 302 303 func TestTrimTree(t *testing.T) { 304 tests := createTrimTreeTestCases() 305 for _, test := range tests { 306 graph := test.initial 307 graph.TrimTree(test.keep) 308 if !graphsEqual(graph, test.expected) { 309 t.Fatalf("Graphs do not match.\nExpected: %s\nFound: %s\n", 310 expectedNodesDebugString(test.expected), 311 graphDebugString(graph)) 312 } 313 } 314 }