2017-02-02 20:41:46 +01:00
|
|
|
package dag
|
|
|
|
|
|
|
|
import (
|
|
|
|
"reflect"
|
|
|
|
"sync"
|
|
|
|
"testing"
|
2017-02-02 21:09:26 +01:00
|
|
|
"time"
|
2017-02-02 20:41:46 +01:00
|
|
|
)
|
|
|
|
|
|
|
|
func TestWalker_basic(t *testing.T) {
|
|
|
|
var g Graph
|
|
|
|
g.Add(1)
|
|
|
|
g.Add(2)
|
|
|
|
g.Connect(BasicEdge(1, 2))
|
|
|
|
|
|
|
|
// Run it a bunch of times since it is timing dependent
|
|
|
|
for i := 0; i < 50; i++ {
|
|
|
|
var order []interface{}
|
|
|
|
w := &walker{Callback: walkCbRecord(&order)}
|
|
|
|
w.Update(g.vertices, g.edges)
|
|
|
|
|
|
|
|
// Wait
|
|
|
|
if err := w.Wait(); err != nil {
|
|
|
|
t.Fatalf("err: %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check
|
|
|
|
expected := []interface{}{1, 2}
|
|
|
|
if !reflect.DeepEqual(order, expected) {
|
|
|
|
t.Fatalf("bad: %#v", order)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-02-02 21:09:26 +01:00
|
|
|
func TestWalker_newVertex(t *testing.T) {
|
|
|
|
// Run it a bunch of times since it is timing dependent
|
|
|
|
for i := 0; i < 50; i++ {
|
|
|
|
var g Graph
|
|
|
|
g.Add(1)
|
|
|
|
g.Add(2)
|
|
|
|
g.Connect(BasicEdge(1, 2))
|
|
|
|
|
|
|
|
var order []interface{}
|
|
|
|
w := &walker{Callback: walkCbRecord(&order)}
|
|
|
|
w.Update(g.vertices, g.edges)
|
|
|
|
|
|
|
|
// Wait a bit
|
|
|
|
time.Sleep(10 * time.Millisecond)
|
|
|
|
|
|
|
|
// Update the graph
|
|
|
|
g.Add(3)
|
|
|
|
w.Update(g.vertices, g.edges)
|
|
|
|
|
|
|
|
// Update the graph again but with the same vertex
|
|
|
|
g.Add(3)
|
|
|
|
w.Update(g.vertices, g.edges)
|
|
|
|
|
|
|
|
// Wait
|
|
|
|
if err := w.Wait(); err != nil {
|
|
|
|
t.Fatalf("err: %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check
|
|
|
|
expected := []interface{}{1, 2, 3}
|
|
|
|
if !reflect.DeepEqual(order, expected) {
|
|
|
|
t.Fatalf("bad: %#v", order)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestWalker_removeVertex(t *testing.T) {
|
|
|
|
// Run it a bunch of times since it is timing dependent
|
|
|
|
for i := 0; i < 50; i++ {
|
|
|
|
var g Graph
|
|
|
|
g.Add(1)
|
|
|
|
g.Add(2)
|
|
|
|
g.Connect(BasicEdge(1, 2))
|
|
|
|
|
|
|
|
// Record function
|
|
|
|
var order []interface{}
|
|
|
|
recordF := walkCbRecord(&order)
|
|
|
|
|
|
|
|
// Build a callback that delays until we close a channel
|
|
|
|
gateCh := make(chan struct{})
|
|
|
|
cb := func(v Vertex) error {
|
|
|
|
if v == 1 {
|
|
|
|
<-gateCh
|
|
|
|
}
|
|
|
|
|
|
|
|
return recordF(v)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add the initial vertices
|
|
|
|
w := &walker{Callback: cb}
|
|
|
|
w.Update(g.vertices, g.edges)
|
|
|
|
|
|
|
|
// Remove a vertex
|
|
|
|
g.Remove(2)
|
|
|
|
w.Update(g.vertices, g.edges)
|
|
|
|
|
|
|
|
// Open gate
|
|
|
|
close(gateCh)
|
|
|
|
|
|
|
|
// Wait
|
|
|
|
if err := w.Wait(); err != nil {
|
|
|
|
t.Fatalf("err: %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check
|
|
|
|
expected := []interface{}{1}
|
|
|
|
if !reflect.DeepEqual(order, expected) {
|
|
|
|
t.Fatalf("bad: %#v", order)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestWalker_newEdge(t *testing.T) {
|
|
|
|
// Run it a bunch of times since it is timing dependent
|
|
|
|
for i := 0; i < 50; i++ {
|
|
|
|
var g Graph
|
|
|
|
g.Add(1)
|
|
|
|
g.Add(2)
|
|
|
|
g.Connect(BasicEdge(1, 2))
|
|
|
|
|
|
|
|
// Record function
|
|
|
|
var order []interface{}
|
|
|
|
recordF := walkCbRecord(&order)
|
|
|
|
|
|
|
|
// Build a callback that delays until we close a channel
|
|
|
|
var w *walker
|
|
|
|
cb := func(v Vertex) error {
|
|
|
|
if v == 1 {
|
|
|
|
g.Add(3)
|
|
|
|
g.Connect(BasicEdge(3, 2))
|
|
|
|
w.Update(g.vertices, g.edges)
|
|
|
|
}
|
|
|
|
|
|
|
|
return recordF(v)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add the initial vertices
|
|
|
|
w = &walker{Callback: cb}
|
|
|
|
w.Update(g.vertices, g.edges)
|
|
|
|
|
|
|
|
// Wait
|
|
|
|
if err := w.Wait(); err != nil {
|
|
|
|
t.Fatalf("err: %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check
|
|
|
|
expected := []interface{}{1, 3, 2}
|
|
|
|
if !reflect.DeepEqual(order, expected) {
|
|
|
|
t.Fatalf("bad: %#v", order)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-02-02 20:41:46 +01:00
|
|
|
// walkCbRecord is a test helper callback that just records the order called.
|
|
|
|
func walkCbRecord(order *[]interface{}) WalkFunc {
|
|
|
|
var l sync.Mutex
|
|
|
|
return func(v Vertex) error {
|
|
|
|
l.Lock()
|
|
|
|
defer l.Unlock()
|
|
|
|
*order = append(*order, v)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
}
|