mirror of
https://github.com/gonum/gonum.git
synced 2025-10-06 07:37:03 +08:00
905 lines
15 KiB
Go
905 lines
15 KiB
Go
// Copyright ©2021 The Gonum Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package gen
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"testing"
|
|
|
|
"gonum.org/v1/gonum/graph"
|
|
"gonum.org/v1/gonum/graph/encoding/dot"
|
|
"gonum.org/v1/gonum/graph/simple"
|
|
)
|
|
|
|
type nodeIDGraphBuilder interface {
|
|
graph.Graph
|
|
NodeIDGraphBuilder
|
|
}
|
|
|
|
func undirected() nodeIDGraphBuilder { return simple.NewUndirectedGraph() }
|
|
func directed() nodeIDGraphBuilder { return simple.NewDirectedGraph() }
|
|
|
|
type empty struct{}
|
|
|
|
func (r empty) Len() int { return 0 }
|
|
func (r empty) ID(i int) int64 { panic("called ID on empty IDer") }
|
|
|
|
func panics(fn func()) (panicked bool, msg string) {
|
|
defer func() {
|
|
r := recover()
|
|
if r != nil {
|
|
panicked = true
|
|
msg = fmt.Sprint(r)
|
|
}
|
|
}()
|
|
fn()
|
|
return
|
|
}
|
|
|
|
func TestComplete(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
ids IDer
|
|
dst func() nodeIDGraphBuilder
|
|
want string
|
|
panics string
|
|
}{
|
|
{
|
|
name: "empty",
|
|
ids: empty{},
|
|
dst: undirected,
|
|
want: `strict graph empty {
|
|
}`,
|
|
},
|
|
{
|
|
name: "single",
|
|
ids: IDRange{First: 1, Last: 1},
|
|
dst: undirected,
|
|
want: `strict graph single {
|
|
// Node definitions.
|
|
1;
|
|
}`,
|
|
},
|
|
{
|
|
name: "pair_undirected",
|
|
ids: IDRange{First: 1, Last: 2},
|
|
dst: undirected,
|
|
want: `strict graph pair_undirected {
|
|
// Node definitions.
|
|
1;
|
|
2;
|
|
|
|
// Edge definitions.
|
|
1 -- 2;
|
|
}`,
|
|
},
|
|
{
|
|
name: "pair_directed",
|
|
ids: IDRange{First: 1, Last: 2},
|
|
dst: directed,
|
|
want: `strict digraph pair_directed {
|
|
// Node definitions.
|
|
1;
|
|
2;
|
|
|
|
// Edge definitions.
|
|
1 -> 2;
|
|
}`,
|
|
},
|
|
{
|
|
name: "quad_undirected",
|
|
ids: IDRange{First: 1, Last: 4},
|
|
dst: undirected,
|
|
want: `strict graph quad_undirected {
|
|
// Node definitions.
|
|
1;
|
|
2;
|
|
3;
|
|
4;
|
|
|
|
// Edge definitions.
|
|
1 -- 2;
|
|
1 -- 3;
|
|
1 -- 4;
|
|
2 -- 3;
|
|
2 -- 4;
|
|
3 -- 4;
|
|
}`,
|
|
},
|
|
{
|
|
name: "quad_directed",
|
|
ids: IDRange{First: 1, Last: 4},
|
|
dst: directed,
|
|
want: `strict digraph quad_directed {
|
|
// Node definitions.
|
|
1;
|
|
2;
|
|
3;
|
|
4;
|
|
|
|
// Edge definitions.
|
|
1 -> 2;
|
|
1 -> 3;
|
|
1 -> 4;
|
|
2 -> 3;
|
|
2 -> 4;
|
|
3 -> 4;
|
|
}`,
|
|
},
|
|
{
|
|
name: "collision",
|
|
ids: IDSet{1, 2, 3, 2},
|
|
dst: undirected,
|
|
panics: "gen: node ID collision i=1 j=3: id=2",
|
|
},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
dst := test.dst()
|
|
panicked, msg := panics(func() { Complete(dst, test.ids) })
|
|
if msg != test.panics {
|
|
t.Errorf("unexpected panic message for %q: got:%q want:%q", test.name, msg, test.panics)
|
|
}
|
|
if panicked {
|
|
continue
|
|
}
|
|
got, err := dot.Marshal(dst, test.name, "", " ")
|
|
if err != nil {
|
|
t.Errorf("unexpected marshaling graph error: %v", err)
|
|
}
|
|
if !bytes.Equal(got, []byte(test.want)) {
|
|
t.Errorf("unexpected result for test %s:\ngot:\n%s\nwant:\n%s", test.name, got, test.want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestCycle(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
ids IDer
|
|
dst func() nodeIDGraphBuilder
|
|
want string
|
|
panics string
|
|
}{
|
|
{
|
|
name: "empty",
|
|
ids: empty{},
|
|
dst: undirected,
|
|
want: `strict graph empty {
|
|
}`,
|
|
},
|
|
{
|
|
name: "single",
|
|
ids: IDRange{First: 1, Last: 1},
|
|
dst: undirected,
|
|
want: `strict graph single {
|
|
// Node definitions.
|
|
1;
|
|
}`,
|
|
},
|
|
{
|
|
name: "pair_undirected",
|
|
ids: IDRange{First: 1, Last: 2},
|
|
dst: undirected,
|
|
want: `strict graph pair_undirected {
|
|
// Node definitions.
|
|
1;
|
|
2;
|
|
|
|
// Edge definitions.
|
|
1 -- 2;
|
|
}`,
|
|
},
|
|
{
|
|
name: "pair_directed",
|
|
ids: IDRange{First: 1, Last: 2},
|
|
dst: directed,
|
|
want: `strict digraph pair_directed {
|
|
// Node definitions.
|
|
1;
|
|
2;
|
|
|
|
// Edge definitions.
|
|
1 -> 2;
|
|
2 -> 1;
|
|
}`,
|
|
},
|
|
{
|
|
name: "quad_undirected",
|
|
ids: IDRange{First: 1, Last: 4},
|
|
dst: undirected,
|
|
want: `strict graph quad_undirected {
|
|
// Node definitions.
|
|
1;
|
|
2;
|
|
3;
|
|
4;
|
|
|
|
// Edge definitions.
|
|
1 -- 2;
|
|
1 -- 4;
|
|
2 -- 3;
|
|
3 -- 4;
|
|
}`,
|
|
},
|
|
{
|
|
name: "quad_directed",
|
|
ids: IDRange{First: 1, Last: 4},
|
|
dst: directed,
|
|
want: `strict digraph quad_directed {
|
|
// Node definitions.
|
|
1;
|
|
2;
|
|
3;
|
|
4;
|
|
|
|
// Edge definitions.
|
|
1 -> 2;
|
|
2 -> 3;
|
|
3 -> 4;
|
|
4 -> 1;
|
|
}`,
|
|
},
|
|
{
|
|
name: "collision",
|
|
ids: IDSet{1, 2, 3, 2},
|
|
dst: undirected,
|
|
panics: "gen: node ID collision i=1 j=3: id=2",
|
|
},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
dst := test.dst()
|
|
panicked, msg := panics(func() { Cycle(dst, test.ids) })
|
|
if msg != test.panics {
|
|
t.Errorf("unexpected panic message for %q: got:%q want:%q", test.name, msg, test.panics)
|
|
}
|
|
if panicked {
|
|
continue
|
|
}
|
|
got, err := dot.Marshal(dst, test.name, "", " ")
|
|
if err != nil {
|
|
t.Errorf("unexpected error marshaling graph: %v", err)
|
|
}
|
|
if !bytes.Equal(got, []byte(test.want)) {
|
|
t.Errorf("unexpected result for test %s:\ngot:\n%s\nwant:\n%s", test.name, got, test.want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestPath(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
ids IDer
|
|
dst func() nodeIDGraphBuilder
|
|
want string
|
|
panics string
|
|
}{
|
|
{
|
|
name: "empty",
|
|
ids: empty{},
|
|
dst: undirected,
|
|
want: `strict graph empty {
|
|
}`,
|
|
},
|
|
{
|
|
name: "single",
|
|
ids: IDRange{First: 1, Last: 1},
|
|
dst: undirected,
|
|
want: `strict graph single {
|
|
// Node definitions.
|
|
1;
|
|
}`,
|
|
},
|
|
{
|
|
name: "pair_undirected",
|
|
ids: IDRange{First: 1, Last: 2},
|
|
dst: undirected,
|
|
want: `strict graph pair_undirected {
|
|
// Node definitions.
|
|
1;
|
|
2;
|
|
|
|
// Edge definitions.
|
|
1 -- 2;
|
|
}`,
|
|
},
|
|
{
|
|
name: "pair_directed",
|
|
ids: IDRange{First: 1, Last: 2},
|
|
dst: directed,
|
|
want: `strict digraph pair_directed {
|
|
// Node definitions.
|
|
1;
|
|
2;
|
|
|
|
// Edge definitions.
|
|
1 -> 2;
|
|
}`,
|
|
},
|
|
{
|
|
name: "quad_undirected",
|
|
ids: IDRange{First: 1, Last: 4},
|
|
dst: undirected,
|
|
want: `strict graph quad_undirected {
|
|
// Node definitions.
|
|
1;
|
|
2;
|
|
3;
|
|
4;
|
|
|
|
// Edge definitions.
|
|
1 -- 2;
|
|
2 -- 3;
|
|
3 -- 4;
|
|
}`,
|
|
},
|
|
{
|
|
name: "quad_directed",
|
|
ids: IDRange{First: 1, Last: 4},
|
|
dst: directed,
|
|
want: `strict digraph quad_directed {
|
|
// Node definitions.
|
|
1;
|
|
2;
|
|
3;
|
|
4;
|
|
|
|
// Edge definitions.
|
|
1 -> 2;
|
|
2 -> 3;
|
|
3 -> 4;
|
|
}`,
|
|
},
|
|
{
|
|
name: "collision",
|
|
ids: IDSet{1, 2, 3, 2},
|
|
dst: undirected,
|
|
panics: "gen: node ID collision i=1 j=3: id=2",
|
|
},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
dst := test.dst()
|
|
panicked, msg := panics(func() { Path(dst, test.ids) })
|
|
if msg != test.panics {
|
|
t.Errorf("unexpected panic message for %q: got:%q want:%q", test.name, msg, test.panics)
|
|
}
|
|
if panicked {
|
|
continue
|
|
}
|
|
got, err := dot.Marshal(dst, test.name, "", " ")
|
|
if err != nil {
|
|
t.Errorf("unexpected error marshaling graph: %v", err)
|
|
}
|
|
if !bytes.Equal(got, []byte(test.want)) {
|
|
t.Errorf("unexpected result for test %s:\ngot:\n%s\nwant:\n%s", test.name, got, test.want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestStar(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
center int64
|
|
leaves IDer
|
|
dst func() nodeIDGraphBuilder
|
|
want string
|
|
panics string
|
|
}{
|
|
{
|
|
name: "empty_leaves",
|
|
center: 0,
|
|
leaves: empty{},
|
|
dst: undirected,
|
|
want: `strict graph empty_leaves {
|
|
// Node definitions.
|
|
0;
|
|
}`,
|
|
},
|
|
{
|
|
name: "single",
|
|
center: 0,
|
|
leaves: IDRange{First: 1, Last: 1},
|
|
dst: undirected,
|
|
want: `strict graph single {
|
|
// Node definitions.
|
|
0;
|
|
1;
|
|
|
|
// Edge definitions.
|
|
0 -- 1;
|
|
}`,
|
|
},
|
|
{
|
|
name: "pair_undirected",
|
|
center: 0,
|
|
leaves: IDRange{First: 1, Last: 2},
|
|
dst: undirected,
|
|
want: `strict graph pair_undirected {
|
|
// Node definitions.
|
|
0;
|
|
1;
|
|
2;
|
|
|
|
// Edge definitions.
|
|
0 -- 1;
|
|
0 -- 2;
|
|
}`,
|
|
},
|
|
{
|
|
name: "pair_directed",
|
|
center: 0,
|
|
leaves: IDRange{First: 1, Last: 2},
|
|
dst: directed,
|
|
want: `strict digraph pair_directed {
|
|
// Node definitions.
|
|
0;
|
|
1;
|
|
2;
|
|
|
|
// Edge definitions.
|
|
0 -> 1;
|
|
0 -> 2;
|
|
}`,
|
|
},
|
|
{
|
|
name: "quad_undirected",
|
|
center: 0,
|
|
leaves: IDRange{First: 1, Last: 4},
|
|
dst: undirected,
|
|
want: `strict graph quad_undirected {
|
|
// Node definitions.
|
|
0;
|
|
1;
|
|
2;
|
|
3;
|
|
4;
|
|
|
|
// Edge definitions.
|
|
0 -- 1;
|
|
0 -- 2;
|
|
0 -- 3;
|
|
0 -- 4;
|
|
}`,
|
|
},
|
|
{
|
|
name: "quad_directed",
|
|
center: 0,
|
|
leaves: IDRange{First: 1, Last: 4},
|
|
dst: directed,
|
|
want: `strict digraph quad_directed {
|
|
// Node definitions.
|
|
0;
|
|
1;
|
|
2;
|
|
3;
|
|
4;
|
|
|
|
// Edge definitions.
|
|
0 -> 1;
|
|
0 -> 2;
|
|
0 -> 3;
|
|
0 -> 4;
|
|
}`,
|
|
},
|
|
{
|
|
name: "center collision",
|
|
center: 1,
|
|
leaves: IDRange{First: 1, Last: 4},
|
|
dst: undirected,
|
|
panics: "gen: node ID collision i=0 with extra: id=1",
|
|
},
|
|
{
|
|
name: "leaf collision",
|
|
center: 0,
|
|
leaves: IDSet{1, 2, 3, 2},
|
|
dst: undirected,
|
|
panics: "gen: node ID collision i=1 j=3: id=2",
|
|
},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
dst := test.dst()
|
|
panicked, msg := panics(func() { Star(dst, test.center, test.leaves) })
|
|
if msg != test.panics {
|
|
t.Errorf("unexpected panic message for %q: got:%q want:%q", test.name, msg, test.panics)
|
|
}
|
|
if panicked {
|
|
continue
|
|
}
|
|
got, err := dot.Marshal(dst, test.name, "", " ")
|
|
if err != nil {
|
|
t.Errorf("unexpected error marshaling graph: %v", err)
|
|
}
|
|
if !bytes.Equal(got, []byte(test.want)) {
|
|
t.Errorf("unexpected result for test %s:\ngot:\n%s\nwant:\n%s", test.name, got, test.want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestWheel(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
center int64
|
|
cycle IDer
|
|
dst func() nodeIDGraphBuilder
|
|
want string
|
|
panics string
|
|
}{
|
|
{
|
|
name: "empty_cycle",
|
|
center: 0,
|
|
cycle: empty{},
|
|
dst: undirected,
|
|
want: `strict graph empty_cycle {
|
|
// Node definitions.
|
|
0;
|
|
}`,
|
|
},
|
|
{
|
|
name: "single",
|
|
cycle: IDRange{First: 1, Last: 1},
|
|
dst: undirected,
|
|
want: `strict graph single {
|
|
// Node definitions.
|
|
0;
|
|
1;
|
|
|
|
// Edge definitions.
|
|
0 -- 1;
|
|
}`,
|
|
},
|
|
{
|
|
name: "pair_undirected",
|
|
center: 0,
|
|
cycle: IDRange{First: 1, Last: 2},
|
|
dst: undirected,
|
|
want: `strict graph pair_undirected {
|
|
// Node definitions.
|
|
0;
|
|
1;
|
|
2;
|
|
|
|
// Edge definitions.
|
|
0 -- 1;
|
|
0 -- 2;
|
|
1 -- 2;
|
|
}`,
|
|
},
|
|
{
|
|
name: "pair_directed",
|
|
center: 0,
|
|
cycle: IDRange{First: 1, Last: 2},
|
|
dst: directed,
|
|
want: `strict digraph pair_directed {
|
|
// Node definitions.
|
|
0;
|
|
1;
|
|
2;
|
|
|
|
// Edge definitions.
|
|
0 -> 1;
|
|
0 -> 2;
|
|
1 -> 2;
|
|
2 -> 1;
|
|
}`,
|
|
},
|
|
{
|
|
name: "quad_undirected",
|
|
center: 0,
|
|
cycle: IDRange{First: 1, Last: 4},
|
|
dst: undirected,
|
|
want: `strict graph quad_undirected {
|
|
// Node definitions.
|
|
0;
|
|
1;
|
|
2;
|
|
3;
|
|
4;
|
|
|
|
// Edge definitions.
|
|
0 -- 1;
|
|
0 -- 2;
|
|
0 -- 3;
|
|
0 -- 4;
|
|
1 -- 2;
|
|
1 -- 4;
|
|
2 -- 3;
|
|
3 -- 4;
|
|
}`,
|
|
},
|
|
{
|
|
name: "quad_directed",
|
|
center: 0,
|
|
cycle: IDRange{First: 1, Last: 4},
|
|
dst: directed,
|
|
want: `strict digraph quad_directed {
|
|
// Node definitions.
|
|
0;
|
|
1;
|
|
2;
|
|
3;
|
|
4;
|
|
|
|
// Edge definitions.
|
|
0 -> 1;
|
|
0 -> 2;
|
|
0 -> 3;
|
|
0 -> 4;
|
|
1 -> 2;
|
|
2 -> 3;
|
|
3 -> 4;
|
|
4 -> 1;
|
|
}`,
|
|
},
|
|
{
|
|
name: "center collision",
|
|
center: 1,
|
|
cycle: IDRange{First: 1, Last: 4},
|
|
dst: undirected,
|
|
panics: "gen: node ID collision i=0 with extra: id=1",
|
|
},
|
|
{
|
|
name: "cycle collision",
|
|
center: 0,
|
|
cycle: IDSet{1, 2, 3, 2},
|
|
dst: undirected,
|
|
panics: "gen: node ID collision i=1 j=3: id=2",
|
|
},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
dst := test.dst()
|
|
panicked, msg := panics(func() { Wheel(dst, test.center, test.cycle) })
|
|
if msg != test.panics {
|
|
t.Errorf("unexpected panic message for %q: got:%q want:%q", test.name, msg, test.panics)
|
|
}
|
|
if panicked {
|
|
continue
|
|
}
|
|
got, err := dot.Marshal(dst, test.name, "", " ")
|
|
if err != nil {
|
|
t.Errorf("unexpected error marshaling graph: %v", err)
|
|
}
|
|
if !bytes.Equal(got, []byte(test.want)) {
|
|
t.Errorf("unexpected result for test %s:\ngot:\n%s\nwant:\n%s", test.name, got, test.want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestCheck(t *testing.T) {
|
|
tests := []struct {
|
|
ids IDer
|
|
extra []int64
|
|
want string
|
|
}{
|
|
{
|
|
ids: IDSet{1, 2, 3, 4}, extra: []int64{1},
|
|
want: "gen: node ID collision i=0 with extra: id=1",
|
|
},
|
|
{
|
|
ids: IDSet{1, 2, 3, 4}, extra: []int64{5, 2},
|
|
want: "gen: node ID collision i=1 with extra j=1: id=2",
|
|
},
|
|
{
|
|
ids: IDSet{}, extra: []int64{1, 2, 1},
|
|
want: "gen: extra node ID collision i=0 j=2: id=1",
|
|
},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
msg := fmt.Sprint(check(test.ids, test.extra...))
|
|
if msg != test.want {
|
|
t.Errorf("unexpected check panic for ids=%#v extra=%v: got:%q want:%q",
|
|
test.ids, test.extra, msg, test.want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestTree(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
dst func() nodeIDGraphBuilder
|
|
nodes IDer
|
|
fanout int
|
|
want string
|
|
panics string
|
|
}{
|
|
{
|
|
name: "empty_tree",
|
|
dst: undirected,
|
|
nodes: empty{},
|
|
fanout: 2,
|
|
want: `strict graph empty_tree {
|
|
}`,
|
|
},
|
|
{
|
|
name: "singleton_tree",
|
|
dst: undirected,
|
|
nodes: IDSet{0},
|
|
fanout: 0,
|
|
want: `strict graph singleton_tree {
|
|
// Node definitions.
|
|
0;
|
|
}`,
|
|
},
|
|
{
|
|
name: "full_binary_tree_undirected",
|
|
dst: undirected,
|
|
nodes: IDRange{First: 0, Last: 14},
|
|
fanout: 2,
|
|
want: `strict graph full_binary_tree_undirected {
|
|
// Node definitions.
|
|
0;
|
|
1;
|
|
2;
|
|
3;
|
|
4;
|
|
5;
|
|
6;
|
|
7;
|
|
8;
|
|
9;
|
|
10;
|
|
11;
|
|
12;
|
|
13;
|
|
14;
|
|
|
|
// Edge definitions.
|
|
0 -- 1;
|
|
0 -- 2;
|
|
1 -- 3;
|
|
1 -- 4;
|
|
2 -- 5;
|
|
2 -- 6;
|
|
3 -- 7;
|
|
3 -- 8;
|
|
4 -- 9;
|
|
4 -- 10;
|
|
5 -- 11;
|
|
5 -- 12;
|
|
6 -- 13;
|
|
6 -- 14;
|
|
}`,
|
|
},
|
|
{
|
|
name: "partial_ternary_tree_undirected",
|
|
dst: undirected,
|
|
nodes: IDRange{First: 0, Last: 17},
|
|
fanout: 3,
|
|
want: `strict graph partial_ternary_tree_undirected {
|
|
// Node definitions.
|
|
0;
|
|
1;
|
|
2;
|
|
3;
|
|
4;
|
|
5;
|
|
6;
|
|
7;
|
|
8;
|
|
9;
|
|
10;
|
|
11;
|
|
12;
|
|
13;
|
|
14;
|
|
15;
|
|
16;
|
|
17;
|
|
|
|
// Edge definitions.
|
|
0 -- 1;
|
|
0 -- 2;
|
|
0 -- 3;
|
|
1 -- 4;
|
|
1 -- 5;
|
|
1 -- 6;
|
|
2 -- 7;
|
|
2 -- 8;
|
|
2 -- 9;
|
|
3 -- 10;
|
|
3 -- 11;
|
|
3 -- 12;
|
|
4 -- 13;
|
|
4 -- 14;
|
|
4 -- 15;
|
|
5 -- 16;
|
|
5 -- 17;
|
|
}`,
|
|
},
|
|
{
|
|
name: "linear_graph_undirected",
|
|
dst: undirected,
|
|
nodes: IDRange{First: 0, Last: 4},
|
|
fanout: 1,
|
|
want: `strict graph linear_graph_undirected {
|
|
// Node definitions.
|
|
0;
|
|
1;
|
|
2;
|
|
3;
|
|
4;
|
|
|
|
// Edge definitions.
|
|
0 -- 1;
|
|
1 -- 2;
|
|
2 -- 3;
|
|
3 -- 4;
|
|
}`,
|
|
},
|
|
{
|
|
name: "full_ternary_tree_directed",
|
|
dst: directed,
|
|
nodes: IDRange{First: 0, Last: 12},
|
|
fanout: 3,
|
|
want: `strict digraph full_ternary_tree_directed {
|
|
// Node definitions.
|
|
0;
|
|
1;
|
|
2;
|
|
3;
|
|
4;
|
|
5;
|
|
6;
|
|
7;
|
|
8;
|
|
9;
|
|
10;
|
|
11;
|
|
12;
|
|
|
|
// Edge definitions.
|
|
0 -> 1;
|
|
0 -> 2;
|
|
0 -> 3;
|
|
1 -> 4;
|
|
1 -> 5;
|
|
1 -> 6;
|
|
2 -> 7;
|
|
2 -> 8;
|
|
2 -> 9;
|
|
3 -> 10;
|
|
3 -> 11;
|
|
3 -> 12;
|
|
}`,
|
|
},
|
|
{
|
|
name: "bad_fanout",
|
|
dst: undirected,
|
|
nodes: IDSet{0, 1, 2, 3},
|
|
fanout: -1,
|
|
panics: "gen: invalid fan-out",
|
|
},
|
|
{
|
|
name: "collision",
|
|
dst: undirected,
|
|
nodes: IDSet{0, 1, 2, 3, 2},
|
|
fanout: 2,
|
|
panics: "gen: node ID collision i=2 j=4: id=2",
|
|
},
|
|
}
|
|
for _, test := range tests {
|
|
dst := test.dst()
|
|
panicked, msg := panics(func() { Tree(dst, test.fanout, test.nodes) })
|
|
if msg != test.panics {
|
|
t.Errorf("unexpected panic message for %q: got:%q want:%q", test.name, msg, test.panics)
|
|
}
|
|
if panicked {
|
|
continue
|
|
}
|
|
got, err := dot.Marshal(dst, test.name, "", " ")
|
|
if err != nil {
|
|
t.Errorf("unexpected error marshaling graph: %v", err)
|
|
}
|
|
if !bytes.Equal(got, []byte(test.want)) {
|
|
t.Errorf("unexpected result for test %s:\ngot:\n%s\nwant:\n%s", test.name, got, test.want)
|
|
}
|
|
}
|
|
}
|