Skip to content

Commit

Permalink
Fix the DFS traversal, which exited too soon
Browse files Browse the repository at this point in the history
  • Loading branch information
Glib Smaga committed Mar 6, 2017
1 parent 7968fd5 commit 266849c
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 21 deletions.
33 changes: 17 additions & 16 deletions dig/dig.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ package dig

import (
"bytes"
"container/list"
"fmt"
"reflect"
"sync"
Expand Down Expand Up @@ -210,28 +209,30 @@ func (g *Graph) registerConstructor(c interface{}) error {

// When a new constructor is being inserted, detect any present cycles
func (g *Graph) detectCycles(n *funcNode) error {
visited := make(map[string]bool)
l := list.New()
return g.recursiveDetectCycles(n, visited, l)
l := []string{}
return g.recursiveDetectCycles(n, l)
}

// DFS and tracking if same node is visited twice
func (g *Graph) recursiveDetectCycles(n graphNode, visited map[string]bool, l *list.List) error {
visited[n.id()] = true
l.PushBack(n.id())
func (g *Graph) recursiveDetectCycles(n graphNode, l []string) error {
for _, el := range l {
if n.id() == el {
b := &bytes.Buffer{}
for _, curr := range l {
fmt.Fprint(b, curr, " -> ")
}
fmt.Fprint(b, n.id())
return fmt.Errorf("detected cycle %s", b.String())
}
}

l = append(l, n.id())

for _, dep := range n.dependencies() {
if node, ok := g.nodes[dep]; ok {
if visited[node.id()] {
b := &bytes.Buffer{}
for curr := l.Front(); curr != nil; curr = curr.Next() {
fmt.Fprint(b, curr.Value, " -> ")
}
fmt.Fprint(b, node.id())
return fmt.Errorf("detected cycle %s", b.String())
if err := g.recursiveDetectCycles(node, l); err != nil {
return err
}

return g.recursiveDetectCycles(node, visited, l)
}
}

Expand Down
16 changes: 11 additions & 5 deletions dig/dig_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -189,19 +189,25 @@ func TestCycles(t *testing.T) {
t.Parallel()
g := New()

// Type1
// / \
// Type2 Type 3
// / \
// Type4 Type 1
type Type1 interface{}
type Type2 interface{}
type Type3 interface{}
c1 := func(t2 Type2) Type1 { return nil }
c2 := func(t3 Type3) Type2 { return nil }
c3 := func(t1 Type1) Type3 { return nil }
type Type4 interface{}
c1 := func(t2 Type2, t3 Type3) Type1 { return nil }
c2 := func(t4 Type4) Type2 { return nil }
c3 := func(t3 Type1) Type3 { return nil }

require.NoError(t, g.Register(c1))
require.NoError(t, g.Register(c2))

err := g.Register(c3)

require.Contains(t, err.Error(), "unable to register dig.Type3")
require.Contains(t, err.Error(), "dig.Type3 -> dig.Type1 -> dig.Type2 -> dig.Type3")
require.Contains(t, err.Error(), "dig.Type3 -> dig.Type1 -> dig.Type3")
}

func TestResolveAll(t *testing.T) {
Expand Down

0 comments on commit 266849c

Please sign in to comment.