dag: detect self references, use multierror

This commit is contained in:
Mitchell Hashimoto 2015-02-07 09:52:34 -08:00
parent de3d9fb9d9
commit 5b0004ffc7
3 changed files with 28 additions and 7 deletions

View File

@ -4,6 +4,8 @@ import (
"fmt" "fmt"
"strings" "strings"
"sync" "sync"
"github.com/hashicorp/go-multierror"
) )
// AcyclicGraph is a specialization of Graph that cannot have cycles. With // AcyclicGraph is a specialization of Graph that cannot have cycles. With
@ -45,6 +47,8 @@ func (g *AcyclicGraph) Validate() error {
return err return err
} }
// Look for cycles of more than 1 component
var err error
var cycles [][]Vertex var cycles [][]Vertex
for _, cycle := range StronglyConnected(&g.Graph) { for _, cycle := range StronglyConnected(&g.Graph) {
if len(cycle) > 1 { if len(cycle) > 1 {
@ -52,20 +56,26 @@ func (g *AcyclicGraph) Validate() error {
} }
} }
if len(cycles) > 0 { if len(cycles) > 0 {
cyclesStr := make([]string, len(cycles)) for _, cycle := range cycles {
for i, cycle := range cycles {
cycleStr := make([]string, len(cycle)) cycleStr := make([]string, len(cycle))
for j, vertex := range cycle { for j, vertex := range cycle {
cycleStr[j] = VertexName(vertex) cycleStr[j] = VertexName(vertex)
} }
cyclesStr[i] = strings.Join(cycleStr, ", ") err = multierror.Append(err, fmt.Errorf(
"Cycle: %s", strings.Join(cycleStr, ", ")))
} }
return fmt.Errorf("cycles: %s", cyclesStr)
} }
return nil // Look for cycles to self
for _, e := range g.Edges() {
if e.Source() == e.Target() {
err = multierror.Append(err, fmt.Errorf(
"Self reference: %s", VertexName(e.Source())))
}
}
return err
} }
// Walk walks the graph, calling your callback as each node is visited. // Walk walks the graph, calling your callback as each node is visited.

View File

@ -75,6 +75,17 @@ func TestAcyclicGraphValidate_cycle(t *testing.T) {
} }
} }
func TestAcyclicGraphValidate_cycleSelf(t *testing.T) {
var g AcyclicGraph
g.Add(1)
g.Add(2)
g.Connect(BasicEdge(1, 1))
if err := g.Validate(); err == nil {
t.Fatal("should error")
}
}
func TestAcyclicGraphWalk(t *testing.T) { func TestAcyclicGraphWalk(t *testing.T) {
var g AcyclicGraph var g AcyclicGraph
g.Add(1) g.Add(1)

View File

@ -39,7 +39,7 @@ func (g *Graph) Vertices() []Vertex {
// Edges returns the list of all the edges in the graph. // Edges returns the list of all the edges in the graph.
func (g *Graph) Edges() []Edge { func (g *Graph) Edges() []Edge {
list := g.vertices.List() list := g.edges.List()
result := make([]Edge, len(list)) result := make([]Edge, len(list))
for i, v := range list { for i, v := range list {
result[i] = v.(Edge) result[i] = v.(Edge)