encoding/dot: make all simple graph marshalling strict

Also fix bug in order of emitting strict keyword.
This commit is contained in:
Dan Kortschak
2018-10-27 17:42:20 +10:30
committed by Dan Kortschak
parent cc0c958a30
commit 609b9d63e8
6 changed files with 56 additions and 58 deletions

View File

@@ -55,7 +55,7 @@ func TestRoundTrip(t *testing.T) {
t.Errorf("i=%d: unable to unmarshal DOT graph; %v", i, err) t.Errorf("i=%d: unable to unmarshal DOT graph; %v", i, err)
continue continue
} }
buf, err := Marshal(dst, "", "", "\t", false) buf, err := Marshal(dst, "", "", "\t")
if err != nil { if err != nil {
t.Errorf("i=%d: unable to marshal graph; %v", i, dst) t.Errorf("i=%d: unable to marshal graph; %v", i, dst)
continue continue
@@ -68,7 +68,7 @@ func TestRoundTrip(t *testing.T) {
} }
} }
const directed = `digraph { const directed = `strict digraph {
graph [ graph [
outputorder=edgesfirst outputorder=edgesfirst
]; ];
@@ -89,7 +89,7 @@ const directed = `digraph {
A -> B [label="baz 2"]; A -> B [label="baz 2"];
}` }`
const undirected = `graph { const undirected = `strict graph {
graph [ graph [
outputorder=edgesfirst outputorder=edgesfirst
]; ];
@@ -110,7 +110,7 @@ const undirected = `graph {
A -- B [label="baz 2"]; A -- B [label="baz 2"];
}` }`
const directedID = `digraph G { const directedID = `strict digraph G {
// Node definitions. // Node definitions.
A; A;
B; B;
@@ -119,7 +119,7 @@ const directedID = `digraph G {
A -> B; A -> B;
}` }`
const undirectedID = `graph H { const undirectedID = `strict graph H {
// Node definitions. // Node definitions.
A; A;
B; B;
@@ -128,7 +128,7 @@ const undirectedID = `graph H {
A -- B; A -- B;
}` }`
const directedWithPorts = `digraph { const directedWithPorts = `strict digraph {
// Node definitions. // Node definitions.
A; A;
B; B;
@@ -146,7 +146,7 @@ const directedWithPorts = `digraph {
E:_ -> F:c; E:_ -> F:c;
}` }`
const undirectedWithPorts = `graph { const undirectedWithPorts = `strict graph {
// Node definitions. // Node definitions.
A; A;
B; B;
@@ -192,7 +192,7 @@ func TestChainedEdgeAttributes(t *testing.T) {
t.Errorf("i=%d: unable to unmarshal DOT graph; %v", i, err) t.Errorf("i=%d: unable to unmarshal DOT graph; %v", i, err)
continue continue
} }
buf, err := Marshal(dst, "", "", "\t", false) buf, err := Marshal(dst, "", "", "\t")
if err != nil { if err != nil {
t.Errorf("i=%d: unable to marshal graph; %v", i, dst) t.Errorf("i=%d: unable to marshal graph; %v", i, dst)
continue continue
@@ -205,7 +205,7 @@ func TestChainedEdgeAttributes(t *testing.T) {
} }
} }
const directedChained = `digraph { const directedChained = `strict digraph {
graph [ graph [
outputorder=edgesfirst outputorder=edgesfirst
]; ];
@@ -226,7 +226,7 @@ const directedChained = `digraph {
A -> B -> A [label="baz 2"]; A -> B -> A [label="baz 2"];
}` }`
const directedNonchained = `digraph { const directedNonchained = `strict digraph {
graph [ graph [
outputorder=edgesfirst outputorder=edgesfirst
]; ];
@@ -270,7 +270,7 @@ const undirectedChained = `graph {
A -- B -- C [label="baz 2"]; A -- B -- C [label="baz 2"];
}` }`
const undirectedNonchained = `graph { const undirectedNonchained = `strict graph {
graph [ graph [
outputorder=edgesfirst outputorder=edgesfirst
]; ];

View File

@@ -76,14 +76,11 @@ type Subgrapher interface {
// however, advanced GraphViz DOT features provided by Marshal depend on // however, advanced GraphViz DOT features provided by Marshal depend on
// implementation of the Node, Attributer, Porter, Attributers, Structurer, // implementation of the Node, Attributer, Porter, Attributers, Structurer,
// Subgrapher and Graph interfaces. // Subgrapher and Graph interfaces.
func Marshal(g graph.Graph, name, prefix, indent string, strict bool) ([]byte, error) { func Marshal(g graph.Graph, name, prefix, indent string) ([]byte, error) {
var p printer var p printer
p.indent = indent p.indent = indent
p.prefix = prefix p.prefix = prefix
p.visited = make(map[edge]bool) p.visited = make(map[edge]bool)
if strict {
p.buf.WriteString("strict ")
}
err := p.print(g, name, false, false) err := p.print(g, name, false, false)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -118,6 +115,9 @@ func (p *printer) print(g graph.Graph, name string, needsIndent, isSubgraph bool
p.buf.WriteString(p.indent) p.buf.WriteString(p.indent)
} }
} }
if !isSubgraph {
p.buf.WriteString("strict ")
}
_, isDirected := g.(graph.Directed) _, isDirected := g.(graph.Directed)
if isSubgraph { if isSubgraph {
p.buf.WriteString("sub") p.buf.WriteString("sub")

View File

@@ -410,9 +410,8 @@ func undirectedSubGraphFrom(g []intset, s map[int64][]intset) graph.Graph {
} }
var encodeTests = []struct { var encodeTests = []struct {
name string name string
g graph.Graph g graph.Graph
strict bool
prefix string prefix string
@@ -423,7 +422,7 @@ var encodeTests = []struct {
name: "PageRank", name: "PageRank",
g: directedGraphFrom(pageRankGraph), g: directedGraphFrom(pageRankGraph),
want: `digraph PageRank { want: `strict digraph PageRank {
// Node definitions. // Node definitions.
0; 0;
1; 1;
@@ -460,7 +459,7 @@ var encodeTests = []struct {
{ {
g: undirectedGraphFrom(pageRankGraph), g: undirectedGraphFrom(pageRankGraph),
want: `graph { want: `strict graph {
// Node definitions. // Node definitions.
0; 0;
1; 1;
@@ -495,7 +494,7 @@ var encodeTests = []struct {
{ {
g: directedGraphFrom(powerMethodGraph), g: directedGraphFrom(powerMethodGraph),
want: `digraph { want: `strict digraph {
// Node definitions. // Node definitions.
0; 0;
1; 1;
@@ -516,7 +515,7 @@ var encodeTests = []struct {
{ {
g: undirectedGraphFrom(powerMethodGraph), g: undirectedGraphFrom(powerMethodGraph),
want: `graph { want: `strict graph {
// Node definitions. // Node definitions.
0; 0;
1; 1;
@@ -538,7 +537,7 @@ var encodeTests = []struct {
g: undirectedGraphFrom(powerMethodGraph), g: undirectedGraphFrom(powerMethodGraph),
prefix: "# ", prefix: "# ",
want: `# graph { want: `# strict graph {
# // Node definitions. # // Node definitions.
# 0; # 0;
# 1; # 1;
@@ -562,7 +561,7 @@ var encodeTests = []struct {
name: "PageRank", name: "PageRank",
g: directedNamedIDGraphFrom(pageRankGraph), g: directedNamedIDGraphFrom(pageRankGraph),
want: `digraph PageRank { want: `strict digraph PageRank {
// Node definitions. // Node definitions.
A; A;
B; B;
@@ -599,7 +598,7 @@ var encodeTests = []struct {
{ {
g: undirectedNamedIDGraphFrom(pageRankGraph), g: undirectedNamedIDGraphFrom(pageRankGraph),
want: `graph { want: `strict graph {
// Node definitions. // Node definitions.
A; A;
B; B;
@@ -634,7 +633,7 @@ var encodeTests = []struct {
{ {
g: directedNamedIDGraphFrom(powerMethodGraph), g: directedNamedIDGraphFrom(powerMethodGraph),
want: `digraph { want: `strict digraph {
// Node definitions. // Node definitions.
A; A;
B; B;
@@ -655,7 +654,7 @@ var encodeTests = []struct {
{ {
g: undirectedNamedIDGraphFrom(powerMethodGraph), g: undirectedNamedIDGraphFrom(powerMethodGraph),
want: `graph { want: `strict graph {
// Node definitions. // Node definitions.
A; A;
B; B;
@@ -677,7 +676,7 @@ var encodeTests = []struct {
g: undirectedNamedIDGraphFrom(powerMethodGraph), g: undirectedNamedIDGraphFrom(powerMethodGraph),
prefix: "# ", prefix: "# ",
want: `# graph { want: `# strict graph {
# // Node definitions. # // Node definitions.
# A; # A;
# B; # B;
@@ -700,7 +699,7 @@ var encodeTests = []struct {
{ {
g: directedNodeAttrGraphFrom(powerMethodGraph, nil), g: directedNodeAttrGraphFrom(powerMethodGraph, nil),
want: `digraph { want: `strict digraph {
// Node definitions. // Node definitions.
0; 0;
1; 1;
@@ -721,7 +720,7 @@ var encodeTests = []struct {
{ {
g: undirectedNodeAttrGraphFrom(powerMethodGraph, nil), g: undirectedNodeAttrGraphFrom(powerMethodGraph, nil),
want: `graph { want: `strict graph {
// Node definitions. // Node definitions.
0; 0;
1; 1;
@@ -745,7 +744,7 @@ var encodeTests = []struct {
4: {}, 4: {},
}), }),
want: `digraph { want: `strict digraph {
// Node definitions. // Node definitions.
0; 0;
1; 1;
@@ -772,7 +771,7 @@ var encodeTests = []struct {
4: {}, 4: {},
}), }),
want: `graph { want: `strict graph {
// Node definitions. // Node definitions.
0; 0;
1; 1;
@@ -799,7 +798,7 @@ var encodeTests = []struct {
4: {}, 4: {},
}), }),
want: `digraph { want: `strict digraph {
// Node definitions. // Node definitions.
A; A;
B; B;
@@ -829,7 +828,7 @@ var encodeTests = []struct {
4: {}, 4: {},
}), }),
want: `graph { want: `strict graph {
// Node definitions. // Node definitions.
A; A;
B; B;
@@ -855,7 +854,7 @@ var encodeTests = []struct {
{ {
g: directedEdgeAttrGraphFrom(powerMethodGraph, nil), g: directedEdgeAttrGraphFrom(powerMethodGraph, nil),
want: `digraph { want: `strict digraph {
// Node definitions. // Node definitions.
0; 0;
1; 1;
@@ -876,7 +875,7 @@ var encodeTests = []struct {
{ {
g: undirectedEdgeAttrGraphFrom(powerMethodGraph, nil), g: undirectedEdgeAttrGraphFrom(powerMethodGraph, nil),
want: `graph { want: `strict graph {
// Node definitions. // Node definitions.
0; 0;
1; 1;
@@ -901,7 +900,7 @@ var encodeTests = []struct {
{from: 3, to: 4}: {{Key: "color", Value: "red"}}, {from: 3, to: 4}: {{Key: "color", Value: "red"}},
}), }),
want: `digraph { want: `strict digraph {
// Node definitions. // Node definitions.
0; 0;
1; 1;
@@ -929,7 +928,7 @@ var encodeTests = []struct {
{from: 3, to: 4}: {{Key: "color", Value: "red"}}, {from: 3, to: 4}: {{Key: "color", Value: "red"}},
}), }),
want: `graph { want: `strict graph {
// Node definitions. // Node definitions.
0; 0;
1; 1;
@@ -955,7 +954,7 @@ var encodeTests = []struct {
{ {
g: directedPortedAttrGraphFrom(powerMethodGraph, nil, nil), g: directedPortedAttrGraphFrom(powerMethodGraph, nil, nil),
want: `digraph { want: `strict digraph {
// Node definitions. // Node definitions.
0; 0;
1; 1;
@@ -976,7 +975,7 @@ var encodeTests = []struct {
{ {
g: undirectedPortedAttrGraphFrom(powerMethodGraph, nil, nil), g: undirectedPortedAttrGraphFrom(powerMethodGraph, nil, nil),
want: `graph { want: `strict graph {
// Node definitions. // Node definitions.
0; 0;
1; 1;
@@ -1010,7 +1009,7 @@ var encodeTests = []struct {
}, },
), ),
want: `digraph { want: `strict digraph {
// Node definitions. // Node definitions.
0; 0;
1; 1;
@@ -1050,7 +1049,7 @@ var encodeTests = []struct {
}, },
), ),
want: `graph { want: `strict graph {
// Node definitions. // Node definitions.
0; 0;
1; 1;
@@ -1083,7 +1082,7 @@ var encodeTests = []struct {
{from: 3, to: 4}: {{Key: "color", Value: "red"}}, {from: 3, to: 4}: {{Key: "color", Value: "red"}},
})}, })},
want: `graph { want: `strict graph {
// Node definitions. // Node definitions.
0; 0;
1; 1;
@@ -1114,7 +1113,7 @@ var encodeTests = []struct {
node: []encoding.Attribute{{Key: "fontsize", Value: "16"}, {Key: "shape", Value: "ellipse"}}, node: []encoding.Attribute{{Key: "fontsize", Value: "16"}, {Key: "shape", Value: "ellipse"}},
}, },
want: `graph { want: `strict graph {
graph [ graph [
rankdir="LR" rankdir="LR"
]; ];
@@ -1148,7 +1147,7 @@ var encodeTests = []struct {
{ {
g: undirectedStructuredGraphFrom(nil, powerMethodGraph, pageRankGraph), g: undirectedStructuredGraphFrom(nil, powerMethodGraph, pageRankGraph),
want: `graph { want: `strict graph {
subgraph A { subgraph A {
// Node definitions. // Node definitions.
0; 0;
@@ -1202,7 +1201,7 @@ var encodeTests = []struct {
{ {
g: undirectedStructuredGraphFrom([]edge{{from: 0, to: 9}}, powerMethodGraph, pageRankGraph), g: undirectedStructuredGraphFrom([]edge{{from: 0, to: 9}}, powerMethodGraph, pageRankGraph),
want: `graph { want: `strict graph {
subgraph A { subgraph A {
// Node definitions. // Node definitions.
0; 0;
@@ -1264,7 +1263,7 @@ var encodeTests = []struct {
{ {
g: undirectedSubGraphFrom(pageRankGraph, map[int64][]intset{2: powerMethodGraph}), g: undirectedSubGraphFrom(pageRankGraph, map[int64][]intset{2: powerMethodGraph}),
want: `graph { want: `strict graph {
// Node definitions. // Node definitions.
5; 5;
6; 6;
@@ -1312,9 +1311,8 @@ var encodeTests = []struct {
}`, }`,
}, },
{ {
name: "H", name: "H",
g: undirectedSubGraphFrom(pageRankGraph, map[int64][]intset{1: powerMethodGraph}), g: undirectedSubGraphFrom(pageRankGraph, map[int64][]intset{1: powerMethodGraph}),
strict: true,
want: `strict graph H { want: `strict graph H {
// Node definitions. // Node definitions.
@@ -1409,7 +1407,7 @@ var encodeTests = []struct {
func TestEncode(t *testing.T) { func TestEncode(t *testing.T) {
for i, test := range encodeTests { for i, test := range encodeTests {
got, err := Marshal(test.g, test.name, test.prefix, "\t", test.strict) got, err := Marshal(test.g, test.name, test.prefix, "\t")
if err != nil { if err != nil {
t.Errorf("unexpected error: %v", err) t.Errorf("unexpected error: %v", err)
continue continue

View File

@@ -32,7 +32,7 @@ func ExamplePorter() {
toPort: "p2", toPort: "p2",
}) })
result, _ := dot.Marshal(g, "", "", " ", true) result, _ := dot.Marshal(g, "", "", " ")
fmt.Print(string(result)) fmt.Print(string(result))
// Output: // Output:

View File

@@ -32,7 +32,7 @@ var decodeTests = []struct {
0xa3cff1a4c3ef3bb6: true, 0xa3cff1a4c3ef3bb6: true,
0xb39aa14d66aedad5: true, 0xb39aa14d66aedad5: true,
}, },
wantDOT: `digraph { wantDOT: `strict digraph {
// Node definitions. // Node definitions.
0x8a10d5a2611fd03f [name="Richard Marquand"]; 0x8a10d5a2611fd03f [name="Richard Marquand"];
0xa3cff1a4c3ef3bb6 [ 0xa3cff1a4c3ef3bb6 [
@@ -70,7 +70,7 @@ var decodeTests = []struct {
0xfd90205a458151f: true, 0xfd90205a458151f: true,
0x52a80955d40ec819: true, 0x52a80955d40ec819: true,
}, },
wantDOT: `digraph { wantDOT: `strict digraph {
// Node definitions. // Node definitions.
0x892a6da7ee1fbdec [ 0x892a6da7ee1fbdec [
age=55 age=55
@@ -139,7 +139,7 @@ func TestDecode(t *testing.T) {
} }
continue continue
} }
b, err := dot.Marshal(dst, "", "", " ", false) b, err := dot.Marshal(dst, "", "", " ")
if err != nil { if err != nil {
t.Fatalf("failed to DOT marshal graph %q: %v", test.name, err) t.Fatalf("failed to DOT marshal graph %q: %v", test.name, err)
} }

View File

@@ -27,7 +27,7 @@ var cliqueGraphTests = []struct {
5: nil, 5: nil,
6: nil, 6: nil,
}, },
want: `graph { want: `strict graph {
// Node definitions. // Node definitions.
0 [nodes="[0 1 2 6]"]; 0 [nodes="[0 1 2 6]"];
1 [nodes="[0 1 4 6]"]; 1 [nodes="[0 1 4 6]"];
@@ -46,7 +46,7 @@ var cliqueGraphTests = []struct {
}, },
{ {
g: batageljZaversnikGraph, g: batageljZaversnikGraph,
want: `graph { want: `strict graph {
// Node definitions. // Node definitions.
0 [nodes="[0]"]; 0 [nodes="[0]"];
1 [nodes="[1 2]"]; 1 [nodes="[1 2]"];
@@ -102,7 +102,7 @@ func TestCliqueGraph(t *testing.T) {
dst := simple.NewUndirectedGraph() dst := simple.NewUndirectedGraph()
CliqueGraph(dst, g) CliqueGraph(dst, g)
b, _ := dot.Marshal(dst, "", "", " ", false) b, _ := dot.Marshal(dst, "", "", " ")
got := string(b) got := string(b)
if got != test.want { if got != test.want {