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

Commit

Permalink
deduplicate methods to allow overlapping methods on embedded interfac…
Browse files Browse the repository at this point in the history
…es (#498)
  • Loading branch information
marten-seemann authored Jan 28, 2021
1 parent 872e315 commit b9a8584
Show file tree
Hide file tree
Showing 12 changed files with 176 additions and 12 deletions.
7 changes: 6 additions & 1 deletion .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,9 @@ jobs:
./ci/check_panic_handling.sh
- name: Run Go tests
run: go test -v ./...
run: |
for i in $(find $PWD -name go.mod); do
pushd $(dirname $i)
go test ./...
popd
done
8 changes: 7 additions & 1 deletion ci/check_go_generate.sh
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,13 @@ trap cleanup EXIT

cp -r . "${TEMP_DIR}/"
cd $TEMP_DIR
go generate ./...

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."
Expand Down
6 changes: 5 additions & 1 deletion ci/check_go_mod.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@

set -euo pipefail

go mod tidy
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
Expand Down
5 changes: 5 additions & 0 deletions mockgen/internal/tests/overlapping_methods/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module github.com/golang/mock/mockgen/internal/tests/overlapping_methods

go 1.14

require github.com/golang/mock v1.4.4
8 changes: 8 additions & 0 deletions mockgen/internal/tests/overlapping_methods/go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
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=
13 changes: 13 additions & 0 deletions mockgen/internal/tests/overlapping_methods/interfaces.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// +build go1.14

package overlap

type ReadCloser interface {
Read([]byte) (int, error)
Close() error
}

type WriteCloser interface {
Write([]byte) (int, error)
Close() error
}
78 changes: 78 additions & 0 deletions mockgen/internal/tests/overlapping_methods/mock.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 9 additions & 0 deletions mockgen/internal/tests/overlapping_methods/overlap.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// +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
type ReadWriteCloser interface {
ReadCloser
WriteCloser
}
21 changes: 21 additions & 0 deletions mockgen/internal/tests/overlapping_methods/overlap_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// +build go1.14

package overlap

import (
"errors"
"testing"

gomock "github.com/golang/mock/gomock"
)

// TestValidInterface assesses whether or not the generated mock is valid
func TestValidInterface(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()

s := NewMockReadWriteCloser(ctrl)
s.EXPECT().Close().Return(errors.New("test"))

s.Close()
}
10 changes: 6 additions & 4 deletions mockgen/mockgen_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -237,10 +237,12 @@ func TestGenerateMockInterface_Helper(t *testing.T) {
}
}

if err := g.GenerateMockInterface(&model.Interface{
Name: "Somename",
Methods: test.Methods,
}, "somepackage"); err != nil {
intf := &model.Interface{Name: "Somename"}
for _, m := range test.Methods {
intf.AddMethod(m)
}

if err := g.GenerateMockInterface(intf, "somepackage"); err != nil {
t.Fatal(err)
}

Expand Down
12 changes: 11 additions & 1 deletion mockgen/model/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,16 @@ func (intf *Interface) addImports(im map[string]bool) {
}
}

// AddMethod adds a new method, deduplicating by method name.
func (intf *Interface) AddMethod(m *Method) {
for _, me := range intf.Methods {
if me.Name == m.Name {
return
}
}
intf.Methods = append(intf.Methods, m)
}

// Method is a single method of an interface.
type Method struct {
Name string
Expand Down Expand Up @@ -311,7 +321,7 @@ func InterfaceFromInterfaceType(it reflect.Type) (*Interface, error) {
return nil, err
}

intf.Methods = append(intf.Methods, m)
intf.AddMethod(m)
}

return intf, nil
Expand Down
11 changes: 7 additions & 4 deletions mockgen/parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,7 @@ func (p *fileParser) parseInterface(name, pkg string, it *ast.InterfaceType) (*m
if err != nil {
return nil, err
}
intf.Methods = append(intf.Methods, m)
intf.AddMethod(m)
case *ast.Ident:
// Embedded interface in this package.
ei := p.auxInterfaces[pkg][v.String()]
Expand All @@ -291,8 +291,9 @@ func (p *fileParser) parseInterface(name, pkg string, it *ast.InterfaceType) (*m
}
}
// Copy the methods.
// TODO: apply shadowing rules.
intf.Methods = append(intf.Methods, eintf.Methods...)
for _, m := range eintf.Methods {
intf.AddMethod(m)
}
case *ast.SelectorExpr:
// Embedded interface in another package.
fpkg, sel := v.X.(*ast.Ident).String(), v.Sel.String()
Expand Down Expand Up @@ -333,7 +334,9 @@ func (p *fileParser) parseInterface(name, pkg string, it *ast.InterfaceType) (*m
}
// Copy the methods.
// TODO: apply shadowing rules.
intf.Methods = append(intf.Methods, eintf.Methods...)
for _, m := range eintf.Methods {
intf.AddMethod(m)
}
default:
return nil, fmt.Errorf("don't know how to mock method of type %T", field.Type)
}
Expand Down

0 comments on commit b9a8584

Please sign in to comment.