4

You can find the code I'm working on at: https://github.com/bigblind/marvin

gometalinter is giving me the following error from go vet:

accounts/interactors/accounts_test.go:16::error: literal copies lock value from ma: github.com/bigblind/marvin/accounts.MockAccountStore contains github.com/bigblind/marvin/vendor/github.com/stretchr/testify/mock.Mock contains sync.Mutex (vet)

If you're not familiar with gometalinter, that shouldn't matter, it just runs other tools, including go vet.

So here's the code from accounts/interactors/accounts_test.go:16 with surrounding lines for context:

ma := accounts.NewMockAccountStore()
ma.On("SaveAccount", mock.AnythingOfType("Account")).Return(nil)
ca := CreateAccount{ma}

Line 16 is the last line of the snippet above. We're taking the result of accounts.NewMockAccountStore() and putting it in the first field of a newCreateAccount` struct.

Here's what MockAccountStore looks like:

type MockAccountStore struct {
    *mock.Mock
}

func NewMockAccountStore() *MockAccountStore {
    mo := mock.Mock{}
    ma := MockAccountStore{&mo}
    return &ma
}

As you can see here, I'm using pointers a lot. NewMockAccountStore returns a pointer to MockAccountStore, and the MockAccountStore contains a pointer to a mock.Mock.

So when I put this newly created MockAccountStore in my CreateAccount sturct, I'd expect that to basically just assign the pointer to that field, without copying anything.

Finally, let's have a look at the CreateAccount struct:

type CreateAccount struct {
    AccountStore domain.AccountStore
}

So CreateAccount has just one field for storing a domain.AccountStore. domain.AccountStore is an interface, which MockAccountStore implements.

The only explanation I can come up with is that assigning to a field that has an interface type somehow causes copying, but I'm not sure why, since as far as I'm aware, an interface value is just a pointer to the underlying type.

Can anyone explain to me why go vet is complaining?


Looks like I'm not actually copying.

I've changed my code as follows:

ma := accounts.NewMockAccountStore()
ma.On("SaveAccount", mock.AnythingOfType("Account")).Return(nil)
s := fmt.Sprintf("Initial %#v\n", ma)
ca := CreateAccount{ma}
panic(s + fmt.Sprintf("assigned: %#v", ca.AccountStore))

When the test containing this code runs, I get the following panic message:

Initial &accounts.MockAccountStore{Mock:(*mock.Mock)(0xc420019780)} assigned: &accounts.MockAccountStore{Mock:(*mock.Mock)(0xc420019780)}

As you can see, both values point to the same mock.Mock pointer (0xc420019780).

So how do I tell go vet that?


At @putu's request, here's the command output of accounts/interactors:

vet: accounts/interactors/accounts_test.go:8:2: could not import github.com/stretchr/testify/require (can't find import: github.com/bigblind/marvin/vendor/github.com/stretchr/testify/require)
Checking file accounts/interactors/accounts.go
Checking file accounts/interactors/login.go
Checking file accounts/interactors/accounts_test.go
accounts/interactors/accounts_test.go:15: literal copies lock value from ma: github.com/bigblind/marvin/accounts.MockAccountStore contains github.com/bigblind/marvin/vendor/github.com/stretchr/testify/mock.Mock contains sync.Mutex
accounts/interactors/accounts_test.go:28: literal copies lock value from ma: github.com/bigblind/marvin/accounts.MockAccountStore contains github.com/bigblind/marvin/vendor/github.com/stretchr/testify/mock.Mock contains sync.Mutex
accounts/interactors/accounts_test.go:35: github.com/bigblind/marvin/accounts/domain.Account composite literal uses unkeyed fields
accounts/interactors/accounts_test.go:40: literal copies lock value from ma: github.com/bigblind/marvin/accounts.MockAccountStore contains github.com/bigblind/marvin/vendor/github.com/stretchr/testify/mock.Mock contains sync.Mutex
Checking file accounts/interactors/login_test.go
accounts/interactors/login_test.go:22: literal copies lock value from ma: github.com/bigblind/marvin/accounts.MockAccountStore contains github.com/bigblind/marvin/vendor/github.com/stretchr/testify/mock.Mock contains sync.Mutex
accounts/interactors/login_test.go:36: literal copies lock value from ma: github.com/bigblind/marvin/accounts.MockAccountStore contains github.com/bigblind/marvin/vendor/github.com/stretchr/testify/mock.Mock contains sync.Mutex
accounts/interactors/login_test.go:47: literal copies lock value from ma: github.com/bigblind/marvin/accounts.MockAccountStore contains github.com/bigblind/marvin/vendor/github.com/stretchr/testify/mock.Mock contains sync.Mutex
accounts/interactors/login_test.go:58: literal copies lock value from ma: github.com/bigblind/marvin/accounts.MockAccountStore contains github.com/bigblind/marvin/vendor/github.com/stretchr/testify/mock.Mock contains sync.Mutex
accounts/interactors/login_test.go:70: literal copies lock value from ma: github.com/bigblind/marvin/accounts.MockAccountStore contains github.com/bigblind/marvin/vendor/github.com/stretchr/testify/mock.Mock contains sync.Mutex
accounts/interactors/login_test.go:80: literal copies lock value from ma: github.com/bigblind/marvin/accounts.MockAccountStore contains github.com/bigblind/marvin/vendor/github.com/stretchr/testify/mock.Mock contains sync.Mutex
bigblind
  • 12,539
  • 14
  • 68
  • 123
  • If `MockAccountStore` implements the interface as opposed to `*MockAccountStore`, the interface value contains a pointer to a copy of the `MockAccountStore` value. Could that be the problem? – Andy Schweig Jul 13 '17 at 14:49
  • Wel actually, *MockAccountStore implements the interface. All receivers are pointer receivers. – bigblind Jul 13 '17 at 14:51
  • What is the output of `go tool vet -v -all accounts/interactors`? I'm creating a test package based on your description, then run `go vet ...`, and I got no errors. – putu Jul 13 '17 at 15:37
  • I've added the command output to my question – bigblind Jul 13 '17 at 15:43
  • The code is now online: https://github.com/bigblind/marvin – bigblind Jul 13 '17 at 16:06
  • I ran `go tool vet -v -all accounts/interactors`, and the output was no error. Perhaps you need to upgrade your `go vet` tool. – putu Jul 13 '17 at 17:01
  • Hmm weird. I'm not sure how you can update individual tools. I'm running Go 1.8.3, which is the latest version. I'm currently creating a small package to try and isolate the problem outside of the project – bigblind Jul 13 '17 at 17:26
  • What is the output of `which vet` command? Just a wild guess, maybe there are more than one `vet` binary. Usually the tool is under `$GOROOT/pkg/tool/OS_ARCH/` – putu Jul 13 '17 at 17:47
  • I don't actually have vet in my PATH, but when I run `go vet -x ./..`, I see the following binary being run on each file: `/usr/local/go/pkg/tool/darwin_amd64/vet`. I see this for both the marvin package, and a test package where I have the exact same setup of assigning a struct containing a Mock to another struct, on a field with an interface type. On the test repo, I can't reproduce the problem. I'm wondering whether my use of go dep is doing something weir. Maybe it's 2 different versions of testify. – bigblind Jul 13 '17 at 18:09

0 Answers0