Files
gonum/graph/encoding/dot/decode_test.go
2017-05-23 00:03:03 -06:00

197 lines
4.8 KiB
Go

// Copyright ©2017 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 dot
import (
"fmt"
"testing"
"gonum.org/v1/gonum/graph"
"gonum.org/v1/gonum/graph/simple"
)
func TestRoundTrip(t *testing.T) {
golden := []struct {
want string
directed bool
}{
{
want: directed,
directed: true,
},
{
want: undirected,
directed: false,
},
}
for i, g := range golden {
var dst Builder
if g.directed {
dst = newDotDirectedGraph()
} else {
dst = newDotUndirectedGraph()
}
data := []byte(g.want)
if err := Unmarshal(data, dst); err != nil {
t.Errorf("i=%d: unable to unmarshal DOT graph; %v", i, err)
continue
}
buf, err := Marshal(dst, "", "", "\t", false)
if err != nil {
t.Errorf("i=%d: unable to marshal graph; %v", i, dst)
continue
}
got := string(buf)
if got != g.want {
t.Errorf("i=%d: graph content mismatch; expected `%s`, got `%s`", i, g.want, got)
continue
}
}
}
const directed = `digraph {
// Node definitions.
0 [label="foo 2"];
1 [label="bar 2"];
// Edge definitions.
0 -> 1 [label="baz 2"];
}`
const undirected = `graph {
// Node definitions.
0 [label="foo 2"];
1 [label="bar 2"];
// Edge definitions.
0 -- 1 [label="baz 2"];
}`
// Below follows a minimal implementation of a graph capable of validating the
// round-trip encoding and decoding of DOT graphs with nodes and edges
// containing DOT attributes.
// dotDirectedGraph extends simple.DirectedGraph to add NewNode and NewEdge
// methods for creating user-defined nodes and edges.
//
// dotDirectedGraph implements the dot.Builder interface.
type dotDirectedGraph struct {
*simple.DirectedGraph
}
// newDotDirectedGraph returns a new directed capable of creating user-defined
// nodes and edges.
func newDotDirectedGraph() *dotDirectedGraph {
return &dotDirectedGraph{DirectedGraph: simple.NewDirectedGraph(0, 0)}
}
// NewNode adds a new node with a unique node ID to the graph.
func (g *dotDirectedGraph) NewNode() graph.Node {
n := &dotNode{Node: simple.Node(g.NewNodeID())}
g.AddNode(n)
return n
}
// NewEdge adds a new edge from the source to the destination node to the graph,
// or returns the existing edge if already present.
func (g *dotDirectedGraph) NewEdge(from, to graph.Node) graph.Edge {
if e := g.Edge(from, to); e != nil {
return e
}
e := &dotEdge{Edge: simple.Edge{F: from, T: to}}
g.SetEdge(e)
return e
}
// dotUndirectedGraph extends simple.UndirectedGraph to add NewNode and NewEdge
// methods for creating user-defined nodes and edges.
//
// dotUndirectedGraph implements the dot.Builder interface.
type dotUndirectedGraph struct {
*simple.UndirectedGraph
}
// newDotUndirectedGraph returns a new undirected capable of creating user-
// defined nodes and edges.
func newDotUndirectedGraph() *dotUndirectedGraph {
return &dotUndirectedGraph{UndirectedGraph: simple.NewUndirectedGraph(0, 0)}
}
// NewNode adds a new node with a unique node ID to the graph.
func (g *dotUndirectedGraph) NewNode() graph.Node {
n := &dotNode{Node: simple.Node(g.NewNodeID())}
g.AddNode(n)
return n
}
// NewEdge adds a new edge from the source to the destination node to the graph,
// or returns the existing edge if already present.
func (g *dotUndirectedGraph) NewEdge(from, to graph.Node) graph.Edge {
if e := g.Edge(from, to); e != nil {
return e
}
e := &dotEdge{Edge: simple.Edge{F: from, T: to}}
g.SetEdge(e)
return e
}
// dotNode extends simple.Node with a label field to test round-trip encoding
// and decoding of node DOT label attributes.
type dotNode struct {
simple.Node
// Node label.
Label string
}
// UnmarshalDOTAttr decodes a single DOT attribute.
func (n *dotNode) UnmarshalDOTAttr(attr Attribute) error {
if attr.Key != "label" {
return fmt.Errorf("unable to unmarshal node DOT attribute with key %q", attr.Key)
}
n.Label = attr.Value
return nil
}
// DOTAttributes returns the DOT attributes of the node.
func (n *dotNode) DOTAttributes() []Attribute {
if len(n.Label) == 0 {
return nil
}
attr := Attribute{
Key: "label",
Value: n.Label,
}
return []Attribute{attr}
}
// dotEdge extends simple.Edge with a label field to test round-trip encoding and
// decoding of edge DOT label attributes.
type dotEdge struct {
simple.Edge
// Edge label.
Label string
}
// UnmarshalDOTAttr decodes a single DOT attribute.
func (e *dotEdge) UnmarshalDOTAttr(attr Attribute) error {
if attr.Key != "label" {
return fmt.Errorf("unable to unmarshal node DOT attribute with key %q", attr.Key)
}
e.Label = attr.Value
return nil
}
// DOTAttributes returns the DOT attributes of the edge.
func (e *dotEdge) DOTAttributes() []Attribute {
if len(e.Label) == 0 {
return nil
}
attr := Attribute{
Key: "label",
Value: e.Label,
}
return []Attribute{attr}
}