early commit for moq command
This commit is contained in:
parent
757a93b481
commit
6a2af83edc
@ -1,2 +1,8 @@
|
|||||||
# moq
|
# moq
|
||||||
Interface mocking tool for go generate
|
Interface mocking tool for go generate
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
```
|
||||||
|
moq Interface1
|
||||||
|
```
|
||||||
|
15
example/example.go
Normal file
15
example/example.go
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
package example
|
||||||
|
|
||||||
|
import "context"
|
||||||
|
|
||||||
|
type Person struct {
|
||||||
|
ID string
|
||||||
|
Name string
|
||||||
|
Company string
|
||||||
|
Website string
|
||||||
|
}
|
||||||
|
|
||||||
|
type PersonStore interface {
|
||||||
|
Get(context.Context, string) (*Person, error)
|
||||||
|
Create(ctx context.Context, person *Person, confirm bool) error
|
||||||
|
}
|
11
main.go
Normal file
11
main.go
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/matryer/moq/package/moq"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
|
||||||
|
m := moq.New()
|
||||||
|
|
||||||
|
}
|
179
package/moq/moq.go
Normal file
179
package/moq/moq.go
Normal file
@ -0,0 +1,179 @@
|
|||||||
|
package moq
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"go/ast"
|
||||||
|
"go/importer"
|
||||||
|
"go/parser"
|
||||||
|
"go/token"
|
||||||
|
"go/types"
|
||||||
|
"html/template"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Mocker struct {
|
||||||
|
src string
|
||||||
|
tmpl *template.Template
|
||||||
|
fset *token.FileSet
|
||||||
|
pkgs map[string]*ast.Package
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(src string) (*Mocker, error) {
|
||||||
|
fset := token.NewFileSet()
|
||||||
|
noTestFiles := func(i os.FileInfo) bool {
|
||||||
|
return !strings.HasSuffix(i.Name(), "_test.go")
|
||||||
|
}
|
||||||
|
pkgs, err := parser.ParseDir(fset, src, noTestFiles, parser.SpuriousErrors)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
tmpl, err := template.New("moq").Parse(moqTemplate)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &Mocker{
|
||||||
|
src: src,
|
||||||
|
tmpl: tmpl,
|
||||||
|
fset: fset,
|
||||||
|
pkgs: pkgs,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mock generates a mock for the specified interface name.
|
||||||
|
func (m *Mocker) Mock(w io.Writer, name ...string) error {
|
||||||
|
var objs []*obj
|
||||||
|
for _, pkg := range m.pkgs {
|
||||||
|
i := 0
|
||||||
|
files := make([]*ast.File, len(pkg.Files))
|
||||||
|
for _, file := range pkg.Files {
|
||||||
|
files[i] = file
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
conf := types.Config{Importer: importer.Default()}
|
||||||
|
tpkg, err := conf.Check(m.src, m.fset, files, nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for _, n := range name {
|
||||||
|
iface := tpkg.Scope().Lookup(n)
|
||||||
|
if !types.IsInterface(iface.Type()) {
|
||||||
|
return fmt.Errorf("%s (%s) not an interface", n, iface.Type().String())
|
||||||
|
}
|
||||||
|
iiface := iface.Type().Underlying().(*types.Interface).Complete()
|
||||||
|
obj := &obj{
|
||||||
|
Name: n,
|
||||||
|
}
|
||||||
|
for i := 0; i < iiface.NumMethods(); i++ {
|
||||||
|
meth := iiface.Method(i)
|
||||||
|
sig := meth.Type().(*types.Signature)
|
||||||
|
method := &method{
|
||||||
|
Name: meth.Name(),
|
||||||
|
}
|
||||||
|
obj.Methods = append(obj.Methods, method)
|
||||||
|
method.Params = extractArgs(sig.Params(), "in%d")
|
||||||
|
method.Returns = extractArgs(sig.Results(), "out%d")
|
||||||
|
}
|
||||||
|
objs = append(objs, obj)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
err := m.tmpl.Execute(w, struct{ Objs []*obj }{Objs: objs})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func extractArgs(list *types.Tuple, nameFormat string) []*param {
|
||||||
|
var params []*param
|
||||||
|
for ii := 0; ii < list.Len(); ii++ {
|
||||||
|
p := list.At(ii)
|
||||||
|
name := p.Name()
|
||||||
|
if name == "" {
|
||||||
|
name = fmt.Sprintf(nameFormat, ii+1)
|
||||||
|
}
|
||||||
|
param := ¶m{
|
||||||
|
Name: name,
|
||||||
|
Type: p.Type().String(),
|
||||||
|
}
|
||||||
|
params = append(params, param)
|
||||||
|
}
|
||||||
|
return params
|
||||||
|
}
|
||||||
|
|
||||||
|
type obj struct {
|
||||||
|
Name string
|
||||||
|
Methods []*method
|
||||||
|
}
|
||||||
|
type method struct {
|
||||||
|
Name string
|
||||||
|
Params []*param
|
||||||
|
Returns []*param
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *method) Arglist() string {
|
||||||
|
params := make([]string, len(m.Params))
|
||||||
|
for i, p := range m.Params {
|
||||||
|
params[i] = p.String()
|
||||||
|
}
|
||||||
|
return strings.Join(params, ", ")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *method) ArgCallList() string {
|
||||||
|
params := make([]string, len(m.Params))
|
||||||
|
for i, p := range m.Params {
|
||||||
|
params[i] = p.Name
|
||||||
|
}
|
||||||
|
return strings.Join(params, ", ")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *method) ReturnArglist() string {
|
||||||
|
params := make([]string, len(m.Returns))
|
||||||
|
for i, p := range m.Returns {
|
||||||
|
params[i] = p.TypeString()
|
||||||
|
}
|
||||||
|
if len(m.Returns) > 1 {
|
||||||
|
return fmt.Sprintf("(%s)", strings.Join(params, ", "))
|
||||||
|
}
|
||||||
|
return strings.Join(params, ", ")
|
||||||
|
}
|
||||||
|
|
||||||
|
type param struct {
|
||||||
|
Name string
|
||||||
|
Type string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p param) String() string {
|
||||||
|
return fmt.Sprintf("%s %s", p.Name, p.TypeString())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p param) TypeString() string {
|
||||||
|
return p.Type
|
||||||
|
}
|
||||||
|
|
||||||
|
var moqTemplate = `
|
||||||
|
package todo
|
||||||
|
|
||||||
|
// AUTOGENERATED BY MOQ
|
||||||
|
// github.com/matryer/moq
|
||||||
|
{{ range .Objs }}
|
||||||
|
// {{.Name}}Mock is a mock implementation of {{.Name}}.
|
||||||
|
type {{.Name}}Mock struct {
|
||||||
|
{{ range .Methods }}
|
||||||
|
// {{.Name}}Func mocks the {{.Name}} function.
|
||||||
|
{{.Name}}Func func({{ .Arglist }}) {{.ReturnArglist}}
|
||||||
|
{{ end }}}
|
||||||
|
{{ range .Methods }}
|
||||||
|
// {{.Name}} calls the mocked {{.Name}}Func function.
|
||||||
|
func (mock *{{.Name}}Mock) {{.Name}}({{ .Arglist }}) {{.ReturnArglist}} {
|
||||||
|
if mock.{{.Name}} == nil {
|
||||||
|
panic("moq: {{.Name}}Func is nil")
|
||||||
|
}
|
||||||
|
return mock.{{.Name}}Func({{ .ArgCallList }})
|
||||||
|
}
|
||||||
|
{{ end }}
|
||||||
|
{{ end }}
|
||||||
|
`
|
24
package/moq/moq_test.go
Normal file
24
package/moq/moq_test.go
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
package moq_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"log"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/matryer/moq/package/moq"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestMoq(t *testing.T) {
|
||||||
|
|
||||||
|
m, err := moq.New("../../example")
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("moq.New: %s", err)
|
||||||
|
}
|
||||||
|
var buf bytes.Buffer
|
||||||
|
err = m.Mock(&buf, "PersonStore")
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("m.Mock: %s", err)
|
||||||
|
}
|
||||||
|
log.Println(buf.String())
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user