Merge branch 'main' into master

This commit is contained in:
Alexander Gehres 2023-02-23 00:20:56 +01:00 коммит произвёл GitHub
Родитель ba2e7f402a 5b455625bd
Коммит 42492e18bc
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
57 изменённых файлов: 2011 добавлений и 766 удалений

29
.github/workflows/test.yaml поставляемый
Просмотреть файл

@ -1,16 +1,16 @@
name: Run tests
on:
push:
branches: [master]
branches: [main]
pull_request:
branches: [master]
branches: [main]
env:
GO111MODULE: on
jobs:
test:
strategy:
matrix:
go-version: [1.11.x, 1.16.x]
go-version: [1.15.x, 1.18.x]
os: [ubuntu-latest]
runs-on: ${{ matrix.os }}
steps:
@ -23,33 +23,30 @@ jobs:
- name: Checkout code
uses: actions/checkout@v2
# Needed for versions <1.14 tests
- name: Install mock
run: |
GO111MODULE=off go get github.com/golang/mock | true
- name: Vet and build
run: |
go vet ./...
go build ./...
- name: Install tools
- name: Install mockgen
run: |
go install github.com/golang/mock/mockgen
GO111MODULE=off go get -u golang.org/x/lint/golint
- name: Run test scripts
- name: Run test script
run: |
./ci/check_go_fmt.sh
./ci/check_go_lint.sh
./ci/check_go_generate.sh
./ci/check_go_mod.sh
./ci/test.sh
./ci/check_panic_handling.sh
- name: Run Go tests
- name: Run Go tests all
if: ${{ startsWith(matrix.go-version, '1.18') }}
run: |
for i in $(find $PWD -name go.mod); do
pushd $(dirname $i)
go test ./...
popd
done
- name: Run Go tests some
if: ${{ startsWith(matrix.go-version, '1.18') == false }}
run: |
go test ./...

3
.gitignore поставляемый
Просмотреть файл

@ -17,3 +17,6 @@ mockgen/mockgen
# Editors
.vscode
.idea
# vendor directory used for IDEs
/vendor

Просмотреть файл

@ -15,6 +15,7 @@ builds:
- linux
goarch:
- amd64
- arm64
- 386
env:
- CGO_ENABLED=0

Просмотреть файл

@ -18,28 +18,18 @@ To get the latest released version use:
### Go version < 1.16
```bash
GO111MODULE=on go get github.com/golang/mock/mockgen@v1.5.0
GO111MODULE=on go get github.com/golang/mock/mockgen@v1.6.0
```
### Go 1.16+
```bash
go install github.com/golang/mock/mockgen@v1.5.0
go install github.com/golang/mock/mockgen@v1.6.0
```
If you use `mockgen` in your CI pipeline, it may be more appropriate to fixate
on a specific mockgen version.
## Documentation
After installing, you can use `go doc` to get documentation:
```bash
go doc github.com/golang/mock/gomock
```
Alternatively, there is an online reference for the package hosted on GoPkgDoc
[here][gomock-reference].
on a specific mockgen version. You should try to keep the library in sync with
the version of mockgen used to generate your mocks.
## Running mockgen
@ -120,6 +110,14 @@ It supports the following flags:
- `-copyright_file`: Copyright file used to add copyright header to the resulting source code.
- `-debug_parser`: Print out parser results only.
- `-exec_only`: (reflect mode) If set, execute this reflection program.
- `-prog_only`: (reflect mode) Only generate the reflection program; write it to stdout and exit.
- `-write_package_comment`: Writes package documentation comment (godoc) if true. (default true)
For an example of the use of `mockgen`, see the `sample/` directory. In simple
cases, you will need only the `-source` flag.
@ -257,3 +255,23 @@ If the received value is `3`, then it will be printed as `03`.
[ci-runs]: https://github.com/golang/mock/actions
[reference-badge]: https://pkg.go.dev/badge/github.com/golang/mock.svg
[reference]: https://pkg.go.dev/github.com/golang/mock
## Debugging Errors
### reflect vendoring error
```text
cannot find package "."
... github.com/golang/mock/mockgen/model
```
If you come across this error while using reflect mode and vendoring
dependencies there are three workarounds you can choose from:
1. Use source mode.
2. Include an empty import `import _ "github.com/golang/mock/mockgen/model"`.
3. Add `--build_flags=--mod=mod` to your mockgen command.
This error is due to changes in default behavior of the `go` command in more
recent versions. More details can be found in
[#494](https://github.com/golang/mock/issues/494).

Просмотреть файл

@ -1,12 +0,0 @@
#!/bin/bash
# This script is used by the CI to check if the code is gofmt formatted.
set -euo pipefail
GOFMT_DIFF=$(IFS=$'\n'; gofmt -d $( find . -type f -name '*.go' ) )
if [[ -n "${GOFMT_DIFF}" ]]; then
echo "${GOFMT_DIFF}"
echo
echo "The go source files aren't gofmt formatted."
exit 1
fi

Просмотреть файл

@ -1,33 +0,0 @@
#!/bin/bash
# This script is used by the CI to check if 'go generate ./...' is up to date.
#
# Note: If the generated files aren't up to date then this script updates
# them despite printing an error message so running it the second time
# might not print any errors. This isn't very useful locally during development
# but it works well with the CI that downloads a fresh version of the repo
# each time before executing this script.
set -euo pipefail
BASE_DIR="$PWD"
TEMP_DIR=$( mktemp -d )
function cleanup() {
rm -rf "${TEMP_DIR}"
}
trap cleanup EXIT
cp -r . "${TEMP_DIR}/"
cd $TEMP_DIR
for i in $(find $PWD -name go.mod); do
pushd $(dirname $i)
go generate ./...
popd
done
if ! diff -r . "${BASE_DIR}"; then
echo
echo "The generated files aren't up to date."
echo "Update them with the 'go generate ./...' command."
exit 1
fi

Просмотреть файл

@ -1,17 +0,0 @@
#!/bin/bash
# This script is used by CI to check if the code passes golint.
set -u
if ! command -v golint >/dev/null; then
echo "error: golint not found; go get -u golang.org/x/lint/golint" >&2
exit 1
fi
GOLINT_OUTPUT=$(IFS=$'\n'; golint ./... | grep -v "mockgen/internal/.*\|sample/.*")
if [[ -n "${GOLINT_OUTPUT}" ]]; then
echo "${GOLINT_OUTPUT}"
echo
echo "The go source files aren't passing golint."
exit 1
fi

Просмотреть файл

@ -1,18 +0,0 @@
#!/bin/bash
# This script is used to ensure that the go.mod file is up to date.
set -euo pipefail
for i in $(find $PWD -name go.mod); do
pushd $(dirname $i)
go mod tidy
popd
done
if [ ! -z "$(git status --porcelain)" ]; then
git status
git diff
echo
echo "The go.mod is not up to date."
exit 1
fi

45
ci/test.sh Executable file
Просмотреть файл

@ -0,0 +1,45 @@
#!/bin/bash
# This script is used to ensure that the go.mod file is up to date.
set -euo pipefail
if [[ $(go version) != *"go1.18"* ]]; then
exit 0
fi
for i in $(find $PWD -name go.mod); do
pushd $(dirname $i)
go mod tidy
popd
done
if [ ! -z "$(git status --porcelain)" ]; then
git status
git diff
echo
echo "The go.mod is not up to date."
exit 1
fi
BASE_DIR="$PWD"
TEMP_DIR=$(mktemp -d)
function cleanup() {
rm -rf "${TEMP_DIR}"
}
trap cleanup EXIT
cp -r . "${TEMP_DIR}/"
cd $TEMP_DIR
for i in $(find $PWD -name go.mod); do
pushd $(dirname $i)
go generate ./...
popd
done
if ! diff -r . "${BASE_DIR}"; then
echo
echo "The generated files aren't up to date."
echo "Update them with the 'go generate ./...' command."
exit 1
fi

6
go.mod
Просмотреть файл

@ -1,8 +1,8 @@
module github.com/golang/mock
require (
golang.org/x/mod v0.4.1
golang.org/x/tools v0.1.0
golang.org/x/mod v0.5.1
golang.org/x/tools v0.1.8
)
go 1.11
go 1.15

29
go.sum
Просмотреть файл

@ -1,27 +1,28 @@
github.com/yuin/goldmark v1.2.1 h1:ruQGxdhGHe7FWOJPT0mKs5+pD2Xs1Bm/kdGlHO04FmM=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.4.1 h1:/vn0k+RBvwlxEmP5E7SZMqNxPhfMVFEJiykr15/0XKM=
github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.1 h1:Kvvh58BN8Y9/lBi7hTekvtMpm07eUZ0ck5pRHpsMWrY=
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.5.1 h1:OJxoQ/rynoF0dcCdI7cLPktw/hR2cueqYfjm43oqK38=
golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4 h1:myAQVi0cGEoqQVR5POX+8RR2mrocKqNN1hmeMqhX27k=
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654 h1:id054HUawV2/6IGm2IV8KZQjqtwAOo2CYlOToYqa0d0=
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.0 h1:po9/4sTYwZU9lPhi1tOrb4hCv3qrhiQ77LZfGa2OjwY=
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
golang.org/x/tools v0.1.8 h1:P1HhGGuLW4aAclzjtmJdf0mJOjVUZUzOTqkAkWL+l6w=
golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=

Просмотреть файл

@ -138,13 +138,25 @@ func (c *Call) MaxTimes(n int) *Call {
// DoAndReturn declares the action to run when the call is matched.
// The return values from this function are returned by the mocked function.
// It takes an interface{} argument to support n-arity functions.
// The anonymous function must match the function signature mocked method.
func (c *Call) DoAndReturn(f interface{}) *Call {
// TODO: Check arity and types here, rather than dying badly elsewhere.
v := reflect.ValueOf(f)
c.addAction(func(args []interface{}) []interface{} {
vArgs := make([]reflect.Value, len(args))
c.t.Helper()
ft := v.Type()
if c.methodType.NumIn() != ft.NumIn() {
if ft.IsVariadic() {
c.t.Fatalf("wrong number of arguments in DoAndReturn func for %T.%v The function signature must match the mocked method, a variadic function cannot be used.",
c.receiver, c.method)
} else {
c.t.Fatalf("wrong number of arguments in DoAndReturn func for %T.%v: got %d, want %d [%s]",
c.receiver, c.method, ft.NumIn(), c.methodType.NumIn(), c.origin)
}
return nil
}
vArgs := make([]reflect.Value, len(args))
for i := 0; i < len(args); i++ {
if args[i] != nil {
vArgs[i] = reflect.ValueOf(args[i])
@ -167,13 +179,25 @@ func (c *Call) DoAndReturn(f interface{}) *Call {
// return values are ignored to retain backward compatibility. To use the
// return values call DoAndReturn.
// It takes an interface{} argument to support n-arity functions.
// The anonymous function must match the function signature mocked method.
func (c *Call) Do(f interface{}) *Call {
// TODO: Check arity and types here, rather than dying badly elsewhere.
v := reflect.ValueOf(f)
c.addAction(func(args []interface{}) []interface{} {
vArgs := make([]reflect.Value, len(args))
c.t.Helper()
ft := v.Type()
if c.methodType.NumIn() != ft.NumIn() {
if ft.IsVariadic() {
c.t.Fatalf("wrong number of arguments in Do func for %T.%v The function signature must match the mocked method, a variadic function cannot be used.",
c.receiver, c.method)
} else {
c.t.Fatalf("wrong number of arguments in Do func for %T.%v: got %d, want %d [%s]",
c.receiver, c.method, ft.NumIn(), c.methodType.NumIn(), c.origin)
}
return nil
}
vArgs := make([]reflect.Value, len(args))
for i := 0; i < len(args); i++ {
if args[i] != nil {
vArgs[i] = reflect.ValueOf(args[i])
@ -239,8 +263,8 @@ func (c *Call) Times(n int) *Call {
}
// SetArg declares an action that will set the nth argument's value,
// indirected through a pointer. Or, in the case of a slice, SetArg
// will copy value's elements into the nth argument.
// indirected through a pointer. Or, in the case of a slice and map, SetArg
// will copy value's elements/key-value pairs into the nth argument.
func (c *Call) SetArg(n int, value interface{}) *Call {
c.t.Helper()
@ -265,8 +289,10 @@ func (c *Call) SetArg(n int, value interface{}) *Call {
// nothing to do
case reflect.Slice:
// nothing to do
case reflect.Map:
// nothing to do
default:
c.t.Fatalf("SetArg(%d, ...) referring to argument of non-pointer non-interface non-slice type %v [%s]",
c.t.Fatalf("SetArg(%d, ...) referring to argument of non-pointer non-interface non-slice non-map type %v [%s]",
n, at, c.origin)
}
@ -275,6 +301,8 @@ func (c *Call) SetArg(n int, value interface{}) *Call {
switch reflect.TypeOf(args[n]).Kind() {
case reflect.Slice:
setSlice(args[n], v)
case reflect.Map:
setMap(args[n], v)
default:
reflect.ValueOf(args[n]).Elem().Set(v)
}
@ -423,7 +451,7 @@ func (c *Call) matches(args []interface{}) error {
// Check that all prerequisite calls have been satisfied.
for _, preReqCall := range c.preReqs {
if !preReqCall.satisfied() {
return fmt.Errorf("Expected call at %s doesn't have a prerequisite call satisfied:\n%v\nshould be called before:\n%v",
return fmt.Errorf("expected call at %s doesn't have a prerequisite call satisfied:\n%v\nshould be called before:\n%v",
c.origin, preReqCall, c)
}
}
@ -463,12 +491,22 @@ func setSlice(arg interface{}, v reflect.Value) {
}
}
func setMap(arg interface{}, v reflect.Value) {
va := reflect.ValueOf(arg)
for _, e := range va.MapKeys() {
va.SetMapIndex(e, reflect.Value{})
}
for _, e := range v.MapKeys() {
va.SetMapIndex(e, v.MapIndex(e))
}
}
func (c *Call) addAction(action func([]interface{}) []interface{}) {
c.actions = append(c.actions, action)
}
func formatGottenArg(m Matcher, arg interface{}) string {
got := fmt.Sprintf("%v", arg)
got := fmt.Sprintf("%v (%T)", arg, arg)
if gs, ok := m.(GotFormatter); ok {
got = gs.Got(arg)
}

Просмотреть файл

@ -126,9 +126,7 @@ var testCases []testCase = []testCase{
{
description: "argument to Do is not a function",
doFunc: "meow",
callFunc: func(x int, y int) {
return
},
callFunc: func(x int, y int) {},
args: []interface{}{0, 1},
expectPanic: true,
}, {
@ -141,14 +139,10 @@ var testCases []testCase = []testCase{
expectPanic: true,
}, {
description: "number of args for Do func don't match Call func",
doFunc: func(x int) {
return
},
callFunc: func(x int, y int) {
return
},
doFunc: func(x int) {},
callFunc: func(x int, y int) {},
args: []interface{}{0, 1},
expectPanic: true,
expectPanic: false,
}, {
description: "number of args for Do func don't match Call func",
doFunc: func(x int) bool {
@ -158,15 +152,11 @@ var testCases []testCase = []testCase{
return true
},
args: []interface{}{0, 1},
expectPanic: true,
expectPanic: false,
}, {
description: "arg type for Do func incompatible with Call func",
doFunc: func(x int) {
return
},
callFunc: func(x string) {
return
},
doFunc: func(x int) {},
callFunc: func(x string) {},
args: []interface{}{"meow"},
expectPanic: true,
}, {
@ -181,21 +171,13 @@ var testCases []testCase = []testCase{
expectPanic: true,
}, {
description: "Do func(int) Call func(int)",
doFunc: func(x int) {
return
},
callFunc: func(x int) {
return
},
doFunc: func(x int) {},
callFunc: func(x int) {},
args: []interface{}{0},
}, {
description: "Do func(int) Call func(interface{})",
doFunc: func(x int) {
return
},
callFunc: func(x interface{}) {
return
},
doFunc: func(x int) {},
callFunc: func(x interface{}) {},
args: []interface{}{0},
}, {
description: "Do func(int) bool Call func(int) bool",
@ -217,12 +199,8 @@ var testCases []testCase = []testCase{
args: []interface{}{0},
}, {
description: "Do func(string) Call func([]byte)",
doFunc: func(x string) {
return
},
callFunc: func(x []byte) {
return
},
doFunc: func(x string) {},
callFunc: func(x []byte) {},
args: []interface{}{[]byte("meow")},
expectPanic: true,
}, {
@ -237,22 +215,14 @@ var testCases []testCase = []testCase{
expectPanic: true,
}, {
description: "Do func(map[int]string) Call func(map[interface{}]int)",
doFunc: func(x map[int]string) {
return
},
callFunc: func(x map[interface{}]int) {
return
},
doFunc: func(x map[int]string) {},
callFunc: func(x map[interface{}]int) {},
args: []interface{}{map[interface{}]int{"meow": 0}},
expectPanic: true,
}, {
description: "Do func(map[int]string) Call func(map[interface{}]interface{})",
doFunc: func(x map[int]string) {
return
},
callFunc: func(x map[interface{}]interface{}) {
return
},
doFunc: func(x map[int]string) {},
callFunc: func(x map[interface{}]interface{}) {},
args: []interface{}{map[interface{}]interface{}{"meow": "meow"}},
expectPanic: true,
}, {
@ -277,61 +247,37 @@ var testCases []testCase = []testCase{
expectPanic: true,
}, {
description: "Do func([]string) Call func([]interface{})",
doFunc: func(x []string) {
return
},
callFunc: func(x []interface{}) {
return
},
doFunc: func(x []string) {},
callFunc: func(x []interface{}) {},
args: []interface{}{[]interface{}{0}},
expectPanic: true,
}, {
description: "Do func([]string) Call func([]int)",
doFunc: func(x []string) {
return
},
callFunc: func(x []int) {
return
},
doFunc: func(x []string) {},
callFunc: func(x []int) {},
args: []interface{}{[]int{0, 1}},
expectPanic: true,
}, {
description: "Do func([]int) Call func([]int)",
doFunc: func(x []int) {
return
},
callFunc: func(x []int) {
return
},
doFunc: func(x []int) {},
callFunc: func(x []int) {},
args: []interface{}{[]int{0, 1}},
}, {
description: "Do func([]int) Call func([]interface{})",
doFunc: func(x []int) {
return
},
callFunc: func(x []interface{}) {
return
},
doFunc: func(x []int) {},
callFunc: func(x []interface{}) {},
args: []interface{}{[]interface{}{0}},
expectPanic: true,
}, {
description: "Do func([]int) Call func(...interface{})",
doFunc: func(x []int) {
return
},
callFunc: func(x ...interface{}) {
return
},
doFunc: func(x []int) {},
callFunc: func(x ...interface{}) {},
args: []interface{}{0, 1},
expectPanic: true,
}, {
description: "Do func([]int) Call func(...int)",
doFunc: func(x []int) {
return
},
callFunc: func(x ...int) {
return
},
doFunc: func(x []int) {},
callFunc: func(x ...int) {},
args: []interface{}{0, 1},
expectPanic: true,
}, {
@ -395,32 +341,20 @@ var testCases []testCase = []testCase{
expectPanic: true,
}, {
description: "Do func(...int) Call func([]int)",
doFunc: func(x ...int) {
return
},
callFunc: func(x []int) {
return
},
doFunc: func(x ...int) {},
callFunc: func(x []int) {},
args: []interface{}{[]int{0, 1}},
expectPanic: true,
}, {
description: "Do func(...int) Call func([]interface{})",
doFunc: func(x ...int) {
return
},
callFunc: func(x []interface{}) {
return
},
doFunc: func(x ...int) {},
callFunc: func(x []interface{}) {},
args: []interface{}{[]interface{}{0, 1}},
expectPanic: true,
}, {
description: "Do func(...int) Call func(...interface{})",
doFunc: func(x ...int) {
return
},
callFunc: func(x ...interface{}) {
return
},
doFunc: func(x ...int) {},
callFunc: func(x ...interface{}) {},
args: []interface{}{0, 1},
}, {
description: "Do func(...int) bool Call func(...int) bool",
@ -462,40 +396,24 @@ var testCases []testCase = []testCase{
args: []interface{}{0, 1},
}, {
description: "Do func(...int) Call func(...int)",
doFunc: func(x ...int) {
return
},
callFunc: func(x ...int) {
return
},
doFunc: func(x ...int) {},
callFunc: func(x ...int) {},
args: []interface{}{0, 1},
}, {
description: "Do func(foo); foo implements interface X Call func(interface X)",
doFunc: func(x foo) {
return
},
callFunc: func(x fmt.Stringer) {
return
},
doFunc: func(x foo) {},
callFunc: func(x fmt.Stringer) {},
args: []interface{}{foo{}},
}, {
description: "Do func(b); b does not implement interface X Call func(interface X)",
doFunc: func(x b) {
return
},
callFunc: func(x fmt.Stringer) {
return
},
doFunc: func(x b) {},
callFunc: func(x fmt.Stringer) {},
args: []interface{}{foo{}},
expectPanic: true,
}, {
description: "Do func(b) Call func(a); a and b are not aliases",
doFunc: func(x b) {
return
},
callFunc: func(x a) {
return
},
doFunc: func(x b) {},
callFunc: func(x a) {},
args: []interface{}{a{}},
expectPanic: true,
}, {
@ -563,6 +481,118 @@ func TestCall_Do(t *testing.T) {
}
}
func TestCall_Do_NumArgValidation(t *testing.T) {
tests := []struct {
name string
methodType reflect.Type
doFn interface{}
args []interface{}
wantErr bool
}{
{
name: "too few",
methodType: reflect.TypeOf(func(one, two string) {}),
doFn: func(one string) {},
args: []interface{}{"too", "few"},
wantErr: true,
},
{
name: "too many",
methodType: reflect.TypeOf(func(one, two string) {}),
doFn: func(one, two, three string) {},
args: []interface{}{"too", "few"},
wantErr: true,
},
{
name: "just right",
methodType: reflect.TypeOf(func(one, two string) {}),
doFn: func(one string, two string) {},
args: []interface{}{"just", "right"},
wantErr: false,
},
{
name: "variadic",
methodType: reflect.TypeOf(func(one, two string) {}),
doFn: func(args ...interface{}) {},
args: []interface{}{"just", "right"},
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tr := &mockTestReporter{}
call := &Call{
t: tr,
methodType: tt.methodType,
}
call.Do(tt.doFn)
call.actions[0](tt.args)
if tt.wantErr && tr.fatalCalls != 1 {
t.Fatalf("expected call to fail")
}
if !tt.wantErr && tr.fatalCalls != 0 {
t.Fatalf("expected call to pass")
}
})
}
}
func TestCall_DoAndReturn_NumArgValidation(t *testing.T) {
tests := []struct {
name string
methodType reflect.Type
doFn interface{}
args []interface{}
wantErr bool
}{
{
name: "too few",
methodType: reflect.TypeOf(func(one, two string) string { return "" }),
doFn: func(one string) {},
args: []interface{}{"too", "few"},
wantErr: true,
},
{
name: "too many",
methodType: reflect.TypeOf(func(one, two string) string { return "" }),
doFn: func(one, two, three string) string { return "" },
args: []interface{}{"too", "few"},
wantErr: true,
},
{
name: "just right",
methodType: reflect.TypeOf(func(one, two string) string { return "" }),
doFn: func(one string, two string) string { return "" },
args: []interface{}{"just", "right"},
wantErr: false,
},
{
name: "variadic",
methodType: reflect.TypeOf(func(one, two string) {}),
doFn: func(args ...interface{}) string { return "" },
args: []interface{}{"just", "right"},
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tr := &mockTestReporter{}
call := &Call{
t: tr,
methodType: tt.methodType,
}
call.DoAndReturn(tt.doFn)
call.actions[0](tt.args)
if tt.wantErr && tr.fatalCalls != 1 {
t.Fatalf("expected call to fail")
}
if !tt.wantErr && tr.fatalCalls != 0 {
t.Fatalf("expected call to pass")
}
})
}
}
func TestCall_DoAndReturn(t *testing.T) {
for _, tc := range testCases {
t.Run(tc.description, func(t *testing.T) {

Просмотреть файл

@ -16,6 +16,7 @@ package gomock
import (
"bytes"
"errors"
"fmt"
)
@ -105,7 +106,7 @@ func (cs callSet) FindMatch(receiver interface{}, method string, args []interfac
_, _ = fmt.Fprintf(&callsErrors, "there are no expected calls of the method %q for that receiver", method)
}
return nil, fmt.Errorf(callsErrors.String())
return nil, errors.New(callsErrors.String())
}
// Failures returns the calls that are not satisfied.

Просмотреть файл

@ -12,44 +12,6 @@
// See the License for the specific language governing permissions and
// limitations under the License.
// Package gomock is a mock framework for Go.
//
// Standard usage:
// (1) Define an interface that you wish to mock.
// type MyInterface interface {
// SomeMethod(x int64, y string)
// }
// (2) Use mockgen to generate a mock from the interface.
// (3) Use the mock in a test:
// func TestMyThing(t *testing.T) {
// mockCtrl := gomock.NewController(t)
// defer mockCtrl.Finish()
//
// mockObj := something.NewMockMyInterface(mockCtrl)
// mockObj.EXPECT().SomeMethod(4, "blah")
// // pass mockObj to a real object and play with it.
// }
//
// By default, expected calls are not enforced to run in any particular order.
// Call order dependency can be enforced by use of InOrder and/or Call.After.
// Call.After can create more varied call order dependencies, but InOrder is
// often more convenient.
//
// The following examples create equivalent call order dependencies.
//
// Example of using Call.After to chain expected call order:
//
// firstCall := mockObj.EXPECT().SomeMethod(1, "first")
// secondCall := mockObj.EXPECT().SomeMethod(2, "second").After(firstCall)
// mockObj.EXPECT().SomeMethod(3, "third").After(secondCall)
//
// Example of using InOrder to declare expected call order:
//
// gomock.InOrder(
// mockObj.EXPECT().SomeMethod(1, "first"),
// mockObj.EXPECT().SomeMethod(2, "second"),
// mockObj.EXPECT().SomeMethod(3, "third"),
// )
package gomock
import (
@ -123,7 +85,7 @@ type Controller struct {
// Controller.
//
// New in go1.14+, if you are passing a *testing.T into this function you no
// longer need to call ctrl.Finish() in your test methods
// longer need to call ctrl.Finish() in your test methods.
func NewController(t TestReporter) *Controller {
h, ok := t.(TestHelper)
if !ok {
@ -259,6 +221,9 @@ func (ctrl *Controller) Call(receiver interface{}, method string, args ...interf
// Finish checks to see if all the methods that were expected to be called
// were called. It should be invoked for each Controller. It is not idempotent
// and therefore can only be invoked once.
//
// New in go1.14+, if you are passing a *testing.T into NewController function you no
// longer need to call ctrl.Finish() in your test methods.
func (ctrl *Controller) Finish() {
// If we're currently panicking, probably because this is a deferred call.
// This must be recovered in the deferred function.

Просмотреть файл

@ -1,28 +0,0 @@
// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// +build !go1.14
package gomock_test
import "testing"
func TestDuplicateFinishCallFails(t *testing.T) {
rep, ctrl := createFixtures(t)
ctrl.Finish()
rep.assertPass("the first Finish call should succeed")
rep.assertFatal(ctrl.Finish, "Controller.Finish was called more than once. It has to be called exactly once.")
}

Просмотреть файл

@ -1,132 +0,0 @@
// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// +build go1.14
package gomock_test
import (
"testing"
"github.com/golang/mock/gomock"
)
func (e *ErrorReporter) Cleanup(f func()) {
e.t.Helper()
e.t.Cleanup(f)
}
func TestMultipleDefers(t *testing.T) {
reporter := NewErrorReporter(t)
reporter.Cleanup(func() {
reporter.assertPass("No errors for multiple calls to Finish")
})
ctrl := gomock.NewController(reporter)
ctrl.Finish()
}
// Equivalent to the TestNoRecordedCallsForAReceiver, but without explicitly
// calling Finish.
func TestDeferNotNeededFail(t *testing.T) {
reporter := NewErrorReporter(t)
subject := new(Subject)
var ctrl *gomock.Controller
reporter.Cleanup(func() {
reporter.assertFatal(func() {
ctrl.Call(subject, "NotRecordedMethod", "argument")
}, "Unexpected call to", "there are no expected calls of the method \"NotRecordedMethod\" for that receiver")
})
ctrl = gomock.NewController(reporter)
}
func TestDeferNotNeededPass(t *testing.T) {
reporter := NewErrorReporter(t)
subject := new(Subject)
var ctrl *gomock.Controller
reporter.Cleanup(func() {
reporter.assertPass("Expected method call made.")
})
ctrl = gomock.NewController(reporter)
ctrl.RecordCall(subject, "FooMethod", "argument")
ctrl.Call(subject, "FooMethod", "argument")
}
func TestOrderedCallsInCorrect(t *testing.T) {
reporter := NewErrorReporter(t)
subjectOne := new(Subject)
subjectTwo := new(Subject)
var ctrl *gomock.Controller
reporter.Cleanup(func() {
reporter.assertFatal(func() {
gomock.InOrder(
ctrl.RecordCall(subjectOne, "FooMethod", "1").AnyTimes(),
ctrl.RecordCall(subjectTwo, "FooMethod", "2"),
ctrl.RecordCall(subjectTwo, "BarMethod", "3"),
)
ctrl.Call(subjectOne, "FooMethod", "1")
// FooMethod(2) should be called before BarMethod(3)
ctrl.Call(subjectTwo, "BarMethod", "3")
}, "Unexpected call to", "Subject.BarMethod([3])", "doesn't have a prerequisite call satisfied")
})
ctrl = gomock.NewController(reporter)
}
// Test that calls that are prerequisites to other calls but have maxCalls >
// minCalls are removed from the expected call set.
func TestOrderedCallsWithPreReqMaxUnbounded(t *testing.T) {
reporter := NewErrorReporter(t)
subjectOne := new(Subject)
subjectTwo := new(Subject)
var ctrl *gomock.Controller
reporter.Cleanup(func() {
reporter.assertFatal(func() {
// Initially we should be able to call FooMethod("1") as many times as we
// want.
ctrl.Call(subjectOne, "FooMethod", "1")
ctrl.Call(subjectOne, "FooMethod", "1")
// But calling something that has it as a prerequite should remove it from
// the expected call set. This allows tests to ensure that FooMethod("1") is
// *not* called after FooMethod("2").
ctrl.Call(subjectTwo, "FooMethod", "2")
ctrl.Call(subjectOne, "FooMethod", "1")
})
})
ctrl = gomock.NewController(reporter)
}
func TestCallAfterLoopPanic(t *testing.T) {
reporter := NewErrorReporter(t)
subject := new(Subject)
var ctrl *gomock.Controller
reporter.Cleanup(func() {
firstCall := ctrl.RecordCall(subject, "FooMethod", "1")
secondCall := ctrl.RecordCall(subject, "FooMethod", "2")
thirdCall := ctrl.RecordCall(subject, "FooMethod", "3")
gomock.InOrder(firstCall, secondCall, thirdCall)
defer func() {
err := recover()
if err == nil {
t.Error("Call.After creation of dependency loop did not panic.")
}
}()
// This should panic due to dependency loop.
firstCall.After(thirdCall)
})
ctrl = gomock.NewController(reporter)
}

Просмотреть файл

@ -54,17 +54,6 @@ func (e *ErrorReporter) assertFail(msg string) {
}
}
func (e *ErrorReporter) assertLogf(expectedErrMsgs ...string) {
if len(e.log) < len(expectedErrMsgs) {
e.t.Fatalf("got %d Logf messages, want %d", len(e.log), len(expectedErrMsgs))
}
for i, expectedErrMsg := range expectedErrMsgs {
if !strings.Contains(e.log[i], expectedErrMsg) {
e.t.Errorf("Error message:\ngot: %q\nwant to contain: %q\n", e.log[i], expectedErrMsg)
}
}
}
// Use to check that code triggers a fatal test failure.
func (e *ErrorReporter) assertFatal(fn func(), expectedErrMsgs ...string) {
defer func() {
@ -169,7 +158,8 @@ func (s *Subject) ActOnTestStructMethod(arg TestStruct, arg1 int) int {
return 0
}
func (s *Subject) SetArgMethod(sliceArg []byte, ptrArg *int) {}
func (s *Subject) SetArgMethod(sliceArg []byte, ptrArg *int, mapArg map[interface{}]interface{}) {}
func (s *Subject) SetArgMethodInterface(sliceArg, ptrArg, mapArg interface{}) {}
func assertEqual(t *testing.T, expected interface{}, actual interface{}) {
if !reflect.DeepEqual(expected, actual) {
@ -292,20 +282,20 @@ func TestUnexpectedArgValue_FirstArg(t *testing.T) {
defer reporter.recoverUnexpectedFatal()
subject := new(Subject)
expectedArg0 := TestStruct{Number: 123, Message: "hello"}
expectedArg0 := TestStruct{Number: 123, Message: "hello %s"}
ctrl.RecordCall(subject, "ActOnTestStructMethod", expectedArg0, 15)
reporter.assertFatal(func() {
// the method argument (of TestStruct type) has 1 unexpected value (for the Message field)
ctrl.Call(subject, "ActOnTestStructMethod", TestStruct{Number: 123, Message: "no message"}, 15)
}, "Unexpected call to", "doesn't match the argument at index 0",
"Got: {123 no message}\nWant: is equal to {123 hello}")
"Got: {123 no message} (gomock_test.TestStruct)\nWant: is equal to {123 hello %s} (gomock_test.TestStruct)")
reporter.assertFatal(func() {
// the method argument (of TestStruct type) has 2 unexpected values (for both fields)
ctrl.Call(subject, "ActOnTestStructMethod", TestStruct{Number: 11, Message: "no message"}, 15)
}, "Unexpected call to", "doesn't match the argument at index 0",
"Got: {11 no message}\nWant: is equal to {123 hello}")
"Got: {11 no message} (gomock_test.TestStruct)\nWant: is equal to {123 hello %s} (gomock_test.TestStruct)")
reporter.assertFatal(func() {
// The expected call wasn't made.
@ -324,7 +314,7 @@ func TestUnexpectedArgValue_SecondArg(t *testing.T) {
reporter.assertFatal(func() {
ctrl.Call(subject, "ActOnTestStructMethod", TestStruct{Number: 123, Message: "hello"}, 3)
}, "Unexpected call to", "doesn't match the argument at index 1",
"Got: 3\nWant: is equal to 15")
"Got: 3 (int)\nWant: is equal to 15 (int)")
reporter.assertFatal(func() {
// The expected call wasn't made.
@ -351,7 +341,7 @@ func TestUnexpectedArgValue_WantFormatter(t *testing.T) {
reporter.assertFatal(func() {
ctrl.Call(subject, "ActOnTestStructMethod", TestStruct{Number: 123, Message: "hello"}, 3)
}, "Unexpected call to", "doesn't match the argument at index 1",
"Got: 3\nWant: is equal to fifteen")
"Got: 3 (int)\nWant: is equal to fifteen")
reporter.assertFatal(func() {
// The expected call wasn't made.
@ -411,14 +401,14 @@ func TestMinTimes1(t *testing.T) {
})
// It succeeds if there is one call
reporter, ctrl = createFixtures(t)
_, ctrl = createFixtures(t)
subject = new(Subject)
ctrl.RecordCall(subject, "FooMethod", "argument").MinTimes(1)
ctrl.Call(subject, "FooMethod", "argument")
ctrl.Finish()
// It succeeds if there are many calls
reporter, ctrl = createFixtures(t)
_, ctrl = createFixtures(t)
subject = new(Subject)
ctrl.RecordCall(subject, "FooMethod", "argument").MinTimes(1)
for i := 0; i < 100; i++ {
@ -473,7 +463,7 @@ func TestMinMaxTimes(t *testing.T) {
})
// It succeeds if there is just the right number of calls
reporter, ctrl = createFixtures(t)
_, ctrl = createFixtures(t)
subject = new(Subject)
ctrl.RecordCall(subject, "FooMethod", "argument").MaxTimes(2).MinTimes(2)
ctrl.Call(subject, "FooMethod", "argument")
@ -491,7 +481,7 @@ func TestMinMaxTimes(t *testing.T) {
})
// If MinTimes is called after MaxTimes is called with 1, MinTimes takes precedence.
reporter, ctrl = createFixtures(t)
_, ctrl = createFixtures(t)
subject = new(Subject)
ctrl.RecordCall(subject, "FooMethod", "argument").MaxTimes(1).MinTimes(2)
for i := 0; i < 100; i++ {
@ -506,7 +496,8 @@ func TestDo(t *testing.T) {
doCalled := false
var argument string
ctrl.RecordCall(subject, "FooMethod", "argument").Do(
wantArg := "argument"
ctrl.RecordCall(subject, "FooMethod", wantArg).Do(
func(arg string) {
doCalled = true
argument = arg
@ -515,12 +506,12 @@ func TestDo(t *testing.T) {
t.Error("Do() callback called too early.")
}
ctrl.Call(subject, "FooMethod", "argument")
ctrl.Call(subject, "FooMethod", wantArg)
if !doCalled {
t.Error("Do() callback not called.")
}
if "argument" != argument {
if wantArg != argument {
t.Error("Do callback received wrong argument.")
}
@ -533,7 +524,8 @@ func TestDoAndReturn(t *testing.T) {
doCalled := false
var argument string
ctrl.RecordCall(subject, "FooMethod", "argument").DoAndReturn(
wantArg := "argument"
ctrl.RecordCall(subject, "FooMethod", wantArg).DoAndReturn(
func(arg string) int {
doCalled = true
argument = arg
@ -543,12 +535,12 @@ func TestDoAndReturn(t *testing.T) {
t.Error("Do() callback called too early.")
}
rets := ctrl.Call(subject, "FooMethod", "argument")
rets := ctrl.Call(subject, "FooMethod", wantArg)
if !doCalled {
t.Error("Do() callback not called.")
}
if "argument" != argument {
if wantArg != argument {
t.Error("Do callback received wrong argument.")
}
if len(rets) != 1 {
@ -569,13 +561,43 @@ func TestSetArgSlice(t *testing.T) {
var in = []byte{4, 5, 6}
var set = []byte{1, 2, 3}
ctrl.RecordCall(subject, "SetArgMethod", in, nil).SetArg(0, set)
ctrl.Call(subject, "SetArgMethod", in, nil)
ctrl.RecordCall(subject, "SetArgMethod", in, nil, nil).SetArg(0, set)
ctrl.Call(subject, "SetArgMethod", in, nil, nil)
if !reflect.DeepEqual(in, set) {
t.Error("Expected SetArg() to modify input slice argument")
}
ctrl.RecordCall(subject, "SetArgMethodInterface", in, nil, nil).SetArg(0, set)
ctrl.Call(subject, "SetArgMethodInterface", in, nil, nil)
if !reflect.DeepEqual(in, set) {
t.Error("Expected SetArg() to modify input slice argument as interface{}")
}
ctrl.Finish()
}
func TestSetArgMap(t *testing.T) {
_, ctrl := createFixtures(t)
subject := new(Subject)
var in = map[interface{}]interface{}{"int": 1, "string": "random string", 1: "1", 0: 0}
var set = map[interface{}]interface{}{"int": 2, 1: "2", 2: 100}
ctrl.RecordCall(subject, "SetArgMethod", nil, nil, in).SetArg(2, set)
ctrl.Call(subject, "SetArgMethod", nil, nil, in)
if !reflect.DeepEqual(in, set) {
t.Error("Expected SetArg() to modify input map argument")
}
ctrl.RecordCall(subject, "SetArgMethodInterface", nil, nil, in).SetArg(2, set)
ctrl.Call(subject, "SetArgMethodInterface", nil, nil, in)
if !reflect.DeepEqual(in, set) {
t.Error("Expected SetArg() to modify input map argument as interface{}")
}
ctrl.Finish()
}
@ -585,13 +607,19 @@ func TestSetArgPtr(t *testing.T) {
var in int = 43
const set = 42
ctrl.RecordCall(subject, "SetArgMethod", nil, &in).SetArg(1, set)
ctrl.Call(subject, "SetArgMethod", nil, &in)
ctrl.RecordCall(subject, "SetArgMethod", nil, &in, nil).SetArg(1, set)
ctrl.Call(subject, "SetArgMethod", nil, &in, nil)
if in != set {
t.Error("Expected SetArg() to modify value pointed to by argument")
}
ctrl.RecordCall(subject, "SetArgMethodInterface", nil, &in, nil).SetArg(1, set)
ctrl.Call(subject, "SetArgMethodInterface", nil, &in, nil)
if in != set {
t.Error("Expected SetArg() to modify value pointed to by argument as interface{}")
}
ctrl.Finish()
}
@ -720,7 +748,7 @@ func TestVariadicNoMatch(t *testing.T) {
rep.assertFatal(func() {
ctrl.Call(s, "VariadicMethod", 1)
}, "expected call at", "doesn't match the argument at index 0",
"Got: 1\nWant: is equal to 0")
"Got: 1 (int)\nWant: is equal to 0 (int)")
ctrl.Call(s, "VariadicMethod", 0)
ctrl.Finish()
}
@ -1075,3 +1103,112 @@ func TestWithHelper(t *testing.T) {
t.Fatal("expected Helper to be invoked")
}
}
func (e *ErrorReporter) Cleanup(f func()) {
e.t.Helper()
e.t.Cleanup(f)
}
func TestMultipleDefers(t *testing.T) {
reporter := NewErrorReporter(t)
reporter.Cleanup(func() {
reporter.assertPass("No errors for multiple calls to Finish")
})
ctrl := gomock.NewController(reporter)
ctrl.Finish()
}
// Equivalent to the TestNoRecordedCallsForAReceiver, but without explicitly
// calling Finish.
func TestDeferNotNeededFail(t *testing.T) {
reporter := NewErrorReporter(t)
subject := new(Subject)
var ctrl *gomock.Controller
reporter.Cleanup(func() {
reporter.assertFatal(func() {
ctrl.Call(subject, "NotRecordedMethod", "argument")
}, "Unexpected call to", "there are no expected calls of the method \"NotRecordedMethod\" for that receiver")
})
ctrl = gomock.NewController(reporter)
}
func TestDeferNotNeededPass(t *testing.T) {
reporter := NewErrorReporter(t)
subject := new(Subject)
var ctrl *gomock.Controller
reporter.Cleanup(func() {
reporter.assertPass("Expected method call made.")
})
ctrl = gomock.NewController(reporter)
ctrl.RecordCall(subject, "FooMethod", "argument")
ctrl.Call(subject, "FooMethod", "argument")
}
func TestOrderedCallsInCorrect(t *testing.T) {
reporter := NewErrorReporter(t)
subjectOne := new(Subject)
subjectTwo := new(Subject)
var ctrl *gomock.Controller
reporter.Cleanup(func() {
reporter.assertFatal(func() {
gomock.InOrder(
ctrl.RecordCall(subjectOne, "FooMethod", "1").AnyTimes(),
ctrl.RecordCall(subjectTwo, "FooMethod", "2"),
ctrl.RecordCall(subjectTwo, "BarMethod", "3"),
)
ctrl.Call(subjectOne, "FooMethod", "1")
// FooMethod(2) should be called before BarMethod(3)
ctrl.Call(subjectTwo, "BarMethod", "3")
}, "Unexpected call to", "Subject.BarMethod([3])", "doesn't have a prerequisite call satisfied")
})
ctrl = gomock.NewController(reporter)
}
// Test that calls that are prerequisites to other calls but have maxCalls >
// minCalls are removed from the expected call set.
func TestOrderedCallsWithPreReqMaxUnbounded(t *testing.T) {
reporter := NewErrorReporter(t)
subjectOne := new(Subject)
subjectTwo := new(Subject)
var ctrl *gomock.Controller
reporter.Cleanup(func() {
reporter.assertFatal(func() {
// Initially we should be able to call FooMethod("1") as many times as we
// want.
ctrl.Call(subjectOne, "FooMethod", "1")
ctrl.Call(subjectOne, "FooMethod", "1")
// But calling something that has it as a prerequite should remove it from
// the expected call set. This allows tests to ensure that FooMethod("1") is
// *not* called after FooMethod("2").
ctrl.Call(subjectTwo, "FooMethod", "2")
ctrl.Call(subjectOne, "FooMethod", "1")
})
})
ctrl = gomock.NewController(reporter)
}
func TestCallAfterLoopPanic(t *testing.T) {
reporter := NewErrorReporter(t)
subject := new(Subject)
var ctrl *gomock.Controller
reporter.Cleanup(func() {
firstCall := ctrl.RecordCall(subject, "FooMethod", "1")
secondCall := ctrl.RecordCall(subject, "FooMethod", "2")
thirdCall := ctrl.RecordCall(subject, "FooMethod", "3")
gomock.InOrder(firstCall, secondCall, thirdCall)
defer func() {
err := recover()
if err == nil {
t.Error("Call.After creation of dependency loop did not panic.")
}
}()
// This should panic due to dependency loop.
firstCall.After(thirdCall)
})
ctrl = gomock.NewController(reporter)
}

59
gomock/doc.go Normal file
Просмотреть файл

@ -0,0 +1,59 @@
// Copyright 2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Package gomock is a mock framework for Go.
//
// Standard usage:
// (1) Define an interface that you wish to mock.
// type MyInterface interface {
// SomeMethod(x int64, y string)
// }
// (2) Use mockgen to generate a mock from the interface.
// (3) Use the mock in a test:
// func TestMyThing(t *testing.T) {
// mockCtrl := gomock.NewController(t)//
// mockObj := something.NewMockMyInterface(mockCtrl)
// mockObj.EXPECT().SomeMethod(4, "blah")
// // pass mockObj to a real object and play with it.
// }
//
// By default, expected calls are not enforced to run in any particular order.
// Call order dependency can be enforced by use of InOrder and/or Call.After.
// Call.After can create more varied call order dependencies, but InOrder is
// often more convenient.
//
// The following examples create equivalent call order dependencies.
//
// Example of using Call.After to chain expected call order:
//
// firstCall := mockObj.EXPECT().SomeMethod(1, "first")
// secondCall := mockObj.EXPECT().SomeMethod(2, "second").After(firstCall)
// mockObj.EXPECT().SomeMethod(3, "third").After(secondCall)
//
// Example of using InOrder to declare expected call order:
//
// gomock.InOrder(
// mockObj.EXPECT().SomeMethod(1, "first"),
// mockObj.EXPECT().SomeMethod(2, "second"),
// mockObj.EXPECT().SomeMethod(3, "third"),
// )
//
// The standard TestReporter most users will pass to `NewController` is a
// `*testing.T` from the context of the test. Note that this will use the
// standard `t.Error` and `t.Fatal` methods to report what happened in the test.
// In some cases this can leave your testing package in a weird state if global
// state is used since `t.Fatal` is like calling panic in the middle of a
// function. In these cases it is recommended that you pass in your own
// `TestReporter`.
package gomock

Просмотреть файл

@ -1,82 +0,0 @@
package gomock_test
import (
"fmt"
"testing"
"time"
"github.com/golang/mock/gomock"
mock_sample "github.com/golang/mock/sample/mock_user"
)
func ExampleCall_DoAndReturn_latency() {
t := &testing.T{} // provided by test
ctrl := gomock.NewController(t)
mockIndex := mock_sample.NewMockIndex(ctrl)
mockIndex.EXPECT().Get(gomock.Any()).DoAndReturn(
// signature of anonymous function must have the same number of input and output arguments as the mocked method.
func(arg string) string {
time.Sleep(1 * time.Millisecond)
return "I'm sleepy"
},
)
r := mockIndex.Get("foo")
fmt.Println(r)
// Output: I'm sleepy
}
func ExampleCall_DoAndReturn_captureArguments() {
t := &testing.T{} // provided by test
ctrl := gomock.NewController(t)
mockIndex := mock_sample.NewMockIndex(ctrl)
var s string
mockIndex.EXPECT().Get(gomock.AssignableToTypeOf(s)).DoAndReturn(
// signature of anonymous function must have the same number of input and output arguments as the mocked method.
func(arg string) interface{} {
s = arg
return "I'm sleepy"
},
)
r := mockIndex.Get("foo")
fmt.Printf("%s %s", r, s)
// Output: I'm sleepy foo
}
func ExampleCall_Do_latency() {
t := &testing.T{} // provided by test
ctrl := gomock.NewController(t)
mockIndex := mock_sample.NewMockIndex(ctrl)
mockIndex.EXPECT().Anon(gomock.Any()).Do(
// signature of anonymous function must have the same number of input and output arguments as the mocked method.
func(_ string) {
fmt.Println("sleeping")
time.Sleep(1 * time.Millisecond)
},
)
mockIndex.Anon("foo")
// Output: sleeping
}
func ExampleCall_Do_captureArguments() {
t := &testing.T{} // provided by test
ctrl := gomock.NewController(t)
mockIndex := mock_sample.NewMockIndex(ctrl)
var s string
mockIndex.EXPECT().Anon(gomock.AssignableToTypeOf(s)).Do(
// signature of anonymous function must have the same number of input and output arguments as the mocked method.
func(arg string) {
s = arg
},
)
mockIndex.Anon("foo")
fmt.Println(s)
// Output: foo
}

50
gomock/example_test.go Normal file
Просмотреть файл

@ -0,0 +1,50 @@
package gomock_test
//go:generate mockgen -destination mock_test.go -package gomock_test -source example_test.go
import (
"fmt"
"testing"
"time"
"github.com/golang/mock/gomock"
)
type Foo interface {
Bar(string) string
}
func ExampleCall_DoAndReturn_latency() {
t := &testing.T{} // provided by test
ctrl := gomock.NewController(t)
mockIndex := NewMockFoo(ctrl)
mockIndex.EXPECT().Bar(gomock.Any()).DoAndReturn(
func(arg string) string {
time.Sleep(1 * time.Millisecond)
return "I'm sleepy"
},
)
r := mockIndex.Bar("foo")
fmt.Println(r)
// Output: I'm sleepy
}
func ExampleCall_DoAndReturn_captureArguments() {
t := &testing.T{} // provided by test
ctrl := gomock.NewController(t)
mockIndex := NewMockFoo(ctrl)
var s string
mockIndex.EXPECT().Bar(gomock.AssignableToTypeOf(s)).DoAndReturn(
func(arg string) interface{} {
s = arg
return "I'm sleepy"
},
)
r := mockIndex.Bar("foo")
fmt.Printf("%s %s", r, s)
// Output: I'm sleepy foo
}

Просмотреть файл

@ -120,7 +120,7 @@ func (e eqMatcher) Matches(x interface{}) bool {
}
func (e eqMatcher) String() string {
return fmt.Sprintf("is equal to %v", e.x)
return fmt.Sprintf("is equal to %v (%T)", e.x, e.x)
}
type nilMatcher struct{}
@ -207,6 +207,70 @@ func (m lenMatcher) String() string {
return fmt.Sprintf("has length %d", m.i)
}
type inAnyOrderMatcher struct {
x interface{}
}
func (m inAnyOrderMatcher) Matches(x interface{}) bool {
given, ok := m.prepareValue(x)
if !ok {
return false
}
wanted, ok := m.prepareValue(m.x)
if !ok {
return false
}
if given.Len() != wanted.Len() {
return false
}
usedFromGiven := make([]bool, given.Len())
foundFromWanted := make([]bool, wanted.Len())
for i := 0; i < wanted.Len(); i++ {
wantedMatcher := Eq(wanted.Index(i).Interface())
for j := 0; j < given.Len(); j++ {
if usedFromGiven[j] {
continue
}
if wantedMatcher.Matches(given.Index(j).Interface()) {
foundFromWanted[i] = true
usedFromGiven[j] = true
break
}
}
}
missingFromWanted := 0
for _, found := range foundFromWanted {
if !found {
missingFromWanted++
}
}
extraInGiven := 0
for _, used := range usedFromGiven {
if !used {
extraInGiven++
}
}
return extraInGiven == 0 && missingFromWanted == 0
}
func (m inAnyOrderMatcher) prepareValue(x interface{}) (reflect.Value, bool) {
xValue := reflect.ValueOf(x)
switch xValue.Kind() {
case reflect.Slice, reflect.Array:
return xValue, true
default:
return reflect.Value{}, false
}
}
func (m inAnyOrderMatcher) String() string {
return fmt.Sprintf("has the same elements as %v", m.x)
}
// Constructors
// All returns a composite Matcher that returns true if and only all of the
@ -266,3 +330,12 @@ func AssignableToTypeOf(x interface{}) Matcher {
}
return assignableToTypeOfMatcher{reflect.TypeOf(x)}
}
// InAnyOrder is a Matcher that returns true for collections of the same elements ignoring the order.
//
// Example usage:
// InAnyOrder([]int{1, 2, 3}).Matches([]int{1, 3, 2}) // returns true
// InAnyOrder([]int{1, 2, 3}).Matches([]int{1, 2}) // returns false
func InAnyOrder(x interface{}) Matcher {
return inAnyOrderMatcher{x}
}

Просмотреть файл

@ -90,6 +90,8 @@ type Dog struct {
Breed, Name string
}
type ctxKey struct{}
// A thorough test of assignableToTypeOfMatcher
func TestAssignableToTypeOfMatcher(t *testing.T) {
ctrl := gomock.NewController(t)
@ -137,8 +139,157 @@ func TestAssignableToTypeOfMatcher(t *testing.T) {
t.Errorf(`AssignableToTypeOf(context.Context) should not match context.Background()`)
}
ctxWithValue := context.WithValue(context.Background(), "key", "val")
ctxWithValue := context.WithValue(context.Background(), ctxKey{}, "val")
if match := gomock.AssignableToTypeOf(ctxInterface).Matches(ctxWithValue); !match {
t.Errorf(`AssignableToTypeOf(context.Context) should not match ctxWithValue`)
}
}
func TestInAnyOrder(t *testing.T) {
tests := []struct {
name string
wanted interface{}
given interface{}
wantMatch bool
}{
{
name: "match for equal slices",
wanted: []int{1, 2, 3},
given: []int{1, 2, 3},
wantMatch: true,
},
{
name: "match for slices with same elements of different order",
wanted: []int{1, 2, 3},
given: []int{1, 3, 2},
wantMatch: true,
},
{
name: "not match for slices with different elements",
wanted: []int{1, 2, 3},
given: []int{1, 2, 4},
wantMatch: false,
},
{
name: "not match for slices with missing elements",
wanted: []int{1, 2, 3},
given: []int{1, 2},
wantMatch: false,
},
{
name: "not match for slices with extra elements",
wanted: []int{1, 2, 3},
given: []int{1, 2, 3, 4},
wantMatch: false,
},
{
name: "match for empty slices",
wanted: []int{},
given: []int{},
wantMatch: true,
},
{
name: "not match for equal slices of different types",
wanted: []float64{1, 2, 3},
given: []int{1, 2, 3},
wantMatch: false,
},
{
name: "match for equal arrays",
wanted: [3]int{1, 2, 3},
given: [3]int{1, 2, 3},
wantMatch: true,
},
{
name: "match for equal arrays of different order",
wanted: [3]int{1, 2, 3},
given: [3]int{1, 3, 2},
wantMatch: true,
},
{
name: "not match for arrays of different elements",
wanted: [3]int{1, 2, 3},
given: [3]int{1, 2, 4},
wantMatch: false,
},
{
name: "not match for arrays with extra elements",
wanted: [3]int{1, 2, 3},
given: [4]int{1, 2, 3, 4},
wantMatch: false,
},
{
name: "not match for arrays with missing elements",
wanted: [3]int{1, 2, 3},
given: [2]int{1, 2},
wantMatch: false,
},
{
name: "not match for equal strings", // matcher shouldn't treat strings as collections
wanted: "123",
given: "123",
wantMatch: false,
},
{
name: "not match if x type is not iterable",
wanted: 123,
given: []int{123},
wantMatch: false,
},
{
name: "not match if in type is not iterable",
wanted: []int{123},
given: 123,
wantMatch: false,
},
{
name: "not match if both are not iterable",
wanted: 123,
given: 123,
wantMatch: false,
},
{
name: "match for equal slices with unhashable elements",
wanted: [][]int{{1}, {1, 2}, {1, 2, 3}},
given: [][]int{{1}, {1, 2}, {1, 2, 3}},
wantMatch: true,
},
{
name: "match for equal slices with unhashable elements of different order",
wanted: [][]int{{1}, {1, 2, 3}, {1, 2}},
given: [][]int{{1}, {1, 2}, {1, 2, 3}},
wantMatch: true,
},
{
name: "not match for different slices with unhashable elements",
wanted: [][]int{{1}, {1, 2, 3}, {1, 2}},
given: [][]int{{1}, {1, 2, 4}, {1, 3}},
wantMatch: false,
},
{
name: "not match for unhashable missing elements",
wanted: [][]int{{1}, {1, 2}, {1, 2, 3}},
given: [][]int{{1}, {1, 2}},
wantMatch: false,
},
{
name: "not match for unhashable extra elements",
wanted: [][]int{{1}, {1, 2}},
given: [][]int{{1}, {1, 2}, {1, 2, 3}},
wantMatch: false,
},
{
name: "match for equal slices of assignable types",
wanted: [][]string{{"a", "b"}},
given: []A{{"a", "b"}},
wantMatch: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := gomock.InAnyOrder(tt.wanted).Matches(tt.given); got != tt.wantMatch {
t.Errorf("got = %v, wantMatch %v", got, tt.wantMatch)
}
})
}
}

48
gomock/mock_test.go Normal file
Просмотреть файл

@ -0,0 +1,48 @@
// Code generated by MockGen. DO NOT EDIT.
// Source: example_test.go
// Package gomock_test is a generated GoMock package.
package gomock_test
import (
reflect "reflect"
"github.com/golang/mock/gomock"
)
// MockFoo is a mock of Foo interface.
type MockFoo struct {
ctrl *gomock.Controller
recorder *MockFooMockRecorder
}
// MockFooMockRecorder is the mock recorder for MockFoo.
type MockFooMockRecorder struct {
mock *MockFoo
}
// NewMockFoo creates a new mock instance.
func NewMockFoo(ctrl *gomock.Controller) *MockFoo {
mock := &MockFoo{ctrl: ctrl}
mock.recorder = &MockFooMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *MockFoo) EXPECT() *MockFooMockRecorder {
return m.recorder
}
// Bar mocks base method.
func (m *MockFoo) Bar(arg0 string) string {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Bar", arg0)
ret0, _ := ret[0].(string)
return ret0
}
// Bar indicates an expected call of Bar.
func (mr *MockFooMockRecorder) Bar(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Bar", reflect.TypeOf((*MockFoo)(nil).Bar), arg0)
}

88
mockgen/generic_go118.go Normal file
Просмотреть файл

@ -0,0 +1,88 @@
// Copyright 2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// See the License for the specific language governing permissions and
// limitations under the License.
//go:build go1.18
// +build go1.18
package main
import (
"go/ast"
"strings"
"github.com/golang/mock/mockgen/model"
)
func getTypeSpecTypeParams(ts *ast.TypeSpec) []*ast.Field {
if ts == nil || ts.TypeParams == nil {
return nil
}
return ts.TypeParams.List
}
func (p *fileParser) parseGenericType(pkg string, typ ast.Expr, tps map[string]bool) (model.Type, error) {
switch v := typ.(type) {
case *ast.IndexExpr:
m, err := p.parseType(pkg, v.X, tps)
if err != nil {
return nil, err
}
nm, ok := m.(*model.NamedType)
if !ok {
return m, nil
}
t, err := p.parseType(pkg, v.Index, tps)
if err != nil {
return nil, err
}
nm.TypeParams = &model.TypeParametersType{TypeParameters: []model.Type{t}}
return m, nil
case *ast.IndexListExpr:
m, err := p.parseType(pkg, v.X, tps)
if err != nil {
return nil, err
}
nm, ok := m.(*model.NamedType)
if !ok {
return m, nil
}
var ts []model.Type
for _, expr := range v.Indices {
t, err := p.parseType(pkg, expr, tps)
if err != nil {
return nil, err
}
ts = append(ts, t)
}
nm.TypeParams = &model.TypeParametersType{TypeParameters: ts}
return m, nil
}
return nil, nil
}
func getIdentTypeParams(decl interface{}) string {
if decl == nil {
return ""
}
ts, ok := decl.(*ast.TypeSpec)
if !ok {
return ""
}
if ts.TypeParams == nil || len(ts.TypeParams.List) == 0 {
return ""
}
var sb strings.Builder
sb.WriteString("[")
for i, v := range ts.TypeParams.List {
if i != 0 {
sb.WriteString(", ")
}
sb.WriteString(v.Names[0].Name)
}
sb.WriteString("]")
return sb.String()
}

Просмотреть файл

@ -1,4 +1,4 @@
// Copyright 2019 Google LLC
// Copyright 2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -12,15 +12,25 @@
// See the License for the specific language governing permissions and
// limitations under the License.
// +build !go1.12
//go:build !go1.18
// +build !go1.18
package main
import (
"log"
"go/ast"
"github.com/golang/mock/mockgen/model"
)
func printModuleVersion() {
log.Printf("No version information is available for Mockgen compiled with " +
"version 1.11")
func getTypeSpecTypeParams(ts *ast.TypeSpec) []*ast.Field {
return nil
}
func (p *fileParser) parseGenericType(pkg string, typ ast.Expr, tps map[string]bool) (model.Type, error) {
return nil, nil
}
func getIdentTypeParams(decl interface{}) string {
return ""
}

Просмотреть файл

@ -1,5 +1,7 @@
package const_length
import "math"
//go:generate mockgen -package const_length -destination mock.go -source input.go
const C = 2
@ -7,4 +9,8 @@ const C = 2
type I interface {
Foo() [C]int
Bar() [2]int
Baz() [math.MaxInt8]int
Qux() [1 + 2]int
Quux() [(1 + 2)]int
Corge() [math.MaxInt8 - 120]int
}

Просмотреть файл

@ -47,6 +47,34 @@ func (mr *MockIMockRecorder) Bar() *gomock.Call {
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Bar", reflect.TypeOf((*MockI)(nil).Bar))
}
// Baz mocks base method.
func (m *MockI) Baz() [127]int {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Baz")
ret0, _ := ret[0].([127]int)
return ret0
}
// Baz indicates an expected call of Baz.
func (mr *MockIMockRecorder) Baz() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Baz", reflect.TypeOf((*MockI)(nil).Baz))
}
// Corge mocks base method.
func (m *MockI) Corge() [7]int {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Corge")
ret0, _ := ret[0].([7]int)
return ret0
}
// Corge indicates an expected call of Corge.
func (mr *MockIMockRecorder) Corge() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Corge", reflect.TypeOf((*MockI)(nil).Corge))
}
// Foo mocks base method.
func (m *MockI) Foo() [2]int {
m.ctrl.T.Helper()
@ -60,3 +88,31 @@ func (mr *MockIMockRecorder) Foo() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Foo", reflect.TypeOf((*MockI)(nil).Foo))
}
// Quux mocks base method.
func (m *MockI) Quux() [3]int {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Quux")
ret0, _ := ret[0].([3]int)
return ret0
}
// Quux indicates an expected call of Quux.
func (mr *MockIMockRecorder) Quux() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Quux", reflect.TypeOf((*MockI)(nil).Quux))
}
// Qux mocks base method.
func (m *MockI) Qux() [3]int {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Qux")
ret0, _ := ret[0].([3]int)
return ret0
}
// Qux indicates an expected call of Qux.
func (mr *MockIMockRecorder) Qux() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Qux", reflect.TypeOf((*MockI)(nil).Qux))
}

Просмотреть файл

@ -0,0 +1,21 @@
package generics
import (
"github.com/golang/mock/mockgen/internal/tests/generics/other"
"golang.org/x/exp/constraints"
)
//go:generate mockgen --source=external.go --destination=source/mock_external_test.go --package source
type ExternalConstraint[I constraints.Integer, F constraints.Float] interface {
One(string) string
Two(I) string
Three(I) F
Four(I) Foo[I, F]
Five(I) Baz[F]
Six(I) *Baz[F]
Seven(I) other.One[I]
Eight(F) other.Two[I, F]
Nine(Iface[I])
Ten(*I)
}

Просмотреть файл

@ -0,0 +1,40 @@
package generics
import "github.com/golang/mock/mockgen/internal/tests/generics/other"
//go:generate mockgen --source=generics.go --destination=source/mock_generics_test.go --package source
////go:generate mockgen --destination=reflect/mock_test.go --package reflect . Bar,Bar2
type Bar[T any, R any] interface {
One(string) string
Two(T) string
Three(T) R
Four(T) Foo[T, R]
Five(T) Baz[T]
Six(T) *Baz[T]
Seven(T) other.One[T]
Eight(T) other.Two[T, R]
Nine(Iface[T])
Ten(*T)
Eleven() (*other.One[T], error)
Twelve() (*other.Two[T, R], error)
Thirteen() (Baz[StructType], error)
Fourteen() (*Foo[StructType, StructType2], error)
Fifteen() (Iface[StructType], error)
Sixteen() (Baz[other.Three], error)
Seventeen() (*Foo[other.Three, other.Four], error)
Eighteen() (Iface[*other.Five], error)
Nineteen() AliasType
}
type Foo[T any, R any] struct{}
type Baz[T any] struct{}
type Iface[T any] interface{}
type StructType struct{}
type StructType2 struct{}
type AliasType Baz[other.Three]

Просмотреть файл

@ -0,0 +1,10 @@
module github.com/golang/mock/mockgen/internal/tests/generics
go 1.18
require (
github.com/golang/mock v1.6.0
golang.org/x/exp v0.0.0-20220428152302-39d4317da171
)
replace github.com/golang/mock => ../../../..

Просмотреть файл

@ -0,0 +1,26 @@
github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/exp v0.0.0-20220428152302-39d4317da171 h1:TfdoLivD44QwvssI9Sv1xwa5DcL5XQr4au4sZ2F2NV4=
golang.org/x/exp v0.0.0-20220428152302-39d4317da171/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE=
golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=

Просмотреть файл

@ -0,0 +1,11 @@
package other
type One[T any] struct{}
type Two[T any, R any] struct{}
type Three struct{}
type Four struct{}
type Five interface{}

Просмотреть файл

@ -0,0 +1,173 @@
// Code generated by MockGen. DO NOT EDIT.
// Source: external.go
// Package source is a generated GoMock package.
package source
import (
reflect "reflect"
gomock "github.com/golang/mock/gomock"
generics "github.com/golang/mock/mockgen/internal/tests/generics"
other "github.com/golang/mock/mockgen/internal/tests/generics/other"
constraints "golang.org/x/exp/constraints"
)
// MockExternalConstraint is a mock of ExternalConstraint interface.
type MockExternalConstraint[I constraints.Integer, F constraints.Float] struct {
ctrl *gomock.Controller
recorder *MockExternalConstraintMockRecorder[I, F]
}
// MockExternalConstraintMockRecorder is the mock recorder for MockExternalConstraint.
type MockExternalConstraintMockRecorder[I constraints.Integer, F constraints.Float] struct {
mock *MockExternalConstraint[I, F]
}
// NewMockExternalConstraint creates a new mock instance.
func NewMockExternalConstraint[I constraints.Integer, F constraints.Float](ctrl *gomock.Controller) *MockExternalConstraint[I, F] {
mock := &MockExternalConstraint[I, F]{ctrl: ctrl}
mock.recorder = &MockExternalConstraintMockRecorder[I, F]{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *MockExternalConstraint[I, F]) EXPECT() *MockExternalConstraintMockRecorder[I, F] {
return m.recorder
}
// Eight mocks base method.
func (m *MockExternalConstraint[I, F]) Eight(arg0 F) other.Two[I, F] {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Eight", arg0)
ret0, _ := ret[0].(other.Two[I, F])
return ret0
}
// Eight indicates an expected call of Eight.
func (mr *MockExternalConstraintMockRecorder[I, F]) Eight(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Eight", reflect.TypeOf((*MockExternalConstraint[I, F])(nil).Eight), arg0)
}
// Five mocks base method.
func (m *MockExternalConstraint[I, F]) Five(arg0 I) generics.Baz[F] {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Five", arg0)
ret0, _ := ret[0].(generics.Baz[F])
return ret0
}
// Five indicates an expected call of Five.
func (mr *MockExternalConstraintMockRecorder[I, F]) Five(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Five", reflect.TypeOf((*MockExternalConstraint[I, F])(nil).Five), arg0)
}
// Four mocks base method.
func (m *MockExternalConstraint[I, F]) Four(arg0 I) generics.Foo[I, F] {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Four", arg0)
ret0, _ := ret[0].(generics.Foo[I, F])
return ret0
}
// Four indicates an expected call of Four.
func (mr *MockExternalConstraintMockRecorder[I, F]) Four(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Four", reflect.TypeOf((*MockExternalConstraint[I, F])(nil).Four), arg0)
}
// Nine mocks base method.
func (m *MockExternalConstraint[I, F]) Nine(arg0 generics.Iface[I]) {
m.ctrl.T.Helper()
m.ctrl.Call(m, "Nine", arg0)
}
// Nine indicates an expected call of Nine.
func (mr *MockExternalConstraintMockRecorder[I, F]) Nine(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Nine", reflect.TypeOf((*MockExternalConstraint[I, F])(nil).Nine), arg0)
}
// One mocks base method.
func (m *MockExternalConstraint[I, F]) One(arg0 string) string {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "One", arg0)
ret0, _ := ret[0].(string)
return ret0
}
// One indicates an expected call of One.
func (mr *MockExternalConstraintMockRecorder[I, F]) One(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "One", reflect.TypeOf((*MockExternalConstraint[I, F])(nil).One), arg0)
}
// Seven mocks base method.
func (m *MockExternalConstraint[I, F]) Seven(arg0 I) other.One[I] {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Seven", arg0)
ret0, _ := ret[0].(other.One[I])
return ret0
}
// Seven indicates an expected call of Seven.
func (mr *MockExternalConstraintMockRecorder[I, F]) Seven(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Seven", reflect.TypeOf((*MockExternalConstraint[I, F])(nil).Seven), arg0)
}
// Six mocks base method.
func (m *MockExternalConstraint[I, F]) Six(arg0 I) *generics.Baz[F] {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Six", arg0)
ret0, _ := ret[0].(*generics.Baz[F])
return ret0
}
// Six indicates an expected call of Six.
func (mr *MockExternalConstraintMockRecorder[I, F]) Six(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Six", reflect.TypeOf((*MockExternalConstraint[I, F])(nil).Six), arg0)
}
// Ten mocks base method.
func (m *MockExternalConstraint[I, F]) Ten(arg0 *I) {
m.ctrl.T.Helper()
m.ctrl.Call(m, "Ten", arg0)
}
// Ten indicates an expected call of Ten.
func (mr *MockExternalConstraintMockRecorder[I, F]) Ten(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Ten", reflect.TypeOf((*MockExternalConstraint[I, F])(nil).Ten), arg0)
}
// Three mocks base method.
func (m *MockExternalConstraint[I, F]) Three(arg0 I) F {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Three", arg0)
ret0, _ := ret[0].(F)
return ret0
}
// Three indicates an expected call of Three.
func (mr *MockExternalConstraintMockRecorder[I, F]) Three(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Three", reflect.TypeOf((*MockExternalConstraint[I, F])(nil).Three), arg0)
}
// Two mocks base method.
func (m *MockExternalConstraint[I, F]) Two(arg0 I) string {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Two", arg0)
ret0, _ := ret[0].(string)
return ret0
}
// Two indicates an expected call of Two.
func (mr *MockExternalConstraintMockRecorder[I, F]) Two(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Two", reflect.TypeOf((*MockExternalConstraint[I, F])(nil).Two), arg0)
}

Просмотреть файл

@ -0,0 +1,329 @@
// Code generated by MockGen. DO NOT EDIT.
// Source: generics.go
// Package source is a generated GoMock package.
package source
import (
reflect "reflect"
gomock "github.com/golang/mock/gomock"
generics "github.com/golang/mock/mockgen/internal/tests/generics"
other "github.com/golang/mock/mockgen/internal/tests/generics/other"
)
// MockBar is a mock of Bar interface.
type MockBar[T any, R any] struct {
ctrl *gomock.Controller
recorder *MockBarMockRecorder[T, R]
}
// MockBarMockRecorder is the mock recorder for MockBar.
type MockBarMockRecorder[T any, R any] struct {
mock *MockBar[T, R]
}
// NewMockBar creates a new mock instance.
func NewMockBar[T any, R any](ctrl *gomock.Controller) *MockBar[T, R] {
mock := &MockBar[T, R]{ctrl: ctrl}
mock.recorder = &MockBarMockRecorder[T, R]{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *MockBar[T, R]) EXPECT() *MockBarMockRecorder[T, R] {
return m.recorder
}
// Eight mocks base method.
func (m *MockBar[T, R]) Eight(arg0 T) other.Two[T, R] {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Eight", arg0)
ret0, _ := ret[0].(other.Two[T, R])
return ret0
}
// Eight indicates an expected call of Eight.
func (mr *MockBarMockRecorder[T, R]) Eight(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Eight", reflect.TypeOf((*MockBar[T, R])(nil).Eight), arg0)
}
// Eighteen mocks base method.
func (m *MockBar[T, R]) Eighteen() (generics.Iface[*other.Five], error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Eighteen")
ret0, _ := ret[0].(generics.Iface[*other.Five])
ret1, _ := ret[1].(error)
return ret0, ret1
}
// Eighteen indicates an expected call of Eighteen.
func (mr *MockBarMockRecorder[T, R]) Eighteen() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Eighteen", reflect.TypeOf((*MockBar[T, R])(nil).Eighteen))
}
// Eleven mocks base method.
func (m *MockBar[T, R]) Eleven() (*other.One[T], error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Eleven")
ret0, _ := ret[0].(*other.One[T])
ret1, _ := ret[1].(error)
return ret0, ret1
}
// Eleven indicates an expected call of Eleven.
func (mr *MockBarMockRecorder[T, R]) Eleven() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Eleven", reflect.TypeOf((*MockBar[T, R])(nil).Eleven))
}
// Fifteen mocks base method.
func (m *MockBar[T, R]) Fifteen() (generics.Iface[generics.StructType], error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Fifteen")
ret0, _ := ret[0].(generics.Iface[generics.StructType])
ret1, _ := ret[1].(error)
return ret0, ret1
}
// Fifteen indicates an expected call of Fifteen.
func (mr *MockBarMockRecorder[T, R]) Fifteen() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Fifteen", reflect.TypeOf((*MockBar[T, R])(nil).Fifteen))
}
// Five mocks base method.
func (m *MockBar[T, R]) Five(arg0 T) generics.Baz[T] {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Five", arg0)
ret0, _ := ret[0].(generics.Baz[T])
return ret0
}
// Five indicates an expected call of Five.
func (mr *MockBarMockRecorder[T, R]) Five(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Five", reflect.TypeOf((*MockBar[T, R])(nil).Five), arg0)
}
// Four mocks base method.
func (m *MockBar[T, R]) Four(arg0 T) generics.Foo[T, R] {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Four", arg0)
ret0, _ := ret[0].(generics.Foo[T, R])
return ret0
}
// Four indicates an expected call of Four.
func (mr *MockBarMockRecorder[T, R]) Four(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Four", reflect.TypeOf((*MockBar[T, R])(nil).Four), arg0)
}
// Fourteen mocks base method.
func (m *MockBar[T, R]) Fourteen() (*generics.Foo[generics.StructType, generics.StructType2], error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Fourteen")
ret0, _ := ret[0].(*generics.Foo[generics.StructType, generics.StructType2])
ret1, _ := ret[1].(error)
return ret0, ret1
}
// Fourteen indicates an expected call of Fourteen.
func (mr *MockBarMockRecorder[T, R]) Fourteen() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Fourteen", reflect.TypeOf((*MockBar[T, R])(nil).Fourteen))
}
// Nine mocks base method.
func (m *MockBar[T, R]) Nine(arg0 generics.Iface[T]) {
m.ctrl.T.Helper()
m.ctrl.Call(m, "Nine", arg0)
}
// Nine indicates an expected call of Nine.
func (mr *MockBarMockRecorder[T, R]) Nine(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Nine", reflect.TypeOf((*MockBar[T, R])(nil).Nine), arg0)
}
// Nineteen mocks base method.
func (m *MockBar[T, R]) Nineteen() generics.AliasType {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Nineteen")
ret0, _ := ret[0].(generics.AliasType)
return ret0
}
// Nineteen indicates an expected call of Nineteen.
func (mr *MockBarMockRecorder[T, R]) Nineteen() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Nineteen", reflect.TypeOf((*MockBar[T, R])(nil).Nineteen))
}
// One mocks base method.
func (m *MockBar[T, R]) One(arg0 string) string {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "One", arg0)
ret0, _ := ret[0].(string)
return ret0
}
// One indicates an expected call of One.
func (mr *MockBarMockRecorder[T, R]) One(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "One", reflect.TypeOf((*MockBar[T, R])(nil).One), arg0)
}
// Seven mocks base method.
func (m *MockBar[T, R]) Seven(arg0 T) other.One[T] {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Seven", arg0)
ret0, _ := ret[0].(other.One[T])
return ret0
}
// Seven indicates an expected call of Seven.
func (mr *MockBarMockRecorder[T, R]) Seven(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Seven", reflect.TypeOf((*MockBar[T, R])(nil).Seven), arg0)
}
// Seventeen mocks base method.
func (m *MockBar[T, R]) Seventeen() (*generics.Foo[other.Three, other.Four], error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Seventeen")
ret0, _ := ret[0].(*generics.Foo[other.Three, other.Four])
ret1, _ := ret[1].(error)
return ret0, ret1
}
// Seventeen indicates an expected call of Seventeen.
func (mr *MockBarMockRecorder[T, R]) Seventeen() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Seventeen", reflect.TypeOf((*MockBar[T, R])(nil).Seventeen))
}
// Six mocks base method.
func (m *MockBar[T, R]) Six(arg0 T) *generics.Baz[T] {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Six", arg0)
ret0, _ := ret[0].(*generics.Baz[T])
return ret0
}
// Six indicates an expected call of Six.
func (mr *MockBarMockRecorder[T, R]) Six(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Six", reflect.TypeOf((*MockBar[T, R])(nil).Six), arg0)
}
// Sixteen mocks base method.
func (m *MockBar[T, R]) Sixteen() (generics.Baz[other.Three], error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Sixteen")
ret0, _ := ret[0].(generics.Baz[other.Three])
ret1, _ := ret[1].(error)
return ret0, ret1
}
// Sixteen indicates an expected call of Sixteen.
func (mr *MockBarMockRecorder[T, R]) Sixteen() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Sixteen", reflect.TypeOf((*MockBar[T, R])(nil).Sixteen))
}
// Ten mocks base method.
func (m *MockBar[T, R]) Ten(arg0 *T) {
m.ctrl.T.Helper()
m.ctrl.Call(m, "Ten", arg0)
}
// Ten indicates an expected call of Ten.
func (mr *MockBarMockRecorder[T, R]) Ten(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Ten", reflect.TypeOf((*MockBar[T, R])(nil).Ten), arg0)
}
// Thirteen mocks base method.
func (m *MockBar[T, R]) Thirteen() (generics.Baz[generics.StructType], error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Thirteen")
ret0, _ := ret[0].(generics.Baz[generics.StructType])
ret1, _ := ret[1].(error)
return ret0, ret1
}
// Thirteen indicates an expected call of Thirteen.
func (mr *MockBarMockRecorder[T, R]) Thirteen() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Thirteen", reflect.TypeOf((*MockBar[T, R])(nil).Thirteen))
}
// Three mocks base method.
func (m *MockBar[T, R]) Three(arg0 T) R {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Three", arg0)
ret0, _ := ret[0].(R)
return ret0
}
// Three indicates an expected call of Three.
func (mr *MockBarMockRecorder[T, R]) Three(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Three", reflect.TypeOf((*MockBar[T, R])(nil).Three), arg0)
}
// Twelve mocks base method.
func (m *MockBar[T, R]) Twelve() (*other.Two[T, R], error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Twelve")
ret0, _ := ret[0].(*other.Two[T, R])
ret1, _ := ret[1].(error)
return ret0, ret1
}
// Twelve indicates an expected call of Twelve.
func (mr *MockBarMockRecorder[T, R]) Twelve() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Twelve", reflect.TypeOf((*MockBar[T, R])(nil).Twelve))
}
// Two mocks base method.
func (m *MockBar[T, R]) Two(arg0 T) string {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Two", arg0)
ret0, _ := ret[0].(string)
return ret0
}
// Two indicates an expected call of Two.
func (mr *MockBarMockRecorder[T, R]) Two(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Two", reflect.TypeOf((*MockBar[T, R])(nil).Two), arg0)
}
// MockIface is a mock of Iface interface.
type MockIface[T any] struct {
ctrl *gomock.Controller
recorder *MockIfaceMockRecorder[T]
}
// MockIfaceMockRecorder is the mock recorder for MockIface.
type MockIfaceMockRecorder[T any] struct {
mock *MockIface[T]
}
// NewMockIface creates a new mock instance.
func NewMockIface[T any](ctrl *gomock.Controller) *MockIface[T] {
mock := &MockIface[T]{ctrl: ctrl}
mock.recorder = &MockIfaceMockRecorder[T]{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *MockIface[T]) EXPECT() *MockIfaceMockRecorder[T] {
return m.recorder
}

Просмотреть файл

@ -28,6 +28,7 @@ type Source interface {
ersatz.Embedded
faux.Foreign
error
Foo
}
func CallForeignMethod(s Source) {

Просмотреть файл

@ -35,6 +35,20 @@ func (m *MockSource) EXPECT() *MockSourceMockRecorder {
return m.recorder
}
// Bar mocks base method.
func (m *MockSource) Bar() Baz {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Bar")
ret0, _ := ret[0].(Baz)
return ret0
}
// Bar indicates an expected call of Bar.
func (mr *MockSourceMockRecorder) Bar() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Bar", reflect.TypeOf((*MockSource)(nil).Bar))
}
// Error mocks base method.
func (m *MockSource) Error() string {
m.ctrl.T.Helper()

Просмотреть файл

@ -0,0 +1,6 @@
package bugreport
type Foo interface {
Bar() Baz
}
type Baz interface{}

Просмотреть файл

@ -8,7 +8,7 @@ import (
reflect "reflect"
gomock "github.com/golang/mock/gomock"
mock_in_test_package "github.com/golang/mock/mockgen/internal/tests/mock_in_test_package"
users "github.com/golang/mock/mockgen/internal/tests/mock_in_test_package"
)
// MockFinder is a mock of Finder interface.
@ -35,7 +35,7 @@ func (m *MockFinder) EXPECT() *MockFinderMockRecorder {
}
// Add mocks base method.
func (m *MockFinder) Add(u mock_in_test_package.User) {
func (m *MockFinder) Add(u users.User) {
m.ctrl.T.Helper()
m.ctrl.Call(m, "Add", u)
}
@ -47,10 +47,10 @@ func (mr *MockFinderMockRecorder) Add(u interface{}) *gomock.Call {
}
// FindUser mocks base method.
func (m *MockFinder) FindUser(name string) mock_in_test_package.User {
func (m *MockFinder) FindUser(name string) users.User {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "FindUser", name)
ret0, _ := ret[0].(mock_in_test_package.User)
ret0, _ := ret[0].(users.User)
return ret0
}

Просмотреть файл

@ -1,5 +0,0 @@
module github.com/golang/mock/mockgen/internal/tests/overlapping_methods
go 1.14
require github.com/golang/mock v1.4.4

Просмотреть файл

@ -1,8 +0,0 @@
github.com/golang/mock v1.4.4 h1:l75CXGRSwbaYNpl/Z2X1XIIAMSCquvXgpVZDhwEIJsc=
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=

Просмотреть файл

@ -1,5 +1,3 @@
// +build go1.14
package overlap
type ReadCloser interface {

Просмотреть файл

@ -1,5 +1,3 @@
// +build go1.14
package overlap
//go:generate mockgen -package overlap -destination mock.go -source overlap.go -aux_files github.com/golang/mock/mockgen/internal/tests/overlapping_methods=interfaces.go

Просмотреть файл

@ -1,5 +1,3 @@
// +build go1.14
package overlap
import (

Просмотреть файл

@ -1,3 +1,4 @@
//go:build panictest
// +build panictest
// Copyright 2020 Google LLC

Просмотреть файл

@ -2,9 +2,7 @@ package core
//go:generate mockgen -package core -self_package github.com/golang/mock/mockgen/internal/tests/self_package -destination mock.go github.com/golang/mock/mockgen/internal/tests/self_package Methods
type Info struct {
name string
}
type Info struct{}
type Methods interface {
getInfo() Info

Просмотреть файл

@ -21,6 +21,7 @@ package main
import (
"bytes"
"encoding/json"
"errors"
"flag"
"fmt"
"go/token"
@ -107,19 +108,6 @@ func main() {
return
}
dst := os.Stdout
if len(*destination) > 0 {
if err := os.MkdirAll(filepath.Dir(*destination), os.ModePerm); err != nil {
log.Fatalf("Unable to create directory: %v", err)
}
f, err := os.Create(*destination)
if err != nil {
log.Fatalf("Failed opening destination file: %v", err)
}
defer f.Close()
dst = f
}
outputPackageName := *packageOut
if outputPackageName == "" {
// pkg.Name in reflect mode is the base name of the import path,
@ -136,12 +124,15 @@ func main() {
outputPackagePath := *selfPackage
if outputPackagePath == "" && *destination != "" {
dstPath, err := filepath.Abs(filepath.Dir(*destination))
if err != nil {
log.Fatalf("Unable to determine destination file path: %v", err)
if err == nil {
pkgPath, err := parsePackageImport(dstPath)
if err == nil {
outputPackagePath = pkgPath
} else {
log.Println("Unable to infer -self_package from destination file path:", err)
}
outputPackagePath, err = parsePackageImport(dstPath)
if err != nil {
log.Fatalf("Unable to determine destination file path: %v", err)
} else {
log.Println("Unable to determine destination file path:", err)
}
}
@ -168,7 +159,27 @@ func main() {
if err := g.Generate(pkg, outputPackageName, outputPackagePath); err != nil {
log.Fatalf("Failed generating mock: %v", err)
}
if _, err := dst.Write(g.Output()); err != nil {
output := g.Output()
dst := os.Stdout
if len(*destination) > 0 {
if err := os.MkdirAll(filepath.Dir(*destination), os.ModePerm); err != nil {
log.Fatalf("Unable to create directory: %v", err)
}
existing, err := ioutil.ReadFile(*destination)
if err != nil && !errors.Is(err, os.ErrNotExist) {
log.Fatalf("Failed reading pre-exiting destination file: %v", err)
}
if len(existing) == len(output) && bytes.Compare(existing, output) == 0 {
return
}
f, err := os.Create(*destination)
if err != nil {
log.Fatalf("Failed opening destination file: %v", err)
}
defer f.Close()
dst = f
}
if _, err := dst.Write(output); err != nil {
log.Fatalf("Failed writing to destination: %v", err)
}
}
@ -233,13 +244,6 @@ func (g *generator) out() {
}
}
func removeDot(s string) string {
if len(s) > 0 && s[len(s)-1] == '.' {
return s[0 : len(s)-1]
}
return s
}
// sanitize cleans up a string to make a suitable package name.
func sanitize(s string) string {
t := ""
@ -375,32 +379,58 @@ func (g *generator) mockName(typeName string) string {
return "Mock" + typeName
}
// formattedTypeParams returns a long and short form of type param info used for
// printing. If analyzing a interface with type param [I any, O any] the result
// will be:
// "[I any, O any]", "[I, O]"
func (g *generator) formattedTypeParams(it *model.Interface, pkgOverride string) (string, string) {
if len(it.TypeParams) == 0 {
return "", ""
}
var long, short strings.Builder
long.WriteString("[")
short.WriteString("[")
for i, v := range it.TypeParams {
if i != 0 {
long.WriteString(", ")
short.WriteString(", ")
}
long.WriteString(v.Name)
short.WriteString(v.Name)
long.WriteString(fmt.Sprintf(" %s", v.Type.String(g.packageMap, pkgOverride)))
}
long.WriteString("]")
short.WriteString("]")
return long.String(), short.String()
}
func (g *generator) GenerateMockInterface(intf *model.Interface, outputPackagePath string) error {
mockType := g.mockName(intf.Name)
longTp, shortTp := g.formattedTypeParams(intf, outputPackagePath)
g.p("")
g.p("// %v is a mock of %v interface.", mockType, intf.Name)
g.p("type %v struct {", mockType)
g.p("type %v%v struct {", mockType, longTp)
g.in()
g.p("ctrl *gomock.Controller")
g.p("recorder *%vMockRecorder", mockType)
g.p("recorder *%vMockRecorder%v", mockType, shortTp)
g.out()
g.p("}")
g.p("")
g.p("// %vMockRecorder is the mock recorder for %v.", mockType, mockType)
g.p("type %vMockRecorder struct {", mockType)
g.p("type %vMockRecorder%v struct {", mockType, longTp)
g.in()
g.p("mock *%v", mockType)
g.p("mock *%v%v", mockType, shortTp)
g.out()
g.p("}")
g.p("")
g.p("// New%v creates a new mock instance.", mockType)
g.p("func New%v(ctrl *gomock.Controller) *%v {", mockType, mockType)
g.p("func New%v%v(ctrl *gomock.Controller) *%v%v {", mockType, longTp, mockType, shortTp)
g.in()
g.p("mock := &%v{ctrl: ctrl}", mockType)
g.p("mock.recorder = &%vMockRecorder{mock}", mockType)
g.p("mock := &%v%v{ctrl: ctrl}", mockType, shortTp)
g.p("mock.recorder = &%vMockRecorder%v{mock}", mockType, shortTp)
g.p("return mock")
g.out()
g.p("}")
@ -408,13 +438,13 @@ func (g *generator) GenerateMockInterface(intf *model.Interface, outputPackagePa
// XXX: possible name collision here if someone has EXPECT in their interface.
g.p("// EXPECT returns an object that allows the caller to indicate expected use.")
g.p("func (m *%v) EXPECT() *%vMockRecorder {", mockType, mockType)
g.p("func (m *%v%v) EXPECT() *%vMockRecorder%v {", mockType, shortTp, mockType, shortTp)
g.in()
g.p("return m.recorder")
g.out()
g.p("}")
g.GenerateMockMethods(mockType, intf, outputPackagePath)
g.GenerateMockMethods(mockType, intf, outputPackagePath, shortTp)
return nil
}
@ -425,13 +455,13 @@ func (b byMethodName) Len() int { return len(b) }
func (b byMethodName) Swap(i, j int) { b[i], b[j] = b[j], b[i] }
func (b byMethodName) Less(i, j int) bool { return b[i].Name < b[j].Name }
func (g *generator) GenerateMockMethods(mockType string, intf *model.Interface, pkgOverride string) {
func (g *generator) GenerateMockMethods(mockType string, intf *model.Interface, pkgOverride, shortTp string) {
sort.Sort(byMethodName(intf.Methods))
for _, m := range intf.Methods {
g.p("")
_ = g.GenerateMockMethod(mockType, m, pkgOverride)
_ = g.GenerateMockMethod(mockType, m, pkgOverride, shortTp)
g.p("")
_ = g.GenerateMockRecorderMethod(mockType, m)
_ = g.GenerateMockRecorderMethod(mockType, m, shortTp)
}
}
@ -450,7 +480,7 @@ func makeArgString(argNames, argTypes []string) string {
// GenerateMockMethod generates a mock method implementation.
// If non-empty, pkgOverride is the package in which unqualified types reside.
func (g *generator) GenerateMockMethod(mockType string, m *model.Method, pkgOverride string) error {
func (g *generator) GenerateMockMethod(mockType string, m *model.Method, pkgOverride, shortTp string) error {
argNames := g.getArgNames(m)
argTypes := g.getArgTypes(m, pkgOverride)
argString := makeArgString(argNames, argTypes)
@ -471,7 +501,7 @@ func (g *generator) GenerateMockMethod(mockType string, m *model.Method, pkgOver
idRecv := ia.allocateIdentifier("m")
g.p("// %v mocks base method.", m.Name)
g.p("func (%v *%v) %v(%v)%v {", idRecv, mockType, m.Name, argString, retString)
g.p("func (%v *%v%v) %v(%v)%v {", idRecv, mockType, shortTp, m.Name, argString, retString)
g.in()
g.p("%s.ctrl.T.Helper()", idRecv)
@ -515,7 +545,7 @@ func (g *generator) GenerateMockMethod(mockType string, m *model.Method, pkgOver
return nil
}
func (g *generator) GenerateMockRecorderMethod(mockType string, m *model.Method) error {
func (g *generator) GenerateMockRecorderMethod(mockType string, m *model.Method, shortTp string) error {
argNames := g.getArgNames(m)
var argString string
@ -539,7 +569,7 @@ func (g *generator) GenerateMockRecorderMethod(mockType string, m *model.Method)
idRecv := ia.allocateIdentifier("mr")
g.p("// %v indicates an expected call of %v.", m.Name, m.Name)
g.p("func (%s *%vMockRecorder) %v(%v) *gomock.Call {", idRecv, mockType, m.Name, argString)
g.p("func (%s *%vMockRecorder%v) %v(%v) *gomock.Call {", idRecv, mockType, shortTp, m.Name, argString)
g.in()
g.p("%s.mock.ctrl.T.Helper()", idRecv)
@ -562,7 +592,7 @@ func (g *generator) GenerateMockRecorderMethod(mockType string, m *model.Method)
callArgs = ", " + idVarArgs + "..."
}
}
g.p(`return %s.mock.ctrl.RecordCallWithMethodType(%s.mock, "%s", reflect.TypeOf((*%s)(nil).%s)%s)`, idRecv, idRecv, m.Name, mockType, m.Name, callArgs)
g.p(`return %s.mock.ctrl.RecordCallWithMethodType(%s.mock, "%s", reflect.TypeOf((*%s%s)(nil).%s)%s)`, idRecv, idRecv, m.Name, mockType, shortTp, m.Name, callArgs)
g.out()
g.p("}")

Просмотреть файл

@ -47,6 +47,9 @@ func (pkg *Package) Imports() map[string]bool {
im := make(map[string]bool)
for _, intf := range pkg.Interfaces {
intf.addImports(im)
for _, tp := range intf.TypeParams {
tp.Type.addImports(im)
}
}
return im
}
@ -55,6 +58,7 @@ func (pkg *Package) Imports() map[string]bool {
type Interface struct {
Name string
Methods []*Method
TypeParams []*Parameter
}
// Print writes the interface name and its methods.
@ -261,24 +265,26 @@ func (mt *MapType) addImports(im map[string]bool) {
type NamedType struct {
Package string // may be empty
Type string
TypeParams *TypeParametersType
}
func (nt *NamedType) String(pm map[string]string, pkgOverride string) string {
if pkgOverride == nt.Package {
return nt.Type
return nt.Type + nt.TypeParams.String(pm, pkgOverride)
}
prefix := pm[nt.Package]
if prefix != "" {
return prefix + "." + nt.Type
return prefix + "." + nt.Type + nt.TypeParams.String(pm, pkgOverride)
}
return nt.Type
return nt.Type + nt.TypeParams.String(pm, pkgOverride)
}
func (nt *NamedType) addImports(im map[string]bool) {
if nt.Package != "" {
im[nt.Package] = true
}
nt.TypeParams.addImports(im)
}
// PointerType is a pointer to another type.
@ -297,6 +303,36 @@ type PredeclaredType string
func (pt PredeclaredType) String(map[string]string, string) string { return string(pt) }
func (pt PredeclaredType) addImports(map[string]bool) {}
// TypeParametersType contains type paramters for a NamedType.
type TypeParametersType struct {
TypeParameters []Type
}
func (tp *TypeParametersType) String(pm map[string]string, pkgOverride string) string {
if tp == nil || len(tp.TypeParameters) == 0 {
return ""
}
var sb strings.Builder
sb.WriteString("[")
for i, v := range tp.TypeParameters {
if i != 0 {
sb.WriteString(", ")
}
sb.WriteString(v.String(pm, pkgOverride))
}
sb.WriteString("]")
return sb.String()
}
func (tp *TypeParametersType) addImports(im map[string]bool) {
if tp == nil {
return
}
for _, v := range tp.TypeParameters {
v.addImports(im)
}
}
// The following code is intended to be called by the program generated by ../reflect.go.
// InterfaceFromInterfaceType returns a pointer to an interface for the

Просмотреть файл

@ -22,8 +22,10 @@ import (
"fmt"
"go/ast"
"go/build"
"go/importer"
"go/parser"
"go/token"
"go/types"
"io/ioutil"
"log"
"path"
@ -60,8 +62,8 @@ func sourceMode(source string) (*model.Package, error) {
p := &fileParser{
fileSet: fs,
imports: make(map[string]importedPackage),
importedInterfaces: make(map[string]map[string]*ast.InterfaceType),
auxInterfaces: make(map[string]map[string]*ast.InterfaceType),
importedInterfaces: newInterfaceCache(),
auxInterfaces: newInterfaceCache(),
srcDir: srcDir,
}
@ -125,14 +127,47 @@ func (d duplicateImport) Error() string {
func (d duplicateImport) Path() string { log.Fatal(d.Error()); return "" }
func (d duplicateImport) Parser() *fileParser { log.Fatal(d.Error()); return nil }
type interfaceCache struct {
m map[string]map[string]*namedInterface
}
func newInterfaceCache() *interfaceCache {
return &interfaceCache{
m: make(map[string]map[string]*namedInterface),
}
}
func (i *interfaceCache) Set(pkg, name string, it *namedInterface) {
if _, ok := i.m[pkg]; !ok {
i.m[pkg] = make(map[string]*namedInterface)
}
i.m[pkg][name] = it
}
func (i *interfaceCache) Get(pkg, name string) *namedInterface {
if _, ok := i.m[pkg]; !ok {
return nil
}
return i.m[pkg][name]
}
func (i *interfaceCache) GetASTIface(pkg, name string) *ast.InterfaceType {
if _, ok := i.m[pkg]; !ok {
return nil
}
it, ok := i.m[pkg][name]
if !ok {
return nil
}
return it.it
}
type fileParser struct {
fileSet *token.FileSet
imports map[string]importedPackage // package name => imported package
importedInterfaces map[string]map[string]*ast.InterfaceType // package (or "") => name => interface
importedInterfaces *interfaceCache
auxFiles []*ast.File
auxInterfaces map[string]map[string]*ast.InterfaceType // package (or "") => name => interface
auxInterfaces *interfaceCache
srcDir string
}
@ -166,11 +201,8 @@ func (p *fileParser) parseAuxFiles(auxFiles string) error {
}
func (p *fileParser) addAuxInterfacesFromFile(pkg string, file *ast.File) {
if _, ok := p.auxInterfaces[pkg]; !ok {
p.auxInterfaces[pkg] = make(map[string]*ast.InterfaceType)
}
for ni := range iterInterfaces(file) {
p.auxInterfaces[pkg][ni.name.Name] = ni.it
p.auxInterfaces.Set(pkg, ni.name.Name, ni)
}
}
@ -197,7 +229,7 @@ func (p *fileParser) parseFile(importPath string, file *ast.File) (*model.Packag
var is []*model.Interface
for ni := range iterInterfaces(file) {
i, err := p.parseInterface(ni.name.String(), importPath, ni.it)
i, err := p.parseInterface(ni.name.String(), importPath, ni)
if err != nil {
return nil, err
}
@ -217,8 +249,8 @@ func (p *fileParser) parsePackage(path string) (*fileParser, error) {
newP := &fileParser{
fileSet: token.NewFileSet(),
imports: make(map[string]importedPackage),
importedInterfaces: make(map[string]map[string]*ast.InterfaceType),
auxInterfaces: make(map[string]map[string]*ast.InterfaceType),
importedInterfaces: newInterfaceCache(),
auxInterfaces: newInterfaceCache(),
srcDir: p.srcDir,
}
@ -231,11 +263,8 @@ func (p *fileParser) parsePackage(path string) (*fileParser, error) {
for _, pkg := range pkgs {
file := ast.MergePackageFiles(pkg, ast.FilterFuncDuplicates|ast.FilterUnassociatedComments|ast.FilterImportDuplicates)
if _, ok := newP.importedInterfaces[path]; !ok {
newP.importedInterfaces[path] = make(map[string]*ast.InterfaceType)
}
for ni := range iterInterfaces(file) {
newP.importedInterfaces[path][ni.name.Name] = ni.it
newP.importedInterfaces.Set(path, ni.name.Name, ni)
}
imports, _ := importsOfFile(file)
for pkgName, pkgI := range imports {
@ -245,9 +274,20 @@ func (p *fileParser) parsePackage(path string) (*fileParser, error) {
return newP, nil
}
func (p *fileParser) parseInterface(name, pkg string, it *ast.InterfaceType) (*model.Interface, error) {
func (p *fileParser) parseInterface(name, pkg string, it *namedInterface) (*model.Interface, error) {
iface := &model.Interface{Name: name}
for _, field := range it.Methods.List {
tps := make(map[string]bool)
tp, err := p.parseFieldList(pkg, it.typeParams, tps)
if err != nil {
return nil, fmt.Errorf("unable to parse interface type parameters: %v", name)
}
iface.TypeParams = tp
for _, v := range tp {
tps[v.Name] = true
}
for _, field := range it.it.Methods.List {
switch v := field.Type.(type) {
case *ast.FuncType:
if nn := len(field.Names); nn != 1 {
@ -257,16 +297,16 @@ func (p *fileParser) parseInterface(name, pkg string, it *ast.InterfaceType) (*m
Name: field.Names[0].String(),
}
var err error
m.In, m.Variadic, m.Out, err = p.parseFunc(pkg, v)
m.In, m.Variadic, m.Out, err = p.parseFunc(pkg, v, tps)
if err != nil {
return nil, err
}
iface.AddMethod(m)
case *ast.Ident:
// Embedded interface in this package.
embeddedIfaceType := p.auxInterfaces[pkg][v.String()]
embeddedIfaceType := p.auxInterfaces.Get(pkg, v.String())
if embeddedIfaceType == nil {
embeddedIfaceType = p.importedInterfaces[pkg][v.String()]
embeddedIfaceType = p.importedInterfaces.Get(pkg, v.String())
}
var embeddedIface *model.Interface
@ -281,7 +321,19 @@ func (p *fileParser) parseInterface(name, pkg string, it *ast.InterfaceType) (*m
if v.String() == model.ErrorInterface.Name {
embeddedIface = &model.ErrorInterface
} else {
return nil, p.errorf(v.Pos(), "unknown embedded interface %s", v.String())
ip, err := p.parsePackage(pkg)
if err != nil {
return nil, p.errorf(v.Pos(), "could not parse package %s: %v", pkg, err)
}
if embeddedIfaceType = ip.importedInterfaces.Get(pkg, v.String()); embeddedIfaceType == nil {
return nil, p.errorf(v.Pos(), "unknown embedded interface %s.%s", pkg, v.String())
}
embeddedIface, err = ip.parseInterface(v.String(), pkg, embeddedIfaceType)
if err != nil {
return nil, err
}
}
}
// Copy the methods.
@ -298,7 +350,7 @@ func (p *fileParser) parseInterface(name, pkg string, it *ast.InterfaceType) (*m
var embeddedIface *model.Interface
var err error
embeddedIfaceType := p.auxInterfaces[filePkg][sel]
embeddedIfaceType := p.auxInterfaces.Get(filePkg, sel)
if embeddedIfaceType != nil {
embeddedIface, err = p.parseInterface(sel, filePkg, embeddedIfaceType)
if err != nil {
@ -318,7 +370,7 @@ func (p *fileParser) parseInterface(name, pkg string, it *ast.InterfaceType) (*m
parser: parser,
}
}
if embeddedIfaceType = parser.importedInterfaces[path][sel]; embeddedIfaceType == nil {
if embeddedIfaceType = parser.importedInterfaces.Get(path, sel); embeddedIfaceType == nil {
return nil, p.errorf(v.Pos(), "unknown embedded interface %s.%s", path, sel)
}
embeddedIface, err = parser.parseInterface(sel, path, embeddedIfaceType)
@ -338,26 +390,26 @@ func (p *fileParser) parseInterface(name, pkg string, it *ast.InterfaceType) (*m
return iface, nil
}
func (p *fileParser) parseFunc(pkg string, f *ast.FuncType) (inParam []*model.Parameter, variadic *model.Parameter, outParam []*model.Parameter, err error) {
func (p *fileParser) parseFunc(pkg string, f *ast.FuncType, tps map[string]bool) (inParam []*model.Parameter, variadic *model.Parameter, outParam []*model.Parameter, err error) {
if f.Params != nil {
regParams := f.Params.List
if isVariadic(f) {
n := len(regParams)
varParams := regParams[n-1:]
regParams = regParams[:n-1]
vp, err := p.parseFieldList(pkg, varParams)
vp, err := p.parseFieldList(pkg, varParams, tps)
if err != nil {
return nil, nil, nil, p.errorf(varParams[0].Pos(), "failed parsing variadic argument: %v", err)
}
variadic = vp[0]
}
inParam, err = p.parseFieldList(pkg, regParams)
inParam, err = p.parseFieldList(pkg, regParams, tps)
if err != nil {
return nil, nil, nil, p.errorf(f.Pos(), "failed parsing arguments: %v", err)
}
}
if f.Results != nil {
outParam, err = p.parseFieldList(pkg, f.Results.List)
outParam, err = p.parseFieldList(pkg, f.Results.List, tps)
if err != nil {
return nil, nil, nil, p.errorf(f.Pos(), "failed parsing returns: %v", err)
}
@ -365,7 +417,7 @@ func (p *fileParser) parseFunc(pkg string, f *ast.FuncType) (inParam []*model.Pa
return
}
func (p *fileParser) parseFieldList(pkg string, fields []*ast.Field) ([]*model.Parameter, error) {
func (p *fileParser) parseFieldList(pkg string, fields []*ast.Field, tps map[string]bool) ([]*model.Parameter, error) {
nf := 0
for _, f := range fields {
nn := len(f.Names)
@ -380,7 +432,7 @@ func (p *fileParser) parseFieldList(pkg string, fields []*ast.Field) ([]*model.P
ps := make([]*model.Parameter, nf)
i := 0 // destination index
for _, f := range fields {
t, err := p.parseType(pkg, f.Type)
t, err := p.parseType(pkg, f.Type, tps)
if err != nil {
return nil, err
}
@ -399,33 +451,27 @@ func (p *fileParser) parseFieldList(pkg string, fields []*ast.Field) ([]*model.P
return ps, nil
}
func (p *fileParser) parseType(pkg string, typ ast.Expr) (model.Type, error) {
func (p *fileParser) parseType(pkg string, typ ast.Expr, tps map[string]bool) (model.Type, error) {
switch v := typ.(type) {
case *ast.ArrayType:
ln := -1
if v.Len != nil {
var value string
switch val := v.Len.(type) {
case (*ast.BasicLit):
value = val.Value
case (*ast.Ident):
// when the length is a const
value = val.Obj.Decl.(*ast.ValueSpec).Values[0].(*ast.BasicLit).Value
value, err := p.parseArrayLength(v.Len)
if err != nil {
return nil, err
}
x, err := strconv.Atoi(value)
ln, err = strconv.Atoi(value)
if err != nil {
return nil, p.errorf(v.Len.Pos(), "bad array size: %v", err)
}
ln = x
}
t, err := p.parseType(pkg, v.Elt)
t, err := p.parseType(pkg, v.Elt, tps)
if err != nil {
return nil, err
}
return &model.ArrayType{Len: ln, Type: t}, nil
case *ast.ChanType:
t, err := p.parseType(pkg, v.Value)
t, err := p.parseType(pkg, v.Value, tps)
if err != nil {
return nil, err
}
@ -439,15 +485,15 @@ func (p *fileParser) parseType(pkg string, typ ast.Expr) (model.Type, error) {
return &model.ChanType{Dir: dir, Type: t}, nil
case *ast.Ellipsis:
// assume we're parsing a variadic argument
return p.parseType(pkg, v.Elt)
return p.parseType(pkg, v.Elt, tps)
case *ast.FuncType:
in, variadic, out, err := p.parseFunc(pkg, v)
in, variadic, out, err := p.parseFunc(pkg, v, tps)
if err != nil {
return nil, err
}
return &model.FuncType{In: in, Out: out, Variadic: variadic}, nil
case *ast.Ident:
if v.IsExported() {
if v.IsExported() && !tps[v.Name] {
// `pkg` may be an aliased imported pkg
// if so, patch the import w/ the fully qualified import
maybeImportedPkg, ok := p.imports[pkg]
@ -466,11 +512,11 @@ func (p *fileParser) parseType(pkg string, typ ast.Expr) (model.Type, error) {
}
return model.PredeclaredType("interface{}"), nil
case *ast.MapType:
key, err := p.parseType(pkg, v.Key)
key, err := p.parseType(pkg, v.Key, tps)
if err != nil {
return nil, err
}
value, err := p.parseType(pkg, v.Value)
value, err := p.parseType(pkg, v.Value, tps)
if err != nil {
return nil, err
}
@ -483,7 +529,7 @@ func (p *fileParser) parseType(pkg string, typ ast.Expr) (model.Type, error) {
}
return &model.NamedType{Package: pkg.Path(), Type: v.Sel.String()}, nil
case *ast.StarExpr:
t, err := p.parseType(pkg, v.X)
t, err := p.parseType(pkg, v.X, tps)
if err != nil {
return nil, err
}
@ -494,12 +540,61 @@ func (p *fileParser) parseType(pkg string, typ ast.Expr) (model.Type, error) {
}
return model.PredeclaredType("struct{}"), nil
case *ast.ParenExpr:
return p.parseType(pkg, v.X)
return p.parseType(pkg, v.X, tps)
default:
mt, err := p.parseGenericType(pkg, typ, tps)
if err != nil {
return nil, err
}
if mt == nil {
break
}
return mt, nil
}
return nil, fmt.Errorf("don't know how to parse type %T", typ)
}
func (p *fileParser) parseArrayLength(expr ast.Expr) (string, error) {
switch val := expr.(type) {
case (*ast.BasicLit):
return val.Value, nil
case (*ast.Ident):
// when the length is a const defined locally
return val.Obj.Decl.(*ast.ValueSpec).Values[0].(*ast.BasicLit).Value, nil
case (*ast.SelectorExpr):
// when the length is a const defined in an external package
usedPkg, err := importer.Default().Import(fmt.Sprintf("%s", val.X))
if err != nil {
return "", p.errorf(expr.Pos(), "unknown package in array length: %v", err)
}
ev, err := types.Eval(token.NewFileSet(), usedPkg, token.NoPos, val.Sel.Name)
if err != nil {
return "", p.errorf(expr.Pos(), "unknown constant in array length: %v", err)
}
return ev.Value.String(), nil
case (*ast.ParenExpr):
return p.parseArrayLength(val.X)
case (*ast.BinaryExpr):
x, err := p.parseArrayLength(val.X)
if err != nil {
return "", err
}
y, err := p.parseArrayLength(val.Y)
if err != nil {
return "", err
}
biExpr := fmt.Sprintf("%s%v%s", x, val.Op, y)
tv, err := types.Eval(token.NewFileSet(), nil, token.NoPos, biExpr)
if err != nil {
return "", p.errorf(expr.Pos(), "invalid expression in array length: %v", err)
}
return tv.Value.String(), nil
default:
return "", p.errorf(expr.Pos(), "invalid expression in array length: %v", val)
}
}
// importsOfFile returns a map of package name to import path
// of the imports in file.
func importsOfFile(file *ast.File) (normalImports map[string]importedPackage, dotImports []string) {
@ -564,11 +659,12 @@ func importsOfFile(file *ast.File) (normalImports map[string]importedPackage, do
type namedInterface struct {
name *ast.Ident
it *ast.InterfaceType
typeParams []*ast.Field
}
// Create an iterator over all interfaces in file.
func iterInterfaces(file *ast.File) <-chan namedInterface {
ch := make(chan namedInterface)
func iterInterfaces(file *ast.File) <-chan *namedInterface {
ch := make(chan *namedInterface)
go func() {
for _, decl := range file.Decls {
gd, ok := decl.(*ast.GenDecl)
@ -585,7 +681,7 @@ func iterInterfaces(file *ast.File) <-chan namedInterface {
continue
}
ch <- namedInterface{ts.Name, it}
ch <- &namedInterface{ts.Name, it, getTypeSpecTypeParams(ts)}
}
}
close(ch)
@ -628,4 +724,4 @@ func packageNameOfDir(srcDir string) (string, error) {
return packageImport, nil
}
var errOutsideGoPath = errors.New("Source directory is outside GOPATH")
var errOutsideGoPath = errors.New("source directory is outside GOPATH")

Просмотреть файл

@ -1,7 +1,6 @@
package main
import (
"go/ast"
"go/parser"
"go/token"
"testing"
@ -17,7 +16,7 @@ func TestFileParser_ParseFile(t *testing.T) {
p := fileParser{
fileSet: fs,
imports: make(map[string]importedPackage),
importedInterfaces: make(map[string]map[string]*ast.InterfaceType),
importedInterfaces: newInterfaceCache(),
}
pkg, err := p.parseFile("", file)
@ -48,7 +47,7 @@ func TestFileParser_ParsePackage(t *testing.T) {
p := fileParser{
fileSet: fs,
imports: make(map[string]importedPackage),
importedInterfaces: make(map[string]map[string]*ast.InterfaceType),
importedInterfaces: newInterfaceCache(),
}
newP, err := p.parsePackage("github.com/golang/mock/mockgen/internal/tests/custom_package_name/greeter")
@ -116,14 +115,19 @@ func Benchmark_parseFile(b *testing.B) {
func TestParseArrayWithConstLength(t *testing.T) {
fs := token.NewFileSet()
srcDir := "internal/tests/const_array_length/input.go"
file, err := parser.ParseFile(fs, "internal/tests/const_array_length/input.go", nil, 0)
file, err := parser.ParseFile(fs, srcDir, nil, 0)
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}
p := fileParser{
fileSet: fs,
imports: make(map[string]importedPackage),
importedInterfaces: newInterfaceCache(),
auxInterfaces: newInterfaceCache(),
srcDir: srcDir,
}
pkg, err := p.parseFile("", file)
@ -131,9 +135,11 @@ func TestParseArrayWithConstLength(t *testing.T) {
t.Fatalf("Unexpected error: %v", err)
}
expect := "[2]int"
got := pkg.Interfaces[0].Methods[0].Out[0].Type.String(nil, "")
if got != expect {
t.Fatalf("got %v; expected %v", got, expect)
expects := []string{"[2]int", "[2]int", "[127]int", "[3]int", "[3]int", "[7]int"}
for i, e := range expects {
got := pkg.Interfaces[0].Methods[i].Out[0].Type.String(nil, "")
if got != e {
t.Fatalf("got %v; expected %v", got, e)
}
}
}

Просмотреть файл

@ -20,7 +20,9 @@ import (
"bytes"
"encoding/gob"
"flag"
"fmt"
"go/build"
"io"
"io/ioutil"
"log"
"os"
@ -159,11 +161,18 @@ func runInDir(program []byte, dir string) (*model.Package, error) {
cmdArgs = append(cmdArgs, "-o", progBinary, progSource)
// Build the program.
buf := bytes.NewBuffer(nil)
cmd := exec.Command("go", cmdArgs...)
cmd.Dir = tmpDir
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd.Stderr = io.MultiWriter(os.Stderr, buf)
if err := cmd.Run(); err != nil {
sErr := buf.String()
if strings.Contains(sErr, `cannot find package "."`) &&
strings.Contains(sErr, "github.com/golang/mock/mockgen/model") {
fmt.Fprint(os.Stderr, "Please reference the steps in the README to fix this error:\n\thttps://github.com/golang/mock#reflect-vendoring-error.\n")
return nil, err
}
return nil, err
}

Просмотреть файл

@ -1,4 +1,4 @@
// Copyright 2019 Google LLC
// Copyright 2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -11,9 +11,6 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// +build go1.12
package main
@ -31,5 +28,4 @@ func printModuleVersion() {
"GO111MODULE=on when running 'go get' in order to use specific " +
"version of the binary.")
}
}

Просмотреть файл

@ -10,7 +10,7 @@ interface that can be mocked with GoMock. The interesting files are:
interfaces from `user.go` are used. This demonstrates how to create mock
objects, set up expectations, and so on.
* `mock_user/mock_user.go`: The generated mock code. See ../gomock/matchers.go
* `mock_user_test.go`: The generated mock code. See ../gomock/matchers.go
for the `go:generate` command used to generate it.
To run the test,

Просмотреть файл

@ -4,6 +4,7 @@ import (
"testing"
"context"
"github.com/golang/mock/gomock"
mock "github.com/golang/mock/sample/concurrent/mock"
@ -23,10 +24,11 @@ func call(ctx context.Context, m Math) (int, error) {
}
}
// testConcurrentFails is expected to fail (and is disabled). It
// TestConcurrentFails is expected to fail (and is disabled). It
// demonstrates how to use gomock.WithContext to interrupt the test
// from a different goroutine.
func testConcurrentFails(t *testing.T) {
func TestConcurrentFails(t *testing.T) {
t.Skip("Test is expected to fail, remove skip to trying running yourself.")
ctrl, ctx := gomock.WithContext(context.Background(), t)
defer ctrl.Finish()
m := mock.NewMockMath(ctrl)

Просмотреть файл

@ -1,8 +1,8 @@
// Code generated by MockGen. DO NOT EDIT.
// Source: github.com/golang/mock/sample (interfaces: Index,Embed,Embedded)
// Package mock_sample is a generated GoMock package.
package mock_sample
// Package user_test is a generated GoMock package.
package user_test
import (
bufio "bufio"

Просмотреть файл

@ -1,11 +1,12 @@
// Package user is an example package with an interface.
package user
//go:generate mockgen -destination mock_user/mock_user.go github.com/golang/mock/sample Index,Embed,Embedded
//go:generate mockgen -destination mock_user_test.go -package user_test github.com/golang/mock/sample Index,Embed,Embedded
// Random bunch of imports to test mockgen.
import "io"
import (
"io"
btz "bytes"
"hash"
"log"
@ -14,16 +15,21 @@ import (
// Two imports with the same base name.
t1 "html/template"
t2 "text/template"
"github.com/golang/mock/sample/imp1"
// Dependencies outside the standard library.
renamed2 "github.com/golang/mock/sample/imp2"
. "github.com/golang/mock/sample/imp3"
imp_four "github.com/golang/mock/sample/imp4"
)
// Dependencies outside the standard library.
import (
"github.com/golang/mock/sample/imp1"
renamed2 "github.com/golang/mock/sample/imp2"
. "github.com/golang/mock/sample/imp3"
"github.com/golang/mock/sample/imp4" // calls itself "imp_four"
)
// calls itself "imp_four"
// A bizarre interface to test corner cases in mockgen.
// This would normally be in its own file or package,

Просмотреть файл

@ -7,14 +7,13 @@ import (
"github.com/golang/mock/gomock"
user "github.com/golang/mock/sample"
"github.com/golang/mock/sample/imp1"
mock_user "github.com/golang/mock/sample/mock_user"
)
func TestRemember(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
mockIndex := mock_user.NewMockIndex(ctrl)
mockIndex := NewMockIndex(ctrl)
mockIndex.EXPECT().Put("a", 1) // literals work
mockIndex.EXPECT().Put("b", gomock.Eq(2)) // matchers work too
@ -67,14 +66,14 @@ func TestVariadicFunction(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
mockIndex := mock_user.NewMockIndex(ctrl)
mockIndex := NewMockIndex(ctrl)
mockIndex.EXPECT().Ellip("%d", 5, 6, 7, 8).Do(func(format string, nums ...int) {
sum := 0
for _, value := range nums {
sum += value
}
if sum != 26 {
t.Errorf("Expected 7, got %d", sum)
t.Errorf("Expected 26, got %d", sum)
}
})
mockIndex.EXPECT().Ellip("%d", gomock.Any()).Do(func(format string, nums ...int) {
@ -83,7 +82,7 @@ func TestVariadicFunction(t *testing.T) {
sum += value
}
if sum != 10 {
t.Errorf("Expected 7, got %d", sum)
t.Errorf("Expected 10, got %d", sum)
}
})
mockIndex.EXPECT().Ellip("%d", gomock.Any()).Do(func(format string, nums ...int) {
@ -125,7 +124,7 @@ func TestGrabPointer(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
mockIndex := mock_user.NewMockIndex(ctrl)
mockIndex := NewMockIndex(ctrl)
mockIndex.EXPECT().Ptr(gomock.Any()).SetArg(0, 7) // set first argument to 7
i := user.GrabPointer(mockIndex)
@ -138,7 +137,7 @@ func TestEmbeddedInterface(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
mockEmbed := mock_user.NewMockEmbed(ctrl)
mockEmbed := NewMockEmbed(ctrl)
mockEmbed.EXPECT().RegularMethod()
mockEmbed.EXPECT().EmbeddedMethod()
mockEmbed.EXPECT().ForeignEmbeddedMethod()
@ -155,7 +154,7 @@ func TestExpectTrueNil(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
mockIndex := mock_user.NewMockIndex(ctrl)
mockIndex := NewMockIndex(ctrl)
mockIndex.EXPECT().Ptr(nil) // this nil is a nil interface{}
mockIndex.Ptr(nil) // this nil is a nil *int
}
@ -165,12 +164,11 @@ func TestDoAndReturnSignature(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
mockIndex := mock_user.NewMockIndex(ctrl)
mockIndex := NewMockIndex(ctrl)
mockIndex.EXPECT().Slice(gomock.Any(), gomock.Any()).DoAndReturn(
func(_ []int, _ []byte) {
return
})
func(_ []int, _ []byte) {},
)
defer func() {
if r := recover(); r == nil {
@ -185,7 +183,7 @@ func TestDoAndReturnSignature(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
mockIndex := mock_user.NewMockIndex(ctrl)
mockIndex := NewMockIndex(ctrl)
mockIndex.EXPECT().Slice(gomock.Any(), gomock.Any()).DoAndReturn(
func(_ []int, _ []byte) bool {