mirror of
https://github.com/gonum/gonum.git
synced 2025-10-08 08:30:14 +08:00
585 lines
9.4 KiB
Go
585 lines
9.4 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"
|
|
"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 TestComplete(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
ids IDer
|
|
dst func() nodeIDGraphBuilder
|
|
want 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;
|
|
}`,
|
|
},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
dst := test.dst()
|
|
err := Complete(dst, test.ids)
|
|
if err != nil {
|
|
t.Errorf("unexpected error constructing graph: %v", err)
|
|
}
|
|
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
|
|
}{
|
|
{
|
|
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;
|
|
}`,
|
|
},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
dst := test.dst()
|
|
err := Cycle(dst, test.ids)
|
|
if err != nil {
|
|
t.Errorf("unexpected error constructing graph: %v", err)
|
|
}
|
|
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
|
|
}{
|
|
{
|
|
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;
|
|
}`,
|
|
},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
dst := test.dst()
|
|
err := Path(dst, test.ids)
|
|
if err != nil {
|
|
t.Errorf("unexpected error constructing graph: %v", err)
|
|
}
|
|
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
|
|
}{
|
|
{
|
|
name: "empty_leaves",
|
|
center: 0,
|
|
leaves: empty{},
|
|
dst: undirected,
|
|
want: `strict graph empty_leaves {
|
|
// Node definitions.
|
|
0;
|
|
}`,
|
|
},
|
|
{
|
|
name: "single",
|
|
leaves: IDRange{First: 1, Last: 1},
|
|
dst: undirected,
|
|
want: `strict graph single {
|
|
// Node definitions.
|
|
0;
|
|
1;
|
|
|
|
// Edge definitions.
|
|
0 -- 1;
|
|
}`,
|
|
},
|
|
{
|
|
name: "pair_undirected",
|
|
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",
|
|
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",
|
|
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",
|
|
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;
|
|
}`,
|
|
},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
dst := test.dst()
|
|
err := Star(dst, test.center, test.leaves)
|
|
if err != nil {
|
|
t.Errorf("unexpected error constructing graph: %v", err)
|
|
}
|
|
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
|
|
}{
|
|
{
|
|
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",
|
|
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",
|
|
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",
|
|
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",
|
|
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;
|
|
}`,
|
|
},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
dst := test.dst()
|
|
err := Wheel(dst, test.center, test.cycle)
|
|
if err != nil {
|
|
t.Errorf("unexpected error constructing graph: %v", err)
|
|
}
|
|
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)
|
|
}
|
|
}
|
|
}
|