Move external dependency mockimpl to monorepo (#15863)
#15560 Probably best to review commit by commit. First commit adds the mockimpl files, second commit amends README.md and third commit fixes golangci-lint issues. - [X] Manual QA for all new/changed functionality Tested by adding a dummy method to service.go and running `make generate-mock`. --------- Co-authored-by: Victor Lyuboslavsky <victor.lyuboslavsky@gmail.com>
This commit is contained in:
co-authored by
Victor Lyuboslavsky
parent
4627a92447
commit
eeb9931f40
@@ -173,7 +173,6 @@ generate-dev: .prefix
|
||||
NODE_ENV=development yarn run webpack --progress --watch
|
||||
|
||||
generate-mock: .prefix
|
||||
go install github.com/fleetdm/mockimpl@ecbb3041eabfc9e046a3f2e414e32c28254b75b2
|
||||
go generate github.com/fleetdm/fleet/v4/server/mock github.com/fleetdm/fleet/v4/server/mock/mockresult github.com/fleetdm/fleet/v4/server/service/mock
|
||||
|
||||
generate-doc: .prefix
|
||||
|
||||
@@ -6,11 +6,11 @@ import (
|
||||
"github.com/fleetdm/fleet/v4/server/fleet"
|
||||
)
|
||||
|
||||
//go:generate mockimpl -o datastore_mock.go "s *DataStore" "fleet.Datastore"
|
||||
//go:generate mockimpl -o datastore_installers.go "s *InstallerStore" "fleet.InstallerStore"
|
||||
//go:generate mockimpl -o nanomdm/storage.go "s *Storage" "github.com/micromdm/nanomdm/storage.AllStorage"
|
||||
//go:generate mockimpl -o nanodep/storage.go "s *Storage" "github.com/micromdm/nanodep/storage.AllStorage"
|
||||
//go:generate mockimpl -o scep/depot.go "d *Depot" "depot.Depot"
|
||||
//go:generate go run ./mockimpl/impl.go -o datastore_mock.go "s *DataStore" "fleet.Datastore"
|
||||
//go:generate go run ./mockimpl/impl.go -o datastore_installers.go "s *InstallerStore" "fleet.InstallerStore"
|
||||
//go:generate go run ./mockimpl/impl.go -o nanomdm/storage.go "s *Storage" "github.com/micromdm/nanomdm/storage.AllStorage"
|
||||
//go:generate go run ./mockimpl/impl.go -o nanodep/storage.go "s *Storage" "github.com/micromdm/nanodep/storage.AllStorage"
|
||||
//go:generate go run ./mockimpl/impl.go -o scep/depot.go "d *Depot" "depot.Depot"
|
||||
|
||||
var _ fleet.Datastore = (*Store)(nil)
|
||||
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014 Josh Bleecher Snyder
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
@@ -0,0 +1,66 @@
|
||||
# mockimpl
|
||||
|
||||
> The contents of this directory were copied (on December 2023) from https://github.com/fleetdm/mockimpl which was forked from https://github.com/groob/mockimpl.
|
||||
|
||||
`mockimpl` generates mock method stubs for implementing an interface.
|
||||
mockimpl is based on [impl](https://github.com/josharian/impl)
|
||||
|
||||
|
||||
```bash
|
||||
go get -u github.com/groob/mockimpl
|
||||
```
|
||||
|
||||
Sample usage:
|
||||
|
||||
```bash
|
||||
$ impl 'f *File' io.ReadWriteCloser
|
||||
// Automatically generated by mockimpl. DO NOT EDIT!
|
||||
|
||||
package mock
|
||||
|
||||
import "io"
|
||||
|
||||
var _ io.ReadWriteCloser = (*File)(nil)
|
||||
|
||||
type ReadFunc func(p []byte) (n int, err error)
|
||||
|
||||
type WriteFunc func(p []byte) (n int, err error)
|
||||
|
||||
type CloseFunc func() error
|
||||
|
||||
type File struct {
|
||||
ReadFunc ReadFunc
|
||||
ReadFuncInvoked bool
|
||||
|
||||
WriteFunc WriteFunc
|
||||
WriteFuncInvoked bool
|
||||
|
||||
CloseFunc CloseFunc
|
||||
CloseFuncInvoked bool
|
||||
}
|
||||
|
||||
func (f *File) Read(p []byte) (n int, err error) {
|
||||
f.ReadFuncInvoked = true
|
||||
return f.ReadFunc(p)
|
||||
}
|
||||
|
||||
func (f *File) Write(p []byte) (n int, err error) {
|
||||
f.WriteFuncInvoked = true
|
||||
return f.WriteFunc(p)
|
||||
}
|
||||
|
||||
func (f *File) Close() error {
|
||||
f.CloseFuncInvoked = true
|
||||
return f.CloseFunc()
|
||||
}
|
||||
|
||||
# You can also provide a full name by specifying the package path.
|
||||
# This helps in cases where the interface can't be guessed
|
||||
# just from the package name and interface name.
|
||||
$ impl 's *Source' golang.org/x/oauth2.TokenSource
|
||||
func (s *Source) Token() (*oauth2.Token, error) {
|
||||
panic("not implemented")
|
||||
}
|
||||
```
|
||||
|
||||
You can use `impl` from Vim with [vim-go-impl](https://github.com/rhysd/vim-go-impl)
|
||||
@@ -0,0 +1,424 @@
|
||||
// impl generates method stubs for implementing an interface.
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"flag"
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/build"
|
||||
"go/format"
|
||||
"go/parser"
|
||||
"go/printer"
|
||||
"go/token"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"text/template"
|
||||
|
||||
"golang.org/x/tools/imports"
|
||||
)
|
||||
|
||||
const usage = `impl [o output.go] <recv> <iface>
|
||||
|
||||
impl generates method stubs for recv to implement iface.
|
||||
|
||||
Examples:
|
||||
|
||||
impl 'f *File' io.Reader
|
||||
impl Murmur hash.Hash
|
||||
|
||||
Don't forget the single quotes around the receiver type
|
||||
to prevent shell globbing.
|
||||
`
|
||||
|
||||
// findInterface returns the import path and identifier of an interface.
|
||||
// For example, given "http.ResponseWriter", findInterface returns
|
||||
// "net/http", "ResponseWriter".
|
||||
// If a fully qualified interface is given, such as "net/http.ResponseWriter",
|
||||
// it simply parses the input.
|
||||
func findInterface(iface string) (path string, id string, err error) {
|
||||
if len(strings.Fields(iface)) != 1 {
|
||||
return "", "", fmt.Errorf("couldn't parse interface: %s", iface)
|
||||
}
|
||||
|
||||
if slash := strings.LastIndex(iface, "/"); slash > -1 {
|
||||
// package path provided
|
||||
dot := strings.LastIndex(iface, ".")
|
||||
// make sure iface does not end with "/" (e.g. reject net/http/)
|
||||
if slash+1 == len(iface) {
|
||||
return "", "", fmt.Errorf("interface name cannot end with a '/' character: %s", iface)
|
||||
}
|
||||
// make sure iface does not end with "." (e.g. reject net/http.)
|
||||
if dot+1 == len(iface) {
|
||||
return "", "", fmt.Errorf("interface name cannot end with a '.' character: %s", iface)
|
||||
}
|
||||
// make sure iface has exactly one "." after "/" (e.g. reject net/http/httputil)
|
||||
if strings.Count(iface[slash:], ".") != 1 {
|
||||
return "", "", fmt.Errorf("invalid interface name: %s", iface)
|
||||
}
|
||||
return iface[:dot], iface[dot+1:], nil
|
||||
}
|
||||
|
||||
src := []byte("package hack\n" + "var i " + iface)
|
||||
// If we couldn't determine the import path, goimports will
|
||||
// auto fix the import path.
|
||||
imp, err := imports.Process(".", src, nil)
|
||||
if err != nil {
|
||||
return "", "", fmt.Errorf("couldn't parse interface: %s", iface)
|
||||
}
|
||||
|
||||
// imp should now contain an appropriate import.
|
||||
// Parse out the import and the identifier.
|
||||
fset := token.NewFileSet()
|
||||
f, err := parser.ParseFile(fset, "", imp, 0)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if len(f.Imports) == 0 {
|
||||
return "", "", fmt.Errorf("unrecognized interface: %s", iface)
|
||||
}
|
||||
raw := f.Imports[0].Path.Value // "io"
|
||||
path, err = strconv.Unquote(raw) // io
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
decl := f.Decls[1].(*ast.GenDecl) // var i io.Reader
|
||||
spec := decl.Specs[0].(*ast.ValueSpec) // i io.Reader
|
||||
sel := spec.Type.(*ast.SelectorExpr) // io.Reader
|
||||
id = sel.Sel.Name // Reader
|
||||
return path, id, nil
|
||||
}
|
||||
|
||||
// Pkg is a parsed build.Package.
|
||||
type Pkg struct {
|
||||
*build.Package
|
||||
*token.FileSet
|
||||
}
|
||||
|
||||
// typeSpec locates the *ast.TypeSpec for type id in the import path.
|
||||
func typeSpec(path string, id string) (Pkg, *ast.TypeSpec, error) {
|
||||
pkg, err := build.Import(path, "", 0)
|
||||
if err != nil {
|
||||
return Pkg{}, nil, fmt.Errorf("couldn't find package %s: %v", path, err)
|
||||
}
|
||||
|
||||
fset := token.NewFileSet() // share one fset across the whole package
|
||||
for _, file := range pkg.GoFiles {
|
||||
f, err := parser.ParseFile(fset, filepath.Join(pkg.Dir, file), nil, 0)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
for _, decl := range f.Decls {
|
||||
decl, ok := decl.(*ast.GenDecl)
|
||||
if !ok || decl.Tok != token.TYPE {
|
||||
continue
|
||||
}
|
||||
for _, spec := range decl.Specs {
|
||||
spec := spec.(*ast.TypeSpec)
|
||||
if spec.Name.Name != id {
|
||||
continue
|
||||
}
|
||||
return Pkg{Package: pkg, FileSet: fset}, spec, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
return Pkg{}, nil, fmt.Errorf("type %s not found in %s", id, path)
|
||||
}
|
||||
|
||||
// gofmt pretty-prints e.
|
||||
func (p Pkg) gofmt(e ast.Expr) string {
|
||||
var buf bytes.Buffer
|
||||
printer.Fprint(&buf, p.FileSet, e)
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
// fullType returns the fully qualified type of e.
|
||||
// Examples, assuming package net/http:
|
||||
//
|
||||
// fullType(int) => "int"
|
||||
// fullType(Handler) => "http.Handler"
|
||||
// fullType(io.Reader) => "io.Reader"
|
||||
// fullType(*Request) => "*http.Request"
|
||||
func (p Pkg) fullType(e ast.Expr) string {
|
||||
ast.Inspect(e, func(n ast.Node) bool {
|
||||
switch n := n.(type) {
|
||||
case *ast.Ident:
|
||||
// Using typeSpec instead of IsExported here would be
|
||||
// more accurate, but it'd be crazy expensive, and if
|
||||
// the type isn't exported, there's no point trying
|
||||
// to implement it anyway.
|
||||
if n.IsExported() {
|
||||
n.Name = p.Package.Name + "." + n.Name
|
||||
}
|
||||
case *ast.SelectorExpr:
|
||||
return false
|
||||
}
|
||||
return true
|
||||
})
|
||||
return p.gofmt(e)
|
||||
}
|
||||
|
||||
func (p Pkg) params(field *ast.Field, defaultName string) []Param {
|
||||
var params []Param
|
||||
typ := p.fullType(field.Type)
|
||||
for _, name := range field.Names {
|
||||
params = append(params, Param{Name: name.Name, Type: typ})
|
||||
}
|
||||
// Handle anonymous params
|
||||
if len(params) == 0 {
|
||||
params = []Param{{Type: typ, Name: defaultName}}
|
||||
}
|
||||
return params
|
||||
}
|
||||
|
||||
// Method represents a method signature.
|
||||
type Method struct {
|
||||
RecvShort string
|
||||
Recv string
|
||||
Func
|
||||
}
|
||||
|
||||
type Struc struct {
|
||||
IName string
|
||||
Func
|
||||
}
|
||||
|
||||
// Func represents a function signature.
|
||||
type Func struct {
|
||||
Name string
|
||||
Params []Param
|
||||
Res []Param
|
||||
}
|
||||
|
||||
// Param represents a parameter in a function or method signature.
|
||||
type Param struct {
|
||||
Name string
|
||||
Type string
|
||||
}
|
||||
|
||||
// CalledArgument will correctly generate call to a function with a
|
||||
// variadic parameter
|
||||
func (p *Param) CalledArgument() string {
|
||||
variadic, _ := regexp.MatchString("^[.]{3}", p.Type)
|
||||
if variadic {
|
||||
return p.Name + "..."
|
||||
}
|
||||
return p.Name
|
||||
}
|
||||
|
||||
func (p Pkg) funcsig(f *ast.Field) Func {
|
||||
fn := Func{Name: f.Names[0].Name}
|
||||
typ := f.Type.(*ast.FuncType)
|
||||
if typ.Params != nil {
|
||||
for pos, field := range typ.Params.List {
|
||||
defaultName := fmt.Sprintf("p%d", pos)
|
||||
fn.Params = append(fn.Params, p.params(field, defaultName)...)
|
||||
}
|
||||
}
|
||||
if typ.Results != nil {
|
||||
for _, field := range typ.Results.List {
|
||||
fn.Res = append(fn.Res, p.params(field, "")...)
|
||||
}
|
||||
}
|
||||
return fn
|
||||
}
|
||||
|
||||
// funcs returns the set of methods required to implement iface.
|
||||
// It is called funcs rather than methods because the
|
||||
// function descriptions are functions; there is no receiver.
|
||||
func funcs(iface string) ([]Func, error) {
|
||||
// Locate the interface.
|
||||
path, id, err := findInterface(iface)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Parse the package and find the interface declaration.
|
||||
p, spec, err := typeSpec(path, id)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("interface %s not found: %s", iface, err)
|
||||
}
|
||||
idecl, ok := spec.Type.(*ast.InterfaceType)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("not an interface: %s", iface)
|
||||
}
|
||||
|
||||
if idecl.Methods == nil {
|
||||
return nil, fmt.Errorf("empty interface: %s", iface)
|
||||
}
|
||||
|
||||
var fns []Func
|
||||
for _, fndecl := range idecl.Methods.List {
|
||||
if len(fndecl.Names) == 0 {
|
||||
// Embedded interface: recurse
|
||||
embedded, err := funcs(p.fullType(fndecl.Type))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
fns = append(fns, embedded...)
|
||||
continue
|
||||
}
|
||||
|
||||
fn := p.funcsig(fndecl)
|
||||
fns = append(fns, fn)
|
||||
}
|
||||
return fns, nil
|
||||
}
|
||||
|
||||
const stub = "func ({{.Recv}}) {{.Name}}" +
|
||||
"({{range .Params}}{{.Name}} {{.Type}}, {{end}})" +
|
||||
"({{range .Res}}{{.Name}} {{.Type}}, {{end}})" +
|
||||
"{\n" + "{{.RecvShort}}.mu.Lock()" + "\n" +
|
||||
"{{.RecvShort}}.{{.Name}}FuncInvoked = true" + "\n" +
|
||||
"{{.RecvShort}}.mu.Unlock()" + "\n" +
|
||||
"return {{.RecvShort}}.{{.Name}}Func({{range .Params}}{{.CalledArgument}}, {{end}})" +
|
||||
"\n" + "}\n\n"
|
||||
|
||||
var tmpl = template.Must(template.New("test").Parse(stub))
|
||||
|
||||
// genStubs prints nicely formatted method stubs
|
||||
// for fns using receiver expression recv.
|
||||
// If recv is not a valid receiver expression,
|
||||
// genStubs will panic.
|
||||
func genStubs(recv string, fns []Func) []byte {
|
||||
var buf bytes.Buffer
|
||||
for _, fn := range fns {
|
||||
meth := Method{Recv: recv, RecvShort: shortRecv(recv), Func: fn}
|
||||
tmpl.Execute(&buf, meth) //nolint:errcheck
|
||||
}
|
||||
|
||||
pretty, err := format.Source(buf.Bytes())
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return pretty
|
||||
}
|
||||
|
||||
func shortRecv(recv string) string {
|
||||
s := strings.SplitN(recv, "*", 2)[0]
|
||||
return s
|
||||
}
|
||||
|
||||
const packageStr = "// Automatically generated by mockimpl. DO NOT EDIT!" +
|
||||
"\n\n" + "package mock" + "\n\n"
|
||||
|
||||
const str = "{{.Name}}Func {{.Name}}Func" +
|
||||
"\n" + "{{.Name}}FuncInvoked bool" +
|
||||
"\n\n"
|
||||
|
||||
const funcTypeStr = "type {{.Name}}Func func" +
|
||||
"({{range .Params}}{{.Name}} {{.Type}}, {{end}})" +
|
||||
"({{range .Res}}{{.Name}} {{.Type}}, {{end}})" +
|
||||
"\n\n"
|
||||
|
||||
var (
|
||||
tmplStr = template.Must(template.New("testtwo").Parse(str))
|
||||
funcTypetmplStr = template.Must(template.New("funcTypetmpl").Parse(funcTypeStr))
|
||||
)
|
||||
|
||||
func genStr(name string, fns []Func) []byte {
|
||||
var buf bytes.Buffer
|
||||
for _, fn := range fns {
|
||||
meth := Struc{IName: name, Func: fn}
|
||||
funcTypetmplStr.Execute(&buf, meth) //nolint:errcheck
|
||||
}
|
||||
buf.WriteString("type ")
|
||||
buf.WriteString(name)
|
||||
buf.WriteString(" struct {\n")
|
||||
for _, fn := range fns {
|
||||
meth := Struc{IName: name, Func: fn}
|
||||
tmplStr.Execute(&buf, meth) //nolint:errcheck
|
||||
}
|
||||
buf.WriteString("\n")
|
||||
buf.WriteString("mu sync.Mutex")
|
||||
buf.WriteString("\n")
|
||||
buf.WriteString("}")
|
||||
|
||||
pretty, err := format.Source(buf.Bytes())
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return pretty
|
||||
// return buf.Bytes()
|
||||
}
|
||||
|
||||
// validReceiver reports whether recv is a valid receiver expression.
|
||||
func validReceiver(recv string) bool {
|
||||
if recv == "" {
|
||||
// The parse will parse empty receivers, but we don't want to accept them,
|
||||
// since it won't generate a usable code snippet.
|
||||
return false
|
||||
}
|
||||
fset := token.NewFileSet()
|
||||
_, err := parser.ParseFile(fset, "", "package hack\nfunc ("+recv+") Foo()", 0)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
flOut := flag.String("o", "", "output file")
|
||||
flag.Parse()
|
||||
args := flag.Args()
|
||||
if len(args) != 2 {
|
||||
fmt.Fprint(os.Stderr, usage)
|
||||
os.Exit(2)
|
||||
}
|
||||
recv, iface := args[0], args[1]
|
||||
if !validReceiver(recv) {
|
||||
fatal(fmt.Sprintf("invalid receiver: %q", recv))
|
||||
}
|
||||
|
||||
fns, err := funcs(iface)
|
||||
if err != nil {
|
||||
fatal(err)
|
||||
}
|
||||
|
||||
src := genStubs(recv, fns)
|
||||
recName := strings.SplitN(recv, " ", 2)
|
||||
name := strings.TrimPrefix(recName[1], "*")
|
||||
src2 := genStr(name, fns)
|
||||
|
||||
path, ifaceID, err := findInterface(iface)
|
||||
if err != nil {
|
||||
fatal(err)
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
fmt.Fprint(&buf, packageStr)
|
||||
fmt.Fprintf(&buf, "import \"%s\"\n\n", path)
|
||||
fmt.Fprintf(&buf, "var _ %s.%s = (*%s)(nil)\n\n", filepath.Base(path), ifaceID, name)
|
||||
fmt.Fprint(&buf, string(src2))
|
||||
buf.WriteString("\n")
|
||||
fmt.Fprint(&buf, string(src))
|
||||
pretty, err := format.Source(buf.Bytes())
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
imp, err := imports.Process("", pretty, nil)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
switch *flOut {
|
||||
case "":
|
||||
fmt.Println(string(imp))
|
||||
default:
|
||||
f, err := os.Create(*flOut)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer f.Close()
|
||||
_, err = f.Write(imp)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func fatal(msg interface{}) {
|
||||
fmt.Fprintln(os.Stderr, msg)
|
||||
os.Exit(1)
|
||||
}
|
||||
@@ -0,0 +1,218 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type errBool bool
|
||||
|
||||
func (b errBool) String() string {
|
||||
if b {
|
||||
return "an error"
|
||||
}
|
||||
return "no error"
|
||||
}
|
||||
|
||||
func TestFindInterface(t *testing.T) {
|
||||
cases := []struct {
|
||||
iface string
|
||||
path string
|
||||
id string
|
||||
wantErr bool
|
||||
}{
|
||||
{iface: "net.Conn", path: "net", id: "Conn"},
|
||||
{iface: "http.ResponseWriter", path: "net/http", id: "ResponseWriter"},
|
||||
{iface: "net.Tennis", wantErr: true},
|
||||
{iface: "a + b", wantErr: true},
|
||||
{iface: "a/b/c/", wantErr: true},
|
||||
{iface: "a/b/c/pkg", wantErr: true},
|
||||
{iface: "a/b/c/pkg.", wantErr: true},
|
||||
{iface: "a/b/c/pkg.Typ", path: "a/b/c/pkg", id: "Typ"},
|
||||
{iface: "a/b/c/pkg.Typ.Foo", wantErr: true},
|
||||
}
|
||||
|
||||
for _, tt := range cases {
|
||||
path, id, err := findInterface(tt.iface)
|
||||
gotErr := err != nil
|
||||
if tt.wantErr != gotErr {
|
||||
t.Errorf("findInterface(%q).err=%v want %s", tt.iface, err, errBool(tt.wantErr))
|
||||
continue
|
||||
}
|
||||
if tt.path != path {
|
||||
t.Errorf("findInterface(%q).path=%q want %q", tt.iface, path, tt.path)
|
||||
}
|
||||
if tt.id != id {
|
||||
t.Errorf("findInterface(%q).id=%q want %q", tt.iface, id, tt.id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestTypeSpec(t *testing.T) {
|
||||
// For now, just test whether we can find the interface.
|
||||
cases := []struct {
|
||||
path string
|
||||
id string
|
||||
wantErr bool
|
||||
}{
|
||||
{path: "net", id: "Conn"},
|
||||
{path: "net", id: "Con", wantErr: true},
|
||||
}
|
||||
|
||||
for _, tt := range cases {
|
||||
p, spec, err := typeSpec(tt.path, tt.id)
|
||||
gotErr := err != nil
|
||||
if tt.wantErr != gotErr {
|
||||
t.Errorf("typeSpec(%q, %q).err=%v want %s", tt.path, tt.id, err, errBool(tt.wantErr))
|
||||
continue
|
||||
}
|
||||
if err == nil {
|
||||
if reflect.DeepEqual(p, Pkg{}) {
|
||||
t.Errorf("typeSpec(%q, %q).pkg=Pkg{} want non-nil", tt.path, tt.id)
|
||||
}
|
||||
if spec == nil {
|
||||
t.Errorf("typeSpec(%q, %q).spec=nil want non-nil", tt.path, tt.id)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestFuncs(t *testing.T) {
|
||||
cases := []struct {
|
||||
iface string
|
||||
want []Func
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
iface: "io.ReadWriter",
|
||||
want: []Func{
|
||||
{
|
||||
Name: "Read",
|
||||
Params: []Param{{Name: "p", Type: "[]byte"}},
|
||||
Res: []Param{
|
||||
{Name: "n", Type: "int"},
|
||||
{Name: "err", Type: "error"},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Write",
|
||||
Params: []Param{{Name: "p", Type: "[]byte"}},
|
||||
Res: []Param{
|
||||
{Name: "n", Type: "int"},
|
||||
{Name: "err", Type: "error"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
iface: "http.ResponseWriter",
|
||||
want: []Func{
|
||||
{
|
||||
Name: "Header",
|
||||
Res: []Param{{Type: "http.Header"}},
|
||||
},
|
||||
{
|
||||
Name: "Write",
|
||||
Params: []Param{{Type: "[]byte", Name: "p0"}},
|
||||
Res: []Param{{Type: "int"}, {Type: "error"}},
|
||||
},
|
||||
{
|
||||
Name: "WriteHeader",
|
||||
Params: []Param{{Type: "int", Name: "statusCode"}},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
iface: "http.Handler",
|
||||
want: []Func{
|
||||
{
|
||||
Name: "ServeHTTP",
|
||||
Params: []Param{
|
||||
{Name: "p0", Type: "http.ResponseWriter"},
|
||||
{Name: "p1", Type: "*http.Request"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
iface: "ast.Node",
|
||||
want: []Func{
|
||||
{
|
||||
Name: "Pos",
|
||||
Res: []Param{{Type: "token.Pos"}},
|
||||
},
|
||||
{
|
||||
Name: "End",
|
||||
Res: []Param{{Type: "token.Pos"}},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
iface: "cipher.AEAD",
|
||||
want: []Func{
|
||||
{
|
||||
Name: "NonceSize",
|
||||
Res: []Param{{Type: "int"}},
|
||||
},
|
||||
{
|
||||
Name: "Overhead",
|
||||
Res: []Param{{Type: "int"}},
|
||||
},
|
||||
{
|
||||
Name: "Seal",
|
||||
Params: []Param{
|
||||
{Name: "dst", Type: "[]byte"},
|
||||
{Name: "nonce", Type: "[]byte"},
|
||||
{Name: "plaintext", Type: "[]byte"},
|
||||
{Name: "additionalData", Type: "[]byte"},
|
||||
},
|
||||
Res: []Param{{Type: "[]byte"}},
|
||||
},
|
||||
{
|
||||
Name: "Open",
|
||||
Params: []Param{
|
||||
{Name: "dst", Type: "[]byte"},
|
||||
{Name: "nonce", Type: "[]byte"},
|
||||
{Name: "ciphertext", Type: "[]byte"},
|
||||
{Name: "additionalData", Type: "[]byte"},
|
||||
},
|
||||
Res: []Param{{Type: "[]byte"}, {Type: "error"}},
|
||||
},
|
||||
},
|
||||
},
|
||||
{iface: "net.Tennis", wantErr: true},
|
||||
}
|
||||
|
||||
for _, tt := range cases {
|
||||
fns, err := funcs(tt.iface)
|
||||
gotErr := err != nil
|
||||
if tt.wantErr != gotErr {
|
||||
t.Errorf("funcs(%q).err=%v want %s", tt.iface, err, errBool(tt.wantErr))
|
||||
continue
|
||||
}
|
||||
if !reflect.DeepEqual(fns, tt.want) {
|
||||
t.Errorf("funcs(%q).fns=\n%v\nwant\n%v\n", tt.iface, fns, tt.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidReceiver(t *testing.T) {
|
||||
cases := []struct {
|
||||
recv string
|
||||
want bool
|
||||
}{
|
||||
{recv: "f", want: true},
|
||||
{recv: "F", want: true},
|
||||
{recv: "f F", want: true},
|
||||
{recv: "f *F", want: true},
|
||||
{recv: "", want: false},
|
||||
{recv: "a+b", want: false},
|
||||
}
|
||||
|
||||
for _, tt := range cases {
|
||||
got := validReceiver(tt.recv)
|
||||
if got != tt.want {
|
||||
t.Errorf("validReceiver(%q)=%t want %t", tt.recv, got, tt.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,3 @@
|
||||
package mock
|
||||
|
||||
//go:generate mockimpl -o datastore_query_results.go "s *QueryResultStore" "fleet.QueryResultStore"
|
||||
//go:generate go run ../mockimpl/impl.go -o datastore_query_results.go "s *QueryResultStore" "fleet.QueryResultStore"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
package mock
|
||||
|
||||
//go:generate mockimpl -o service_osquery.go "s *TLSService" "fleet.OsqueryService"
|
||||
//go:generate mockimpl -o service_pusher_factory.go "s *APNSPushProviderFactory" "github.com/micromdm/nanomdm/push.PushProviderFactory"
|
||||
//go:generate mockimpl -o service_push_provider.go "s *APNSPushProvider" "github.com/micromdm/nanomdm/push.PushProvider"
|
||||
//go:generate go run ../../mock/mockimpl/impl.go -o service_osquery.go "s *TLSService" "fleet.OsqueryService"
|
||||
//go:generate go run ../../mock/mockimpl/impl.go -o service_pusher_factory.go "s *APNSPushProviderFactory" "github.com/micromdm/nanomdm/push.PushProviderFactory"
|
||||
//go:generate go run ../../mock/mockimpl/impl.go -o service_push_provider.go "s *APNSPushProvider" "github.com/micromdm/nanomdm/push.PushProvider"
|
||||
|
||||
Reference in New Issue
Block a user