ginger/graph/graph_test.go

175 lines
3.8 KiB
Go

package graph
import (
"fmt"
. "testing"
"time"
"github.com/mediocregopher/mediocre-go-lib/mrand"
"github.com/mediocregopher/mediocre-go-lib/mtest/massert"
"github.com/mediocregopher/mediocre-go-lib/mtest/mchk"
)
func strV(s string) Value {
return Value{ID: s, V: s}
}
func TestGraph(t *T) {
t.Parallel()
type state struct {
Graph
m map[string]Edge
}
type params struct {
add Edge
del Edge
}
chk := mchk.Checker{
Init: func() mchk.State {
return state{
m: map[string]Edge{},
}
},
Next: func(ss mchk.State) mchk.Action {
s := ss.(state)
var p params
if i := mrand.Intn(10); i == 0 {
// add edge which is already there
for _, e := range s.m {
p.add = e
break
}
} else if i == 1 {
// delete edge which isn't there
p.del = Edge{Tail: strV("z"), Head: strV("z")}
} else if i <= 5 {
// add probably new edge
p.add = Edge{Tail: strV(mrand.Hex(1)), Head: strV(mrand.Hex(1))}
} else {
// probably del edge
p.del = Edge{Tail: strV(mrand.Hex(1)), Head: strV(mrand.Hex(1))}
}
return mchk.Action{Params: p}
},
Apply: func(ss mchk.State, a mchk.Action) (mchk.State, error) {
s, p := ss.(state), a.Params.(params)
if p.add != (Edge{}) {
s.Graph = s.Graph.AddEdge(p.add)
s.m[p.add.id()] = p.add
} else {
s.Graph = s.Graph.DelEdge(p.del)
delete(s.m, p.del.id())
}
{ // test Values and Edges methods
vals := s.Graph.Values()
edges := s.Graph.Edges()
var aa []massert.Assertion
found := map[string]bool{}
tryAssert := func(v Value) {
if ok := found[v.ID]; !ok {
found[v.ID] = true
aa = append(aa, massert.Has(vals, v))
}
}
for _, e := range s.m {
aa = append(aa, massert.Has(edges, e))
tryAssert(e.Head)
tryAssert(e.Tail)
}
aa = append(aa, massert.Len(vals, len(found)))
aa = append(aa, massert.Len(edges, len(s.m)))
if err := massert.All(aa...).Assert(); err != nil {
return nil, err
}
}
{ // test ValueEdges
for _, val := range s.Graph.Values() {
in, out := s.Graph.ValueEdges(val)
var expIn, expOut []Edge
for _, e := range s.m {
if e.Tail.ID == val.ID {
expOut = append(expOut, e)
}
if e.Head.ID == val.ID {
expIn = append(expIn, e)
}
}
if err := massert.Comment(massert.All(
massert.Subset(expIn, in),
massert.Len(in, len(expIn)),
massert.Subset(expOut, out),
massert.Len(out, len(expOut)),
), "val:%q", val.V).Assert(); err != nil {
return nil, err
}
}
}
return s, nil
},
}
if err := chk.RunFor(5 * time.Second); err != nil {
t.Fatal(err)
}
}
func TestSubGraphAndEqual(t *T) {
t.Parallel()
type state struct {
g1, g2 Graph
expEqual, expSubGraph bool
}
type params struct {
e Edge
add1, add2 bool
}
chk := mchk.Checker{
Init: func() mchk.State {
return state{expEqual: true, expSubGraph: true}
},
Next: func(ss mchk.State) mchk.Action {
i := mrand.Intn(10)
p := params{
e: Edge{Tail: strV(mrand.Hex(4)), Head: strV(mrand.Hex(4))},
add1: i != 0,
add2: i != 1,
}
return mchk.Action{Params: p}
},
Apply: func(ss mchk.State, a mchk.Action) (mchk.State, error) {
s, p := ss.(state), a.Params.(params)
if p.add1 {
s.g1 = s.g1.AddEdge(p.e)
}
if p.add2 {
s.g2 = s.g2.AddEdge(p.e)
}
s.expSubGraph = s.expSubGraph && p.add1
s.expEqual = s.expEqual && p.add1 && p.add2
if s.g1.SubGraph(s.g2) != s.expSubGraph {
return nil, fmt.Errorf("SubGraph expected to return %v", s.expSubGraph)
}
if s.g1.Equal(s.g2) != s.expEqual {
return nil, fmt.Errorf("Equal expected to return %v", s.expEqual)
}
return s, nil
},
MaxLength: 100,
}
if err := chk.RunFor(5 * time.Second); err != nil {
t.Fatal(err)
}
}