Merge pull request #20 from matryer/cleaner-locks

Cleaner locks
This commit is contained in:
Mat Ryer 2017-07-11 21:32:51 +01:00 committed by GitHub
commit d6bc24ab27
6 changed files with 242 additions and 88 deletions

View File

@ -97,7 +97,7 @@ The mocked structure implements the interface, where each method calls the assoc
* It will panic if a nil function gets called * It will panic if a nil function gets called
* Name arguments in the interface for a better experience * Name arguments in the interface for a better experience
* Use closured variables inside your test function to capture details about the calls to the methods * Use closured variables inside your test function to capture details about the calls to the methods
* Use `.CallsTo.Method` to track the calls * Use `.MethodCalls()` to track the calls
* Use `go:generate` to invoke the `moq` command * Use `go:generate` to invoke the `moq` command
## License ## License

134
example/mockpersonstore_test.go Executable file
View File

@ -0,0 +1,134 @@
package example
// AUTOGENERATED BY MOQ - DO NOT EDIT
// github.com/matryer/moq
import (
"sync"
"context"
)
var (
lockPersonStoreMockCreate sync.RWMutex
lockPersonStoreMockGet sync.RWMutex
)
// PersonStoreMock is a mock implementation of PersonStore.
//
// func TestSomethingThatUsesPersonStore(t *testing.T) {
//
// // make and configure a mocked PersonStore
// mockedPersonStore := &PersonStoreMock{
// CreateFunc: func(ctx context.Context, person *Person, confirm bool) error {
// panic("TODO: mock out the Create method")
// },
// GetFunc: func(ctx context.Context, id string) (*Person, error) {
// panic("TODO: mock out the Get method")
// },
// }
//
// // TODO: use mockedPersonStore in code that requires PersonStore
// // and then make assertions.
//
// }
type PersonStoreMock struct {
// CreateFunc mocks the Create method.
CreateFunc func(ctx context.Context, person *Person, confirm bool) error
// GetFunc mocks the Get method.
GetFunc func(ctx context.Context, id string) (*Person, error)
// calls tracks calls to the methods.
calls struct {
// Create holds details about calls to the Create method.
Create []struct {
// Ctx is the ctx argument value.
Ctx context.Context
// Person is the person argument value.
Person *Person
// Confirm is the confirm argument value.
Confirm bool
}
// Get holds details about calls to the Get method.
Get []struct {
// Ctx is the ctx argument value.
Ctx context.Context
// Id is the id argument value.
Id string
}
}
}
// Create calls CreateFunc.
func (mock *PersonStoreMock) Create(ctx context.Context, person *Person, confirm bool) error {
if mock.CreateFunc == nil {
panic("moq: PersonStoreMock.CreateFunc is nil but PersonStore.Create was just called")
}
callInfo := struct {
Ctx context.Context
Person *Person
Confirm bool
}{
Ctx: ctx,
Person: person,
Confirm: confirm,
}
lockPersonStoreMockCreate.Lock()
mock.calls.Create = append(mock.calls.Create, callInfo)
lockPersonStoreMockCreate.Unlock()
return mock.CreateFunc(ctx, person, confirm)
}
// CreateCalls gets all the calls that were made to Create.
// Check the length with:
// len(mockedPersonStore.CreateCalls())
func (mock *PersonStoreMock) CreateCalls() []struct {
Ctx context.Context
Person *Person
Confirm bool
} {
var calls []struct {
Ctx context.Context
Person *Person
Confirm bool
}
lockPersonStoreMockCreate.RLock()
calls = mock.calls.Create
lockPersonStoreMockCreate.RUnlock()
return calls
}
// Get calls GetFunc.
func (mock *PersonStoreMock) Get(ctx context.Context, id string) (*Person, error) {
if mock.GetFunc == nil {
panic("moq: PersonStoreMock.GetFunc is nil but PersonStore.Get was just called")
}
callInfo := struct {
Ctx context.Context
Id string
}{
Ctx: ctx,
Id: id,
}
lockPersonStoreMockGet.Lock()
mock.calls.Get = append(mock.calls.Get, callInfo)
lockPersonStoreMockGet.Unlock()
return mock.GetFunc(ctx, id)
}
// GetCalls gets all the calls that were made to Get.
// Check the length with:
// len(mockedPersonStore.GetCalls())
func (mock *PersonStoreMock) GetCalls() []struct {
Ctx context.Context
Id string
} {
var calls []struct {
Ctx context.Context
Id string
}
lockPersonStoreMockGet.RLock()
calls = mock.calls.Get
lockPersonStoreMockGet.RUnlock()
return calls
}

View File

@ -221,84 +221,3 @@ var templateFuncs = template.FuncMap{
return strings.ToUpper(s[0:1]) + s[1:] return strings.ToUpper(s[0:1]) + s[1:]
}, },
} }
// moqImports are the imports all moq files get.
var moqImports = []string{"sync"}
// moqTemplate is the template for mocked code.
var moqTemplate = `package {{.PackageName}}
// AUTOGENERATED BY MOQ
// github.com/matryer/moq
import (
{{- range .Imports }}
"{{.}}"
{{- end }}
)
{{ range $i, $obj := .Objects }}
// {{.InterfaceName}}Mock is a mock implementation of {{.InterfaceName}}.
//
// func TestSomethingThatUses{{.InterfaceName}}(t *testing.T) {
//
// // make and configure a mocked {{.InterfaceName}}
// mocked{{.InterfaceName}} := &{{.InterfaceName}}Mock{ {{ range .Methods }}
// {{.Name}}Func: func({{ .Arglist }}) {{.ReturnArglist}} {
// panic("TODO: mock out the {{.Name}} method")
// },{{- end }}
// }
//
// // TODO: use mocked{{.InterfaceName}} in code that requires {{.InterfaceName}}
// // and then make assertions.
// //
// // Use the CallsTo structure to access details about what calls were made:
// //
// // if len(mocked{{.InterfaceName}}.CallsTo.MethodFunc) != 1 {
// // t.Errorf("expected 1 call there were %d", len(mocked{{.InterfaceName}}.CallsTo.MethodFunc))
// // }
//
// }
type {{.InterfaceName}}Mock struct {
{{- range .Methods }}
// {{.Name}}Func mocks the {{.Name}} method.
{{.Name}}Func func({{ .Arglist }}) {{.ReturnArglist}}
{{ end }}
// CallsTo tracks calls to the methods.
CallsTo struct {
{{- range .Methods }}
lock{{.Name}} sync.Mutex // protects {{ .Name }}
// {{ .Name }} holds details about calls to the {{.Name}} method.
{{ .Name }} []struct {
{{- range .Params }}
// {{ .Name | Exported }} is the {{ .Name }} argument value.
{{ .Name | Exported }} {{ .Type }}
{{- end }}
}
{{- end }}
}
}
{{ range .Methods }}
// {{.Name}} calls {{.Name}}Func.
func (mock *{{$obj.InterfaceName}}Mock) {{.Name}}({{.Arglist}}) {{.ReturnArglist}} {
if mock.{{.Name}}Func == nil {
panic("moq: {{$obj.InterfaceName}}Mock.{{.Name}}Func is nil but was just called")
}
mock.CallsTo.lock{{.Name}}.Lock()
mock.CallsTo.{{.Name}} = append(mock.CallsTo.{{.Name}}, struct{
{{- range .Params }}
{{ .Name | Exported }} {{ .Type }}
{{- end }}
}{
{{- range .Params }}
{{ .Name | Exported }}: {{ .Name }},
{{- end }}
})
mock.CallsTo.lock{{.Name}}.Unlock()
{{- if .ReturnArglist }}
return mock.{{.Name}}Func({{.ArgCallList}})
{{- else }}
mock.{{.Name}}Func({{.ArgCallList}})
{{- end }}
}
{{ end -}}
{{ end -}}`

View File

@ -25,18 +25,17 @@ func TestMoq(t *testing.T) {
"GetFunc func(ctx context.Context, id string) (*Person, error)", "GetFunc func(ctx context.Context, id string) (*Person, error)",
"func (mock *PersonStoreMock) Create(ctx context.Context, person *Person, confirm bool) error", "func (mock *PersonStoreMock) Create(ctx context.Context, person *Person, confirm bool) error",
"func (mock *PersonStoreMock) Get(ctx context.Context, id string) (*Person, error)", "func (mock *PersonStoreMock) Get(ctx context.Context, id string) (*Person, error)",
"panic(\"moq: PersonStoreMock.CreateFunc is nil but was just called\")", "panic(\"moq: PersonStoreMock.CreateFunc is nil but PersonStore.Create was just called\")",
"panic(\"moq: PersonStoreMock.GetFunc is nil but was just called\")", "panic(\"moq: PersonStoreMock.GetFunc is nil but PersonStore.Get was just called\")",
"mock.CallsTo.lockGet.Lock()", "lockPersonStoreMockGet.Lock()",
"mock.CallsTo.Get = append(mock.CallsTo.Get, struct{", "mock.calls.Get = append(mock.calls.Get, callInfo)",
"mock.CallsTo.lockGet.Unlock()", "lockPersonStoreMockGet.Unlock()",
} }
for _, str := range strs { for _, str := range strs {
if !strings.Contains(s, str) { if !strings.Contains(s, str) {
t.Errorf("expected but missing: \"%s\"", str) t.Errorf("expected but missing: \"%s\"", str)
} }
} }
} }
func TestMoqExplicitPackage(t *testing.T) { func TestMoqExplicitPackage(t *testing.T) {

102
pkg/moq/template.go Normal file
View File

@ -0,0 +1,102 @@
package moq
// moqImports are the imports all moq files get.
var moqImports = []string{"sync"}
// moqTemplate is the template for mocked code.
var moqTemplate = `package {{.PackageName}}
// AUTOGENERATED BY MOQ - DO NOT EDIT
// github.com/matryer/moq
import (
{{- range .Imports }}
"{{.}}"
{{- end }}
)
{{ range $i, $obj := .Objects -}}
var (
{{- range .Methods }}
lock{{$obj.InterfaceName}}Mock{{.Name}} sync.RWMutex
{{- end }}
)
// {{.InterfaceName}}Mock is a mock implementation of {{.InterfaceName}}.
//
// func TestSomethingThatUses{{.InterfaceName}}(t *testing.T) {
//
// // make and configure a mocked {{.InterfaceName}}
// mocked{{.InterfaceName}} := &{{.InterfaceName}}Mock{ {{ range .Methods }}
// {{.Name}}Func: func({{ .Arglist }}) {{.ReturnArglist}} {
// panic("TODO: mock out the {{.Name}} method")
// },{{- end }}
// }
//
// // TODO: use mocked{{.InterfaceName}} in code that requires {{.InterfaceName}}
// // and then make assertions.
//
// }
type {{.InterfaceName}}Mock struct {
{{- range .Methods }}
// {{.Name}}Func mocks the {{.Name}} method.
{{.Name}}Func func({{ .Arglist }}) {{.ReturnArglist}}
{{ end }}
// calls tracks calls to the methods.
calls struct {
{{- range .Methods }}
// {{ .Name }} holds details about calls to the {{.Name}} method.
{{ .Name }} []struct {
{{- range .Params }}
// {{ .Name | Exported }} is the {{ .Name }} argument value.
{{ .Name | Exported }} {{ .Type }}
{{- end }}
}
{{- end }}
}
}
{{ range .Methods }}
// {{.Name}} calls {{.Name}}Func.
func (mock *{{$obj.InterfaceName}}Mock) {{.Name}}({{.Arglist}}) {{.ReturnArglist}} {
if mock.{{.Name}}Func == nil {
panic("moq: {{$obj.InterfaceName}}Mock.{{.Name}}Func is nil but {{$obj.InterfaceName}}.{{.Name}} was just called")
}
callInfo := struct {
{{- range .Params }}
{{ .Name | Exported }} {{ .Type }}
{{- end }}
}{
{{- range .Params }}
{{ .Name | Exported }}: {{ .Name }},
{{- end }}
}
lock{{$obj.InterfaceName}}Mock{{.Name}}.Lock()
mock.calls.{{.Name}} = append(mock.calls.{{.Name}}, callInfo)
lock{{$obj.InterfaceName}}Mock{{.Name}}.Unlock()
{{- if .ReturnArglist }}
return mock.{{.Name}}Func({{.ArgCallList}})
{{- else }}
mock.{{.Name}}Func({{.ArgCallList}})
{{- end }}
}
// {{.Name}}Calls gets all the calls that were made to {{.Name}}.
// Check the length with:
// len(mocked{{$obj.InterfaceName}}.{{.Name}}Calls())
func (mock *{{$obj.InterfaceName}}Mock) {{.Name}}Calls() []struct {
{{- range .Params }}
{{ .Name | Exported }} {{ .Type }}
{{- end }}
} {
var calls []struct {
{{- range .Params }}
{{ .Name | Exported }} {{ .Type }}
{{- end }}
}
lock{{$obj.InterfaceName}}Mock{{.Name}}.RLock()
calls = mock.calls.{{.Name}}
lock{{$obj.InterfaceName}}Mock{{.Name}}.RUnlock()
return calls
}
{{ end -}}
{{ end -}}`

Binary file not shown.

Before

Width:  |  Height:  |  Size: 694 KiB

After

Width:  |  Height:  |  Size: 726 KiB