diff --git a/graph/encoding/dot/decode_test.go b/graph/encoding/dot/decode_test.go index 4d652c71..9d1e880f 100644 --- a/graph/encoding/dot/decode_test.go +++ b/graph/encoding/dot/decode_test.go @@ -393,6 +393,77 @@ func TestMultigraphDecoding(t *testing.T) { } } +func TestMultigraphLineIDsharing(t *testing.T) { + for i, test := range []struct { + directed bool + lines []multi.Line + expected string + }{ + { + directed: true, + lines: []multi.Line{ + {F: multi.Node(0), T: multi.Node(1), UID: 0}, + {F: multi.Node(0), T: multi.Node(1), UID: 1}, + {F: multi.Node(0), T: multi.Node(2), UID: 0}, + {F: multi.Node(2), T: multi.Node(0), UID: 0}, + }, + expected: directedMultigraph, + }, + { + directed: false, + lines: []multi.Line{ + {F: multi.Node(0), T: multi.Node(1), UID: 0}, + {F: multi.Node(0), T: multi.Node(1), UID: 1}, + {F: multi.Node(0), T: multi.Node(2), UID: 0}, + {F: multi.Node(0), T: multi.Node(2), UID: 1}, + }, + expected: undirectedMultigraph, + }, + { + directed: true, + lines: []multi.Line{ + {F: multi.Node(0), T: multi.Node(0), UID: 0}, + {F: multi.Node(0), T: multi.Node(0), UID: 1}, + {F: multi.Node(1), T: multi.Node(1), UID: 0}, + {F: multi.Node(1), T: multi.Node(1), UID: 1}, + }, + expected: directedSelfLoopMultigraph, + }, + { + directed: false, + lines: []multi.Line{ + {F: multi.Node(0), T: multi.Node(0), UID: 0}, + {F: multi.Node(0), T: multi.Node(0), UID: 1}, + {F: multi.Node(1), T: multi.Node(1), UID: 0}, + {F: multi.Node(1), T: multi.Node(1), UID: 1}, + }, + expected: undirectedSelfLoopMultigraph, + }, + } { + var dst encoding.MultiBuilder + if test.directed { + dst = multi.NewDirectedGraph() + } else { + dst = multi.NewUndirectedGraph() + } + + for _, l := range test.lines { + dst.SetLine(l) + } + + buf, err := MarshalMulti(dst, "", "", "\t") + if err != nil { + t.Errorf("i=%d: unable to marshal graph; %v", i, dst) + continue + } + actual := string(buf) + if actual != test.expected { + t.Errorf("i=%d: graph content mismatch; want:\n%s\n\nactual:\n%s", i, test.expected, actual) + continue + } + } +} + const directedMultigraph = `digraph { // Node definitions. 0; diff --git a/graph/encoding/dot/encode.go b/graph/encoding/dot/encode.go index 3e3955c5..1cba7c10 100644 --- a/graph/encoding/dot/encode.go +++ b/graph/encoding/dot/encode.go @@ -220,7 +220,7 @@ func (p *simpleGraphPrinter) print(g graph.Graph, name string, needsIndent, isSu continue } p.visited[edge{inGraph: name, from: nid, to: tid}] = true - p.visited[edge{inGraph: name, from: tid, to: n.ID()}] = true + p.visited[edge{inGraph: name, from: tid, to: nid}] = true } if !havePrintedEdgeHeader { @@ -432,6 +432,8 @@ type multiGraphPrinter struct { type line struct { inGraph string + from int64 + to int64 id int64 } @@ -510,10 +512,18 @@ func (p *multiGraphPrinter) print(g graph.Multigraph, name string, needsIndent, for _, l := range lines { lid := l.ID() - if p.visited[line{inGraph: name, id: lid}] { - continue + if isDirected { + if p.visited[line{inGraph: name, from: nid, to: tid, id: lid}] { + continue + } + p.visited[line{inGraph: name, from: nid, to: tid, id: lid}] = true + } else { + if p.visited[line{inGraph: name, from: nid, to: tid, id: lid}] { + continue + } + p.visited[line{inGraph: name, from: nid, to: tid, id: lid}] = true + p.visited[line{inGraph: name, from: tid, to: nid, id: lid}] = true } - p.visited[line{inGraph: name, id: lid}] = true if !havePrintedEdgeHeader { p.buf.WriteByte('\n')