Skip to content

Commit

Permalink
Merge pull request #14 from fgrosse/feature/build-types-without-factory
Browse files Browse the repository at this point in the history
Feature/build types without factory
  • Loading branch information
fgrosse committed May 16, 2015
2 parents 49633f1 + ddddfbd commit bf2e86b
Show file tree
Hide file tree
Showing 5 changed files with 270 additions and 97 deletions.
2 changes: 1 addition & 1 deletion README.md
Expand Up @@ -112,7 +112,7 @@ import (

// RegisterTypes registers all types that have been defined in the file "types.yml"
//
// DO NOT EDIT THIS FILE: it has been generated by goldigen v0.5.0.
// DO NOT EDIT THIS FILE: it has been generated by goldigen v0.6.0.
// It is however good practice to put this file under version control.
// See https://github.com/fgrosse/goldi for what is going on here.
func RegisterTypes(types goldi.TypeRegistry) {
Expand Down
2 changes: 1 addition & 1 deletion generator/generator.go
Expand Up @@ -10,7 +10,7 @@ import (
"strings"
)

const Version = "0.5.0"
const Version = "0.6.0"

// The Generator is used to generate compilable go code from a yaml configuration
type Generator struct {
Expand Down
4 changes: 4 additions & 0 deletions tests/testAPI/mocks.go
Expand Up @@ -29,3 +29,7 @@ type TypeForServiceInjection struct {
func NewTypeForServiceInjection(injectedType *MockType) *TypeForServiceInjection {
return &TypeForServiceInjection{injectedType}
}

func NewTypeForServiceInjectionWithArgs(injectedType *MockType, name, location string, flag bool) *TypeForServiceInjection {
return &TypeForServiceInjection{injectedType}
}
223 changes: 159 additions & 64 deletions tests/type_test.go
Expand Up @@ -5,6 +5,7 @@ import (
. "github.com/onsi/gomega"

"errors"
"fmt"
"github.com/fgrosse/goldi"
"github.com/fgrosse/goldi/tests/testAPI"
)
Expand All @@ -14,10 +15,15 @@ var _ = Describe("Type", func() {

Describe("NewType()", func() {
Context("with invalid factory function", func() {
It("should panic if the generator is no function", func() {
It("should panic if the generator is no function or pointer to a struct", func() {
Expect(func() { goldi.NewType(42) }).To(Panic())
})

It("should panic if the generator is a pointer to something other than a struct", func() {
something := "Hello Pointer World!"
Expect(func() { goldi.NewType(&something) }).To(Panic())
})

It("should panic if the generator has no output parameters", func() {
Expect(func() { goldi.NewType(func() {}) }).To(Panic())
})
Expand All @@ -35,42 +41,51 @@ var _ = Describe("Type", func() {
})
})

Context("with factory functions without arguments", func() {
Context("when no factory argument is given", func() {
It("should create the type", func() {
typeDef = goldi.NewType(testAPI.NewMockType)
Expect(typeDef).NotTo(BeNil())
Context("with factory functions", func() {
Context("without arguments", func() {
Context("when no factory argument is given", func() {
It("should create the type", func() {
typeDef = goldi.NewType(testAPI.NewMockType)
Expect(typeDef).NotTo(BeNil())
})
})
})

Context("when any argument is given", func() {
It("should panic", func() {
Expect(func() { goldi.NewType(testAPI.NewMockType, "foo") }).To(Panic())
Context("when any argument is given", func() {
It("should panic", func() {
Expect(func() { goldi.NewType(testAPI.NewMockType, "foo") }).To(Panic())
})
})
})
})

Context("with factory functions with one or more arguments", func() {
Context("when an invalid number of arguments is given", func() {
It("should panic", func() {
Expect(func() { goldi.NewType(testAPI.NewMockTypeWithArgs) }).To(Panic())
Expect(func() { goldi.NewType(testAPI.NewMockTypeWithArgs, "foo") }).To(Panic())
Expect(func() { goldi.NewType(testAPI.NewMockTypeWithArgs, "foo", false, 42) }).To(Panic())
Context("with one or more arguments", func() {
Context("when an invalid number of arguments is given", func() {
It("should panic", func() {
Expect(func() { goldi.NewType(testAPI.NewMockTypeWithArgs) }).To(Panic())
Expect(func() { goldi.NewType(testAPI.NewMockTypeWithArgs, "foo") }).To(Panic())
Expect(func() { goldi.NewType(testAPI.NewMockTypeWithArgs, "foo", false, 42) }).To(Panic())
})
})

Context("when the wrong argument types are given", func() {
It("should panic", func() {
Expect(func() { goldi.NewType(testAPI.NewMockTypeWithArgs, "foo", "bar") }).To(Panic())
Expect(func() { goldi.NewType(testAPI.NewMockTypeWithArgs, true, "bar") }).To(Panic())
})
})
})

Context("when the wrong argument types are given", func() {
It("should panic", func() {
Expect(func() { goldi.NewType(testAPI.NewMockTypeWithArgs, "foo", "bar") }).To(Panic())
Expect(func() { goldi.NewType(testAPI.NewMockTypeWithArgs, true, "bar") }).To(Panic())
Context("when the correct argument number and types are given", func() {
It("should create the type", func() {
typeDef = goldi.NewType(testAPI.NewMockTypeWithArgs, "foo", true)
Expect(typeDef).NotTo(BeNil())
})
})
})
})

Context("when the correct argument number and types are given", func() {
It("should create the type", func() {
typeDef = goldi.NewType(testAPI.NewMockTypeWithArgs, "foo", true)
Expect(typeDef).NotTo(BeNil())
})
Context("with struct factory", func() {
It("should create the type", func() {
typeDef = goldi.NewType(&testAPI.MockType{})
Expect(typeDef).NotTo(BeNil())
})
})
})
Expand All @@ -85,56 +100,136 @@ var _ = Describe("Type", func() {
typeRegistry = goldi.NewTypeRegistry()
})

Context("with factory functions without arguments", func() {
It("should generate the type", func() {
typeDef = goldi.NewType(testAPI.NewMockType)
Expect(typeDef.Generate(config, typeRegistry)).To(BeAssignableToTypeOf(&testAPI.MockType{}))
})
It("should panic if Generate is called on an uninitialized type", func() {
typeDef = &goldi.Type{}
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: this type is not initialized. Did you use NewType to create it?"))
}()

typeDef.Generate(config, typeRegistry)
})

Context("with factory functions with one or more arguments", func() {
It("should generate the type", func() {
typeDef = goldi.NewType(testAPI.NewMockTypeWithArgs, "foo", true)
Context("with a type factory", func() {
Context("without arguments", func() {
It("should generate the type", func() {
typeDef = goldi.NewType(&testAPI.MockType{})
Expect(typeDef.Generate(config, typeRegistry)).To(BeAssignableToTypeOf(&testAPI.MockType{}))
})

generatedType := typeDef.Generate(config, typeRegistry)
Expect(generatedType).To(BeAssignableToTypeOf(&testAPI.MockType{}))
It("should generate a new type each time", func() {
typeDef = goldi.NewType(&testAPI.MockType{})
t1 := typeDef.Generate(config, typeRegistry)
t2 := typeDef.Generate(config, typeRegistry)

Expect(t1).NotTo(BeNil())
Expect(t2).NotTo(BeNil())
Expect(t1 == t2).To(BeFalse(), fmt.Sprintf("t1 (%p) should not point to the same instance as t2 (%p)", t1, t2))

// Just to make the whole issue more explicit:
t1Mock := t1.(*testAPI.MockType)
t2Mock := t2.(*testAPI.MockType)
t1Mock.StringParameter = "CHANGED"
Expect(t2Mock.StringParameter).NotTo(Equal(t1Mock.StringParameter),
"Changing two indipendently generated types should not affect both at the same time",
)
})
})

generatedMock := generatedType.(*testAPI.MockType)
Expect(generatedMock.StringParameter).To(Equal("foo"))
Expect(generatedMock.BoolParameter).To(Equal(true))
Context("with one or more arguments", func() {
It("should generate the type", func() {
typeDef = goldi.NewType(&testAPI.MockType{}, "foo", true)

generatedType := typeDef.Generate(config, typeRegistry)
Expect(generatedType).To(BeAssignableToTypeOf(&testAPI.MockType{}))

generatedMock := generatedType.(*testAPI.MockType)
Expect(generatedMock.StringParameter).To(Equal("foo"))
Expect(generatedMock.BoolParameter).To(Equal(true))
})

It("should use the given parameters", func() {
typeDef = goldi.NewType(&testAPI.MockType{}, "%param1%", "%param2%")
config["param1"] = "TEST"
config["param2"] = true
generatedType := typeDef.Generate(config, typeRegistry)
Expect(generatedType).To(BeAssignableToTypeOf(&testAPI.MockType{}))

generatedMock := generatedType.(*testAPI.MockType)
Expect(generatedMock.StringParameter).To(Equal("TEST"))
Expect(generatedMock.BoolParameter).To(Equal(true))
})

It("should panic if more factory arguments where provided than the struct has fields", func() {
typeDef = goldi.NewType(&testAPI.MockType{}, "foo", true, "bar")
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 struct testAPI.MockType has only 2 fields but 3 arguments where provided on type registration"))
}()

typeDef.Generate(config, typeRegistry)
})
})
})

Context("when a type reference is given", func() {
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())
Context("with factory functions", func() {
Context("without arguments", func() {
It("should generate the type", func() {
typeDef = goldi.NewType(testAPI.NewMockType)
Expect(typeDef.Generate(config, typeRegistry)).To(BeAssignableToTypeOf(&testAPI.MockType{}))
})
})

typeDef = goldi.NewType(testAPI.NewTypeForServiceInjection, "@foo")
generatedType := typeDef.Generate(config, typeRegistry)
Expect(generatedType).To(BeAssignableToTypeOf(&testAPI.TypeForServiceInjection{}))
Context("with one or more arguments", func() {
It("should generate the type", func() {
typeDef = goldi.NewType(testAPI.NewMockTypeWithArgs, "foo", true)

generatedMock := generatedType.(*testAPI.TypeForServiceInjection)
Expect(generatedMock.InjectedType).To(BeAssignableToTypeOf(&testAPI.MockType{}))
})
generatedType := typeDef.Generate(config, typeRegistry)
Expect(generatedType).To(BeAssignableToTypeOf(&testAPI.MockType{}))

generatedMock := generatedType.(*testAPI.MockType)
Expect(generatedMock.StringParameter).To(Equal("foo"))
Expect(generatedMock.BoolParameter).To(Equal(true))
})

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())
Context("when a type reference is given", func() {
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.NewTypeForServiceInjectionWithArgs, "@foo", "arg1", "arg2", true)

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)"))
}()
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 testAPI.NewTypeForServiceInjectionWithArgs(*testAPI.MockType, string, string, bool)"))
}()

typeDef.Generate(config, typeRegistry)
typeDef.Generate(config, typeRegistry)
})
})
})
})
Expand Down

0 comments on commit bf2e86b

Please sign in to comment.