Skip to content

Commit

Permalink
add warning about duplicated types to DetailedError (#57)
Browse files Browse the repository at this point in the history
  • Loading branch information
muir authored Feb 1, 2023
1 parent 785a803 commit bfb9833
Show file tree
Hide file tree
Showing 5 changed files with 90 additions and 2 deletions.
38 changes: 38 additions & 0 deletions error.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package nject

import (
"errors"
"sync"
)

type njectError struct {
Expand All @@ -20,7 +21,44 @@ func (ne *njectError) Error() string {
func DetailedError(err error) string {
var njectError *njectError
if errors.As(err, &njectError) {
dups := duplicateTypes()
if dups != "" {
return err.Error() + "\n\n" + njectError.details +
"\n\nWarning: the following type names refer to more than one type:\n" +
dups
}
return err.Error() + "\n\n" + njectError.details
}
return err.Error()
}

var duplicatesThrough int
var dupLock sync.Mutex
var duplicates string
var duplicatesFound = make(map[string]struct{})

func duplicateTypes() string {
max := func() int {
lock.Lock()
defer lock.Unlock()
return typeCounter
}()
dupLock.Lock()
defer dupLock.Unlock()
if duplicatesThrough == max {
return duplicates
}
names := make(map[string]struct{})
for i := 1; i <= typeCounter; i++ {
n := typeCode(i).String()
if _, ok := names[n]; ok {
if _, ok := duplicatesFound[n]; !ok {
duplicates += " " + n
duplicatesFound[n] = struct{}{}
}
}
names[n] = struct{}{}
}
duplicatesThrough = max
return duplicates
}
3 changes: 3 additions & 0 deletions internal/foo/foo.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package foo

type Bar struct {}
3 changes: 3 additions & 0 deletions internal/foo/v2/foo.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package foo

type Bar struct {}
20 changes: 18 additions & 2 deletions type_codes.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
package nject

// TODO: switch from typeCode to reflect.Type
// TODO: switch from typeCode to reflect.Type -- duplicate detection would be lost

import (
"path"
"reflect"
"regexp"
"strings"
"sync"
)

Expand Down Expand Up @@ -73,9 +76,22 @@ func (tc typeCode) Type() reflect.Type {
return reverseMap[tc]
}

var versionRE = regexp.MustCompile(`/v(\d+)$`)

// Type returns the reflect.Type for this typeCode
func (tc typeCode) String() string {
return tc.Type().String()
ts := tc.Type().String()
if versionRE.MatchString(tc.Type().PkgPath()) {
pp := tc.Type().PkgPath()
version := path.Base(pp)
pn := path.Base(path.Dir(pp))
revised := strings.Replace(ts, pn, pn+"/"+version, 1)
if revised != ts {
return revised
}
return "(" + version + ")" + ts
}
return ts
}

func (tcs typeCodes) Types() []reflect.Type {
Expand Down
28 changes: 28 additions & 0 deletions type_codes_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package nject

import (
"reflect"
"testing"

v1 "github.com/muir/nject/internal/foo"
v2 "github.com/muir/nject/internal/foo/v2"

"github.com/stretchr/testify/assert"
)

func TestVersionedNames(t *testing.T) {
x1 := getTypeCode(v1.Bar{})
assert.Equal(t, "foo.Bar", x1.String())
t.Log("base type", reflect.TypeOf(v2.Bar{}).PkgPath())
assert.Equal(t, "foo/v2.Bar", getTypeCode(v2.Bar{}).String())
t.Log("pointer", reflect.TypeOf(&v2.Bar{}).PkgPath())
assert.Equal(t, "*foo.Bar", getTypeCode(&v2.Bar{}).String()) // :(
assert.Equal(t, "*foo.Bar", getTypeCode(&v1.Bar{}).String()) // :(
t.Log("slice", reflect.TypeOf([]v2.Bar{}).PkgPath())
assert.Equal(t, "[]foo.Bar", getTypeCode([]v2.Bar{}).String()) // :(
assert.Equal(t, "[]foo.Bar", getTypeCode([]v1.Bar{}).String()) // :(
dups := duplicateTypes()
assert.Contains(t, dups, "[]foo.Bar")
assert.Contains(t, dups, "*foo.Bar")
t.Log("duplicates", dups)
}

0 comments on commit bfb9833

Please sign in to comment.