Skip to content
This repository was archived by the owner on Jun 27, 2023. It is now read-only.

Implement OverridableController to allow for mock overrides #686

Open
wants to merge 17 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 12 additions & 13 deletions .github/workflows/test.yaml
Original file line number Diff line number Diff line change
@@ -1,27 +1,32 @@
name: Run tests
on:
push:
branches: [main]
branches: ['*']
pull_request:
branches: [main]
branches: ['*']

permissions:
contents: read

env:
GO111MODULE: on

jobs:
test:
strategy:
matrix:
go-version: [1.15.x, 1.18.x]
go-version: [1.19.x, 1.20.x]
os: [ubuntu-latest]
runs-on: ${{ matrix.os }}
steps:

- name: Install Go
uses: actions/setup-go@v2
uses: actions/setup-go@v4
with:
go-version: ${{ matrix.go-version }}

- name: Checkout code
uses: actions/checkout@v2
uses: actions/checkout@v3

- name: Vet and build
run: |
Expand All @@ -30,23 +35,17 @@ jobs:

- name: Install mockgen
run: |
go install github.com/golang/mock/mockgen
go install go.uber.org/mock/mockgen

- name: Run test script
run: |
./ci/test.sh
./ci/check_panic_handling.sh

- name: Run Go tests all
if: ${{ startsWith(matrix.go-version, '1.18') }}
- name: Run Tests
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 ./...
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Changelog
All notable changes to this project will be documented in this file.

This project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).

## 0.1.0 (29 Jun 2023)

This is a minor version that mirrors the original golang/mock
project that this project originates from.

Any users on golang/mock project should be able to migrate to
this project as-is, and expect exact same set of features (apart
from supported Go versions. See [README](README.md#supported-go-versions)
for more details.
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ First off, thank you for taking an interest to contribute to this project!

## Opening issues

When opening a [new issue](https://github.com/golang/mock/issues/new/choose)
When opening a [new issue](https://github.com/uber/mock/issues/new/choose)
please:

1. Make sure there are not other open/closed issues asking/reporting/requesting
Expand Down
5 changes: 5 additions & 0 deletions MAINTAINERS
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# This is the current list of maintainers to Uber's fork of gomock repository.

Sung Yoon Whang <[email protected]>
Ryan Hang <[email protected]>
Zhongpeng Lin <[email protected]>
58 changes: 14 additions & 44 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,30 +6,21 @@ gomock is a mocking framework for the [Go programming language][golang]. It
integrates well with Go's built-in `testing` package, but can be used in other
contexts too.

## Installation
This project originates from Google's `golang/mock` repo. Unfortunately Google
no longer maintains this project, and given the heavy usage of gomock project
within Uber, we've decided to fork and maintain this going forward at Uber.

Once you have [installed Go][golang-install], install the `mockgen` tool.
Contributions are welcome in the form of GitHub issue or PR!

**Note**: If you have not done so already be sure to add `$GOPATH/bin` to your
`PATH`.
## Status

To get the latest released version use:
This project is still WIP. We will be tagging a release shortly, in early July.

### Go version < 1.16
## Supported Go Versions

```bash
GO111MODULE=on go get github.com/golang/mock/[email protected]
```

### Go 1.16+

```bash
go install github.com/golang/mock/[email protected]
```

If you use `mockgen` in your CI pipeline, it may be more appropriate to fixate
on a specific mockgen version. You should try to keep the library in sync with
the version of mockgen used to generate your mocks.
go.uber.org/mock supports all Go versions supported by the official
[Go Release Policy](https://go.dev/doc/devel/release#policy). That is,
the two most recent releases of Go.

## Running mockgen

Expand Down Expand Up @@ -250,28 +241,7 @@ If the received value is `3`, then it will be printed as `03`.

[golang]: http://golang.org/
[golang-install]: http://golang.org/doc/install.html#releases
[gomock-reference]: https://pkg.go.dev/github.com/golang/mock/gomock
[ci-badge]: https://github.com/golang/mock/actions/workflows/test.yaml/badge.svg
[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).
[ci-badge]: https://github.com/uber/mock/actions/workflows/test.yaml/badge.svg
[ci-runs]: https://github.com/uber/mock/actions
[reference-badge]: https://pkg.go.dev/badge/github.com/uber/mock.svg
[reference]: https://pkg.go.dev/github.com/uber/mock
10 changes: 8 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
module github.com/golang/mock
module go.uber.org/mock

go 1.19

require (
golang.org/x/mod v0.5.1
golang.org/x/tools v0.1.8
)

go 1.15
require (
github.com/yuin/goldmark v1.4.1 // indirect
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654 // indirect
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
)
19 changes: 0 additions & 19 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,29 +1,10 @@
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/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-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 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.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 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=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
55 changes: 53 additions & 2 deletions gomock/callset.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,19 @@ import (
"bytes"
"errors"
"fmt"
"sync"
)

// callSet represents a set of expected calls, indexed by receiver and method
// name.
type callSet struct {
// Calls that are still expected.
expected map[callSetKey][]*Call
expected map[callSetKey][]*Call
expectedMu *sync.Mutex
// Calls that have been exhausted.
exhausted map[callSetKey][]*Call
// when set to true, existing call expectations are overridden when new call expectations are made
allowOverride bool
}

// callSetKey is the key in the maps in callSet
Expand All @@ -36,22 +40,47 @@ type callSetKey struct {
}

func newCallSet() *callSet {
return &callSet{make(map[callSetKey][]*Call), make(map[callSetKey][]*Call)}
return &callSet{
expected: make(map[callSetKey][]*Call),
expectedMu: &sync.Mutex{},
exhausted: make(map[callSetKey][]*Call),
}
}

func newOverridableCallSet() *callSet {
return &callSet{
expected: make(map[callSetKey][]*Call),
expectedMu: &sync.Mutex{},
exhausted: make(map[callSetKey][]*Call),
allowOverride: true,
}
}

// Add adds a new expected call.
func (cs callSet) Add(call *Call) {
key := callSetKey{call.receiver, call.method}

cs.expectedMu.Lock()
defer cs.expectedMu.Unlock()

m := cs.expected
if call.exhausted() {
m = cs.exhausted
}
if cs.allowOverride {
m[key] = make([]*Call, 0)
}

m[key] = append(m[key], call)
}

// Remove removes an expected call.
func (cs callSet) Remove(call *Call) {
key := callSetKey{call.receiver, call.method}

cs.expectedMu.Lock()
defer cs.expectedMu.Unlock()

calls := cs.expected[key]
for i, c := range calls {
if c == call {
Expand All @@ -67,6 +96,9 @@ func (cs callSet) Remove(call *Call) {
func (cs callSet) FindMatch(receiver interface{}, method string, args []interface{}) (*Call, error) {
key := callSetKey{receiver, method}

cs.expectedMu.Lock()
defer cs.expectedMu.Unlock()

// Search through the expected calls.
expected := cs.expected[key]
var callsErrors bytes.Buffer
Expand Down Expand Up @@ -101,6 +133,9 @@ func (cs callSet) FindMatch(receiver interface{}, method string, args []interfac

// Failures returns the calls that are not satisfied.
func (cs callSet) Failures() []*Call {
cs.expectedMu.Lock()
defer cs.expectedMu.Unlock()

failures := make([]*Call, 0, len(cs.expected))
for _, calls := range cs.expected {
for _, call := range calls {
Expand All @@ -111,3 +146,19 @@ func (cs callSet) Failures() []*Call {
}
return failures
}

// Satisfied returns true in case all expected calls in this callSet are satisfied.
func (cs callSet) Satisfied() bool {
cs.expectedMu.Lock()
defer cs.expectedMu.Unlock()

for _, calls := range cs.expected {
for _, call := range calls {
if !call.satisfied() {
return false
}
}
}

return true
}
20 changes: 19 additions & 1 deletion gomock/callset_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,24 @@ func TestCallSetAdd(t *testing.T) {
}
}

func TestCallSetAdd_WhenOverridable_ClearsPreviousExpectedAndExhausted(t *testing.T) {
method := "TestMethod"
var receiver interface{} = "TestReceiver"
cs := newOverridableCallSet()

cs.Add(newCall(t, receiver, method, reflect.TypeOf(receiverType{}.Func)))
numExpectedCalls := len(cs.expected[callSetKey{receiver, method}])
if numExpectedCalls != 1 {
t.Fatalf("Expected 1 expected call in callset, got %d", numExpectedCalls)
}

cs.Add(newCall(t, receiver, method, reflect.TypeOf(receiverType{}.Func)))
newNumExpectedCalls := len(cs.expected[callSetKey{receiver, method}])
if newNumExpectedCalls != 1 {
t.Fatalf("Expected 1 expected call in callset, got %d", newNumExpectedCalls)
}
}

func TestCallSetRemove(t *testing.T) {
method := "TestMethod"
var receiver interface{} = "TestReceiver"
Expand Down Expand Up @@ -77,7 +95,7 @@ func TestCallSetRemove(t *testing.T) {

func TestCallSetFindMatch(t *testing.T) {
t.Run("call is exhausted", func(t *testing.T) {
cs := callSet{}
cs := newCallSet()
var receiver interface{} = "TestReceiver"
method := "TestMethod"
args := []interface{}{}
Expand Down
Loading