diff --git a/condense_test.go b/condense_test.go index 818799c..1172c5e 100644 --- a/condense_test.go +++ b/condense_test.go @@ -89,3 +89,46 @@ func TestCondenseDebugging(t *testing.T) { x() assert.True(t, called, "called") } + +func TestCondenseSelfSatisfied(t *testing.T) { + var called bool + var alsoCalled bool + var x func() + condensed := nject.Required(nject.Sequence("c", + func(_ int) string { + return "foo" + }, + func(_ string) { + called = true + }, + ).MustCondense(true)) + + nject.Sequence("s1", + func() int { + return 7 + }, + condensed, + func() { + alsoCalled = true + }, + ).Bind(&x, nil) + x() + assert.True(t, called, "condensed called") + assert.True(t, alsoCalled, "main called") + assert.Equal(t, + " [(int)]", + condensed.String(), + "presentation of condensed") +} + +func TestCondenseStringified(t *testing.T) { + c1 := nject.Sequence("x", + func() (int, string) { return 7, "foo" }, + ).MustCondense(true) + assert.Equal(t, " [() (int, string)]", c1.String(), "c1") + + c2 := nject.Sequence("x", + func() float32 { return 7 }, + ).MustCondense(true) + assert.Equal(t, " [() float32]", c2.String(), "c2") +} diff --git a/nject.go b/nject.go index 52d36ac..9a7c7bb 100644 --- a/nject.go +++ b/nject.go @@ -147,12 +147,17 @@ func newProvider(fn interface{}, index int, origin string) *provider { } func (fm provider) String() string { - var t string - if fm.fn == nil { - t = "nil" - } else { - t = reflect.TypeOf(fm.fn).String() - } + t := func() string { + if fm.fn == nil { + return "nil" + } + if _, ok := fm.fn.(Reflective); ok { + if s, ok := fm.fn.(fmt.Stringer); ok { + return s.String() + } + } + return reflect.TypeOf(fm.fn).String() + }() class := "" if fm.class != unsetClassType { class = fm.class.String() + ": " diff --git a/reflective.go b/reflective.go index e32e704..69233ee 100644 --- a/reflective.go +++ b/reflective.go @@ -1,6 +1,7 @@ package nject import ( + "fmt" "reflect" "strings" ) @@ -81,14 +82,34 @@ type reflectiveBinder struct { thinReflective } -var _ ReflectiveInvoker = &reflectiveBinder{} -var _ Reflective = reflectiveBinder{} +var ( + _ ReflectiveInvoker = &reflectiveBinder{} + _ Reflective = reflectiveBinder{} +) func (b *reflectiveBinder) Set(fun func([]reflect.Value) []reflect.Value) { b.fun = fun } func (r thinReflective) Call(in []reflect.Value) []reflect.Value { return r.fun(in) } +func (r thinReflective) String() string { + in := make([]string, len(r.inputs)) + for i, input := range r.inputs { + in[i] = input.String() + } + switch len(r.outputs) { + case 0: + return fmt.Sprintf("(%s)", strings.Join(in, ", ")) + case 1: + return fmt.Sprintf("(%s) %s", strings.Join(in, ", "), r.outputs[0].String()) + default: + out := make([]string, len(r.outputs)) + for i, output := range r.outputs { + out[i] = output.String() + } + return fmt.Sprintf("(%s) (%s)", strings.Join(in, ", "), strings.Join(out, ", ")) + } +} // MakeReflectiveWrapper is a utility to create a ReflectiveWrapper // diff --git a/utils_test.go b/utils_test.go index f7be9ab..6e91b66 100644 --- a/utils_test.go +++ b/utils_test.go @@ -7,7 +7,7 @@ import ( "github.com/stretchr/testify/assert" ) -func TestSaveTo(t *testing.T) { +func TestSaveToInvalid(t *testing.T) { f := func() {} cases := []struct { want string @@ -38,6 +38,43 @@ func TestSaveTo(t *testing.T) { } } +func TestSaveToValid(t *testing.T) { + type foo struct { + i int + } + var fooDst foo + var fooPtrDst *foo + cases := []struct { + inject interface{} + ptr interface{} + check func() + }{ + { + inject: foo{i: 7}, + ptr: &fooDst, + check: func() { + assert.Equal(t, foo{i: 7}, fooDst) + }, + }, + { + inject: &foo{i: 7}, + ptr: &fooPtrDst, + check: func() { + assert.Equal(t, foo{i: 7}, *fooPtrDst) + }, + }, + } + for i, tc := range cases { + err := Run("x", + tc.inject, + MustSaveTo(tc.ptr), + ) + if assert.NoErrorf(t, err, "%d", i) { + assert.NotPanics(t, tc.check, "check") + } + } +} + func TestCurry(t *testing.T) { t.Parallel() seq := Sequence("available",