234 lines
3.5 KiB
Go
234 lines
3.5 KiB
Go
|
package digraph
|
||
|
|
||
|
import (
|
||
|
"reflect"
|
||
|
"testing"
|
||
|
)
|
||
|
|
||
|
func TestDepthFirstWalk(t *testing.T) {
|
||
|
nodes := ParseBasic(`a -> b
|
||
|
a -> c
|
||
|
a -> d
|
||
|
b -> e
|
||
|
d -> f
|
||
|
e -> a ; cycle`)
|
||
|
root := nodes["a"]
|
||
|
expected := []string{
|
||
|
"a",
|
||
|
"b",
|
||
|
"e",
|
||
|
"c",
|
||
|
"d",
|
||
|
"f",
|
||
|
}
|
||
|
index := 0
|
||
|
DepthFirstWalk(root, func(n Node) bool {
|
||
|
name := n.(*BasicNode).Name
|
||
|
if expected[index] != name {
|
||
|
t.Fatalf("expected: %v, got %v", expected[index], name)
|
||
|
}
|
||
|
index++
|
||
|
return true
|
||
|
})
|
||
|
}
|
||
|
|
||
|
func TestInDegree(t *testing.T) {
|
||
|
nodes := ParseBasic(`a -> b
|
||
|
a -> c
|
||
|
a -> d
|
||
|
b -> e
|
||
|
c -> e
|
||
|
d -> f`)
|
||
|
var nlist []Node
|
||
|
for _, n := range nodes {
|
||
|
nlist = append(nlist, n)
|
||
|
}
|
||
|
|
||
|
expected := map[string]int{
|
||
|
"a": 0,
|
||
|
"b": 1,
|
||
|
"c": 1,
|
||
|
"d": 1,
|
||
|
"e": 2,
|
||
|
"f": 1,
|
||
|
}
|
||
|
indegree := InDegree(nlist)
|
||
|
for n, d := range indegree {
|
||
|
name := n.(*BasicNode).Name
|
||
|
exp := expected[name]
|
||
|
if exp != d {
|
||
|
t.Fatalf("Expected %d for %s, got %d",
|
||
|
exp, name, d)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestOutDegree(t *testing.T) {
|
||
|
nodes := ParseBasic(`a -> b
|
||
|
a -> c
|
||
|
a -> d
|
||
|
b -> e
|
||
|
c -> e
|
||
|
d -> f`)
|
||
|
var nlist []Node
|
||
|
for _, n := range nodes {
|
||
|
nlist = append(nlist, n)
|
||
|
}
|
||
|
|
||
|
expected := map[string]int{
|
||
|
"a": 3,
|
||
|
"b": 1,
|
||
|
"c": 1,
|
||
|
"d": 1,
|
||
|
"e": 0,
|
||
|
"f": 0,
|
||
|
}
|
||
|
outDegree := OutDegree(nlist)
|
||
|
for n, d := range outDegree {
|
||
|
name := n.(*BasicNode).Name
|
||
|
exp := expected[name]
|
||
|
if exp != d {
|
||
|
t.Fatalf("Expected %d for %s, got %d",
|
||
|
exp, name, d)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestSinks(t *testing.T) {
|
||
|
nodes := ParseBasic(`a -> b
|
||
|
a -> c
|
||
|
a -> d
|
||
|
b -> e
|
||
|
c -> e
|
||
|
d -> f`)
|
||
|
var nlist []Node
|
||
|
for _, n := range nodes {
|
||
|
nlist = append(nlist, n)
|
||
|
}
|
||
|
|
||
|
sinks := Sinks(nlist)
|
||
|
|
||
|
var haveE, haveF bool
|
||
|
for _, n := range sinks {
|
||
|
name := n.(*BasicNode).Name
|
||
|
switch name {
|
||
|
case "e":
|
||
|
haveE = true
|
||
|
case "f":
|
||
|
haveF = true
|
||
|
}
|
||
|
}
|
||
|
if !haveE || !haveF {
|
||
|
t.Fatalf("missing sink")
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestSources(t *testing.T) {
|
||
|
nodes := ParseBasic(`a -> b
|
||
|
a -> c
|
||
|
a -> d
|
||
|
b -> e
|
||
|
c -> e
|
||
|
d -> f
|
||
|
x -> y`)
|
||
|
var nlist []Node
|
||
|
for _, n := range nodes {
|
||
|
nlist = append(nlist, n)
|
||
|
}
|
||
|
|
||
|
sources := Sources(nlist)
|
||
|
if len(sources) != 2 {
|
||
|
t.Fatalf("bad: %v", sources)
|
||
|
}
|
||
|
|
||
|
var haveA, haveX bool
|
||
|
for _, n := range sources {
|
||
|
name := n.(*BasicNode).Name
|
||
|
switch name {
|
||
|
case "a":
|
||
|
haveA = true
|
||
|
case "x":
|
||
|
haveX = true
|
||
|
}
|
||
|
}
|
||
|
if !haveA || !haveX {
|
||
|
t.Fatalf("missing source %v %v", haveA, haveX)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestUnreachable(t *testing.T) {
|
||
|
nodes := ParseBasic(`a -> b
|
||
|
a -> c
|
||
|
a -> d
|
||
|
b -> e
|
||
|
c -> e
|
||
|
d -> f
|
||
|
f -> a
|
||
|
x -> y
|
||
|
y -> z`)
|
||
|
var nlist []Node
|
||
|
for _, n := range nodes {
|
||
|
nlist = append(nlist, n)
|
||
|
}
|
||
|
|
||
|
unreached := Unreachable(nodes["a"], nlist)
|
||
|
if len(unreached) != 3 {
|
||
|
t.Fatalf("bad: %v", unreached)
|
||
|
}
|
||
|
|
||
|
var haveX, haveY, haveZ bool
|
||
|
for _, n := range unreached {
|
||
|
name := n.(*BasicNode).Name
|
||
|
switch name {
|
||
|
case "x":
|
||
|
haveX = true
|
||
|
case "y":
|
||
|
haveY = true
|
||
|
case "z":
|
||
|
haveZ = true
|
||
|
}
|
||
|
}
|
||
|
if !haveX || !haveY || !haveZ {
|
||
|
t.Fatalf("missing %v %v %v", haveX, haveY, haveZ)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestUnreachable2(t *testing.T) {
|
||
|
nodes := ParseBasic(`a -> b
|
||
|
a -> c
|
||
|
a -> d
|
||
|
b -> e
|
||
|
c -> e
|
||
|
d -> f
|
||
|
f -> a
|
||
|
x -> y
|
||
|
y -> z`)
|
||
|
var nlist []Node
|
||
|
for _, n := range nodes {
|
||
|
nlist = append(nlist, n)
|
||
|
}
|
||
|
|
||
|
unreached := Unreachable(nodes["x"], nlist)
|
||
|
if len(unreached) != 6 {
|
||
|
t.Fatalf("bad: %v", unreached)
|
||
|
}
|
||
|
|
||
|
expected := map[string]struct{}{
|
||
|
"a": struct{}{},
|
||
|
"b": struct{}{},
|
||
|
"c": struct{}{},
|
||
|
"d": struct{}{},
|
||
|
"e": struct{}{},
|
||
|
"f": struct{}{},
|
||
|
}
|
||
|
out := map[string]struct{}{}
|
||
|
for _, n := range unreached {
|
||
|
name := n.(*BasicNode).Name
|
||
|
out[name] = struct{}{}
|
||
|
}
|
||
|
|
||
|
if !reflect.DeepEqual(out, expected) {
|
||
|
t.Fatalf("bad: %v %v", out, expected)
|
||
|
}
|
||
|
}
|