github.com/gopherd/gonum@v0.0.4/graph/testgraph/testgraph.go (about) 1 // Copyright ©2018 The Gonum Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // Package testgraph provides a set of testing helper functions 6 // that test Gonum graph interface implementations. 7 package testgraph // import "github.com/gopherd/gonum/graph/testgraph" 8 9 import ( 10 "fmt" 11 "reflect" 12 "sort" 13 "testing" 14 15 "math/rand" 16 17 "github.com/gopherd/gonum/floats/scalar" 18 "github.com/gopherd/gonum/graph" 19 "github.com/gopherd/gonum/graph/internal/ordered" 20 "github.com/gopherd/gonum/graph/internal/set" 21 "github.com/gopherd/gonum/mat" 22 ) 23 24 // BUG(kortschak): Edge equality is tested in part with reflect.DeepEqual and 25 // direct equality of weight values. This means that edges returned by graphs 26 // must not contain NaN values. Weights returned by the Weight method are 27 // compared with NaN-awareness, so they may be NaN when there is no edge 28 // associated with the Weight call. 29 30 func isValidIterator(it graph.Iterator) bool { 31 return it != nil 32 } 33 34 func checkEmptyIterator(t *testing.T, it graph.Iterator, useEmpty bool) { 35 t.Helper() 36 37 if it.Len() != 0 { 38 return 39 } 40 if it != graph.Empty { 41 if useEmpty { 42 t.Errorf("unexpected empty iterator: got:%T", it) 43 return 44 } 45 // Only log this since we say that a graph should 46 // return a graph.Empty when it is empty. 47 t.Logf("unexpected empty iterator: got:%T", it) 48 } 49 } 50 51 func hasEnds(x, y graph.Node, e Edge) bool { 52 return (e.From().ID() == x.ID() && e.To().ID() == y.ID()) || 53 (e.From().ID() == y.ID() && e.To().ID() == x.ID()) 54 } 55 56 // Edge supports basic edge operations. 57 type Edge interface { 58 // From returns the from node of the edge. 59 From() graph.Node 60 61 // To returns the to node of the edge. 62 To() graph.Node 63 } 64 65 // WeightedLine is a generalized graph edge that supports all graph 66 // edge operations except reversal. 67 type WeightedLine interface { 68 Edge 69 70 // ID returns the unique ID for the Line. 71 ID() int64 72 73 // Weight returns the weight of the edge. 74 Weight() float64 75 } 76 77 // A Builder function returns a graph constructed from the nodes, edges and 78 // default weights passed in, potentially altering the nodes and edges to 79 // conform to the requirements of the graph. The graph is returned along with 80 // the nodes, edges and default weights used to construct the graph. 81 // The returned edges may be any of graph.Edge, graph.WeightedEdge, graph.Line 82 // or graph.WeightedLine depending on what the graph requires. 83 // The client may skip a test case by returning ok=false when the input is not 84 // a valid graph construction. 85 type Builder func(nodes []graph.Node, edges []WeightedLine, self, absent float64) (g graph.Graph, n []graph.Node, e []Edge, s, a float64, ok bool) 86 87 // edgeLister is a graph that can return all its edges. 88 type edgeLister interface { 89 // Edges returns all the edges of a graph. 90 Edges() graph.Edges 91 } 92 93 // weightedEdgeLister is a graph that can return all its weighted edges. 94 type weightedEdgeLister interface { 95 // WeightedEdges returns all the weighted edges of a graph. 96 WeightedEdges() graph.WeightedEdges 97 } 98 99 // matrixer is a graph that can return an adjacency matrix. 100 type matrixer interface { 101 // Matrix returns the graph's adjacency matrix. 102 Matrix() mat.Matrix 103 } 104 105 // ReturnAllNodes tests the constructed graph for the ability to return all 106 // the nodes it claims it has used in its construction. This is a check of 107 // the Nodes method of graph.Graph and the iterator that is returned. 108 // If useEmpty is true, graph iterators will be checked for the use of 109 // graph.Empty if they are empty. 110 func ReturnAllNodes(t *testing.T, b Builder, useEmpty bool) { 111 for _, test := range testCases { 112 g, want, _, _, _, ok := b(test.nodes, test.edges, test.self, test.absent) 113 if !ok { 114 t.Logf("skipping test case: %q", test.name) 115 continue 116 } 117 118 it := g.Nodes() 119 if !isValidIterator(it) { 120 t.Errorf("invalid iterator for test %q: got:%#v", test.name, it) 121 continue 122 } 123 checkEmptyIterator(t, it, useEmpty) 124 var got []graph.Node 125 for it.Next() { 126 got = append(got, it.Node()) 127 } 128 129 ordered.ByID(got) 130 ordered.ByID(want) 131 132 if !reflect.DeepEqual(got, want) { 133 t.Errorf("unexpected nodes result for test %q:\ngot: %v\nwant:%v", test.name, got, want) 134 } 135 } 136 } 137 138 // ReturnNodeSlice tests the constructed graph for the ability to return all 139 // the nodes it claims it has used in its construction using the NodeSlicer 140 // interface. This is a check of the Nodes method of graph.Graph and the 141 // iterator that is returned. 142 // If useEmpty is true, graph iterators will be checked for the use of 143 // graph.Empty if they are empty. 144 func ReturnNodeSlice(t *testing.T, b Builder, useEmpty bool) { 145 for _, test := range testCases { 146 g, want, _, _, _, ok := b(test.nodes, test.edges, test.self, test.absent) 147 if !ok { 148 t.Logf("skipping test case: %q", test.name) 149 continue 150 } 151 152 it := g.Nodes() 153 if !isValidIterator(it) { 154 t.Errorf("invalid iterator for test %q: got:%#v", test.name, it) 155 continue 156 } 157 checkEmptyIterator(t, it, useEmpty) 158 if it == nil { 159 continue 160 } 161 s, ok := it.(graph.NodeSlicer) 162 if !ok { 163 t.Errorf("invalid type for test %q: %T cannot return node slicer", test.name, g) 164 continue 165 } 166 got := s.NodeSlice() 167 168 ordered.ByID(got) 169 ordered.ByID(want) 170 171 if !reflect.DeepEqual(got, want) { 172 t.Errorf("unexpected nodes result for test %q:\ngot: %v\nwant:%v", test.name, got, want) 173 } 174 } 175 } 176 177 // NodeExistence tests the constructed graph for the ability to correctly 178 // return the existence of nodes within the graph. This is a check of the 179 // Node method of graph.Graph. 180 func NodeExistence(t *testing.T, b Builder) { 181 for _, test := range testCases { 182 g, want, _, _, _, ok := b(test.nodes, test.edges, test.self, test.absent) 183 if !ok { 184 t.Logf("skipping test case: %q", test.name) 185 continue 186 } 187 188 seen := set.NewNodes() 189 for _, exist := range want { 190 seen.Add(exist) 191 if g.Node(exist.ID()) == nil { 192 t.Errorf("missing node for test %q: %v", test.name, exist) 193 } 194 } 195 for _, ghost := range test.nonexist { 196 if g.Node(ghost.ID()) != nil { 197 if seen.Has(ghost) { 198 // Do not fail nodes that the graph builder says can exist 199 // even if the test case input thinks they should not. 200 t.Logf("builder has modified non-exist node set: %v is now allowed and present", ghost) 201 continue 202 } 203 t.Errorf("unexpected node for test %q: %v", test.name, ghost) 204 } 205 } 206 } 207 } 208 209 // ReturnAllEdges tests the constructed graph for the ability to return all 210 // the edges it claims it has used in its construction. This is a check of 211 // the Edges method of graph.Graph and the iterator that is returned. 212 // ReturnAllEdges also checks that the edge end nodes exist within the graph, 213 // checking the Node method of graph.Graph. 214 // If useEmpty is true, graph iterators will be checked for the use of 215 // graph.Empty if they are empty. 216 func ReturnAllEdges(t *testing.T, b Builder, useEmpty bool) { 217 for _, test := range testCases { 218 g, _, want, _, _, ok := b(test.nodes, test.edges, test.self, test.absent) 219 if !ok { 220 t.Logf("skipping test case: %q", test.name) 221 continue 222 } 223 224 var got []Edge 225 switch eg := g.(type) { 226 case edgeLister: 227 it := eg.Edges() 228 if !isValidIterator(it) { 229 t.Errorf("invalid iterator for test %q: got:%#v", test.name, it) 230 continue 231 } 232 checkEmptyIterator(t, it, useEmpty) 233 for it.Next() { 234 e := it.Edge() 235 got = append(got, e) 236 qe := g.Edge(e.From().ID(), e.To().ID()) 237 if qe == nil { 238 t.Errorf("missing edge for test %q: %v", test.name, e) 239 } else if qe.From().ID() != e.From().ID() || qe.To().ID() != e.To().ID() { 240 t.Errorf("inverted edge for test %q query with F=%d T=%d: got:%#v", 241 test.name, e.From().ID(), e.To().ID(), qe) 242 } 243 if g.Node(e.From().ID()) == nil { 244 t.Errorf("missing from node for test %q: %v", test.name, e.From().ID()) 245 } 246 if g.Node(e.To().ID()) == nil { 247 t.Errorf("missing to node for test %q: %v", test.name, e.To().ID()) 248 } 249 } 250 251 default: 252 t.Errorf("invalid type for test %q: %T cannot return edge iterator", test.name, g) 253 continue 254 } 255 256 checkEdges(t, test.name, g, got, want) 257 } 258 } 259 260 // ReturnEdgeSlice tests the constructed graph for the ability to return all 261 // the edges it claims it has used in its construction using the EdgeSlicer 262 // interface. This is a check of the Edges method of graph.Graph and the 263 // iterator that is returned. ReturnEdgeSlice also checks that the edge end 264 // nodes exist within the graph, checking the Node method of graph.Graph. 265 // If useEmpty is true, graph iterators will be checked for the use of 266 // graph.Empty if they are empty. 267 func ReturnEdgeSlice(t *testing.T, b Builder, useEmpty bool) { 268 for _, test := range testCases { 269 g, _, want, _, _, ok := b(test.nodes, test.edges, test.self, test.absent) 270 if !ok { 271 t.Logf("skipping test case: %q", test.name) 272 continue 273 } 274 275 var got []Edge 276 switch eg := g.(type) { 277 case edgeLister: 278 it := eg.Edges() 279 if !isValidIterator(it) { 280 t.Errorf("invalid iterator for test %q: got:%#v", test.name, it) 281 continue 282 } 283 checkEmptyIterator(t, it, useEmpty) 284 if it == nil { 285 continue 286 } 287 s, ok := it.(graph.EdgeSlicer) 288 if !ok { 289 t.Errorf("invalid type for test %q: %T cannot return edge slicer", test.name, g) 290 continue 291 } 292 gotNative := s.EdgeSlice() 293 if len(gotNative) != 0 { 294 got = make([]Edge, len(gotNative)) 295 } 296 for i, e := range gotNative { 297 got[i] = e 298 299 qe := g.Edge(e.From().ID(), e.To().ID()) 300 if qe == nil { 301 t.Errorf("missing edge for test %q: %v", test.name, e) 302 } else if qe.From().ID() != e.From().ID() || qe.To().ID() != e.To().ID() { 303 t.Errorf("inverted edge for test %q query with F=%d T=%d: got:%#v", 304 test.name, e.From().ID(), e.To().ID(), qe) 305 } 306 if g.Node(e.From().ID()) == nil { 307 t.Errorf("missing from node for test %q: %v", test.name, e.From().ID()) 308 } 309 if g.Node(e.To().ID()) == nil { 310 t.Errorf("missing to node for test %q: %v", test.name, e.To().ID()) 311 } 312 } 313 314 default: 315 t.Errorf("invalid type for test %T: cannot return edge iterator", g) 316 continue 317 } 318 319 checkEdges(t, test.name, g, got, want) 320 } 321 } 322 323 // ReturnAllLines tests the constructed graph for the ability to return all 324 // the edges it claims it has used in its construction and then recover all 325 // the lines that contribute to those edges. This is a check of the Edges 326 // method of graph.Graph and the iterator that is returned and the graph.Lines 327 // implementation of those edges. ReturnAllLines also checks that the edge 328 // end nodes exist within the graph, checking the Node method of graph.Graph. 329 // 330 // The edges used within and returned by the Builder function should be 331 // graph.Line. The edge parameter passed to b will contain only graph.Line. 332 // If useEmpty is true, graph iterators will be checked for the use of 333 // graph.Empty if they are empty. 334 func ReturnAllLines(t *testing.T, b Builder, useEmpty bool) { 335 for _, test := range testCases { 336 g, _, want, _, _, ok := b(test.nodes, test.edges, test.self, test.absent) 337 if !ok { 338 t.Logf("skipping test case: %q", test.name) 339 continue 340 } 341 342 var got []Edge 343 switch eg := g.(type) { 344 case edgeLister: 345 it := eg.Edges() 346 if !isValidIterator(it) { 347 t.Errorf("invalid iterator for test %q: got:%#v", test.name, it) 348 continue 349 } 350 checkEmptyIterator(t, it, useEmpty) 351 for _, e := range graph.EdgesOf(it) { 352 qe := g.Edge(e.From().ID(), e.To().ID()) 353 if qe == nil { 354 t.Errorf("missing edge for test %q: %v", test.name, e) 355 } else if qe.From().ID() != e.From().ID() || qe.To().ID() != e.To().ID() { 356 t.Errorf("inverted edge for test %q query with F=%d T=%d: got:%#v", 357 test.name, e.From().ID(), e.To().ID(), qe) 358 } 359 360 // FIXME(kortschak): This would not be necessary 361 // if graph.WeightedLines (and by symmetry) 362 // graph.WeightedEdges also were graph.Lines 363 // and graph.Edges. 364 switch lit := e.(type) { 365 case graph.Lines: 366 if !isValidIterator(lit) { 367 t.Errorf("invalid iterator for test %q: got:%#v", test.name, lit) 368 continue 369 } 370 checkEmptyIterator(t, lit, useEmpty) 371 for lit.Next() { 372 got = append(got, lit.Line()) 373 } 374 case graph.WeightedLines: 375 if !isValidIterator(lit) { 376 t.Errorf("invalid iterator for test %q: got:%#v", test.name, lit) 377 continue 378 } 379 checkEmptyIterator(t, lit, useEmpty) 380 for lit.Next() { 381 got = append(got, lit.WeightedLine()) 382 } 383 default: 384 continue 385 } 386 387 if g.Node(e.From().ID()) == nil { 388 t.Errorf("missing from node for test %q: %v", test.name, e.From().ID()) 389 } 390 if g.Node(e.To().ID()) == nil { 391 t.Errorf("missing to node for test %q: %v", test.name, e.To().ID()) 392 } 393 } 394 395 default: 396 t.Errorf("invalid type for test: %T cannot return edge iterator", g) 397 continue 398 } 399 400 checkEdges(t, test.name, g, got, want) 401 } 402 } 403 404 // ReturnAllWeightedEdges tests the constructed graph for the ability to return 405 // all the edges it claims it has used in its construction. This is a check of 406 // the Edges method of graph.Graph and the iterator that is returned. 407 // ReturnAllWeightedEdges also checks that the edge end nodes exist within the 408 // graph, checking the Node method of graph.Graph. 409 // 410 // The edges used within and returned by the Builder function should be 411 // graph.WeightedEdge. The edge parameter passed to b will contain only 412 // graph.WeightedEdge. 413 // If useEmpty is true, graph iterators will be checked for the use of 414 // graph.Empty if they are empty. 415 func ReturnAllWeightedEdges(t *testing.T, b Builder, useEmpty bool) { 416 for _, test := range testCases { 417 g, _, want, _, _, ok := b(test.nodes, test.edges, test.self, test.absent) 418 if !ok { 419 t.Logf("skipping test case: %q", test.name) 420 continue 421 } 422 423 var got []Edge 424 switch eg := g.(type) { 425 case weightedEdgeLister: 426 it := eg.WeightedEdges() 427 if !isValidIterator(it) { 428 t.Errorf("invalid iterator for test %q: got:%#v", test.name, it) 429 continue 430 } 431 checkEmptyIterator(t, it, useEmpty) 432 for it.Next() { 433 e := it.WeightedEdge() 434 got = append(got, e) 435 switch g := g.(type) { 436 case graph.Weighted: 437 qe := g.WeightedEdge(e.From().ID(), e.To().ID()) 438 if qe == nil { 439 t.Errorf("missing edge for test %q: %v", test.name, e) 440 } else if qe.From().ID() != e.From().ID() || qe.To().ID() != e.To().ID() { 441 t.Errorf("inverted edge for test %q query with F=%d T=%d: got:%#v", 442 test.name, e.From().ID(), e.To().ID(), qe) 443 } 444 default: 445 t.Logf("weighted edge lister is not a weighted graph - are you sure?: %T", g) 446 qe := g.Edge(e.From().ID(), e.To().ID()) 447 if qe == nil { 448 t.Errorf("missing edge for test %q: %v", test.name, e) 449 } else if qe.From().ID() != e.From().ID() || qe.To().ID() != e.To().ID() { 450 t.Errorf("inverted edge for test %q query with F=%d T=%d: got:%#v", 451 test.name, e.From().ID(), e.To().ID(), qe) 452 } 453 } 454 if g.Node(e.From().ID()) == nil { 455 t.Errorf("missing from node for test %q: %v", test.name, e.From().ID()) 456 } 457 if g.Node(e.To().ID()) == nil { 458 t.Errorf("missing to node for test %q: %v", test.name, e.To().ID()) 459 } 460 } 461 462 default: 463 t.Errorf("invalid type for test: %T cannot return weighted edge iterator", g) 464 continue 465 } 466 467 checkEdges(t, test.name, g, got, want) 468 } 469 } 470 471 // ReturnWeightedEdgeSlice tests the constructed graph for the ability to 472 // return all the edges it claims it has used in its construction using the 473 // WeightedEdgeSlicer interface. This is a check of the Edges method of 474 // graph.Graph and the iterator that is returned. ReturnWeightedEdgeSlice 475 // also checks that the edge end nodes exist within the graph, checking 476 // the Node method of graph.Graph. 477 // 478 // The edges used within and returned by the Builder function should be 479 // graph.WeightedEdge. The edge parameter passed to b will contain only 480 // graph.WeightedEdge. 481 // If useEmpty is true, graph iterators will be checked for the use of 482 // graph.Empty if they are empty. 483 func ReturnWeightedEdgeSlice(t *testing.T, b Builder, useEmpty bool) { 484 for _, test := range testCases { 485 g, _, want, _, _, ok := b(test.nodes, test.edges, test.self, test.absent) 486 if !ok { 487 t.Logf("skipping test case: %q", test.name) 488 continue 489 } 490 491 var got []Edge 492 switch eg := g.(type) { 493 case weightedEdgeLister: 494 it := eg.WeightedEdges() 495 if !isValidIterator(it) { 496 t.Errorf("invalid iterator for test %q: got:%#v", test.name, it) 497 continue 498 } 499 checkEmptyIterator(t, it, useEmpty) 500 s, ok := it.(graph.WeightedEdgeSlicer) 501 if !ok { 502 t.Errorf("invalid type for test %T: cannot return weighted edge slice", g) 503 continue 504 } 505 for _, e := range s.WeightedEdgeSlice() { 506 got = append(got, e) 507 qe := g.Edge(e.From().ID(), e.To().ID()) 508 if qe == nil { 509 t.Errorf("missing edge for test %q: %v", test.name, e) 510 } else if qe.From().ID() != e.From().ID() || qe.To().ID() != e.To().ID() { 511 t.Errorf("inverted edge for test %q query with F=%d T=%d: got:%#v", 512 test.name, e.From().ID(), e.To().ID(), qe) 513 } 514 if g.Node(e.From().ID()) == nil { 515 t.Errorf("missing from node for test %q: %v", test.name, e.From().ID()) 516 } 517 if g.Node(e.To().ID()) == nil { 518 t.Errorf("missing to node for test %q: %v", test.name, e.To().ID()) 519 } 520 } 521 522 default: 523 t.Errorf("invalid type for test: %T cannot return weighted edge iterator", g) 524 continue 525 } 526 527 checkEdges(t, test.name, g, got, want) 528 } 529 } 530 531 // ReturnAllWeightedLines tests the constructed graph for the ability to return 532 // all the edges it claims it has used in its construction and then recover all 533 // the lines that contribute to those edges. This is a check of the Edges 534 // method of graph.Graph and the iterator that is returned and the graph.Lines 535 // implementation of those edges. ReturnAllWeightedLines also checks that the 536 // edge end nodes exist within the graph, checking the Node method of 537 // graph.Graph. 538 // 539 // The edges used within and returned by the Builder function should be 540 // graph.WeightedLine. The edge parameter passed to b will contain only 541 // graph.WeightedLine. 542 // If useEmpty is true, graph iterators will be checked for the use of 543 // graph.Empty if they are empty. 544 func ReturnAllWeightedLines(t *testing.T, b Builder, useEmpty bool) { 545 for _, test := range testCases { 546 g, _, want, _, _, ok := b(test.nodes, test.edges, test.self, test.absent) 547 if !ok { 548 t.Logf("skipping test case: %q", test.name) 549 continue 550 } 551 552 var got []Edge 553 switch eg := g.(type) { 554 case weightedEdgeLister: 555 it := eg.WeightedEdges() 556 if !isValidIterator(it) { 557 t.Errorf("invalid iterator for test %q: got:%#v", test.name, it) 558 continue 559 } 560 checkEmptyIterator(t, it, useEmpty) 561 for _, e := range graph.WeightedEdgesOf(it) { 562 qe := g.Edge(e.From().ID(), e.To().ID()) 563 if qe == nil { 564 t.Errorf("missing edge for test %q: %v", test.name, e) 565 } else if qe.From().ID() != e.From().ID() || qe.To().ID() != e.To().ID() { 566 t.Errorf("inverted edge for test %q query with F=%d T=%d: got:%#v", 567 test.name, e.From().ID(), e.To().ID(), qe) 568 } 569 570 // FIXME(kortschak): This would not be necessary 571 // if graph.WeightedLines (and by symmetry) 572 // graph.WeightedEdges also were graph.Lines 573 // and graph.Edges. 574 switch lit := e.(type) { 575 case graph.Lines: 576 if !isValidIterator(lit) { 577 t.Errorf("invalid iterator for test %q: got:%#v", test.name, lit) 578 continue 579 } 580 checkEmptyIterator(t, lit, useEmpty) 581 for lit.Next() { 582 got = append(got, lit.Line()) 583 } 584 case graph.WeightedLines: 585 if !isValidIterator(lit) { 586 t.Errorf("invalid iterator for test %q: got:%#v", test.name, lit) 587 continue 588 } 589 checkEmptyIterator(t, lit, useEmpty) 590 for lit.Next() { 591 got = append(got, lit.WeightedLine()) 592 } 593 default: 594 continue 595 } 596 597 if g.Node(e.From().ID()) == nil { 598 t.Errorf("missing from node for test %q: %v", test.name, e.From().ID()) 599 } 600 if g.Node(e.To().ID()) == nil { 601 t.Errorf("missing to node for test %q: %v", test.name, e.To().ID()) 602 } 603 } 604 605 default: 606 t.Errorf("invalid type for test: %T cannot return edge iterator", g) 607 continue 608 } 609 610 checkEdges(t, test.name, g, got, want) 611 } 612 } 613 614 // checkEdges compares got and want for the given graph type. 615 func checkEdges(t *testing.T, name string, g graph.Graph, got, want []Edge) { 616 t.Helper() 617 switch g.(type) { 618 case graph.Undirected: 619 sort.Sort(lexicalUndirectedEdges(got)) 620 sort.Sort(lexicalUndirectedEdges(want)) 621 if !undirectedEdgeSetEqual(got, want) { 622 t.Errorf("unexpected edges result for test %q:\ngot: %#v\nwant:%#v", name, got, want) 623 } 624 default: 625 sort.Sort(lexicalEdges(got)) 626 sort.Sort(lexicalEdges(want)) 627 if !reflect.DeepEqual(got, want) { 628 t.Errorf("unexpected edges result for test %q:\ngot: %#v\nwant:%#v", name, got, want) 629 } 630 } 631 } 632 633 // EdgeExistence tests the constructed graph for the ability to correctly 634 // return the existence of edges within the graph. This is a check of the 635 // Edge methods of graph.Graph, the EdgeBetween method of graph.Undirected 636 // and the EdgeFromTo method of graph.Directed. EdgeExistence also checks 637 // that the nodes and traversed edges exist within the graph, checking the 638 // Node, Edge, EdgeBetween and HasEdgeBetween methods of graph.Graph, the 639 // EdgeBetween method of graph.Undirected and the HasEdgeFromTo method of 640 // graph.Directed. If reversedEdge is true, edges will be checked to make 641 // sure edges returned match the orientation of an Edge or WeightedEdge 642 // call. 643 func EdgeExistence(t *testing.T, b Builder, reversedEdge bool) { 644 for _, test := range testCases { 645 g, nodes, edges, _, _, ok := b(test.nodes, test.edges, test.self, test.absent) 646 if !ok { 647 t.Logf("skipping test case: %q", test.name) 648 continue 649 } 650 651 want := make(map[edge]bool) 652 for _, e := range edges { 653 want[edge{f: e.From().ID(), t: e.To().ID()}] = true 654 } 655 for _, x := range nodes { 656 for _, y := range nodes { 657 between := want[edge{f: x.ID(), t: y.ID()}] || want[edge{f: y.ID(), t: x.ID()}] 658 659 if has := g.HasEdgeBetween(x.ID(), y.ID()); has != between { 660 if has { 661 t.Errorf("unexpected edge for test %q: (%v)--(%v)", test.name, x.ID(), y.ID()) 662 } else { 663 t.Errorf("missing edge for test %q: (%v)--(%v)", test.name, x.ID(), y.ID()) 664 } 665 } else { 666 if want[edge{f: x.ID(), t: y.ID()}] { 667 e := g.Edge(x.ID(), y.ID()) 668 if e == nil || !hasEnds(x, y, e) { 669 t.Errorf("missing edge for test %q: (%v)--(%v)", test.name, x.ID(), y.ID()) 670 } else if reversedEdge && (e.From().ID() != x.ID() || e.To().ID() != y.ID()) { 671 t.Errorf("inverted edge for test %q query with F=%d T=%d: got:%#v", 672 test.name, x.ID(), y.ID(), e) 673 } 674 } 675 if between && !g.HasEdgeBetween(x.ID(), y.ID()) { 676 t.Errorf("missing edge for test %q: (%v)--(%v)", test.name, x.ID(), y.ID()) 677 } 678 if g.Node(x.ID()) == nil { 679 t.Errorf("missing from node for test %q: %v", test.name, x.ID()) 680 } 681 if g.Node(y.ID()) == nil { 682 t.Errorf("missing to node for test %q: %v", test.name, y.ID()) 683 } 684 } 685 686 switch g := g.(type) { 687 case graph.Directed: 688 u := x 689 v := y 690 if has := g.HasEdgeFromTo(u.ID(), v.ID()); has != want[edge{f: u.ID(), t: v.ID()}] { 691 if has { 692 t.Errorf("unexpected edge for test %q: (%v)->(%v)", test.name, u.ID(), v.ID()) 693 } else { 694 t.Errorf("missing edge for test %q: (%v)->(%v)", test.name, u.ID(), v.ID()) 695 } 696 continue 697 } 698 // Edge has already been tested above. 699 if g.Node(u.ID()) == nil { 700 t.Errorf("missing from node for test %q: %v", test.name, u.ID()) 701 } 702 if g.Node(v.ID()) == nil { 703 t.Errorf("missing to node for test %q: %v", test.name, v.ID()) 704 } 705 706 case graph.Undirected: 707 // HasEdgeBetween is already tested above. 708 if between && g.Edge(x.ID(), y.ID()) == nil { 709 t.Errorf("missing edge for test %q: (%v)--(%v)", test.name, x.ID(), y.ID()) 710 } 711 if between && g.EdgeBetween(x.ID(), y.ID()) == nil { 712 t.Errorf("missing edge for test %q: (%v)--(%v)", test.name, x.ID(), y.ID()) 713 } 714 } 715 716 switch g := g.(type) { 717 case graph.WeightedDirected: 718 u := x 719 v := y 720 if has := g.WeightedEdge(u.ID(), v.ID()) != nil; has != want[edge{f: u.ID(), t: v.ID()}] { 721 if has { 722 t.Errorf("unexpected edge for test %q: (%v)->(%v)", test.name, u.ID(), v.ID()) 723 } else { 724 t.Errorf("missing edge for test %q: (%v)->(%v)", test.name, u.ID(), v.ID()) 725 } 726 continue 727 } 728 729 case graph.WeightedUndirected: 730 // HasEdgeBetween is already tested above. 731 if between && g.WeightedEdge(x.ID(), y.ID()) == nil { 732 t.Errorf("missing edge for test %q: (%v)--(%v)", test.name, x.ID(), y.ID()) 733 } 734 if between && g.WeightedEdgeBetween(x.ID(), y.ID()) == nil { 735 t.Errorf("missing edge for test %q: (%v)--(%v)", test.name, x.ID(), y.ID()) 736 } 737 } 738 } 739 } 740 } 741 } 742 743 // LineExistence tests the constructed graph for the ability to correctly 744 // return the existence of lines within the graph. This is a check of the 745 // Line methods of graph.MultiGraph, the EdgeBetween method of graph.Undirected 746 // and the EdgeFromTo method of graph.Directed. LineExistence also checks 747 // that the nodes and traversed edges exist within the graph, checking the 748 // Node, Edge, EdgeBetween and HasEdgeBetween methods of graph.Graph, the 749 // EdgeBetween method of graph.Undirected and the HasEdgeFromTo method of 750 // graph.Directed. If reversedLine is true, lines will be checked to make 751 // sure lines returned match the orientation of an Line or WeightedLine 752 // call. 753 func LineExistence(t *testing.T, b Builder, useEmpty, reversedLine bool) { 754 for _, test := range testCases { 755 g, nodes, edges, _, _, ok := b(test.nodes, test.edges, test.self, test.absent) 756 if !ok { 757 t.Logf("skipping test case: %q", test.name) 758 continue 759 } 760 761 switch mg := g.(type) { 762 case graph.Multigraph: 763 want := make(map[edge]bool) 764 for _, e := range edges { 765 want[edge{f: e.From().ID(), t: e.To().ID()}] = true 766 } 767 for _, x := range nodes { 768 for _, y := range nodes { 769 between := want[edge{f: x.ID(), t: y.ID()}] || want[edge{f: y.ID(), t: x.ID()}] 770 771 if has := g.HasEdgeBetween(x.ID(), y.ID()); has != between { 772 if has { 773 t.Errorf("unexpected edge for test %q: (%v)--(%v)", test.name, x.ID(), y.ID()) 774 } else { 775 t.Errorf("missing edge for test %q: (%v)--(%v)", test.name, x.ID(), y.ID()) 776 } 777 } else { 778 if want[edge{f: x.ID(), t: y.ID()}] { 779 lit := mg.Lines(x.ID(), y.ID()) 780 if !isValidIterator(lit) { 781 t.Errorf("invalid iterator for test %q: got:%#v", test.name, lit) 782 continue 783 } 784 checkEmptyIterator(t, lit, useEmpty) 785 if lit.Len() == 0 { 786 t.Errorf("missing edge for test %q: (%v)--(%v)", test.name, x.ID(), y.ID()) 787 } else { 788 for lit.Next() { 789 l := lit.Line() 790 if l == nil || !hasEnds(x, y, l) { 791 t.Errorf("missing edge for test %q: (%v)--(%v)", test.name, x.ID(), y.ID()) 792 } else if reversedLine && (l.From().ID() != x.ID() || l.To().ID() != y.ID()) { 793 t.Errorf("inverted edge for test %q query with F=%d T=%d: got:%#v", 794 test.name, x.ID(), y.ID(), l) 795 } 796 } 797 } 798 } 799 if between && !g.HasEdgeBetween(x.ID(), y.ID()) { 800 t.Errorf("missing edge for test %q: (%v)--(%v)", test.name, x.ID(), y.ID()) 801 } 802 if g.Node(x.ID()) == nil { 803 t.Errorf("missing from node for test %q: %v", test.name, x.ID()) 804 } 805 if g.Node(y.ID()) == nil { 806 t.Errorf("missing to node for test %q: %v", test.name, y.ID()) 807 } 808 } 809 810 switch g := g.(type) { 811 case graph.DirectedMultigraph: 812 u := x 813 v := y 814 if has := g.HasEdgeFromTo(u.ID(), v.ID()); has != want[edge{f: u.ID(), t: v.ID()}] { 815 if has { 816 t.Errorf("unexpected edge for test %q: (%v)->(%v)", test.name, u.ID(), v.ID()) 817 } else { 818 t.Errorf("missing edge for test %q: (%v)->(%v)", test.name, u.ID(), v.ID()) 819 } 820 continue 821 } 822 // Edge has already been tested above. 823 if g.Node(u.ID()) == nil { 824 t.Errorf("missing from node for test %q: %v", test.name, u.ID()) 825 } 826 if g.Node(v.ID()) == nil { 827 t.Errorf("missing to node for test %q: %v", test.name, v.ID()) 828 } 829 830 case graph.UndirectedMultigraph: 831 // HasEdgeBetween is already tested above. 832 lit := g.Lines(x.ID(), y.ID()) 833 if !isValidIterator(lit) { 834 t.Errorf("invalid iterator for test %q: got:%#v", test.name, lit) 835 continue 836 } 837 checkEmptyIterator(t, lit, useEmpty) 838 if between && lit.Len() == 0 { 839 t.Errorf("missing edge for test %q: (%v)--(%v)", test.name, x.ID(), y.ID()) 840 } else { 841 for lit.Next() { 842 l := lit.Line() 843 if l == nil || !hasEnds(x, y, l) { 844 t.Errorf("missing edge for test %q: (%v)--(%v)", test.name, x.ID(), y.ID()) 845 } else if reversedLine && (l.From().ID() != x.ID() || l.To().ID() != y.ID()) { 846 t.Errorf("inverted edge for test %q query with F=%d T=%d: got:%#v", 847 test.name, x.ID(), y.ID(), l) 848 } 849 } 850 } 851 lit = g.LinesBetween(x.ID(), y.ID()) 852 if !isValidIterator(lit) { 853 t.Errorf("invalid iterator for test %q: got:%#v", test.name, lit) 854 continue 855 } 856 checkEmptyIterator(t, lit, useEmpty) 857 if between && lit.Len() == 0 { 858 t.Errorf("missing edge for test %q: (%v)--(%v)", test.name, x.ID(), y.ID()) 859 } else { 860 for lit.Next() { 861 l := lit.Line() 862 if l == nil || !hasEnds(x, y, l) { 863 t.Errorf("missing edge for test %q: (%v)--(%v)", test.name, x.ID(), y.ID()) 864 } else if reversedLine && (l.From().ID() != x.ID() || l.To().ID() != y.ID()) { 865 t.Errorf("inverted edge for test %q query with F=%d T=%d: got:%#v", 866 test.name, x.ID(), y.ID(), l) 867 } 868 } 869 } 870 } 871 872 switch g := g.(type) { 873 case graph.WeightedDirectedMultigraph: 874 u := x 875 v := y 876 lit := g.WeightedLines(u.ID(), v.ID()) 877 if !isValidIterator(lit) { 878 t.Errorf("invalid iterator for test %q: got:%#v", test.name, lit) 879 continue 880 } 881 checkEmptyIterator(t, lit, useEmpty) 882 if has := lit != graph.Empty; has != want[edge{f: u.ID(), t: v.ID()}] { 883 if has { 884 t.Errorf("unexpected edge for test %q: (%v)->(%v)", test.name, u.ID(), v.ID()) 885 } else { 886 t.Errorf("missing edge for test %q: (%v)->(%v)", test.name, u.ID(), v.ID()) 887 } 888 continue 889 } 890 for lit.Next() { 891 l := lit.WeightedLine() 892 if l.From().ID() != x.ID() || l.To().ID() != y.ID() { 893 t.Errorf("inverted edge for test %q query with F=%d T=%d: got:%#v", 894 test.name, x.ID(), y.ID(), l) 895 } 896 } 897 // Edge has already been tested above. 898 if g.Node(u.ID()) == nil { 899 t.Errorf("missing from node for test %q: %v", test.name, u.ID()) 900 } 901 if g.Node(v.ID()) == nil { 902 t.Errorf("missing to node for test %q: %v", test.name, v.ID()) 903 } 904 905 case graph.WeightedUndirectedMultigraph: 906 // HasEdgeBetween is already tested above. 907 lit := g.WeightedLines(x.ID(), y.ID()) 908 if !isValidIterator(lit) { 909 t.Errorf("invalid iterator for test %q: got:%#v", test.name, lit) 910 continue 911 } 912 checkEmptyIterator(t, lit, useEmpty) 913 if between && lit.Len() == 0 { 914 t.Errorf("missing edge for test %q: (%v)--(%v)", test.name, x.ID(), y.ID()) 915 } else { 916 for lit.Next() { 917 l := lit.WeightedLine() 918 if reversedLine && (l.From().ID() != x.ID() || l.To().ID() != y.ID()) { 919 t.Errorf("inverted edge for test %q query with F=%d T=%d: got:%#v", 920 test.name, x.ID(), y.ID(), l) 921 } 922 } 923 } 924 lit = g.WeightedLinesBetween(x.ID(), y.ID()) 925 if !isValidIterator(lit) { 926 t.Errorf("invalid iterator for test %q: got:%#v", test.name, lit) 927 continue 928 } 929 checkEmptyIterator(t, lit, useEmpty) 930 if between && lit.Len() == 0 { 931 t.Errorf("missing edge for test %q: (%v)--(%v)", test.name, x.ID(), y.ID()) 932 } else { 933 for lit.Next() { 934 l := lit.WeightedLine() 935 if reversedLine && (l.From().ID() != x.ID() || l.To().ID() != y.ID()) { 936 t.Errorf("inverted edge for test %q query with F=%d T=%d: got:%#v", 937 test.name, x.ID(), y.ID(), l) 938 } 939 } 940 } 941 } 942 } 943 } 944 default: 945 t.Errorf("invalid type for test: %T not a multigraph", g) 946 continue 947 } 948 } 949 } 950 951 // ReturnAdjacentNodes tests the constructed graph for the ability to correctly 952 // return the nodes reachable from each node within the graph. This is a check 953 // of the From method of graph.Graph and the To method of graph.Directed. 954 // ReturnAdjacentNodes also checks that the nodes and traversed edges exist 955 // within the graph, checking the Node, Edge, EdgeBetween and HasEdgeBetween 956 // methods of graph.Graph, the EdgeBetween method of graph.Undirected and the 957 // HasEdgeFromTo method of graph.Directed. 958 // If useEmpty is true, graph iterators will be checked for the use of 959 // graph.Empty if they are empty. If reversedEdge is true, edges will be checked 960 // to make sure edges returned match the orientation of an Edge or WeightedEdge 961 // call. 962 func ReturnAdjacentNodes(t *testing.T, b Builder, useEmpty, reversedEdge bool) { 963 for _, test := range testCases { 964 g, nodes, edges, _, _, ok := b(test.nodes, test.edges, test.self, test.absent) 965 if !ok { 966 t.Logf("skipping test case: %q", test.name) 967 continue 968 } 969 970 want := make(map[edge]bool) 971 for _, e := range edges { 972 want[edge{f: e.From().ID(), t: e.To().ID()}] = true 973 if g.From(e.From().ID()).Len() == 0 { 974 t.Errorf("missing path from node %v with outbound edge %v", e.From().ID(), e) 975 } 976 } 977 for _, x := range nodes { 978 switch g := g.(type) { 979 case graph.Directed: 980 // Test forward. 981 u := x 982 it := g.From(u.ID()) 983 if !isValidIterator(it) { 984 t.Errorf("invalid iterator for test %q: got:%#v", test.name, it) 985 continue 986 } 987 checkEmptyIterator(t, it, useEmpty) 988 for i := 0; it.Next(); i++ { 989 v := it.Node() 990 if i == 0 && g.Node(u.ID()) == nil { 991 t.Errorf("missing from node for test %q: %v", test.name, u.ID()) 992 } 993 if g.Node(v.ID()) == nil { 994 t.Errorf("missing to node for test %q: %v", test.name, v.ID()) 995 } 996 qe := g.Edge(u.ID(), v.ID()) 997 if qe == nil { 998 t.Errorf("missing from edge for test %q: (%v)->(%v)", test.name, u.ID(), v.ID()) 999 } else if qe.From().ID() != u.ID() || qe.To().ID() != v.ID() { 1000 t.Errorf("inverted edge for test %q query with F=%d T=%d: got:%#v", 1001 test.name, u.ID(), v.ID(), qe) 1002 } 1003 if !g.HasEdgeBetween(u.ID(), v.ID()) { 1004 t.Errorf("missing from edge for test %q: (%v)--(%v)", test.name, u.ID(), v.ID()) 1005 } 1006 if !g.HasEdgeFromTo(u.ID(), v.ID()) { 1007 t.Errorf("missing from edge for test %q: (%v)->(%v)", test.name, u.ID(), v.ID()) 1008 } 1009 if !want[edge{f: u.ID(), t: v.ID()}] { 1010 t.Errorf("unexpected edge for test %q: (%v)->(%v)", test.name, u.ID(), v.ID()) 1011 } 1012 } 1013 1014 // Test backward. 1015 v := x 1016 it = g.To(v.ID()) 1017 if !isValidIterator(it) { 1018 t.Errorf("invalid iterator for test %q: got:%#v", test.name, it) 1019 continue 1020 } 1021 checkEmptyIterator(t, it, useEmpty) 1022 for i := 0; it.Next(); i++ { 1023 u := it.Node() 1024 if i == 0 && g.Node(v.ID()) == nil { 1025 t.Errorf("missing to node for test %q: %v", test.name, v.ID()) 1026 } 1027 if g.Node(u.ID()) == nil { 1028 t.Errorf("missing from node for test %q: %v", test.name, u.ID()) 1029 } 1030 qe := g.Edge(u.ID(), v.ID()) 1031 if qe == nil { 1032 t.Errorf("missing from edge for test %q: (%v)->(%v)", test.name, u.ID(), v.ID()) 1033 continue 1034 } 1035 if qe.From().ID() != u.ID() || qe.To().ID() != v.ID() { 1036 t.Errorf("inverted edge for test %q query with F=%d T=%d: got:%#v", 1037 test.name, u.ID(), v.ID(), qe) 1038 } 1039 if !g.HasEdgeBetween(u.ID(), v.ID()) { 1040 t.Errorf("missing from edge for test %q: (%v)--(%v)", test.name, u.ID(), v.ID()) 1041 continue 1042 } 1043 if !g.HasEdgeFromTo(u.ID(), v.ID()) { 1044 t.Errorf("missing from edge for test %q: (%v)->(%v)", test.name, u.ID(), v.ID()) 1045 continue 1046 } 1047 if !want[edge{f: u.ID(), t: v.ID()}] { 1048 t.Errorf("unexpected edge for test %q: (%v)->(%v)", test.name, u.ID(), v.ID()) 1049 } 1050 } 1051 for _, e := range edges { 1052 if g.To(e.To().ID()).Len() == 0 { 1053 t.Errorf("missing path to node %v with inbound edge %v", e.To().ID(), e) 1054 } 1055 } 1056 1057 case graph.Undirected: 1058 u := x 1059 it := g.From(u.ID()) 1060 if !isValidIterator(it) { 1061 t.Errorf("invalid iterator for test %q: got:%#v", test.name, it) 1062 continue 1063 } 1064 checkEmptyIterator(t, it, useEmpty) 1065 for i := 0; it.Next(); i++ { 1066 v := it.Node() 1067 if i == 0 && g.Node(u.ID()) == nil { 1068 t.Errorf("missing from node for test %q: %v", test.name, u.ID()) 1069 } 1070 qe := g.Edge(u.ID(), v.ID()) 1071 if qe == nil || !hasEnds(u, v, qe) { 1072 t.Errorf("missing from edge for test %q: (%v)--(%v)", test.name, u.ID(), v.ID()) 1073 continue 1074 } 1075 if reversedEdge && (qe.From().ID() != u.ID() || qe.To().ID() != v.ID()) { 1076 t.Errorf("inverted edge for test %q query with F=%d T=%d: got:%#v", 1077 test.name, u.ID(), v.ID(), qe) 1078 } 1079 qe = g.EdgeBetween(u.ID(), v.ID()) 1080 if qe == nil || !hasEnds(u, v, qe) { 1081 t.Errorf("missing from edge for test %q: (%v)--(%v)", test.name, u.ID(), v.ID()) 1082 continue 1083 } 1084 if reversedEdge && (qe.From().ID() != u.ID() || qe.To().ID() != v.ID()) { 1085 t.Errorf("inverted edge for test %q query with F=%d T=%d: got:%#v", 1086 test.name, u.ID(), v.ID(), qe) 1087 } 1088 if !g.HasEdgeBetween(u.ID(), v.ID()) { 1089 t.Errorf("missing from edge for test %q: (%v)--(%v)", test.name, u.ID(), v.ID()) 1090 continue 1091 } 1092 between := want[edge{f: u.ID(), t: v.ID()}] || want[edge{f: v.ID(), t: u.ID()}] 1093 if !between { 1094 t.Errorf("unexpected edge for test %q: (%v)->(%v)", test.name, u.ID(), v.ID()) 1095 } 1096 } 1097 1098 default: 1099 u := x 1100 it := g.From(u.ID()) 1101 if !isValidIterator(it) { 1102 t.Errorf("invalid iterator for test %q: got:%#v", test.name, it) 1103 continue 1104 } 1105 checkEmptyIterator(t, it, useEmpty) 1106 for i := 0; it.Next(); i++ { 1107 v := it.Node() 1108 if i == 0 && g.Node(u.ID()) == nil { 1109 t.Errorf("missing from node for test %q: %v", test.name, u.ID()) 1110 } 1111 qe := g.Edge(u.ID(), v.ID()) 1112 if qe == nil { 1113 t.Errorf("missing from edge for test %q: (%v)--(%v)", test.name, u.ID(), v.ID()) 1114 continue 1115 } 1116 if qe.From().ID() != u.ID() || qe.To().ID() != v.ID() { 1117 t.Errorf("inverted edge for test %q query with F=%d T=%d: got:%#v", 1118 test.name, u.ID(), v.ID(), qe) 1119 } 1120 if !g.HasEdgeBetween(u.ID(), v.ID()) { 1121 t.Errorf("missing from edge for test %q: (%v)--(%v)", test.name, u.ID(), v.ID()) 1122 continue 1123 } 1124 between := want[edge{f: u.ID(), t: v.ID()}] || want[edge{f: v.ID(), t: u.ID()}] 1125 if !between { 1126 t.Errorf("unexpected edge for test %q: (%v)->(%v)", test.name, u.ID(), v.ID()) 1127 } 1128 } 1129 } 1130 } 1131 } 1132 } 1133 1134 // Weight tests the constructed graph for the ability to correctly return 1135 // the weight between to nodes, checking the Weight method of graph.Weighted. 1136 // 1137 // The self and absent values returned by the Builder should match the values 1138 // used by the Weight method. 1139 func Weight(t *testing.T, b Builder) { 1140 for _, test := range testCases { 1141 g, nodes, _, self, absent, ok := b(test.nodes, test.edges, test.self, test.absent) 1142 if !ok { 1143 t.Logf("skipping test case: %q", test.name) 1144 continue 1145 } 1146 wg, ok := g.(graph.Weighted) 1147 if !ok { 1148 t.Errorf("invalid graph type for test %q: %T is not graph.Weighted", test.name, g) 1149 } 1150 _, multi := g.(graph.Multigraph) 1151 1152 for _, x := range nodes { 1153 for _, y := range nodes { 1154 w, ok := wg.Weight(x.ID(), y.ID()) 1155 e := wg.WeightedEdge(x.ID(), y.ID()) 1156 switch { 1157 case !ok: 1158 if e != nil { 1159 t.Errorf("missing edge weight for existing edge for test %q: (%v)--(%v)", test.name, x.ID(), y.ID()) 1160 } 1161 if !scalar.Same(w, absent) { 1162 t.Errorf("unexpected absent weight for test %q: got:%v want:%v", test.name, w, absent) 1163 } 1164 1165 case !multi && x.ID() == y.ID(): 1166 if !scalar.Same(w, self) { 1167 t.Errorf("unexpected self weight for test %q: got:%v want:%v", test.name, w, self) 1168 } 1169 1170 case e == nil: 1171 t.Errorf("missing edge for existing non-self weight for test %q: (%v)--(%v)", test.name, x.ID(), y.ID()) 1172 1173 case e.Weight() != w: 1174 t.Errorf("weight mismatch for test %q: edge=%v graph=%v", test.name, e.Weight(), w) 1175 } 1176 } 1177 } 1178 } 1179 } 1180 1181 // AdjacencyMatrix tests the constructed graph for the ability to correctly 1182 // return an adjacency matrix that matches the weights returned by the graphs 1183 // Weight method. 1184 // 1185 // The self and absent values returned by the Builder should match the values 1186 // used by the Weight method. 1187 func AdjacencyMatrix(t *testing.T, b Builder) { 1188 for _, test := range testCases { 1189 g, nodes, _, self, absent, ok := b(test.nodes, test.edges, test.self, test.absent) 1190 if !ok { 1191 t.Logf("skipping test case: %q", test.name) 1192 continue 1193 } 1194 wg, ok := g.(graph.Weighted) 1195 if !ok { 1196 t.Errorf("invalid graph type for test %q: %T is not graph.Weighted", test.name, g) 1197 } 1198 mg, ok := g.(matrixer) 1199 if !ok { 1200 t.Errorf("invalid graph type for test %q: %T cannot return adjacency matrix", test.name, g) 1201 } 1202 m := mg.Matrix() 1203 1204 r, c := m.Dims() 1205 if r != c || r != len(nodes) { 1206 t.Errorf("dimension mismatch for test %q: r=%d c=%d order=%d", test.name, r, c, len(nodes)) 1207 } 1208 1209 for _, x := range nodes { 1210 i := int(x.ID()) 1211 for _, y := range nodes { 1212 j := int(y.ID()) 1213 w, ok := wg.Weight(x.ID(), y.ID()) 1214 switch { 1215 case !ok: 1216 if !scalar.Same(m.At(i, j), absent) { 1217 t.Errorf("weight mismatch for test %q: (%v)--(%v) matrix=%v graph=%v", test.name, x.ID(), y.ID(), m.At(i, j), w) 1218 } 1219 case x.ID() == y.ID(): 1220 if !scalar.Same(m.At(i, j), self) { 1221 t.Errorf("weight mismatch for test %q: (%v)--(%v) matrix=%v graph=%v", test.name, x.ID(), y.ID(), m.At(i, j), w) 1222 } 1223 default: 1224 if !scalar.Same(m.At(i, j), w) { 1225 t.Errorf("weight mismatch for test %q: (%v)--(%v) matrix=%v graph=%v", test.name, x.ID(), y.ID(), m.At(i, j), w) 1226 } 1227 } 1228 } 1229 } 1230 } 1231 } 1232 1233 // lexicalEdges sorts a collection of edges lexically on the 1234 // keys: from.ID > to.ID > [line.ID] > [weight]. 1235 type lexicalEdges []Edge 1236 1237 func (e lexicalEdges) Len() int { return len(e) } 1238 func (e lexicalEdges) Less(i, j int) bool { 1239 if e[i].From().ID() < e[j].From().ID() { 1240 return true 1241 } 1242 sf := e[i].From().ID() == e[j].From().ID() 1243 if sf && e[i].To().ID() < e[j].To().ID() { 1244 return true 1245 } 1246 st := e[i].To().ID() == e[j].To().ID() 1247 li, oki := e[i].(graph.Line) 1248 lj, okj := e[j].(graph.Line) 1249 if oki != okj { 1250 panic(fmt.Sprintf("testgraph: mismatched types %T != %T", e[i], e[j])) 1251 } 1252 if !oki { 1253 return sf && st && lessWeight(e[i], e[j]) 1254 } 1255 if sf && st && li.ID() < lj.ID() { 1256 return true 1257 } 1258 return sf && st && li.ID() == lj.ID() && lessWeight(e[i], e[j]) 1259 } 1260 func (e lexicalEdges) Swap(i, j int) { e[i], e[j] = e[j], e[i] } 1261 1262 // lexicalUndirectedEdges sorts a collection of edges lexically on the 1263 // keys: lo.ID > hi.ID > [line.ID] > [weight]. 1264 type lexicalUndirectedEdges []Edge 1265 1266 func (e lexicalUndirectedEdges) Len() int { return len(e) } 1267 func (e lexicalUndirectedEdges) Less(i, j int) bool { 1268 lidi, hidi, _ := undirectedIDs(e[i]) 1269 lidj, hidj, _ := undirectedIDs(e[j]) 1270 1271 if lidi < lidj { 1272 return true 1273 } 1274 sl := lidi == lidj 1275 if sl && hidi < hidj { 1276 return true 1277 } 1278 sh := hidi == hidj 1279 li, oki := e[i].(graph.Line) 1280 lj, okj := e[j].(graph.Line) 1281 if oki != okj { 1282 panic(fmt.Sprintf("testgraph: mismatched types %T != %T", e[i], e[j])) 1283 } 1284 if !oki { 1285 return sl && sh && lessWeight(e[i], e[j]) 1286 } 1287 if sl && sh && li.ID() < lj.ID() { 1288 return true 1289 } 1290 return sl && sh && li.ID() == lj.ID() && lessWeight(e[i], e[j]) 1291 } 1292 func (e lexicalUndirectedEdges) Swap(i, j int) { e[i], e[j] = e[j], e[i] } 1293 1294 func lessWeight(ei, ej Edge) bool { 1295 wei, oki := ei.(graph.WeightedEdge) 1296 wej, okj := ej.(graph.WeightedEdge) 1297 if oki != okj { 1298 panic(fmt.Sprintf("testgraph: mismatched types %T != %T", ei, ej)) 1299 } 1300 if !oki { 1301 return false 1302 } 1303 return wei.Weight() < wej.Weight() 1304 } 1305 1306 // undirectedEdgeSetEqual returned whether a pair of undirected edge 1307 // slices sorted by lexicalUndirectedEdges are equal. 1308 func undirectedEdgeSetEqual(a, b []Edge) bool { 1309 if len(a) == 0 && len(b) == 0 { 1310 return true 1311 } 1312 if len(a) == 0 || len(b) == 0 { 1313 return false 1314 } 1315 if !undirectedEdgeEqual(a[0], b[0]) { 1316 return false 1317 } 1318 i, j := 0, 0 1319 for { 1320 switch { 1321 case i == len(a)-1 && j == len(b)-1: 1322 return true 1323 1324 case i < len(a)-1 && undirectedEdgeEqual(a[i+1], b[j]): 1325 i++ 1326 1327 case j < len(b)-1 && undirectedEdgeEqual(a[i], b[j+1]): 1328 j++ 1329 1330 case i < len(a)-1 && j < len(b)-1 && undirectedEdgeEqual(a[i+1], b[j+1]): 1331 i++ 1332 j++ 1333 1334 default: 1335 return false 1336 } 1337 } 1338 } 1339 1340 // undirectedEdgeEqual returns whether a pair of undirected edges are equal 1341 // after canonicalising from and to IDs by numerical sort order. 1342 func undirectedEdgeEqual(a, b Edge) bool { 1343 loa, hia, inva := undirectedIDs(a) 1344 lob, hib, invb := undirectedIDs(b) 1345 // Use reflect.DeepEqual if the edges are parallel 1346 // rather anti-parallel. 1347 if inva == invb { 1348 return reflect.DeepEqual(a, b) 1349 } 1350 if loa != lob || hia != hib { 1351 return false 1352 } 1353 la, oka := a.(graph.Line) 1354 lb, okb := b.(graph.Line) 1355 if !oka && !okb { 1356 return true 1357 } 1358 if la.ID() != lb.ID() { 1359 return false 1360 } 1361 wea, oka := a.(graph.WeightedEdge) 1362 web, okb := b.(graph.WeightedEdge) 1363 if !oka && !okb { 1364 return true 1365 } 1366 return wea.Weight() == web.Weight() 1367 } 1368 1369 // NodeAdder is a graph.NodeAdder graph. 1370 type NodeAdder interface { 1371 graph.Graph 1372 graph.NodeAdder 1373 } 1374 1375 // AddNodes tests whether g correctly implements the graph.NodeAdder interface. 1376 // AddNodes gets a new node from g and adds it to the graph, repeating this pair 1377 // of operations n times. The existence of added nodes is confirmed in the graph. 1378 // AddNodes also checks that re-adding each of the added nodes causes a panic. 1379 // If g satisfies NodeWithIDer, the NodeWithID method is tested for an additional 1380 // n rounds of node addition using NodeWithID to create new nodes as well as 1381 // confirming that NodeWithID returns existing nodes. 1382 func AddNodes(t *testing.T, g NodeAdder, n int) { 1383 defer func() { 1384 r := recover() 1385 if r != nil { 1386 t.Errorf("unexpected panic: %v", r) 1387 } 1388 }() 1389 1390 var addedNodes []graph.Node 1391 for i := 0; i < n; i++ { 1392 node := g.NewNode() 1393 prev := len(graph.NodesOf(g.Nodes())) 1394 if g.Node(node.ID()) != nil { 1395 curr := g.Nodes().Len() 1396 if curr != prev { 1397 t.Fatalf("NewNode mutated graph: prev graph order != curr graph order, %d != %d", prev, curr) 1398 } 1399 t.Fatalf("NewNode returned existing: %#v", node) 1400 } 1401 g.AddNode(node) 1402 addedNodes = append(addedNodes, node) 1403 curr := len(graph.NodesOf(g.Nodes())) 1404 if curr != prev+1 { 1405 t.Fatalf("AddNode failed to mutate graph: curr graph order != prev graph order+1, %d != %d", curr, prev+1) 1406 } 1407 if g.Node(node.ID()) == nil { 1408 t.Fatalf("AddNode failed to add node to graph trying to add %#v", node) 1409 } 1410 } 1411 1412 ordered.ByID(addedNodes) 1413 graphNodes := graph.NodesOf(g.Nodes()) 1414 ordered.ByID(graphNodes) 1415 if !reflect.DeepEqual(addedNodes, graphNodes) { 1416 if n > 20 { 1417 t.Errorf("unexpected node set after node addition: got len:%v want len:%v", len(graphNodes), len(addedNodes)) 1418 } else { 1419 t.Errorf("unexpected node set after node addition: got:\n %v\nwant:\n%v", graphNodes, addedNodes) 1420 } 1421 } 1422 1423 it := g.Nodes() 1424 for it.Next() { 1425 panicked := panics(func() { 1426 g.AddNode(it.Node()) 1427 }) 1428 if !panicked { 1429 t.Fatalf("expected panic adding existing node: %v", it.Node()) 1430 } 1431 } 1432 1433 if gwi, ok := g.(graph.NodeWithIDer); ok { 1434 // Test existing nodes. 1435 it := g.Nodes() 1436 for it.Next() { 1437 id := it.Node().ID() 1438 n, new := gwi.NodeWithID(id) 1439 if n == nil { 1440 t.Errorf("unexpected nil node for existing node with ID=%d", id) 1441 } 1442 if new { 1443 t.Errorf("unexpected new node for existing node with ID=%d", id) 1444 } 1445 } 1446 // Run n rounds of ID-specified node addition. 1447 for i := 0; i < n; i++ { 1448 id := g.NewNode().ID() // Get a guaranteed non-existing node. 1449 n, new := gwi.NodeWithID(id) 1450 if n == nil { 1451 // Could not create a node, valid behaviour. 1452 continue 1453 } 1454 if !new { 1455 t.Errorf("unexpected old node for non-existing node with ID=%d", id) 1456 } 1457 g.AddNode(n) // Use the node to advance to a new non-existing node. 1458 } 1459 } 1460 } 1461 1462 // AddArbitraryNodes tests whether g correctly implements the AddNode method. Not all 1463 // graph.NodeAdder graphs are expected to implement the semantics of this test. 1464 // AddArbitraryNodes iterates over add, adding each node to the graph. The existence 1465 // of each added node in the graph is confirmed. 1466 func AddArbitraryNodes(t *testing.T, g NodeAdder, add graph.Nodes) { 1467 defer func() { 1468 r := recover() 1469 if r != nil { 1470 t.Errorf("unexpected panic: %v", r) 1471 } 1472 }() 1473 1474 for add.Next() { 1475 node := add.Node() 1476 prev := len(graph.NodesOf(g.Nodes())) 1477 g.AddNode(node) 1478 curr := len(graph.NodesOf(g.Nodes())) 1479 if curr != prev+1 { 1480 t.Fatalf("AddNode failed to mutate graph: curr graph order != prev graph order+1, %d != %d", curr, prev+1) 1481 } 1482 if g.Node(node.ID()) == nil { 1483 t.Fatalf("AddNode failed to add node to graph trying to add %#v", node) 1484 } 1485 } 1486 1487 add.Reset() 1488 addedNodes := graph.NodesOf(add) 1489 ordered.ByID(addedNodes) 1490 graphNodes := graph.NodesOf(g.Nodes()) 1491 ordered.ByID(graphNodes) 1492 if !reflect.DeepEqual(addedNodes, graphNodes) { 1493 t.Errorf("unexpected node set after node addition: got:\n %v\nwant:\n%v", graphNodes, addedNodes) 1494 } 1495 1496 it := g.Nodes() 1497 for it.Next() { 1498 panicked := panics(func() { 1499 g.AddNode(it.Node()) 1500 }) 1501 if !panicked { 1502 t.Fatalf("expected panic adding existing node: %v", it.Node()) 1503 } 1504 } 1505 } 1506 1507 // NodeRemover is a graph.NodeRemover graph. 1508 type NodeRemover interface { 1509 graph.Graph 1510 graph.NodeRemover 1511 } 1512 1513 // RemoveNodes tests whether g correctly implements the graph.NodeRemover interface. 1514 // The input graph g must contain a set of nodes with some edges between them. 1515 func RemoveNodes(t *testing.T, g NodeRemover) { 1516 defer func() { 1517 r := recover() 1518 if r != nil { 1519 t.Errorf("unexpected panic: %v", r) 1520 } 1521 }() 1522 1523 it := g.Nodes() 1524 first := true 1525 for it.Next() { 1526 u := it.Node() 1527 1528 seen := make(map[edge]struct{}) 1529 1530 // Collect all incident edges. 1531 var incident []graph.Edge 1532 to := g.From(u.ID()) 1533 for to.Next() { 1534 v := to.Node() 1535 e := g.Edge(u.ID(), v.ID()) 1536 if e == nil { 1537 t.Fatalf("bad graph: neighbors not connected: u=%#v v=%#v", u, v) 1538 } 1539 if _, ok := g.(graph.Undirected); ok { 1540 seen[edge{f: e.To().ID(), t: e.From().ID()}] = struct{}{} 1541 } 1542 seen[edge{f: e.From().ID(), t: e.To().ID()}] = struct{}{} 1543 incident = append(incident, e) 1544 } 1545 1546 // Collect all other edges. 1547 var others []graph.Edge 1548 currit := g.Nodes() 1549 for currit.Next() { 1550 u := currit.Node() 1551 to := g.From(u.ID()) 1552 for to.Next() { 1553 v := to.Node() 1554 e := g.Edge(u.ID(), v.ID()) 1555 if e == nil { 1556 t.Fatalf("bad graph: neighbors not connected: u=%#v v=%#v", u, v) 1557 } 1558 seen[edge{f: e.From().ID(), t: e.To().ID()}] = struct{}{} 1559 others = append(others, e) 1560 } 1561 } 1562 1563 if first && len(seen) == 0 { 1564 t.Fatal("incomplete test: no edges in graph") 1565 } 1566 first = false 1567 1568 prev := len(graph.NodesOf(g.Nodes())) 1569 g.RemoveNode(u.ID()) 1570 curr := len(graph.NodesOf(g.Nodes())) 1571 if curr != prev-1 { 1572 t.Fatalf("RemoveNode failed to mutate graph: curr graph order != prev graph order-1, %d != %d", curr, prev-1) 1573 } 1574 if g.Node(u.ID()) != nil { 1575 t.Fatalf("failed to remove node: %#v", u) 1576 } 1577 1578 for _, e := range incident { 1579 if g.HasEdgeBetween(e.From().ID(), e.To().ID()) { 1580 t.Fatalf("RemoveNode failed to remove connected edge: %#v", e) 1581 } 1582 } 1583 1584 for _, e := range others { 1585 if e.From().ID() == u.ID() || e.To().ID() == u.ID() { 1586 continue 1587 } 1588 if g.Edge(e.From().ID(), e.To().ID()) == nil { 1589 t.Fatalf("RemoveNode %v removed unconnected edge: %#v", u, e) 1590 } 1591 } 1592 } 1593 } 1594 1595 // EdgeAdder is a graph.EdgeAdder graph. 1596 type EdgeAdder interface { 1597 graph.Graph 1598 graph.EdgeAdder 1599 } 1600 1601 // AddEdges tests whether g correctly implements the graph.EdgeAdder interface. 1602 // AddEdges creates n pairs of nodes with random IDs in [0,n) and joins edges 1603 // each node in the pair using SetEdge. AddEdges confirms that the end point 1604 // nodes are added to the graph and that the edges are stored in the graph. 1605 // If canLoop is true, self edges may be created. If canSet is true, a second 1606 // call to SetEdge is made for each edge to confirm that the nodes corresponding 1607 // the end points are updated. 1608 func AddEdges(t *testing.T, n int, g EdgeAdder, newNode func(id int64) graph.Node, canLoop, canSetNode bool) { 1609 defer func() { 1610 r := recover() 1611 if r != nil { 1612 t.Errorf("unexpected panic: %v", r) 1613 } 1614 }() 1615 1616 type altNode struct { 1617 graph.Node 1618 } 1619 1620 rnd := rand.New(rand.NewSource(1)) 1621 for i := 0; i < n; i++ { 1622 u := newNode(rnd.Int63n(int64(n))) 1623 var v graph.Node 1624 for { 1625 v = newNode(rnd.Int63n(int64(n))) 1626 if canLoop || u.ID() != v.ID() { 1627 break 1628 } 1629 } 1630 e := g.NewEdge(u, v) 1631 if g.Edge(u.ID(), v.ID()) != nil { 1632 t.Fatalf("NewEdge returned existing: %#v", e) 1633 } 1634 g.SetEdge(e) 1635 if g.Edge(u.ID(), v.ID()) == nil { 1636 t.Fatalf("SetEdge failed to add edge: %#v", e) 1637 } 1638 if g.Node(u.ID()) == nil { 1639 t.Fatalf("SetEdge failed to add from node: %#v", u) 1640 } 1641 if g.Node(v.ID()) == nil { 1642 t.Fatalf("SetEdge failed to add to node: %#v", v) 1643 } 1644 1645 if !canSetNode { 1646 continue 1647 } 1648 1649 g.SetEdge(g.NewEdge(altNode{u}, altNode{v})) 1650 if nu := g.Node(u.ID()); nu == u { 1651 t.Fatalf("SetEdge failed to update from node: u=%#v nu=%#v", u, nu) 1652 } 1653 if nv := g.Node(v.ID()); nv == v { 1654 t.Fatalf("SetEdge failed to update to node: v=%#v nv=%#v", v, nv) 1655 } 1656 } 1657 } 1658 1659 // WeightedEdgeAdder is a graph.EdgeAdder graph. 1660 type WeightedEdgeAdder interface { 1661 graph.Graph 1662 graph.WeightedEdgeAdder 1663 } 1664 1665 // AddWeightedEdges tests whether g correctly implements the graph.WeightedEdgeAdder 1666 // interface. AddWeightedEdges creates n pairs of nodes with random IDs in [0,n) and 1667 // joins edges each node in the pair using SetWeightedEdge with weight w. 1668 // AddWeightedEdges confirms that the end point nodes are added to the graph and that 1669 // the edges are stored in the graph. If canLoop is true, self edges may be created. 1670 // If canSet is true, a second call to SetWeightedEdge is made for each edge to 1671 // confirm that the nodes corresponding the end points are updated. 1672 func AddWeightedEdges(t *testing.T, n int, g WeightedEdgeAdder, w float64, newNode func(id int64) graph.Node, canLoop, canSetNode bool) { 1673 defer func() { 1674 r := recover() 1675 if r != nil { 1676 t.Errorf("unexpected panic: %v", r) 1677 } 1678 }() 1679 1680 type altNode struct { 1681 graph.Node 1682 } 1683 1684 rnd := rand.New(rand.NewSource(1)) 1685 for i := 0; i < n; i++ { 1686 u := newNode(rnd.Int63n(int64(n))) 1687 var v graph.Node 1688 for { 1689 v = newNode(rnd.Int63n(int64(n))) 1690 if canLoop || u.ID() != v.ID() { 1691 break 1692 } 1693 } 1694 e := g.NewWeightedEdge(u, v, w) 1695 if g.Edge(u.ID(), v.ID()) != nil { 1696 t.Fatalf("NewEdge returned existing: %#v", e) 1697 } 1698 g.SetWeightedEdge(e) 1699 ne := g.Edge(u.ID(), v.ID()) 1700 if ne == nil { 1701 t.Fatalf("SetWeightedEdge failed to add edge: %#v", e) 1702 } 1703 we, ok := ne.(graph.WeightedEdge) 1704 if !ok { 1705 t.Fatalf("SetWeightedEdge failed to add weighted edge: %#v", e) 1706 } 1707 if we.Weight() != w { 1708 t.Fatalf("edge weight mismatch: got:%f want:%f", we.Weight(), w) 1709 } 1710 1711 if g.Node(u.ID()) == nil { 1712 t.Fatalf("SetWeightedEdge failed to add from node: %#v", u) 1713 } 1714 if g.Node(v.ID()) == nil { 1715 t.Fatalf("SetWeightedEdge failed to add to node: %#v", v) 1716 } 1717 1718 if !canSetNode { 1719 continue 1720 } 1721 1722 g.SetWeightedEdge(g.NewWeightedEdge(altNode{u}, altNode{v}, w)) 1723 if nu := g.Node(u.ID()); nu == u { 1724 t.Fatalf("SetWeightedEdge failed to update from node: u=%#v nu=%#v", u, nu) 1725 } 1726 if nv := g.Node(v.ID()); nv == v { 1727 t.Fatalf("SetWeightedEdge failed to update to node: v=%#v nv=%#v", v, nv) 1728 } 1729 } 1730 } 1731 1732 // NoLoopAddEdges tests whether g panics for self-loop addition. NoLoopAddEdges 1733 // adds n nodes with IDs in [0,n) and creates an edge from the graph with NewEdge. 1734 // NoLoopAddEdges confirms that this does not panic and then adds the edge to the 1735 // graph to ensure that SetEdge will panic when adding a self-loop. 1736 func NoLoopAddEdges(t *testing.T, n int, g EdgeAdder, newNode func(id int64) graph.Node) { 1737 defer func() { 1738 r := recover() 1739 if r != nil { 1740 t.Errorf("unexpected panic: %v", r) 1741 } 1742 }() 1743 1744 for id := 0; id < n; id++ { 1745 node := newNode(int64(id)) 1746 e := g.NewEdge(node, node) 1747 panicked := panics(func() { 1748 g.SetEdge(e) 1749 }) 1750 if !panicked { 1751 t.Errorf("expected panic for self-edge: %#v", e) 1752 } 1753 } 1754 } 1755 1756 // NoLoopAddWeightedEdges tests whether g panics for self-loop addition. NoLoopAddWeightedEdges 1757 // adds n nodes with IDs in [0,n) and creates an edge from the graph with NewWeightedEdge. 1758 // NoLoopAddWeightedEdges confirms that this does not panic and then adds the edge to the 1759 // graph to ensure that SetWeightedEdge will panic when adding a self-loop. 1760 func NoLoopAddWeightedEdges(t *testing.T, n int, g WeightedEdgeAdder, w float64, newNode func(id int64) graph.Node) { 1761 defer func() { 1762 r := recover() 1763 if r != nil { 1764 t.Errorf("unexpected panic: %v", r) 1765 } 1766 }() 1767 1768 for id := 0; id < n; id++ { 1769 node := newNode(int64(id)) 1770 e := g.NewWeightedEdge(node, node, w) 1771 panicked := panics(func() { 1772 g.SetWeightedEdge(e) 1773 }) 1774 if !panicked { 1775 t.Errorf("expected panic for self-edge: %#v", e) 1776 } 1777 } 1778 } 1779 1780 // LineAdder is a graph.LineAdder multigraph. 1781 type LineAdder interface { 1782 graph.Multigraph 1783 graph.LineAdder 1784 } 1785 1786 // AddLines tests whether g correctly implements the graph.LineAdder interface. 1787 // AddLines creates n pairs of nodes with random IDs in [0,n) and joins edges 1788 // each node in the pair using SetLine. AddLines confirms that the end point 1789 // nodes are added to the graph and that the edges are stored in the graph. 1790 // If canSet is true, a second call to SetLine is made for each edge to confirm 1791 // that the nodes corresponding the end points are updated. 1792 func AddLines(t *testing.T, n int, g LineAdder, newNode func(id int64) graph.Node, canSetNode bool) { 1793 defer func() { 1794 r := recover() 1795 if r != nil { 1796 t.Errorf("unexpected panic: %v", r) 1797 } 1798 }() 1799 1800 type altNode struct { 1801 graph.Node 1802 } 1803 1804 rnd := rand.New(rand.NewSource(1)) 1805 seen := make(tripleInt64s) 1806 for i := 0; i < n; i++ { 1807 u := newNode(rnd.Int63n(int64(n))) 1808 v := newNode(rnd.Int63n(int64(n))) 1809 prev := g.Lines(u.ID(), v.ID()) 1810 l := g.NewLine(u, v) 1811 if seen.has(u.ID(), v.ID(), l.ID()) { 1812 t.Fatalf("NewLine returned an existing line: %#v", l) 1813 } 1814 if g.Lines(u.ID(), v.ID()).Len() != prev.Len() { 1815 t.Fatalf("NewLine added a line: %#v", l) 1816 } 1817 g.SetLine(l) 1818 seen.add(u.ID(), v.ID(), l.ID()) 1819 if g.Lines(u.ID(), v.ID()).Len() != prev.Len()+1 { 1820 t.Fatalf("SetLine failed to add line: %#v", l) 1821 } 1822 if g.Node(u.ID()) == nil { 1823 t.Fatalf("SetLine failed to add from node: %#v", u) 1824 } 1825 if g.Node(v.ID()) == nil { 1826 t.Fatalf("SetLine failed to add to node: %#v", v) 1827 } 1828 1829 if !canSetNode { 1830 continue 1831 } 1832 1833 g.SetLine(g.NewLine(altNode{u}, altNode{v})) 1834 if nu := g.Node(u.ID()); nu == u { 1835 t.Fatalf("SetLine failed to update from node: u=%#v nu=%#v", u, nu) 1836 } 1837 if nv := g.Node(v.ID()); nv == v { 1838 t.Fatalf("SetLine failed to update to node: v=%#v nv=%#v", v, nv) 1839 } 1840 } 1841 } 1842 1843 // WeightedLineAdder is a graph.WeightedLineAdder multigraph. 1844 type WeightedLineAdder interface { 1845 graph.Multigraph 1846 graph.WeightedLineAdder 1847 } 1848 1849 // AddWeightedLines tests whether g correctly implements the graph.WeightedEdgeAdder 1850 // interface. AddWeightedLines creates n pairs of nodes with random IDs in [0,n) and 1851 // joins edges each node in the pair using SetWeightedLine with weight w. 1852 // AddWeightedLines confirms that the end point nodes are added to the graph and that 1853 // the edges are stored in the graph. If canSet is true, a second call to SetWeightedLine 1854 // is made for each edge to confirm that the nodes corresponding the end points are 1855 // updated. 1856 func AddWeightedLines(t *testing.T, n int, g WeightedLineAdder, w float64, newNode func(id int64) graph.Node, canSetNode bool) { 1857 defer func() { 1858 r := recover() 1859 if r != nil { 1860 t.Errorf("unexpected panic: %v", r) 1861 } 1862 }() 1863 1864 type altNode struct { 1865 graph.Node 1866 } 1867 1868 rnd := rand.New(rand.NewSource(1)) 1869 seen := make(tripleInt64s) 1870 for i := 0; i < n; i++ { 1871 u := newNode(rnd.Int63n(int64(n))) 1872 v := newNode(rnd.Int63n(int64(n))) 1873 prev := g.Lines(u.ID(), v.ID()) 1874 l := g.NewWeightedLine(u, v, w) 1875 if seen.has(u.ID(), v.ID(), l.ID()) { 1876 t.Fatalf("NewWeightedLine returned an existing line: %#v", l) 1877 } 1878 if g.Lines(u.ID(), v.ID()).Len() != prev.Len() { 1879 t.Fatalf("NewWeightedLine added a line: %#v", l) 1880 } 1881 g.SetWeightedLine(l) 1882 seen.add(u.ID(), v.ID(), l.ID()) 1883 curr := g.Lines(u.ID(), v.ID()) 1884 if curr.Len() != prev.Len()+1 { 1885 t.Fatalf("SetWeightedLine failed to add line: %#v", l) 1886 } 1887 var found bool 1888 for curr.Next() { 1889 if curr.Line().ID() == l.ID() { 1890 found = true 1891 wl, ok := curr.Line().(graph.WeightedLine) 1892 if !ok { 1893 t.Fatalf("SetWeightedLine failed to add weighted line: %#v", l) 1894 } 1895 if wl.Weight() != w { 1896 t.Fatalf("line weight mismatch: got:%f want:%f", wl.Weight(), w) 1897 } 1898 break 1899 } 1900 } 1901 if !found { 1902 t.Fatalf("SetWeightedLine failed to add line: %#v", l) 1903 } 1904 if g.Node(u.ID()) == nil { 1905 t.Fatalf("SetWeightedLine failed to add from node: %#v", u) 1906 } 1907 if g.Node(v.ID()) == nil { 1908 t.Fatalf("SetWeightedLine failed to add to node: %#v", v) 1909 } 1910 1911 if !canSetNode { 1912 continue 1913 } 1914 1915 g.SetWeightedLine(g.NewWeightedLine(altNode{u}, altNode{v}, w)) 1916 if nu := g.Node(u.ID()); nu == u { 1917 t.Fatalf("SetWeightedLine failed to update from node: u=%#v nu=%#v", u, nu) 1918 } 1919 if nv := g.Node(v.ID()); nv == v { 1920 t.Fatalf("SetWeightedLine failed to update to node: v=%#v nv=%#v", v, nv) 1921 } 1922 } 1923 } 1924 1925 // EdgeRemover is a graph.EdgeRemover graph. 1926 type EdgeRemover interface { 1927 graph.Graph 1928 graph.EdgeRemover 1929 } 1930 1931 // RemoveEdges tests whether g correctly implements the graph.EdgeRemover interface. 1932 // The input graph g must contain a set of nodes with some edges between them. 1933 // RemoveEdges iterates over remove, which must contain edges in g, removing each 1934 // edge. RemoveEdges confirms that the edge is removed, leaving its end-point nodes 1935 // and all other edges in the graph. 1936 func RemoveEdges(t *testing.T, g EdgeRemover, remove graph.Edges) { 1937 edges := make(map[edge]struct{}) 1938 nodes := g.Nodes() 1939 for nodes.Next() { 1940 u := nodes.Node() 1941 uid := u.ID() 1942 to := g.From(uid) 1943 for to.Next() { 1944 v := to.Node() 1945 edges[edge{f: u.ID(), t: v.ID()}] = struct{}{} 1946 } 1947 } 1948 1949 for remove.Next() { 1950 e := remove.Edge() 1951 if g.Edge(e.From().ID(), e.To().ID()) == nil { 1952 t.Fatalf("bad tests: missing edge: %#v", e) 1953 } 1954 if g.Node(e.From().ID()) == nil { 1955 t.Fatalf("bad tests: missing from node: %#v", e.From()) 1956 } 1957 if g.Node(e.To().ID()) == nil { 1958 t.Fatalf("bad tests: missing to node: %#v", e.To()) 1959 } 1960 1961 g.RemoveEdge(e.From().ID(), e.To().ID()) 1962 1963 if _, ok := g.(graph.Undirected); ok { 1964 delete(edges, edge{f: e.To().ID(), t: e.From().ID()}) 1965 } 1966 delete(edges, edge{f: e.From().ID(), t: e.To().ID()}) 1967 for ge := range edges { 1968 if g.Edge(ge.f, ge.t) == nil { 1969 t.Fatalf("unexpected missing edge after removing edge %#v: %#v", e, ge) 1970 } 1971 } 1972 1973 if ne := g.Edge(e.From().ID(), e.To().ID()); ne != nil { 1974 t.Fatalf("expected nil edge: got:%#v", ne) 1975 } 1976 if g.Node(e.From().ID()) == nil { 1977 t.Fatalf("unexpected deletion of from node: %#v", e.From()) 1978 } 1979 if g.Node(e.To().ID()) == nil { 1980 t.Fatalf("unexpected deletion to node: %#v", e.To()) 1981 } 1982 } 1983 } 1984 1985 // LineRemover is a graph.EdgeRemove graph. 1986 type LineRemover interface { 1987 graph.Multigraph 1988 graph.LineRemover 1989 } 1990 1991 // RemoveLines tests whether g correctly implements the graph.LineRemover interface. 1992 // The input graph g must contain a set of nodes with some lines between them. 1993 // RemoveLines iterates over remove, which must contain lines in g, removing each 1994 // line. RemoveLines confirms that the line is removed, leaving its end-point nodes 1995 // and all other lines in the graph. 1996 func RemoveLines(t *testing.T, g LineRemover, remove graph.Lines) { 1997 // lines is the set of lines in the graph. 1998 // The presence of a key indicates that the 1999 // line should exist in the graph. The value 2000 // for each key is used to indicate whether 2001 // it has been found during testing. 2002 lines := make(map[edge]bool) 2003 nodes := g.Nodes() 2004 for nodes.Next() { 2005 u := nodes.Node() 2006 uid := u.ID() 2007 to := g.From(uid) 2008 for to.Next() { 2009 v := to.Node() 2010 lit := g.Lines(u.ID(), v.ID()) 2011 for lit.Next() { 2012 lines[edge{f: u.ID(), t: v.ID(), id: lit.Line().ID()}] = true 2013 } 2014 } 2015 } 2016 2017 for remove.Next() { 2018 l := remove.Line() 2019 if g.Lines(l.From().ID(), l.To().ID()) == graph.Empty { 2020 t.Fatalf("bad tests: missing line: %#v", l) 2021 } 2022 if g.Node(l.From().ID()) == nil { 2023 t.Fatalf("bad tests: missing from node: %#v", l.From()) 2024 } 2025 if g.Node(l.To().ID()) == nil { 2026 t.Fatalf("bad tests: missing to node: %#v", l.To()) 2027 } 2028 2029 prev := g.Lines(l.From().ID(), l.To().ID()) 2030 2031 g.RemoveLine(l.From().ID(), l.To().ID(), l.ID()) 2032 2033 if _, ok := g.(graph.Undirected); ok { 2034 delete(lines, edge{f: l.To().ID(), t: l.From().ID(), id: l.ID()}) 2035 } 2036 delete(lines, edge{f: l.From().ID(), t: l.To().ID(), id: l.ID()}) 2037 2038 // Mark all lines as not found. 2039 for gl := range lines { 2040 lines[gl] = false 2041 } 2042 2043 // Mark found lines. This could be done far more efficiently. 2044 for gl := range lines { 2045 lit := g.Lines(gl.f, gl.t) 2046 for lit.Next() { 2047 lid := lit.Line().ID() 2048 if lid == gl.id { 2049 lines[gl] = true 2050 break 2051 } 2052 } 2053 } 2054 for gl, found := range lines { 2055 if !found { 2056 t.Fatalf("unexpected missing line after removing line %#v: %#v", l, gl) 2057 } 2058 } 2059 2060 if curr := g.Lines(l.From().ID(), l.To().ID()); curr.Len() != prev.Len()-1 { 2061 t.Fatalf("RemoveLine failed to mutate graph: curr edge size != prev edge size-1, %d != %d", curr.Len(), prev.Len()-1) 2062 } 2063 if g.Node(l.From().ID()) == nil { 2064 t.Fatalf("unexpected deletion of from node: %#v", l.From()) 2065 } 2066 if g.Node(l.To().ID()) == nil { 2067 t.Fatalf("unexpected deletion to node: %#v", l.To()) 2068 } 2069 } 2070 } 2071 2072 // undirectedIDs returns a numerical sort ordered canonicalisation of the 2073 // IDs of e. 2074 func undirectedIDs(e Edge) (lo, hi int64, inverted bool) { 2075 lid := e.From().ID() 2076 hid := e.To().ID() 2077 if hid < lid { 2078 inverted = true 2079 hid, lid = lid, hid 2080 } 2081 return lid, hid, inverted 2082 } 2083 2084 type edge struct { 2085 f, t, id int64 2086 } 2087 2088 func panics(fn func()) (ok bool) { 2089 defer func() { 2090 ok = recover() != nil 2091 }() 2092 fn() 2093 return 2094 } 2095 2096 // RandomNodes implements the graph.Nodes interface for a set of random nodes. 2097 type RandomNodes struct { 2098 n int 2099 seed uint64 2100 newNode func(int64) graph.Node 2101 2102 curr int64 2103 2104 state *rand.Rand 2105 seen set.Int64s 2106 count int 2107 } 2108 2109 var _ graph.Nodes = (*RandomNodes)(nil) 2110 2111 // NewRandomNodes returns a new implicit node iterator containing a set of n nodes 2112 // with IDs generated from a PRNG seeded by the given seed. 2113 // The provided new func maps the id to a graph.Node. 2114 func NewRandomNodes(n int, seed uint64, new func(id int64) graph.Node) *RandomNodes { 2115 return &RandomNodes{ 2116 n: n, 2117 seed: seed, 2118 newNode: new, 2119 2120 state: rand.New(rand.NewSource(int64(seed))), 2121 seen: make(set.Int64s), 2122 count: 0, 2123 } 2124 } 2125 2126 // Len returns the remaining number of nodes to be iterated over. 2127 func (n *RandomNodes) Len() int { 2128 return n.n - n.count 2129 } 2130 2131 // Next returns whether the next call of Node will return a valid node. 2132 func (n *RandomNodes) Next() bool { 2133 if n.count >= n.n { 2134 return false 2135 } 2136 n.count++ 2137 for { 2138 sign := int64(1) 2139 if n.state.Float64() < 0.5 { 2140 sign *= -1 2141 } 2142 n.curr = sign * n.state.Int63() 2143 if !n.seen.Has(n.curr) { 2144 n.seen.Add(n.curr) 2145 return true 2146 } 2147 } 2148 } 2149 2150 // Node returns the current node of the iterator. Next must have been 2151 // called prior to a call to Node. 2152 func (n *RandomNodes) Node() graph.Node { 2153 if n.Len() == -1 || n.count == 0 { 2154 return nil 2155 } 2156 return n.newNode(n.curr) 2157 } 2158 2159 // Reset returns the iterator to its initial state. 2160 func (n *RandomNodes) Reset() { 2161 n.state = rand.New(rand.NewSource(int64(n.seed))) 2162 n.seen = make(set.Int64s) 2163 n.count = 0 2164 } 2165 2166 // tripleInt64s is a set of [3]int64 identifiers. 2167 type tripleInt64s map[[3]int64]struct{} 2168 2169 // add inserts an element into the set. 2170 func (s tripleInt64s) add(x, y, z int64) { 2171 s[[3]int64{x, y, z}] = struct{}{} 2172 } 2173 2174 // has reports the existence of the element in the set. 2175 func (s tripleInt64s) has(x, y, z int64) bool { 2176 _, ok := s[[3]int64{x, y, z}] 2177 return ok 2178 }