Skip to content

Commit

Permalink
Merge pull request #10 from fgrosse/task/check-referenced-types
Browse files Browse the repository at this point in the history
Check referenced types
  • Loading branch information
fgrosse committed May 14, 2015
2 parents aef0d82 + 7f4a8b7 commit 49633f1
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 14 deletions.
38 changes: 30 additions & 8 deletions tests/type_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"

"errors"
"github.com/fgrosse/goldi"
"github.com/fgrosse/goldi/tests/testAPI"
)
Expand Down Expand Up @@ -104,16 +105,37 @@ var _ = Describe("Type", func() {
})

Context("when a type reference is given", func() {
It("should generate the type", func() {
err := typeRegistry.RegisterType("foo", testAPI.NewMockType)
Expect(err).NotTo(HaveOccurred())
Context("and its type matches the function signature", func() {
It("should generate the type", func() {
err := typeRegistry.RegisterType("foo", testAPI.NewMockType)
Expect(err).NotTo(HaveOccurred())

typeDef = goldi.NewType(testAPI.NewTypeForServiceInjection, "@foo")
generatedType := typeDef.Generate(config, typeRegistry)
Expect(generatedType).To(BeAssignableToTypeOf(&testAPI.TypeForServiceInjection{}))

generatedMock := generatedType.(*testAPI.TypeForServiceInjection)
Expect(generatedMock.InjectedType).To(BeAssignableToTypeOf(&testAPI.MockType{}))
})
})

Context("and its type does not match the function signature", func() {
It("should panic with a helpful error message", func() {
err := typeRegistry.RegisterType("foo", testAPI.NewFoo)
Expect(err).NotTo(HaveOccurred())

typeDef = goldi.NewType(testAPI.NewTypeForServiceInjection, "@foo")

typeDef = goldi.NewType(testAPI.NewTypeForServiceInjection, "@foo")
generatedType := typeDef.Generate(config, typeRegistry)
Expect(generatedType).To(BeAssignableToTypeOf(&testAPI.TypeForServiceInjection{}))
defer func() {
r := recover()
Expect(r).NotTo(BeNil(), "Expected Generate to panic")
Expect(r).To(BeAssignableToTypeOf(errors.New("")))
err := r.(error)
Expect(err.Error()).To(Equal("could not generate type: the referenced type \"@foo\" (type *testAPI.Foo) can not be passed as argument 1 to the function signature github.com/fgrosse/goldi/tests/testAPI.NewTypeForServiceInjection(*testAPI.MockType)"))
}()

generatedMock := generatedType.(*testAPI.TypeForServiceInjection)
Expect(generatedMock.InjectedType).To(BeAssignableToTypeOf(&testAPI.MockType{}))
typeDef.Generate(config, typeRegistry)
})
})
})
})
Expand Down
21 changes: 15 additions & 6 deletions type.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package goldi
import (
"fmt"
"reflect"
"runtime"
)

// A Type holds all information that is necessary to create a new instance of a type ID
Expand Down Expand Up @@ -77,7 +78,7 @@ func (t *Type) Generate(config map[string]interface{}, registry TypeRegistry) in

args := make([]reflect.Value, len(t.generatorArguments))
for i, argument := range t.generatorArguments {
args[i] = t.resolveParameter(argument, t.generatorType.In(i), config, registry)
args[i] = t.resolveParameter(i, argument, t.generatorType.In(i), config, registry)
}

result := t.generator.Call(args)
Expand All @@ -88,7 +89,7 @@ func (t *Type) Generate(config map[string]interface{}, registry TypeRegistry) in
return result[0].Interface()
}

func (t *Type) resolveParameter(argument reflect.Value, expectedArgument reflect.Type, config map[string]interface{}, registry TypeRegistry) reflect.Value {
func (t *Type) resolveParameter(i int, argument reflect.Value, expectedArgument reflect.Type, config map[string]interface{}, registry TypeRegistry) reflect.Value {
if argument.Kind() != reflect.String {
return argument
}
Expand All @@ -99,7 +100,7 @@ func (t *Type) resolveParameter(argument reflect.Value, expectedArgument reflect
}

if stringArgument[0] == '@' {
return resolveTypeReference(stringArgument[1:], config, registry, expectedArgument)
return t.resolveTypeReference(i, stringArgument[1:], config, registry, expectedArgument)
}

parameterName := stringArgument[1 : len(stringArgument)-1]
Expand All @@ -113,13 +114,21 @@ func (t *Type) resolveParameter(argument reflect.Value, expectedArgument reflect
return argument
}

func resolveTypeReference(typeID string, config map[string]interface{}, registry TypeRegistry, expectedArgument reflect.Type) reflect.Value {
t, typeDefined := registry[typeID]
func (t *Type) resolveTypeReference(i int, typeID string, config map[string]interface{}, registry TypeRegistry, expectedArgument reflect.Type) reflect.Value {
referencedType, typeDefined := registry[typeID]
if typeDefined == false {
panic(fmt.Errorf("the referenced type \"@%s\" has not been defined", typeID))
}

typeInstance := t.Generate(config, registry)
typeInstance := referencedType.Generate(config, registry)
if reflect.TypeOf(typeInstance).AssignableTo(expectedArgument) == false {
factoryName := runtime.FuncForPC(t.generator.Pointer()).Name()
err := fmt.Errorf("the referenced type \"@%s\" (type %T) can not be passed as argument %d to the function signature %s(%s)",
typeID, typeInstance, i+1, factoryName, expectedArgument.String(),
)
panic(err)
}

// TODO check if this type is assignable and generate helpful error message if not
argument := reflect.New(expectedArgument).Elem()
argument.Set(reflect.ValueOf(typeInstance))
Expand Down

0 comments on commit 49633f1

Please sign in to comment.