The following program sample.go triggers an unexpected result
package int
import (
"fmt"
"testing"
)
type Logger struct {
}
func (*Logger) WriteWithReceiver(name string, opts ...Option) {
messageWritten := false
for _, opt := range opts {
if !messageWritten {
messageWritten = true
opt(name)
}
}
}
func WriteWithoutReceiver(name string, opts ...Option) {
messageWritten := false
for _, opt := range opts {
if !messageWritten {
messageWritten = true
opt(name)
}
}
}
type Option func(name string)
func WithOption() Option {
return func(name string) {
fmt.Println(name)
}
}
func TestVariadicFunctionWithReceiver(t *testing.T) {
logger := &Logger{}
//////////// fails here //////////////////
//This is a relatively popular method
logger.WriteWithReceiver("WriteWithReceiver - Nothing passed at all fails")
fmt.Println("WriteWithReceiver - Nothing passed at all fails") //Enumerate empty args will not output a message
//////////// fails here //////////////////
logger.WriteWithReceiver("WriteWithReceiver - WithOption() works", WithOption())
logger.WriteWithReceiver("WriteWithReceiver - WithOption(), WithOption() works", WithOption(), WithOption())
oneOption := []Option{WithOption()}
logger.WriteWithReceiver("WriteWithReceiver - []Option{WithOption()} works", oneOption...)
twoOption := []Option{WithOption(), WithOption()}
logger.WriteWithReceiver("WriteWithReceiver - []Option{WithOption(), WithOption()} works", twoOption...)
emptyOption := []Option{}
logger.WriteWithReceiver("WriteWithReceiver - []Option{} works", emptyOption...)
fmt.Println("WriteWithReceiver - []Option{} works") //Enumerate empty args will not output a message
var nilOption []Option
logger.WriteWithReceiver("WriteWithReceiver - var nilOption []Option works", nilOption...)
fmt.Println("WriteWithReceiver - var nilOption []Option works") //Enumerate empty args will not output a message
}
func TestVariadicFunctionWithoutReceiver(t *testing.T) {
WriteWithoutReceiver("WriteWithoutReceiver - WithOption() works", WithOption())
WriteWithoutReceiver("WriteWithoutReceiver - WithOption(), WithOption() works", WithOption(), WithOption())
oneOption := []Option{WithOption()}
WriteWithoutReceiver("WriteWithoutReceiver - []Option{WithOption()} works", oneOption...)
twoOption := []Option{WithOption(), WithOption()}
WriteWithoutReceiver("WriteWithoutReceiver - []Option{WithOption(), WithOption()} works", twoOption...)
emptyOption := []Option{}
WriteWithoutReceiver("WriteWithoutReceiver - []Option{} works", emptyOption...)
fmt.Println("WriteWithoutReceiver - []Option{} works") //Enumerate empty args will not output a message
var nilOption []Option
WriteWithoutReceiver("WriteWithoutReceiver - var nilOption []Option works", nilOption...)
fmt.Println("WriteWithoutReceiver - var nilOption []Option works") //Enumerate empty args will not output a message
WriteWithoutReceiver("WriteWithoutReceiver - Nothing passed at all works")
fmt.Println("WriteWithoutReceiver - Nothing passed at all works") //Enumerate empty args will not output a message
}
Expected result
C:\Users\taliesin.sisson\go\src\github.com\taliesins\traefik-plugin-oidc>yaegi test -v github.com/taliesins/traefik-plugin-oidc/int
=== RUN TestVariadicFunctionWithReceiver
WriteWithReceiver - Nothing passed at all fails
WriteWithReceiver - WithOption() works
WriteWithReceiver - WithOption(), WithOption() works
WriteWithReceiver - []Option{WithOption()} works
WriteWithReceiver - []Option{WithOption(), WithOption()} works
WriteWithReceiver - []Option{} works
WriteWithReceiver - var nilOption []Option works
--- PASS: TestVariadicFunctionWithReceiver (0.00s)
=== RUN TestVariadicFunctionWithoutReceiver
WriteWithoutReceiver - WithOption() works
WriteWithoutReceiver - WithOption(), WithOption() works
WriteWithoutReceiver - []Option{WithOption()} works
WriteWithoutReceiver - []Option{WithOption(), WithOption()} works
WriteWithoutReceiver - []Option{} works
WriteWithoutReceiver - var nilOption []Option works
WriteWithoutReceiver - Nothing passed at all works
--- PASS: TestVariadicFunctionWithoutReceiver (0.00s)
PASS
Got
C:\Users\taliesin.sisson\go\src\github.com\taliesins\traefik-plugin-oidc>yaegi test -v github.com/taliesins/traefik-plugin-oidc/int
=== RUN TestVariadicFunctionWithReceiver
C:\Users\taliesin.sisson\go\src\github.com\taliesins\traefik-plugin-oidc\int\do_test.go:40:13: panic
--- FAIL: TestVariadicFunctionWithReceiver (0.00s)
panic: reflect: Call using *struct {} as type string [recovered]
panic: reflect: Call using *struct {} as type string [recovered]
panic: reflect: Call using *struct {} as type string
goroutine 7 [running]:
testing.tRunner.func1.2({0x12c2be0, 0xc0004184f0})
C:/Program Files/Go/src/testing/testing.go:1396 +0x24e
testing.tRunner.func1()
C:/Program Files/Go/src/testing/testing.go:1399 +0x39f
panic({0x12c2be0, 0xc0004184f0})
C:/Program Files/Go/src/runtime/panic.go:884 +0x212
github.com/traefik/yaegi/interp.runCfg.func1()
C:/Users/taliesin.sisson/go/pkg/mod/github.com/traefik/yaegi@v0.14.3/interp/run.go:192 +0x148
panic({0x12c2be0, 0xc0004184f0})
C:/Program Files/Go/src/runtime/panic.go:884 +0x212
reflect.Value.call({0xc00008ab40?, 0xc00041b2c0?, 0x970e5f?}, {0x13eb30e, 0x4}, {0xc00041b2f0, 0x2, 0x0?})
C:/Program Files/Go/src/reflect/value.go:440 +0x1abf
reflect.Value.Call({0xc00008ab40?, 0xc00041b2c0?, 0x9b5bb2?}, {0xc00041b2f0?, 0x13e9360?, 0x1?})
C:/Program Files/Go/src/reflect/value.go:368 +0xbc
github.com/traefik/yaegi/interp.call.func9.2({0xc00041b2f0?, 0xc00041b2c0?, 0x5?})
C:/Users/taliesin.sisson/go/pkg/mod/github.com/traefik/yaegi@v0.14.3/interp/run.go:1288 +0x3c
github.com/traefik/yaegi/interp.call.func9(0xc0000cc8f0)
C:/Users/taliesin.sisson/go/pkg/mod/github.com/traefik/yaegi@v0.14.3/interp/run.go:1303 +0x122f
github.com/traefik/yaegi/interp.runCfg(0xc0003eb440, 0xc0000cc8f0, 0x0?, 0x13d5d40?)
C:/Users/taliesin.sisson/go/pkg/mod/github.com/traefik/yaegi@v0.14.3/interp/run.go:200 +0x29d
github.com/traefik/yaegi/interp.genFunctionWrapper.func1.1({0xc000009650, 0x1, 0x1?})
C:/Users/taliesin.sisson/go/pkg/mod/github.com/traefik/yaegi@v0.14.3/interp/run.go:1002 +0x4a5
testing.tRunner(0xc0001a31e0, 0xc00041b050)
C:/Program Files/Go/src/testing/testing.go:1446 +0x10b
created by testing.(*T).Run
C:/Program Files/Go/src/testing/testing.go:1493 +0x35f
C:\Users\taliesin.sisson\go\src\github.com\taliesins\traefik-plugin-oidc>
Yaegi Version
v0.14.3
Additional Notes
It is quite a popular use case in structured logging, to make use of a variadic function with a method receiver e.g.
The following program
sample.go
triggers an unexpected resultExpected result
Got
Yaegi Version
v0.14.3
Additional Notes
It is quite a popular use case in structured logging, to make use of a variadic function with a method receiver e.g.