2017-10-21 18:39:23 +00:00
|
|
|
package gg
|
|
|
|
|
|
|
|
import (
|
2018-06-07 02:21:44 +00:00
|
|
|
"fmt"
|
|
|
|
"sort"
|
|
|
|
"strings"
|
2017-10-21 18:39:23 +00:00
|
|
|
. "testing"
|
|
|
|
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
|
|
)
|
|
|
|
|
2018-01-21 15:39:25 +00:00
|
|
|
func edge(val Value, from *Vertex) Edge {
|
|
|
|
return Edge{Value: val, From: from}
|
2017-10-21 18:39:23 +00:00
|
|
|
}
|
|
|
|
|
2018-01-21 15:39:25 +00:00
|
|
|
func value(val Value, in ...Edge) *Vertex {
|
2017-10-21 18:39:23 +00:00
|
|
|
return &Vertex{
|
2018-01-21 15:39:25 +00:00
|
|
|
VertexType: ValueVertex,
|
|
|
|
Value: val,
|
2017-10-21 18:39:23 +00:00
|
|
|
In: in,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-08-27 03:26:24 +00:00
|
|
|
func tuple(val Value, in ...Edge) Edge {
|
2017-10-21 18:39:23 +00:00
|
|
|
return Edge{
|
|
|
|
From: &Vertex{
|
2021-08-27 03:26:24 +00:00
|
|
|
VertexType: TupleVertex,
|
2017-10-21 18:39:23 +00:00
|
|
|
In: in,
|
|
|
|
},
|
2018-01-21 15:39:25 +00:00
|
|
|
Value: val,
|
2017-10-21 18:39:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func assertVertexEqual(t *T, exp, got *Vertex, msgAndArgs ...interface{}) bool {
|
|
|
|
var assertInner func(*Vertex, *Vertex, map[*Vertex]bool) bool
|
|
|
|
assertInner = func(exp, got *Vertex, m map[*Vertex]bool) bool {
|
|
|
|
// if got is already in m then we've already looked at it
|
|
|
|
if m[got] {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
m[got] = true
|
|
|
|
|
|
|
|
assert.Equal(t, exp.VertexType, got.VertexType, msgAndArgs...)
|
|
|
|
assert.Equal(t, exp.Value, got.Value, msgAndArgs...)
|
|
|
|
if !assert.Len(t, got.In, len(exp.In), msgAndArgs...) {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
for i := range exp.In {
|
|
|
|
assertInner(exp.In[i].From, got.In[i].From, m)
|
|
|
|
assert.Equal(t, exp.In[i].Value, got.In[i].Value, msgAndArgs...)
|
|
|
|
assert.Equal(t, got, got.In[i].To)
|
|
|
|
assert.Contains(t, got.In[i].From.Out, got.In[i])
|
|
|
|
}
|
|
|
|
return true
|
|
|
|
|
|
|
|
}
|
|
|
|
return assertInner(exp, got, map[*Vertex]bool{})
|
|
|
|
}
|
|
|
|
|
2018-06-07 02:21:44 +00:00
|
|
|
func assertIter(t *T, expVals, expJuncs int, g *Graph, msgAndArgs ...interface{}) {
|
2017-11-05 16:57:57 +00:00
|
|
|
seen := map[*Vertex]bool{}
|
|
|
|
var gotVals, gotJuncs int
|
2018-06-07 02:21:44 +00:00
|
|
|
g.Iter(func(v *Vertex) bool {
|
2017-11-05 16:57:57 +00:00
|
|
|
assert.NotContains(t, seen, v, msgAndArgs...)
|
|
|
|
seen[v] = true
|
2018-01-21 15:39:25 +00:00
|
|
|
if v.VertexType == ValueVertex {
|
2017-11-05 16:57:57 +00:00
|
|
|
gotVals++
|
|
|
|
} else {
|
|
|
|
gotJuncs++
|
|
|
|
}
|
|
|
|
return true
|
|
|
|
})
|
|
|
|
assert.Equal(t, expVals, gotVals, msgAndArgs...)
|
|
|
|
assert.Equal(t, expJuncs, gotJuncs, msgAndArgs...)
|
|
|
|
}
|
|
|
|
|
2017-10-21 18:39:23 +00:00
|
|
|
type graphTest struct {
|
2017-11-05 16:57:57 +00:00
|
|
|
name string
|
|
|
|
out func() *Graph
|
|
|
|
exp []*Vertex
|
|
|
|
numVals, numJuncs int
|
2017-10-21 18:39:23 +00:00
|
|
|
}
|
|
|
|
|
2017-11-05 16:57:57 +00:00
|
|
|
func mkTest(name string, out func() *Graph, numVals, numJuncs int, exp ...*Vertex) graphTest {
|
|
|
|
return graphTest{
|
|
|
|
name: name,
|
|
|
|
out: out,
|
|
|
|
exp: exp,
|
|
|
|
numVals: numVals, numJuncs: numJuncs,
|
|
|
|
}
|
2017-10-21 18:39:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestGraph(t *T) {
|
2018-01-21 15:39:25 +00:00
|
|
|
var (
|
|
|
|
v0 = NewValue("v0")
|
|
|
|
v1 = NewValue("v1")
|
|
|
|
v2 = NewValue("v2")
|
|
|
|
v3 = NewValue("v3")
|
|
|
|
e0 = NewValue("e0")
|
|
|
|
e00 = NewValue("e00")
|
|
|
|
e01 = NewValue("e01")
|
|
|
|
e1 = NewValue("e1")
|
|
|
|
e10 = NewValue("e10")
|
|
|
|
e11 = NewValue("e11")
|
|
|
|
e2 = NewValue("e2")
|
|
|
|
e20 = NewValue("e20")
|
|
|
|
e21 = NewValue("e21")
|
|
|
|
ej0 = NewValue("ej0")
|
|
|
|
ej1 = NewValue("ej1")
|
|
|
|
ej2 = NewValue("ej2")
|
|
|
|
)
|
2017-10-21 18:39:23 +00:00
|
|
|
tests := []graphTest{
|
|
|
|
mkTest(
|
|
|
|
"values-basic",
|
|
|
|
func() *Graph {
|
2021-08-27 03:26:24 +00:00
|
|
|
return ZeroGraph.AddValueIn(ValueOut(v0, e0), v1)
|
2017-10-21 18:39:23 +00:00
|
|
|
},
|
2017-11-05 16:57:57 +00:00
|
|
|
2, 0,
|
2018-01-21 15:39:25 +00:00
|
|
|
value(v0),
|
|
|
|
value(v1, edge(e0, value(v0))),
|
2017-10-21 18:39:23 +00:00
|
|
|
),
|
|
|
|
|
|
|
|
mkTest(
|
|
|
|
"values-2edges",
|
|
|
|
func() *Graph {
|
2021-08-27 03:26:24 +00:00
|
|
|
g0 := ZeroGraph.AddValueIn(ValueOut(v0, e0), v2)
|
2018-01-21 15:39:25 +00:00
|
|
|
return g0.AddValueIn(ValueOut(v1, e1), v2)
|
2017-10-21 18:39:23 +00:00
|
|
|
},
|
2017-11-05 16:57:57 +00:00
|
|
|
3, 0,
|
2018-01-21 15:39:25 +00:00
|
|
|
value(v0),
|
|
|
|
value(v1),
|
|
|
|
value(v2,
|
|
|
|
edge(e0, value(v0)),
|
|
|
|
edge(e1, value(v1)),
|
2017-10-21 18:39:23 +00:00
|
|
|
),
|
|
|
|
),
|
|
|
|
|
|
|
|
mkTest(
|
|
|
|
"values-separate",
|
|
|
|
func() *Graph {
|
2021-08-27 03:26:24 +00:00
|
|
|
g0 := ZeroGraph.AddValueIn(ValueOut(v0, e0), v1)
|
2018-01-21 15:39:25 +00:00
|
|
|
return g0.AddValueIn(ValueOut(v2, e2), v3)
|
2017-10-21 18:39:23 +00:00
|
|
|
},
|
2017-11-05 16:57:57 +00:00
|
|
|
4, 0,
|
2018-01-21 15:39:25 +00:00
|
|
|
value(v0),
|
|
|
|
value(v1, edge(e0, value(v0))),
|
|
|
|
value(v2),
|
|
|
|
value(v3, edge(e2, value(v2))),
|
2017-10-21 18:39:23 +00:00
|
|
|
),
|
|
|
|
|
|
|
|
mkTest(
|
|
|
|
"values-circular",
|
|
|
|
func() *Graph {
|
2021-08-27 03:26:24 +00:00
|
|
|
return ZeroGraph.AddValueIn(ValueOut(v0, e0), v0)
|
2017-10-21 18:39:23 +00:00
|
|
|
},
|
2017-11-05 16:57:57 +00:00
|
|
|
1, 0,
|
2018-01-21 15:39:25 +00:00
|
|
|
value(v0, edge(e0, value(v0))),
|
2017-10-21 18:39:23 +00:00
|
|
|
),
|
|
|
|
|
|
|
|
mkTest(
|
|
|
|
"values-circular2",
|
|
|
|
func() *Graph {
|
2021-08-27 03:26:24 +00:00
|
|
|
g0 := ZeroGraph.AddValueIn(ValueOut(v0, e0), v1)
|
2018-01-21 15:39:25 +00:00
|
|
|
return g0.AddValueIn(ValueOut(v1, e1), v0)
|
2017-10-21 18:39:23 +00:00
|
|
|
},
|
2017-11-05 16:57:57 +00:00
|
|
|
2, 0,
|
2018-01-21 15:39:25 +00:00
|
|
|
value(v0, edge(e1, value(v1, edge(e0, value(v0))))),
|
|
|
|
value(v1, edge(e0, value(v0, edge(e1, value(v1))))),
|
2017-10-21 18:39:23 +00:00
|
|
|
),
|
|
|
|
|
|
|
|
mkTest(
|
|
|
|
"values-circular3",
|
|
|
|
func() *Graph {
|
2021-08-27 03:26:24 +00:00
|
|
|
g0 := ZeroGraph.AddValueIn(ValueOut(v0, e0), v1)
|
2018-01-21 15:39:25 +00:00
|
|
|
g1 := g0.AddValueIn(ValueOut(v1, e1), v2)
|
|
|
|
return g1.AddValueIn(ValueOut(v2, e2), v1)
|
2017-10-21 18:39:23 +00:00
|
|
|
},
|
2017-11-05 16:57:57 +00:00
|
|
|
3, 0,
|
2018-01-21 15:39:25 +00:00
|
|
|
value(v0),
|
|
|
|
value(v1,
|
|
|
|
edge(e0, value(v0)),
|
|
|
|
edge(e2, value(v2, edge(e1, value(v1)))),
|
2017-10-21 18:39:23 +00:00
|
|
|
),
|
2018-01-21 15:39:25 +00:00
|
|
|
value(v2, edge(e1, value(v1,
|
|
|
|
edge(e0, value(v0)),
|
|
|
|
edge(e2, value(v2)),
|
2017-10-21 18:39:23 +00:00
|
|
|
))),
|
|
|
|
),
|
|
|
|
|
|
|
|
mkTest(
|
2021-08-27 03:26:24 +00:00
|
|
|
"tuple-basic",
|
2017-10-21 18:39:23 +00:00
|
|
|
func() *Graph {
|
2018-01-21 15:39:25 +00:00
|
|
|
e0 := ValueOut(v0, e0)
|
|
|
|
e1 := ValueOut(v1, e1)
|
2021-08-27 03:26:24 +00:00
|
|
|
ej0 := TupleOut([]OpenEdge{e0, e1}, ej0)
|
|
|
|
return ZeroGraph.AddValueIn(ej0, v2)
|
2017-10-21 18:39:23 +00:00
|
|
|
},
|
2017-11-05 16:57:57 +00:00
|
|
|
3, 1,
|
2018-01-21 15:39:25 +00:00
|
|
|
value(v0), value(v1),
|
2021-08-27 03:26:24 +00:00
|
|
|
value(v2, tuple(ej0,
|
2018-01-21 15:39:25 +00:00
|
|
|
edge(e0, value(v0)),
|
|
|
|
edge(e1, value(v1)),
|
2017-10-21 18:39:23 +00:00
|
|
|
)),
|
|
|
|
),
|
|
|
|
|
|
|
|
mkTest(
|
2021-08-27 03:26:24 +00:00
|
|
|
"tuple-basic2",
|
2017-10-21 18:39:23 +00:00
|
|
|
func() *Graph {
|
2018-01-21 15:39:25 +00:00
|
|
|
e00 := ValueOut(v0, e00)
|
|
|
|
e10 := ValueOut(v1, e10)
|
2021-08-27 03:26:24 +00:00
|
|
|
ej0 := TupleOut([]OpenEdge{e00, e10}, ej0)
|
2018-01-21 15:39:25 +00:00
|
|
|
e01 := ValueOut(v0, e01)
|
|
|
|
e11 := ValueOut(v1, e11)
|
2021-08-27 03:26:24 +00:00
|
|
|
ej1 := TupleOut([]OpenEdge{e01, e11}, ej1)
|
|
|
|
ej2 := TupleOut([]OpenEdge{ej0, ej1}, ej2)
|
|
|
|
return ZeroGraph.AddValueIn(ej2, v2)
|
2017-10-21 18:39:23 +00:00
|
|
|
},
|
2017-11-05 16:57:57 +00:00
|
|
|
3, 3,
|
2018-01-21 15:39:25 +00:00
|
|
|
value(v0), value(v1),
|
2021-08-27 03:26:24 +00:00
|
|
|
value(v2, tuple(ej2,
|
|
|
|
tuple(ej0,
|
2018-01-21 15:39:25 +00:00
|
|
|
edge(e00, value(v0)),
|
|
|
|
edge(e10, value(v1)),
|
2017-10-21 18:39:23 +00:00
|
|
|
),
|
2021-08-27 03:26:24 +00:00
|
|
|
tuple(ej1,
|
2018-01-21 15:39:25 +00:00
|
|
|
edge(e01, value(v0)),
|
|
|
|
edge(e11, value(v1)),
|
2017-10-21 18:39:23 +00:00
|
|
|
),
|
|
|
|
)),
|
|
|
|
),
|
|
|
|
|
|
|
|
mkTest(
|
2021-08-27 03:26:24 +00:00
|
|
|
"tuple-circular",
|
2017-10-21 18:39:23 +00:00
|
|
|
func() *Graph {
|
2018-01-21 15:39:25 +00:00
|
|
|
e0 := ValueOut(v0, e0)
|
|
|
|
e1 := ValueOut(v1, e1)
|
2021-08-27 03:26:24 +00:00
|
|
|
ej0 := TupleOut([]OpenEdge{e0, e1}, ej0)
|
|
|
|
g0 := ZeroGraph.AddValueIn(ej0, v2)
|
2018-01-21 15:39:25 +00:00
|
|
|
e20 := ValueOut(v2, e20)
|
|
|
|
g1 := g0.AddValueIn(e20, v0)
|
|
|
|
e21 := ValueOut(v2, e21)
|
|
|
|
return g1.AddValueIn(e21, v1)
|
2017-10-21 18:39:23 +00:00
|
|
|
},
|
2017-11-05 16:57:57 +00:00
|
|
|
3, 1,
|
2021-08-27 03:26:24 +00:00
|
|
|
value(v0, edge(e20, value(v2, tuple(ej0,
|
2018-01-21 15:39:25 +00:00
|
|
|
edge(e0, value(v0)),
|
|
|
|
edge(e1, value(v1, edge(e21, value(v2)))),
|
2017-10-21 18:39:23 +00:00
|
|
|
)))),
|
2021-08-27 03:26:24 +00:00
|
|
|
value(v1, edge(e21, value(v2, tuple(ej0,
|
2018-01-21 15:39:25 +00:00
|
|
|
edge(e0, value(v0, edge(e20, value(v2)))),
|
|
|
|
edge(e1, value(v1)),
|
2017-10-21 18:39:23 +00:00
|
|
|
)))),
|
2021-08-27 03:26:24 +00:00
|
|
|
value(v2, tuple(ej0,
|
2018-01-21 15:39:25 +00:00
|
|
|
edge(e0, value(v0, edge(e20, value(v2)))),
|
|
|
|
edge(e1, value(v1, edge(e21, value(v2)))),
|
2017-10-21 18:39:23 +00:00
|
|
|
)),
|
|
|
|
),
|
|
|
|
}
|
|
|
|
|
|
|
|
for i := range tests {
|
2017-11-05 16:57:57 +00:00
|
|
|
t.Logf("test[%d]:%q", i, tests[i].name)
|
2017-10-21 18:39:23 +00:00
|
|
|
out := tests[i].out()
|
|
|
|
for j, exp := range tests[i].exp {
|
|
|
|
msgAndArgs := []interface{}{
|
|
|
|
"tests[%d].name:%q exp[%d].val:%q",
|
2018-01-21 15:39:25 +00:00
|
|
|
i, tests[i].name, j, exp.Value.V.(string),
|
2017-10-21 18:39:23 +00:00
|
|
|
}
|
2018-01-21 15:39:25 +00:00
|
|
|
v := out.ValueVertex(exp.Value)
|
2017-10-21 18:39:23 +00:00
|
|
|
if !assert.NotNil(t, v, msgAndArgs...) {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
assertVertexEqual(t, exp, v, msgAndArgs...)
|
|
|
|
}
|
|
|
|
|
2017-11-05 16:57:57 +00:00
|
|
|
msgAndArgs := []interface{}{
|
|
|
|
"tests[%d].name:%q",
|
|
|
|
i, tests[i].name,
|
|
|
|
}
|
|
|
|
|
2017-10-21 18:39:23 +00:00
|
|
|
// sanity check that graphs are equal to themselves
|
2017-11-05 16:57:57 +00:00
|
|
|
assert.True(t, Equal(out, out), msgAndArgs...)
|
|
|
|
|
2018-06-07 02:21:44 +00:00
|
|
|
// test the Iter method in here too
|
|
|
|
assertIter(t, tests[i].numVals, tests[i].numJuncs, out, msgAndArgs...)
|
2017-10-21 18:39:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestGraphImmutability(t *T) {
|
2018-01-21 15:39:25 +00:00
|
|
|
v0 := NewValue("v0")
|
|
|
|
v1 := NewValue("v1")
|
|
|
|
e0 := NewValue("e0")
|
|
|
|
oe0 := ValueOut(v0, e0)
|
2021-08-27 03:26:24 +00:00
|
|
|
g0 := ZeroGraph.AddValueIn(oe0, v1)
|
|
|
|
assert.Nil(t, ZeroGraph.ValueVertex(v0))
|
|
|
|
assert.Nil(t, ZeroGraph.ValueVertex(v1))
|
2018-01-21 15:39:25 +00:00
|
|
|
assert.NotNil(t, g0.ValueVertex(v0))
|
|
|
|
assert.NotNil(t, g0.ValueVertex(v1))
|
2017-10-21 18:39:23 +00:00
|
|
|
|
|
|
|
// half-edges should be re-usable
|
2018-01-21 15:39:25 +00:00
|
|
|
v2 := NewValue("v2")
|
|
|
|
v3a, v3b := NewValue("v3a"), NewValue("v3b")
|
|
|
|
e1 := NewValue("e1")
|
|
|
|
oe1 := ValueOut(v2, e1)
|
|
|
|
g1a := g0.AddValueIn(oe1, v3a)
|
|
|
|
g1b := g0.AddValueIn(oe1, v3b)
|
|
|
|
assertVertexEqual(t, value(v3a, edge(e1, value(v2))), g1a.ValueVertex(v3a))
|
|
|
|
assert.Nil(t, g1a.ValueVertex(v3b))
|
|
|
|
assertVertexEqual(t, value(v3b, edge(e1, value(v2))), g1b.ValueVertex(v3b))
|
|
|
|
assert.Nil(t, g1b.ValueVertex(v3a))
|
2017-10-21 18:39:23 +00:00
|
|
|
|
|
|
|
// ... even re-usable twice in succession
|
2018-01-21 15:39:25 +00:00
|
|
|
v3 := NewValue("v3")
|
|
|
|
v4 := NewValue("v4")
|
|
|
|
g2 := g0.AddValueIn(oe1, v3).AddValueIn(oe1, v4)
|
|
|
|
assert.Nil(t, g2.ValueVertex(v3b))
|
|
|
|
assert.Nil(t, g2.ValueVertex(v3a))
|
|
|
|
assertVertexEqual(t, value(v3, edge(e1, value(v2))), g2.ValueVertex(v3))
|
|
|
|
assertVertexEqual(t, value(v4, edge(e1, value(v2))), g2.ValueVertex(v4))
|
2017-10-21 18:39:23 +00:00
|
|
|
}
|
|
|
|
|
2017-10-22 17:39:32 +00:00
|
|
|
func TestGraphDelValueIn(t *T) {
|
2018-01-21 15:39:25 +00:00
|
|
|
v0 := NewValue("v0")
|
|
|
|
v1 := NewValue("v1")
|
|
|
|
e0 := NewValue("e0")
|
2017-10-22 17:39:32 +00:00
|
|
|
{ // removing from null
|
2021-08-27 03:26:24 +00:00
|
|
|
g := ZeroGraph.DelValueIn(ValueOut(v0, e0), v1)
|
|
|
|
assert.True(t, Equal(ZeroGraph, g))
|
2017-10-22 17:39:32 +00:00
|
|
|
}
|
|
|
|
|
2018-01-21 15:39:25 +00:00
|
|
|
e1 := NewValue("e1")
|
2017-10-22 17:39:32 +00:00
|
|
|
{ // removing edge from vertex which doesn't have that edge
|
2021-08-27 03:26:24 +00:00
|
|
|
g0 := ZeroGraph.AddValueIn(ValueOut(v0, e0), v1)
|
2018-01-21 15:39:25 +00:00
|
|
|
g1 := g0.DelValueIn(ValueOut(v0, e1), v1)
|
2017-10-22 17:39:32 +00:00
|
|
|
assert.True(t, Equal(g0, g1))
|
|
|
|
}
|
|
|
|
|
|
|
|
{ // removing only edge
|
2018-01-21 15:39:25 +00:00
|
|
|
oe := ValueOut(v0, e0)
|
2021-08-27 03:26:24 +00:00
|
|
|
g0 := ZeroGraph.AddValueIn(oe, v1)
|
2018-01-21 15:39:25 +00:00
|
|
|
g1 := g0.DelValueIn(oe, v1)
|
2021-08-27 03:26:24 +00:00
|
|
|
assert.True(t, Equal(ZeroGraph, g1))
|
2017-10-22 17:39:32 +00:00
|
|
|
}
|
|
|
|
|
2018-01-21 15:39:25 +00:00
|
|
|
ej0 := NewValue("ej0")
|
|
|
|
v2 := NewValue("v2")
|
2021-08-27 03:26:24 +00:00
|
|
|
{ // removing only edge (tuple)
|
|
|
|
oe := TupleOut([]OpenEdge{
|
2018-01-21 15:39:25 +00:00
|
|
|
ValueOut(v0, e0),
|
|
|
|
ValueOut(v1, e1),
|
|
|
|
}, ej0)
|
2021-08-27 03:26:24 +00:00
|
|
|
g0 := ZeroGraph.AddValueIn(oe, v2)
|
2018-01-21 15:39:25 +00:00
|
|
|
g1 := g0.DelValueIn(oe, v2)
|
2021-08-27 03:26:24 +00:00
|
|
|
assert.True(t, Equal(ZeroGraph, g1))
|
2017-10-22 17:39:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
{ // removing one of two edges
|
2018-01-21 15:39:25 +00:00
|
|
|
oe := ValueOut(v1, e0)
|
2021-08-27 03:26:24 +00:00
|
|
|
g0 := ZeroGraph.AddValueIn(ValueOut(v0, e0), v2)
|
2018-01-21 15:39:25 +00:00
|
|
|
g1 := g0.AddValueIn(oe, v2)
|
|
|
|
g2 := g1.DelValueIn(oe, v2)
|
2017-10-22 17:39:32 +00:00
|
|
|
assert.True(t, Equal(g0, g2))
|
2018-01-21 15:39:25 +00:00
|
|
|
assert.NotNil(t, g2.ValueVertex(v0))
|
|
|
|
assert.Nil(t, g2.ValueVertex(v1))
|
|
|
|
assert.NotNil(t, g2.ValueVertex(v2))
|
2017-10-22 17:39:32 +00:00
|
|
|
}
|
|
|
|
|
2018-01-21 15:39:25 +00:00
|
|
|
e2 := NewValue("e2")
|
|
|
|
eja, ejb := NewValue("eja"), NewValue("ejb")
|
|
|
|
v3 := NewValue("v3")
|
2021-08-27 03:26:24 +00:00
|
|
|
{ // removing one of two edges (tuple)
|
2018-01-21 15:39:25 +00:00
|
|
|
e0 := ValueOut(v0, e0)
|
|
|
|
e1 := ValueOut(v1, e1)
|
|
|
|
e2 := ValueOut(v2, e2)
|
2021-08-27 03:26:24 +00:00
|
|
|
oeA := TupleOut([]OpenEdge{e0, e1}, eja)
|
|
|
|
oeB := TupleOut([]OpenEdge{e1, e2}, ejb)
|
|
|
|
g0a := ZeroGraph.AddValueIn(oeA, v3)
|
|
|
|
g0b := ZeroGraph.AddValueIn(oeB, v3)
|
2018-01-21 15:39:25 +00:00
|
|
|
g1 := g0a.Union(g0b).DelValueIn(oeA, v3)
|
2017-10-22 17:39:32 +00:00
|
|
|
assert.True(t, Equal(g1, g0b))
|
2018-01-21 15:39:25 +00:00
|
|
|
assert.Nil(t, g1.ValueVertex(v0))
|
|
|
|
assert.NotNil(t, g1.ValueVertex(v1))
|
|
|
|
assert.NotNil(t, g1.ValueVertex(v2))
|
|
|
|
assert.NotNil(t, g1.ValueVertex(v3))
|
2017-10-22 17:39:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
{ // removing one of two edges in circular graph
|
2018-01-21 15:39:25 +00:00
|
|
|
e0 := ValueOut(v0, e0)
|
|
|
|
e1 := ValueOut(v1, e1)
|
2021-08-27 03:26:24 +00:00
|
|
|
g0 := ZeroGraph.AddValueIn(e0, v1).AddValueIn(e1, v0)
|
2018-01-21 15:39:25 +00:00
|
|
|
g1 := g0.DelValueIn(e0, v1)
|
2021-08-27 03:26:24 +00:00
|
|
|
assert.True(t, Equal(ZeroGraph.AddValueIn(e1, v0), g1))
|
2018-01-21 15:39:25 +00:00
|
|
|
assert.NotNil(t, g1.ValueVertex(v0))
|
|
|
|
assert.NotNil(t, g1.ValueVertex(v1))
|
2017-10-22 17:39:32 +00:00
|
|
|
}
|
|
|
|
|
2018-01-21 15:39:25 +00:00
|
|
|
ej := NewValue("ej")
|
2017-10-22 17:39:32 +00:00
|
|
|
{ // removing to's only edge, sub-nodes have edge to each other
|
2021-08-27 03:26:24 +00:00
|
|
|
oej := TupleOut([]OpenEdge{
|
2018-01-21 15:39:25 +00:00
|
|
|
ValueOut(v0, ej0),
|
|
|
|
ValueOut(v1, ej0),
|
|
|
|
}, ej)
|
2021-08-27 03:26:24 +00:00
|
|
|
g0 := ZeroGraph.AddValueIn(oej, v2)
|
2018-01-21 15:39:25 +00:00
|
|
|
e0 := ValueOut(v0, e0)
|
|
|
|
g1 := g0.AddValueIn(e0, v1)
|
|
|
|
g2 := g1.DelValueIn(oej, v2)
|
2021-08-27 03:26:24 +00:00
|
|
|
assert.True(t, Equal(ZeroGraph.AddValueIn(e0, v1), g2))
|
2018-01-21 15:39:25 +00:00
|
|
|
assert.NotNil(t, g2.ValueVertex(v0))
|
|
|
|
assert.NotNil(t, g2.ValueVertex(v1))
|
|
|
|
assert.Nil(t, g2.ValueVertex(v2))
|
2017-10-22 17:39:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-26 21:49:22 +00:00
|
|
|
// deterministically hashes a Graph.
|
2018-06-07 02:21:44 +00:00
|
|
|
func graphStr(g *Graph) string {
|
|
|
|
var vStr func(vertex) string
|
|
|
|
var oeStr func(OpenEdge) string
|
|
|
|
vStr = func(v vertex) string {
|
|
|
|
if v.VertexType == ValueVertex {
|
|
|
|
return fmt.Sprintf("v:%q\n", v.val.V.(string))
|
|
|
|
}
|
|
|
|
s := fmt.Sprintf("j:%d\n", len(v.in))
|
|
|
|
ssOE := make([]string, len(v.in))
|
|
|
|
for i := range v.in {
|
|
|
|
ssOE[i] = oeStr(v.in[i])
|
|
|
|
}
|
|
|
|
sort.Strings(ssOE)
|
|
|
|
return s + strings.Join(ssOE, "")
|
|
|
|
}
|
|
|
|
oeStr = func(oe OpenEdge) string {
|
|
|
|
s := fmt.Sprintf("oe:%q\n", oe.val.V.(string))
|
|
|
|
return s + vStr(oe.fromV)
|
|
|
|
}
|
|
|
|
sVV := make([]string, 0, len(g.vM))
|
|
|
|
for _, v := range g.vM {
|
|
|
|
sVV = append(sVV, vStr(v))
|
|
|
|
}
|
|
|
|
sort.Strings(sVV)
|
|
|
|
return strings.Join(sVV, "")
|
|
|
|
}
|
|
|
|
|
|
|
|
func assertEqualSets(t *T, exp, got []*Graph) bool {
|
|
|
|
if !assert.Equal(t, len(exp), len(got)) {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
m := map[*Graph]string{}
|
|
|
|
for _, g := range exp {
|
|
|
|
m[g] = graphStr(g)
|
|
|
|
}
|
|
|
|
for _, g := range got {
|
|
|
|
m[g] = graphStr(g)
|
|
|
|
}
|
|
|
|
|
|
|
|
sort.Slice(exp, func(i, j int) bool {
|
|
|
|
return m[exp[i]] < m[exp[j]]
|
|
|
|
})
|
|
|
|
sort.Slice(got, func(i, j int) bool {
|
|
|
|
return m[got[i]] < m[got[j]]
|
|
|
|
})
|
|
|
|
|
|
|
|
b := true
|
|
|
|
for i := range exp {
|
|
|
|
b = b || assert.True(t, Equal(exp[i], got[i]), "i:%d exp:%q got:%q", i, m[exp[i]], m[got[i]])
|
|
|
|
}
|
|
|
|
return b
|
|
|
|
}
|
|
|
|
|
2017-10-22 17:39:32 +00:00
|
|
|
func TestGraphUnion(t *T) {
|
|
|
|
assertUnion := func(g1, g2 *Graph) *Graph {
|
|
|
|
ga := g1.Union(g2)
|
|
|
|
gb := g2.Union(g1)
|
|
|
|
assert.True(t, Equal(ga, gb))
|
|
|
|
return ga
|
|
|
|
}
|
|
|
|
|
2018-06-07 02:21:44 +00:00
|
|
|
assertDisjoin := func(g *Graph, exp ...*Graph) {
|
|
|
|
ggDisj := g.Disjoin()
|
|
|
|
assertEqualSets(t, exp, ggDisj)
|
|
|
|
}
|
|
|
|
|
2018-01-21 15:39:25 +00:00
|
|
|
v0 := NewValue("v0")
|
|
|
|
v1 := NewValue("v1")
|
|
|
|
e0 := NewValue("e0")
|
2021-08-27 03:26:24 +00:00
|
|
|
{ // Union with ZeroGraph
|
|
|
|
assert.True(t, Equal(ZeroGraph, ZeroGraph.Union(ZeroGraph)))
|
2017-10-22 17:39:32 +00:00
|
|
|
|
2021-08-27 03:26:24 +00:00
|
|
|
g := ZeroGraph.AddValueIn(ValueOut(v0, e0), v1)
|
|
|
|
assert.True(t, Equal(g, assertUnion(g, ZeroGraph)))
|
2018-06-07 02:21:44 +00:00
|
|
|
|
|
|
|
assertDisjoin(g, g)
|
2017-10-22 17:39:32 +00:00
|
|
|
}
|
|
|
|
|
2018-01-21 15:39:25 +00:00
|
|
|
v2 := NewValue("v2")
|
|
|
|
v3 := NewValue("v3")
|
|
|
|
e1 := NewValue("e1")
|
2017-10-22 17:39:32 +00:00
|
|
|
{ // Two disparate graphs union'd
|
2021-08-27 03:26:24 +00:00
|
|
|
g0 := ZeroGraph.AddValueIn(ValueOut(v0, e0), v1)
|
|
|
|
g1 := ZeroGraph.AddValueIn(ValueOut(v2, e1), v3)
|
2017-10-22 17:39:32 +00:00
|
|
|
g := assertUnion(g0, g1)
|
2018-01-21 15:39:25 +00:00
|
|
|
assertVertexEqual(t, value(v0), g.ValueVertex(v0))
|
|
|
|
assertVertexEqual(t, value(v1, edge(e0, value(v0))), g.ValueVertex(v1))
|
|
|
|
assertVertexEqual(t, value(v2), g.ValueVertex(v2))
|
|
|
|
assertVertexEqual(t, value(v3, edge(e1, value(v2))), g.ValueVertex(v3))
|
2018-06-07 02:21:44 +00:00
|
|
|
|
|
|
|
assertDisjoin(g, g0, g1)
|
2017-10-22 17:39:32 +00:00
|
|
|
}
|
|
|
|
|
2018-01-21 15:39:25 +00:00
|
|
|
va0, vb0 := NewValue("va0"), NewValue("vb0")
|
|
|
|
va1, vb1 := NewValue("va1"), NewValue("vb1")
|
|
|
|
va2, vb2 := NewValue("va2"), NewValue("vb2")
|
|
|
|
ea0, eb0 := NewValue("ea0"), NewValue("eb0")
|
|
|
|
ea1, eb1 := NewValue("ea1"), NewValue("eb1")
|
|
|
|
eaj, ebj := NewValue("eaj"), NewValue("ebj")
|
2021-08-27 03:26:24 +00:00
|
|
|
{ // Two disparate graphs with tuples
|
|
|
|
ga := ZeroGraph.AddValueIn(TupleOut([]OpenEdge{
|
2018-01-21 15:39:25 +00:00
|
|
|
ValueOut(va0, ea0),
|
|
|
|
ValueOut(va1, ea1),
|
|
|
|
}, eaj), va2)
|
2021-08-27 03:26:24 +00:00
|
|
|
gb := ZeroGraph.AddValueIn(TupleOut([]OpenEdge{
|
2018-01-21 15:39:25 +00:00
|
|
|
ValueOut(vb0, eb0),
|
|
|
|
ValueOut(vb1, eb1),
|
|
|
|
}, ebj), vb2)
|
2017-10-22 17:39:32 +00:00
|
|
|
g := assertUnion(ga, gb)
|
2018-01-21 15:39:25 +00:00
|
|
|
assertVertexEqual(t, value(va0), g.ValueVertex(va0))
|
|
|
|
assertVertexEqual(t, value(va1), g.ValueVertex(va1))
|
2017-10-22 17:39:32 +00:00
|
|
|
assertVertexEqual(t,
|
2021-08-27 03:26:24 +00:00
|
|
|
value(va2, tuple(eaj,
|
2018-01-21 15:39:25 +00:00
|
|
|
edge(ea0, value(va0)),
|
|
|
|
edge(ea1, value(va1)))),
|
|
|
|
g.ValueVertex(va2),
|
2017-10-22 17:39:32 +00:00
|
|
|
)
|
2018-01-21 15:39:25 +00:00
|
|
|
assertVertexEqual(t, value(vb0), g.ValueVertex(vb0))
|
|
|
|
assertVertexEqual(t, value(vb1), g.ValueVertex(vb1))
|
2017-10-22 17:39:32 +00:00
|
|
|
assertVertexEqual(t,
|
2021-08-27 03:26:24 +00:00
|
|
|
value(vb2, tuple(ebj,
|
2018-01-21 15:39:25 +00:00
|
|
|
edge(eb0, value(vb0)),
|
|
|
|
edge(eb1, value(vb1)))),
|
|
|
|
g.ValueVertex(vb2),
|
2017-10-22 17:39:32 +00:00
|
|
|
)
|
2018-06-07 02:21:44 +00:00
|
|
|
|
|
|
|
assertDisjoin(g, ga, gb)
|
2017-10-22 17:39:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
{ // Two partially overlapping graphs
|
2021-08-27 03:26:24 +00:00
|
|
|
g0 := ZeroGraph.AddValueIn(ValueOut(v0, e0), v2)
|
|
|
|
g1 := ZeroGraph.AddValueIn(ValueOut(v1, e1), v2)
|
2017-10-22 17:39:32 +00:00
|
|
|
g := assertUnion(g0, g1)
|
2018-01-21 15:39:25 +00:00
|
|
|
assertVertexEqual(t, value(v0), g.ValueVertex(v0))
|
|
|
|
assertVertexEqual(t, value(v1), g.ValueVertex(v1))
|
2017-10-22 17:39:32 +00:00
|
|
|
assertVertexEqual(t,
|
2018-01-21 15:39:25 +00:00
|
|
|
value(v2,
|
|
|
|
edge(e0, value(v0)),
|
|
|
|
edge(e1, value(v1)),
|
2017-10-22 17:39:32 +00:00
|
|
|
),
|
2018-01-21 15:39:25 +00:00
|
|
|
g.ValueVertex(v2),
|
2017-10-22 17:39:32 +00:00
|
|
|
)
|
2018-06-07 02:21:44 +00:00
|
|
|
|
|
|
|
assertDisjoin(g, g)
|
2017-10-22 17:39:32 +00:00
|
|
|
}
|
|
|
|
|
2018-01-21 15:39:25 +00:00
|
|
|
ej0 := NewValue("ej0")
|
|
|
|
ej1 := NewValue("ej1")
|
2021-08-27 03:26:24 +00:00
|
|
|
{ // two partially overlapping graphs with tuples
|
|
|
|
g0 := ZeroGraph.AddValueIn(TupleOut([]OpenEdge{
|
2018-01-21 15:39:25 +00:00
|
|
|
ValueOut(v0, e0),
|
|
|
|
ValueOut(v1, e1),
|
|
|
|
}, ej0), v2)
|
2021-08-27 03:26:24 +00:00
|
|
|
g1 := ZeroGraph.AddValueIn(TupleOut([]OpenEdge{
|
2018-01-21 15:39:25 +00:00
|
|
|
ValueOut(v0, e0),
|
|
|
|
ValueOut(v1, e1),
|
|
|
|
}, ej1), v2)
|
2017-10-22 17:39:32 +00:00
|
|
|
g := assertUnion(g0, g1)
|
2018-01-21 15:39:25 +00:00
|
|
|
assertVertexEqual(t, value(v0), g.ValueVertex(v0))
|
|
|
|
assertVertexEqual(t, value(v1), g.ValueVertex(v1))
|
2017-10-22 17:39:32 +00:00
|
|
|
assertVertexEqual(t,
|
2018-01-21 15:39:25 +00:00
|
|
|
value(v2,
|
2021-08-27 03:26:24 +00:00
|
|
|
tuple(ej0, edge(e0, value(v0)), edge(e1, value(v1))),
|
|
|
|
tuple(ej1, edge(e0, value(v0)), edge(e1, value(v1))),
|
2017-10-22 17:39:32 +00:00
|
|
|
),
|
2018-01-21 15:39:25 +00:00
|
|
|
g.ValueVertex(v2),
|
2017-10-22 17:39:32 +00:00
|
|
|
)
|
2018-06-07 02:21:44 +00:00
|
|
|
|
|
|
|
assertDisjoin(g, g)
|
2017-10-22 17:39:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
{ // Two equal graphs
|
2021-08-27 03:26:24 +00:00
|
|
|
g0 := ZeroGraph.AddValueIn(ValueOut(v0, e0), v1)
|
2017-10-22 17:39:32 +00:00
|
|
|
g := assertUnion(g0, g0)
|
2018-01-21 15:39:25 +00:00
|
|
|
assertVertexEqual(t, value(v0), g.ValueVertex(v0))
|
2017-10-22 17:39:32 +00:00
|
|
|
assertVertexEqual(t,
|
2018-01-21 15:39:25 +00:00
|
|
|
value(v1, edge(e0, value(v0))),
|
|
|
|
g.ValueVertex(v1),
|
2017-10-22 17:39:32 +00:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2021-08-27 03:26:24 +00:00
|
|
|
{ // Two equal graphs with tuples
|
|
|
|
g0 := ZeroGraph.AddValueIn(TupleOut([]OpenEdge{
|
2018-01-21 15:39:25 +00:00
|
|
|
ValueOut(v0, e0),
|
|
|
|
ValueOut(v1, e1),
|
|
|
|
}, ej0), v2)
|
2017-10-22 17:39:32 +00:00
|
|
|
g := assertUnion(g0, g0)
|
2018-01-21 15:39:25 +00:00
|
|
|
assertVertexEqual(t, value(v0), g.ValueVertex(v0))
|
|
|
|
assertVertexEqual(t, value(v1), g.ValueVertex(v1))
|
2017-10-22 17:39:32 +00:00
|
|
|
assertVertexEqual(t,
|
2018-01-21 15:39:25 +00:00
|
|
|
value(v2,
|
2021-08-27 03:26:24 +00:00
|
|
|
tuple(ej0, edge(e0, value(v0)), edge(e1, value(v1))),
|
2017-10-22 17:39:32 +00:00
|
|
|
),
|
2018-01-21 15:39:25 +00:00
|
|
|
g.ValueVertex(v2),
|
2017-10-22 17:39:32 +00:00
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-21 18:39:23 +00:00
|
|
|
func TestGraphEqual(t *T) {
|
|
|
|
assertEqual := func(g1, g2 *Graph) {
|
|
|
|
assert.True(t, Equal(g1, g2))
|
|
|
|
assert.True(t, Equal(g2, g1))
|
|
|
|
}
|
|
|
|
|
|
|
|
assertNotEqual := func(g1, g2 *Graph) {
|
|
|
|
assert.False(t, Equal(g1, g2))
|
|
|
|
assert.False(t, Equal(g2, g1))
|
|
|
|
}
|
|
|
|
|
2021-08-27 03:26:24 +00:00
|
|
|
assertEqual(ZeroGraph, ZeroGraph) // duh
|
2017-10-21 18:39:23 +00:00
|
|
|
|
2018-01-21 15:39:25 +00:00
|
|
|
v0 := NewValue("v0")
|
|
|
|
v1 := NewValue("v1")
|
|
|
|
v2 := NewValue("v2")
|
|
|
|
e0 := NewValue("e0")
|
|
|
|
e1 := NewValue("e1")
|
|
|
|
e1a, e1b := NewValue("e1a"), NewValue("e1b")
|
2017-10-21 18:39:23 +00:00
|
|
|
{
|
|
|
|
// graph is equal to itself, not to null
|
2018-01-21 15:39:25 +00:00
|
|
|
e0 := ValueOut(v0, e0)
|
2021-08-27 03:26:24 +00:00
|
|
|
g0 := ZeroGraph.AddValueIn(e0, v1)
|
|
|
|
assertNotEqual(g0, ZeroGraph)
|
2017-10-21 18:39:23 +00:00
|
|
|
assertEqual(g0, g0)
|
|
|
|
|
|
|
|
// adding the an existing edge again shouldn't do anything
|
2018-01-21 15:39:25 +00:00
|
|
|
assertEqual(g0, g0.AddValueIn(e0, v1))
|
2017-10-21 18:39:23 +00:00
|
|
|
|
|
|
|
// g1a and g1b have the same vertices, but the edges are different
|
2018-01-21 15:39:25 +00:00
|
|
|
g1a := g0.AddValueIn(ValueOut(v0, e1a), v2)
|
|
|
|
g1b := g0.AddValueIn(ValueOut(v0, e1b), v2)
|
2017-10-21 18:39:23 +00:00
|
|
|
assertNotEqual(g1a, g1b)
|
|
|
|
}
|
|
|
|
|
|
|
|
{ // equal construction should yield equality, even if out of order
|
2021-08-27 03:26:24 +00:00
|
|
|
ga := ZeroGraph.AddValueIn(ValueOut(v0, e0), v1)
|
2018-01-21 15:39:25 +00:00
|
|
|
ga = ga.AddValueIn(ValueOut(v1, e1), v2)
|
2021-08-27 03:26:24 +00:00
|
|
|
gb := ZeroGraph.AddValueIn(ValueOut(v1, e1), v2)
|
2018-01-21 15:39:25 +00:00
|
|
|
gb = gb.AddValueIn(ValueOut(v0, e0), v1)
|
2017-10-21 18:39:23 +00:00
|
|
|
assertEqual(ga, gb)
|
|
|
|
}
|
|
|
|
|
2018-01-21 15:39:25 +00:00
|
|
|
ej := NewValue("ej")
|
2021-08-27 03:26:24 +00:00
|
|
|
{ // tuple basic test
|
2018-01-21 15:39:25 +00:00
|
|
|
e0 := ValueOut(v0, e0)
|
|
|
|
e1 := ValueOut(v1, e1)
|
2021-08-27 03:26:24 +00:00
|
|
|
ga := ZeroGraph.AddValueIn(TupleOut([]OpenEdge{e0, e1}, ej), v2)
|
|
|
|
gb := ZeroGraph.AddValueIn(TupleOut([]OpenEdge{e1, e0}, ej), v2)
|
2017-10-21 18:39:23 +00:00
|
|
|
assertEqual(ga, ga)
|
|
|
|
assertNotEqual(ga, gb)
|
|
|
|
}
|
|
|
|
}
|