I don't trust or support Microsoft. I've weight the options and decided to move hel to sr.ht. Please submit issues and pull requests there.
No more releases will be made on github.
See the main repo's README.md for details about hel!
Hel rules over Helheim, where the souls unworthy of Valhalla reside. It's also a mock generator for Go.
License: The Unlicense
I don't trust or support Microsoft. I've weight the options and decided to move hel to sr.ht. Please submit issues and pull requests there.
No more releases will be made on github.
See the main repo's README.md for details about hel!
We are trying to land the mock in a package other than where the interface is defined.
my_interface.go
package xyz
//go:generate hel -o ../anotherpackage/mock_my_test.go -t MyInterface
type MyInterface interface {
DoSomething() (err error)
}
This is a pretty important note - hel has thus far been assuming that tests can only be in the test package or the non-test package, not both. Turns out that's an invalid assumption.
It'd be nice to 'opt-out' of generating some interfaces with something like
hel: no
Heh, or whatever
Our local package name logic is working in most cases, but I've just encountered a case where chan (chan<- LocalType)
does not have the local name prepended.
Function takes two parameters of the same type and share the type specifier. First parameter in input struct is lowercase but referenced as uppercase throughout rest of mock.
Looks like the drone link you have is deprecated.
We usually don't want to generate mocks for interface types in other packages, to help reduce the urge to use massive interface types as the source of truth for what a type can do. However, there's an exception to this:
// foo/foo.go
type Baz interface{
//...
}
type Bar interface {
Bar(Baz)
}
type Foo struct {
//...
}
func NewFoo(bar Bar) Foo {
//...
}
// bar/bar.go
type Bar struct {}
func (b *Bar) Bar(foo.Baz)
In this case, Bar has a method that must accept an interface type from another package. Testing this code with hel becomes extremely difficult.
For cases like this, we should provide some way to relate the concrete type back to the interface type that is being implemented. It's easy enough to construct an interface type from the implemented methods, but searching all packages for interface types that are a subset of those methods may not be feasible. We may have to handle some syntax in the local code to deal with that.
As a worst case, we could handle something like this:
// Window is a type to handle windows.
//
// implements: (git.sr.ht/~nelsam/grpc).Window
type Window struct{}
Vaguely speaking: when i have an interface whose return type is a struct that lives in the same package as the interface, go generate
with nelsam/hel
will create mock objects without importing the package and its struct. So, the mock object's return type will be not-found, instead of specifically imported (from the same package).
Example:
package foo
type Bar struct {}
type Gaz interface {
Whatever() []Bar
}
Will output something like:
package foo_test
type mockGaz struct {
WhateverCalled chan bool
WhateverOutput struct {
Ret0 chan []Bar
}
}
When it should be:
package foo_test
import "foo"
type mockGaz struct {
WhateverCalled chan bool
WhateverOutput struct {
Ret0 chan []foo.Bar
}
}
Given:
type Foo interface {
Foo() (<-chan struct{})
}
The generated type looks like:
type mockFoo struct {
FooOutput struct {
ret0 chan<- chan struct{}
}
}
This could be an upstream issue with goimports/gofmt, or it could be that making a chan of directional chans isn't supported.
The package selector for inputs/outputs is wrong for functions/methods returning types from other packages.
I think this should be a fairly uncommon occurrence, but it's sometimes unavoidable.
It looks like hel tries to run goimports on a file that doesn't exist if it finds no mocks to generate.
We need to support relative imports for things like flattening imports and resolving dependent types.
When we have a type like:
type Foo interface {
Foo() bar.Bar
}
Where bar.Bar
is an interface type, we should generate a mock for bar.Bar
as well.
When mocking a function with variadic parameters, the arguments channel is created a channel of a variadic type.
When mocking a type which has other interface types as dependencies, the package name used as a selector is the local alias. This causes issues with the later call to goimports
, which can't find a matching package.
The files generated currently won't create imports. Using goimports seems by far the easiest method to handle this.
I got a 410 when attempting to go get hel:
go get -v -u github.com/nelsam/[email protected]
go: finding github.com v2.3.3
go: finding github.com/nelsam v2.3.3
go: finding github.com/nelsam/hel v2.3.3
go get github.com/nelsam/[email protected]: github.com/nelsam/[email protected]: reading https://proxy.golang.org/github.com/nelsam/hel/@v/v2.3.3.info: 410 Gone
I set GOPROXY
to direct
and got the following:
go get -v -u github.com/nelsam/[email protected]
go: finding github.com/nelsam/hel v2.3.3
go get github.com/nelsam/[email protected]: github.com/nelsam/[email protected]: invalid version: module contains a go.mod file, so major version must be compatible: should be v0 or v1, not v2
Thanks Sam!
Sender
(used in SenderStore
) should have package name.
package routing_test
type mockSender struct {
SendCalled chan bool
SendInput struct {
Data chan []byte
}
}
func newMockSender() *mockSender {
m := &mockSender{}
m.SendCalled = make(chan bool, 100)
m.SendInput.Data = make(chan []byte, 100)
return m
}
func (m *mockSender) Send(data []byte) {
m.SendCalled <- true
m.SendInput.Data <- data
}
type mockSenderStore struct {
TraverseCalled chan bool
TraverseInput struct {
Callback chan func(sender Sender)
}
}
func newMockSenderStore() *mockSenderStore {
m := &mockSenderStore{}
m.TraverseCalled = make(chan bool, 100)
m.TraverseInput.Callback = make(chan func(sender Sender), 100)
return m
}
func (m *mockSenderStore) Traverse(callback func(sender Sender)) {
m.TraverseCalled <- true
m.TraverseInput.Callback <- callback
}
With the below interfaces:
type A interface{
Something() error
}
type B interface{
AnotherThing()(A, error)
}
I get the following Panic:
Loading interface types in matching directories.panic: Can't find anonymous type error
panic: interface conversion: ast.Expr is *ast.Ident, not *ast.FuncType
goroutine 1 [running]:
panic(0x1f55e0, 0xc4249c8780)
/usr/local/go/src/runtime/panic.go:500 +0x1a1
github.com/nelsam/hel/types.dependencies(0xc420a433c0, 0xc4200a6000, 0xc, 0x14, 0xc420bc7a40, 0x6, 0x8, 0x31e060, 0xc4200154b0, 0x34faf0, ...)
/Users/ninok/go/src/github.com/nelsam/hel/types/types.go:160 +0x542
github.com/nelsam/hel/types.loadPkgTypeSpecs.func1(0xc420c94260, 0xc420ad2178, 0xc420ad1f98, 0x31e060, 0xc4200154b0)
/Users/ninok/go/src/github.com/nelsam/hel/types/types.go:251 +0x138
panic(0x1ef020, 0xc420c92420)
/usr/local/go/src/runtime/panic.go:458 +0x243
github.com/nelsam/hel/types.findAnonMethods(0xc420a43280, 0xc4200a6000, 0xc, 0x14, 0xc420bc7a40, 0x6, 0x8, 0x31e060, 0xc4200154b0, 0xc420c07b10, ...)
/Users/ninok/go/src/github.com/nelsam/hel/types/types.go:391 +0x22a
github.com/nelsam/hel/types.flatten(0xc420a433c0, 0xc4200a6000, 0xc, 0x14, 0xc420bc7a40, 0x6, 0x8, 0x31e060, 0xc4200154b0)
/Users/ninok/go/src/github.com/nelsam/hel/types/types.go:308 +0x544
github.com/nelsam/hel/types.flattenAnon(0xc420c8d840, 0x7, 0x8, 0xc4200a6000, 0xc, 0x14, 0xc420bc7a40, 0x6, 0x8, 0x31e060, ...)
/Users/ninok/go/src/github.com/nelsam/hel/types/types.go:294 +0xd5
github.com/nelsam/hel/types.loadPkgTypeSpecs.func2(0xc420c8d840, 0x7, 0x8, 0xc420c94260, 0xc420bc7a40, 0x6, 0x8, 0x31e060, 0xc4200154b0)
/Users/ninok/go/src/github.com/nelsam/hel/types/types.go:269 +0xa6
github.com/nelsam/hel/types.loadPkgTypeSpecs(0xc420fb1e00, 0x31e060, 0xc4200154b0, 0x0, 0x0, 0x0, 0xc420c90570, 0x1)
/Users/ninok/go/src/github.com/nelsam/hel/types/types.go:274 +0x28e
github.com/nelsam/hel/types.Dir.addPkg(0x0, 0x0, 0x0, 0x0, 0xc420c923a0, 0x8, 0x0, 0x0, 0x0, 0xc420c90540, ...)
/Users/ninok/go/src/github.com/nelsam/hel/types/types.go:81 +0x90
github.com/nelsam/hel/types.loadDependencies(0xc4201bbfb0, 0xc4200d6000, 0x18, 0x18, 0xc42049cc00, 0x15, 0x20, 0x31e060, 0xc4200154b0, 0x0, ...)
/Users/ninok/go/src/github.com/nelsam/hel/types/types.go:220 +0x74e
github.com/nelsam/hel/types.dependencies(0xc420763ac0, 0xc4200d6000, 0x18, 0x18, 0xc42049cc00, 0x15, 0x20, 0x31e060, 0xc4200154b0, 0x34faf0, ...)
/Users/ninok/go/src/github.com/nelsam/hel/types/types.go:162 +0x246
github.com/nelsam/hel/types.loadPkgTypeSpecs.func1(0xc420ae9060, 0xc420ad2bc8, 0xc420ad29e8, 0x31e060, 0xc4200154b0)
/Users/ninok/go/src/github.com/nelsam/hel/types/types.go:251 +0x138
github.com/nelsam/hel/types.loadPkgTypeSpecs(0xc42022e420, 0x31e060, 0xc4200154b0, 0x0, 0x0, 0x0, 0xc420ae2d50, 0x1)
/Users/ninok/go/src/github.com/nelsam/hel/types/types.go:274 +0x28e
github.com/nelsam/hel/types.Dir.addPkg(0x0, 0x0, 0x0, 0x0, 0xc420ae4bb3, 0x9, 0x0, 0x0, 0x0, 0xc420ae2d20, ...)
/Users/ninok/go/src/github.com/nelsam/hel/types/types.go:81 +0x90
github.com/nelsam/hel/types.loadDependencies(0xc420102420, 0xc420030208, 0x1, 0x1, 0xc420015e90, 0x2, 0x2, 0x31e060, 0xc4200154b0, 0xc4200dd060, ...)
/Users/ninok/go/src/github.com/nelsam/hel/types/types.go:220 +0x74e
github.com/nelsam/hel/types.dependencies(0xc4200fd7c0, 0xc420030208, 0x1, 0x1, 0xc420015e90, 0x2, 0x2, 0x31e060, 0xc4200154b0, 0x29a91, ...)
/Users/ninok/go/src/github.com/nelsam/hel/types/types.go:161 +0x19a
github.com/nelsam/hel/types.loadPkgTypeSpecs.func1(0xc4201060c0, 0xc420ad3618, 0xc420ad3438, 0x31e060, 0xc4200154b0)
/Users/ninok/go/src/github.com/nelsam/hel/types/types.go:251 +0x138
github.com/nelsam/hel/types.loadPkgTypeSpecs(0xc420102300, 0x31e060, 0xc4200154b0, 0x0, 0x0, 0x0, 0xc420102ab0, 0x0)
/Users/ninok/go/src/github.com/nelsam/hel/types/types.go:274 +0x28e
github.com/nelsam/hel/types.Dir.addPkg(0xc420016a80, 0x30, 0xc420015537, 0x9, 0xc420015537, 0x9, 0x0, 0x0, 0x0, 0xc4200119b0, ...)
/Users/ninok/go/src/github.com/nelsam/hel/types/types.go:81 +0x90
github.com/nelsam/hel/types.Load(0xc4200154a0, 0x1, 0x1, 0x31e060, 0xc4200154b0, 0x1)
/Users/ninok/go/src/github.com/nelsam/hel/types/types.go:127 +0x232
main.init.1.func1.2()
/Users/ninok/go/src/github.com/nelsam/hel/main.go:88 +0x21d
main.progress(0xc420ad3c80)
/Users/ninok/go/src/github.com/nelsam/hel/main.go:147 +0xc8
main.init.1.func1(0xc42009c400, 0xc4200169c0, 0x0, 0x4)
/Users/ninok/go/src/github.com/nelsam/hel/main.go:89 +0x810
github.com/spf13/cobra.(*Command).execute(0xc42009c400, 0xc42000c150, 0x4, 0x4, 0xc42009c400, 0xc42000c150)
/Users/ninok/go/src/github.com/spf13/cobra/command.go:565 +0x411
github.com/spf13/cobra.(*Command).ExecuteC(0xc42009c400, 0x0, 0x0, 0x0)
/Users/ninok/go/src/github.com/spf13/cobra/command.go:651 +0x367
github.com/spf13/cobra.(*Command).Execute(0xc42009c400, 0x0, 0xc420000340)
/Users/ninok/go/src/github.com/spf13/cobra/command.go:610 +0x2b
main.main()
/Users/ninok/go/src/github.com/nelsam/hel/main.go:184 +0x2d
session_handler.go:9: running "hel": exit status 2
Any suggestions?
Hey Sam,
Could we get a comment added to the top of each generated file indicating the source of the generated code and some sort of warning about altering the code?
Hope all is well.
Thanks,
Dwayne
Should probably just append an '_' to the argument name or some other kind of munging.
Eachers has a testhelpers package that is specific to hel's way of channels. I think the better home would be here.
If a mock is in a different package than the package containing the interface, some types may need the package name added as a prefix. E.g.
package bacon
type Bar int
type Foo interface {
Foo() Bar
}
In the above, I'm pretty sure that we need some additional logic to change Foo() Bar
to Foo() bacon.Bar
if the generated mock is in the bacon_test
package.
Some of this may be easy, but I expect at least some parts to be difficult. Still, It's at least worth doing the easier stuff; and I'd like to do the more difficult stuff some day. Basically, when the mock is in a separate test package (which is the default), we should ignore any interface types that should not be implemented outside of the main package (i.e. are unexported, include unexported methods, or include unexported types in method params or results).
type foo interface {}
should be ignored (unexported type)type Foo interface { foo() }
should be ignored (unexported method)type Foo interface { Foo(f foo) }
should be ignored (unexported type in param/return value)Your README indicates that you plan to hook one up, so this is more of a checkbox.
Mock actually ends up being invalid.
Interface:
package foo
import baz "bar"
type Buz interface {
Close() (baz.Thing)
}
Generated a mock with baz
prefixes but no import for baz
or bar
.
When two types (or even two methods on the same type?) both depend on the same type, we get a duplicate mock for that dependency. Dependencies should be de-duped.
Issue #4 showed us that types local to a package containing an interface that we're mocking will not get their package name added automatically when they're written to a file with a different package name.
This means that we'll need to figure out a way to detect types being used as parameters or results that are local to an interface's package and include the package name if the test package is different from the main package.
Type filtering hasn't been implemented yet, but the flag exists.
Struct fields are generated with an underscore to disambiguate from the receiver. This isn't necessary and fails to compile as the underscore is not included in field names when assigning to them in the mock implementations:
struct field definition:
SendMsgInput struct {
M_ chan interface{}
}
struct field use:
func (m *mockDopplerIngestor_PushServer) RecvMsg(m_ interface{}) error {
m.RecvMsgCalled <- true
m.RecvMsgInput.M <- m_
return <-m.RecvMsgOutput.Ret0
}
/cc @jasonkeene
Consider:
type Foo interface {
Foo() string
}
type Bar interface {
Foo
Bar() int
}
Currently, the generated mockBar
would only have the Bar()
method, which is obviously wrong.
Given:
type Foo interface {
Bar(bacon string, eggs int) (int, string)
}
We currently generate (give or take):
type mockFoo interface {
BarCalled chan bool
BarInput struct {
bacon chan string
eggs chan int
}
BarOutput struct {
ret0 chan int
ret1 chan string
}
}
func (m *mockFoo) Foo(bacon string, eggs int) (int, string) {
m.BarCalled <- true
m.BarInput.bacon <- bacon
m.BarInput.eggs <- eggs
return <-m.BarOutput.ret0, <-m.BarOutput.ret1
}
We should explore the possibility of changing that to something along the lines of:
type mockFoo_input {
bacon string
eggs int
}
type mockFoo_output {
ret0 int
ret1 string
}
type mockFoo interface {
BarInput chan mockFoo_input
BarOutput chan mockFoo_output
}
func (m *mockFoo) Foo(bacon string, eggs int) (int, string) {
m.BarInput <- mockFoo_input{
bacon: bacon,
eggs: eggs,
}
ret := <-m.BarOutput
return ret.ret0, ret.ret1
}
It seems like prependLocalPackage
is not always being called on dependencies.
Say we have an integration test package that requires a mock from an interface. Hel does not analyze the test code at all.
I think I would would want to use the:
//go:generate hel --type somepackage.Foo --output mock_foo_test.go
syntax to indicate that I would want a certain mock.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.