rjeczalik / interfaces

Code generation tools for Go.
MIT License
420 stars 31 forks source link

Panic when generating interface for redis client #4

Closed jenspinney closed 7 years ago

jenspinney commented 7 years ago

I love the idea of this project! Unfortunately this is what I hit when I tried it out:

> interfacer -for \"github.com/go-redis/redis\".Client -as mock.redis

panic: internal: t=*types.Signature, orig=*types.Signature

goroutine 1 [running]:
panic(0x217c40, 0x429cf5550)
    $GOROOT/src/runtime/panic.go:500 +0x1a1
github.com/rjeczalik/interfaces.(*Type).setFromType(0x430661878, 0x367400, 0x425b33290, 0x0, 0x367400, 0x425b33290)
    $GOPATH/src/github.com/rjeczalik/interfaces/type.go:65 +0x350
github.com/rjeczalik/interfaces.newType(0x42596d1d0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0)
    $GOPATH/src/github.com/rjeczalik/interfaces/type.go:29 +0x8b
github.com/rjeczalik/interfaces.buildInterfaceForPkg(0x4204b20b0, 0x430661eb0, 0x7fff5fbfe4e1, 0x19, 0x42582d818, 0x1, 0x0)
    $GOPATH/src/github.com/rjeczalik/interfaces/interface.go:140 +0x41c
github.com/rjeczalik/interfaces.buildInterface(0x430661eb0, 0x420433dd8, 0x95de4, 0x7fff5fbfe4e1, 0x21, 0x266bba)
    $GOPATH/src/github.com/rjeczalik/interfaces/interface.go:84 +0x2c0
github.com/rjeczalik/interfaces.NewWithOptions(0x430661eb0, 0x21, 0x4204a8060, 0x0, 0x0, 0x4204a2000)
    $GOPATH/src/github.com/rjeczalik/interfaces/interface.go:45 +0x156
main.main()
    $GOPATH/src/github.com/rjeczalik/interfaces/cmd/interfacer/main.go:73 +0xf0

Am I using it wrong or is there a bug here?

rjeczalik commented 7 years ago

@jenspinney What go version are you using and what's the HEAD of your local redis repo?

I'm getting:

$ go version
go version go1.8.3 darwin/amd64
src/github.com/go-redis/redis $ git rev-parse HEAD
eb066030c08c254136a0dbfe9f7a3625a0871beb
$ interfacer  -for \"github.com/go-redis/redis\".Client -as mock.redis
panic: recursive types not supported: github.com/go-redis/redis.Client

goroutine 1 [running]:
github.com/rjeczalik/interfaces.collectMethods(0xc426d599d8, 0xc4243cb170, 0x81, 0x136c320, 0xc4236c0c00)
        /Users/rjeczalik/src/github.com/rjeczalik/interfaces/interface.go:160 +0x331
github.com/rjeczalik/interfaces.collectMethods(0xc426d599d8, 0xc4243cb350, 0x80, 0x136c320, 0xc4236c0c00)
        /Users/rjeczalik/src/github.com/rjeczalik/interfaces/interface.go:176 +0x22e
github.com/rjeczalik/interfaces.collectMethods(0xc426d599d8, 0xc422dab740, 0x7f, 0x136c320, 0xc4236c0c00)
        /Users/rjeczalik/src/github.com/rjeczalik/interfaces/interface.go:176 +0x22e
...
rjeczalik commented 7 years ago

Ok, with #5 I'm able to reproduce the problem:

$ interfacer  -for \"github.com/go-redis/redis\".Client -as mock.Redis
panic: internal: t=*types.Signature, orig=*types.Signature

goroutine 1 [running]:
github.com/rjeczalik/interfaces.(*Type).setFromType(0xc421f1b8f8, 0x136c3a0, 0xc4246e0420, 0x0, 0x136c3a0, 0xc4246e0420)
        /Users/rjeczalik/src/github.com/rjeczalik/interfaces/type.go:65 +0x2f1
github.com/rjeczalik/interfaces.newType(0xc422110960, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0)
        /Users/rjeczalik/src/github.com/rjeczalik/interfaces/type.go:29 +0x89
github.com/rjeczalik/interfaces.buildInterfaceForPkg(0xc4200de0b0, 0xc421f1bf20, 0x7fff5fbfe23b, 0x19, 0xc423fd2e58, 0x127a901, 0x0)
        /Users/rjeczalik/src/github.com/rjeczalik/interfaces/interface.go:140 +0x41d
github.com/rjeczalik/interfaces.buildInterface(0xc421f1bf20, 0xc4200cbe18, 0x11f510c, 0x7fff5fbfe23b, 0x21, 0x126d6c9)
        /Users/rjeczalik/src/github.com/rjeczalik/interfaces/interface.go:84 +0x227
github.com/rjeczalik/interfaces.NewWithOptions(0xc4200cbf20, 0x21, 0xc42000a800, 0x0, 0x0, 0xc4200aa200)
        /Users/rjeczalik/src/github.com/rjeczalik/interfaces/interface.go:45 +0x151
main.main()
        /Users/rjeczalik/src/github.com/rjeczalik/interfaces/cmd/interfacer/main.go:73 +0x105

👀

rjeczalik commented 7 years ago

Hey @jenspinney, I fixed the interfacer, so it generates an interface for *redis.Client.

However one method of redis.Client depend on a package which is internal, so I believe you won't be able to use out-of-the box - you may want to remove Pool() method from the interface manually. At some point I might add a switch to interfacer to do that for the user instead.

$ interfacer  -for \"github.com/go-redis/redis\".Client -as mock.Redis
// Created by interfacer; DO NOT EDIT

package mock

import (
    "context"
    "github.com/go-redis/redis"
    "github.com/go-redis/redis/internal/pool"
    "time"
)

// Redis is an interface generated for "github.com/go-redis/redis".Client.
type Redis interface {
    Append(string, string) *redis.IntCmd
    BLPop(time.Duration, []string) *redis.StringSliceCmd
    BRPop(time.Duration, []string) *redis.StringSliceCmd
    BRPopLPush(string, string, time.Duration) *redis.StringCmd
    BgRewriteAOF() *redis.StatusCmd
    BgSave() *redis.StatusCmd
    BitCount(string, *redis.BitCount) *redis.IntCmd
    BitOpAnd(string, []string) *redis.IntCmd
    BitOpNot(string, string) *redis.IntCmd
    BitOpOr(string, []string) *redis.IntCmd
    BitOpXor(string, []string) *redis.IntCmd
    BitPos(string, int64, []int64) *redis.IntCmd
    ClientGetName() *redis.StringCmd
    ClientKill(string) *redis.StatusCmd
    ClientList() *redis.StringCmd
    ClientPause(time.Duration) *redis.BoolCmd
    Close() error
    ClusterAddSlots([]int) *redis.StatusCmd
    ClusterAddSlotsRange(int, int) *redis.StatusCmd
    ClusterCountFailureReports(string) *redis.IntCmd
    ClusterCountKeysInSlot(int) *redis.IntCmd
    ClusterDelSlots([]int) *redis.StatusCmd
    ClusterDelSlotsRange(int, int) *redis.StatusCmd
    ClusterFailover() *redis.StatusCmd
    ClusterForget(string) *redis.StatusCmd
    ClusterInfo() *redis.StringCmd
    ClusterKeySlot(string) *redis.IntCmd
    ClusterMeet(string, string) *redis.StatusCmd
    ClusterNodes() *redis.StringCmd
    ClusterReplicate(string) *redis.StatusCmd
    ClusterResetHard() *redis.StatusCmd
    ClusterResetSoft() *redis.StatusCmd
    ClusterSaveConfig() *redis.StatusCmd
    ClusterSlaves(string) *redis.StringSliceCmd
    ClusterSlots() *redis.ClusterSlotsCmd
    Command() *redis.CommandsInfoCmd
    ConfigGet(string) *redis.SliceCmd
    ConfigResetStat() *redis.StatusCmd
    ConfigSet(string, string) *redis.StatusCmd
    Context() context.Context
    DbSize() *redis.IntCmd
    DebugObject(string) *redis.StringCmd
    Decr(string) *redis.IntCmd
    DecrBy(string, int64) *redis.IntCmd
    Del([]string) *redis.IntCmd
    Dump(string) *redis.StringCmd
    Echo(interface{}) *redis.StringCmd
    Eval(string, []string, []interface{}) *redis.Cmd
    EvalSha(string, []string, []interface{}) *redis.Cmd
    Exists([]string) *redis.IntCmd
    Expire(string, time.Duration) *redis.BoolCmd
    ExpireAt(string, time.Time) *redis.BoolCmd
    FlushAll() *redis.StatusCmd
    FlushDb() *redis.StatusCmd
    GeoAdd(string, []*redis.GeoLocation) *redis.IntCmd
    GeoDist(string, string, string, string) *redis.FloatCmd
    GeoHash(string, []string) *redis.StringSliceCmd
    GeoPos(string, []string) *redis.GeoPosCmd
    GeoRadius(string, float64, float64, *redis.GeoRadiusQuery) *redis.GeoLocationCmd
    GeoRadiusByMember(string, string, *redis.GeoRadiusQuery) *redis.GeoLocationCmd
    Get(string) *redis.StringCmd
    GetBit(string, int64) *redis.IntCmd
    GetRange(string, int64, int64) *redis.StringCmd
    GetSet(string, interface{}) *redis.StringCmd
    HDel(string, []string) *redis.IntCmd
    HExists(string, string) *redis.BoolCmd
    HGet(string, string) *redis.StringCmd
    HGetAll(string) *redis.StringStringMapCmd
    HIncrBy(string, string, int64) *redis.IntCmd
    HIncrByFloat(string, string, float64) *redis.FloatCmd
    HKeys(string) *redis.StringSliceCmd
    HLen(string) *redis.IntCmd
    HMGet(string, []string) *redis.SliceCmd
    HMSet(string, map[string]interface{}) *redis.StatusCmd
    HScan(string, uint64, string, int64) *redis.ScanCmd
    HSet(string, string, interface{}) *redis.BoolCmd
    HSetNX(string, string, interface{}) *redis.BoolCmd
    HVals(string) *redis.StringSliceCmd
    Incr(string) *redis.IntCmd
    IncrBy(string, int64) *redis.IntCmd
    IncrByFloat(string, float64) *redis.FloatCmd
    Info([]string) *redis.StringCmd
    Keys(string) *redis.StringSliceCmd
    LIndex(string, int64) *redis.StringCmd
    LInsert(string, string, interface{}, interface{}) *redis.IntCmd
    LInsertAfter(string, interface{}, interface{}) *redis.IntCmd
    LInsertBefore(string, interface{}, interface{}) *redis.IntCmd
    LLen(string) *redis.IntCmd
    LPop(string) *redis.StringCmd
    LPush(string, []interface{}) *redis.IntCmd
    LPushX(string, interface{}) *redis.IntCmd
    LRange(string, int64, int64) *redis.StringSliceCmd
    LRem(string, int64, interface{}) *redis.IntCmd
    LSet(string, int64, interface{}) *redis.StatusCmd
    LTrim(string, int64, int64) *redis.StatusCmd
    LastSave() *redis.IntCmd
    MGet([]string) *redis.SliceCmd
    MSet([]interface{}) *redis.StatusCmd
    MSetNX([]interface{}) *redis.BoolCmd
    Migrate(string, string, string, int64, time.Duration) *redis.StatusCmd
    Move(string, int64) *redis.BoolCmd
    ObjectEncoding(string) *redis.StringCmd
    ObjectIdleTime(string) *redis.DurationCmd
    ObjectRefCount(string) *redis.IntCmd
    Options() *redis.Options
    PExpire(string, time.Duration) *redis.BoolCmd
    PExpireAt(string, time.Time) *redis.BoolCmd
    PFAdd(string, []interface{}) *redis.IntCmd
    PFCount([]string) *redis.IntCmd
    PFMerge(string, []string) *redis.StatusCmd
    PSubscribe([]string) *redis.PubSub
    PTTL(string) *redis.DurationCmd
    Persist(string) *redis.BoolCmd
    Ping() *redis.StatusCmd
    Pipeline() redis.Pipeliner
    Pipelined(func(redis.Pipeliner) error) ([]redis.Cmder, error)
    Pool() pool.Pooler
    PoolStats() *redis.PoolStats
    Process(redis.Cmder) error
    PubSubChannels(string) *redis.StringSliceCmd
    PubSubNumPat() *redis.IntCmd
    PubSubNumSub([]string) *redis.StringIntMapCmd
    Publish(string, string) *redis.IntCmd
    Quit() *redis.StatusCmd
    RPop(string) *redis.StringCmd
    RPopLPush(string, string) *redis.StringCmd
    RPush(string, []interface{}) *redis.IntCmd
    RPushX(string, interface{}) *redis.IntCmd
    RandomKey() *redis.StringCmd
    Rename(string, string) *redis.StatusCmd
    RenameNX(string, string) *redis.BoolCmd
    Restore(string, time.Duration, string) *redis.StatusCmd
    RestoreReplace(string, time.Duration, string) *redis.StatusCmd
    SAdd(string, []interface{}) *redis.IntCmd
    SCard(string) *redis.IntCmd
    SDiff([]string) *redis.StringSliceCmd
    SDiffStore(string, []string) *redis.IntCmd
    SInter([]string) *redis.StringSliceCmd
    SInterStore(string, []string) *redis.IntCmd
    SIsMember(string, interface{}) *redis.BoolCmd
    SMembers(string) *redis.StringSliceCmd
    SMove(string, string, interface{}) *redis.BoolCmd
    SPop(string) *redis.StringCmd
    SPopN(string, int64) *redis.StringSliceCmd
    SRandMember(string) *redis.StringCmd
    SRandMemberN(string, int64) *redis.StringSliceCmd
    SRem(string, []interface{}) *redis.IntCmd
    SScan(string, uint64, string, int64) *redis.ScanCmd
    SUnion([]string) *redis.StringSliceCmd
    SUnionStore(string, []string) *redis.IntCmd
    Save() *redis.StatusCmd
    Scan(uint64, string, int64) *redis.ScanCmd
    ScriptExists([]string) *redis.BoolSliceCmd
    ScriptFlush() *redis.StatusCmd
    ScriptKill() *redis.StatusCmd
    ScriptLoad(string) *redis.StringCmd
    Set(string, interface{}, time.Duration) *redis.StatusCmd
    SetBit(string, int64, int) *redis.IntCmd
    SetNX(string, interface{}, time.Duration) *redis.BoolCmd
    SetRange(string, int64, string) *redis.IntCmd
    SetXX(string, interface{}, time.Duration) *redis.BoolCmd
    Shutdown() *redis.StatusCmd
    ShutdownNoSave() *redis.StatusCmd
    ShutdownSave() *redis.StatusCmd
    SlaveOf(string, string) *redis.StatusCmd
    SlowLog()
    Sort(string, redis.Sort) *redis.StringSliceCmd
    SortInterfaces(string, redis.Sort) *redis.SliceCmd
    StrLen(string) *redis.IntCmd
    String() string
    Subscribe([]string) *redis.PubSub
    Sync()
    TTL(string) *redis.DurationCmd
    Time() *redis.TimeCmd
    TxPipeline() redis.Pipeliner
    TxPipelined(func(redis.Pipeliner) error) ([]redis.Cmder, error)
    Type(string) *redis.StatusCmd
    Unlink([]string) *redis.IntCmd
    Wait(int, time.Duration) *redis.IntCmd
    Watch(func(*redis.Tx) error, []string) error
    WithContext(context.Context) *redis.Client
    WrapProcess(func(oldProcess func(cmd redis.Cmder) error) func(cmd redis.Cmder) error)
    ZAdd(string, []redis.Z) *redis.IntCmd
    ZAddCh(string, []redis.Z) *redis.IntCmd
    ZAddNX(string, []redis.Z) *redis.IntCmd
    ZAddNXCh(string, []redis.Z) *redis.IntCmd
    ZAddXX(string, []redis.Z) *redis.IntCmd
    ZAddXXCh(string, []redis.Z) *redis.IntCmd
    ZCard(string) *redis.IntCmd
    ZCount(string, string, string) *redis.IntCmd
    ZIncr(string, redis.Z) *redis.FloatCmd
    ZIncrBy(string, float64, string) *redis.FloatCmd
    ZIncrNX(string, redis.Z) *redis.FloatCmd
    ZIncrXX(string, redis.Z) *redis.FloatCmd
    ZInterStore(string, redis.ZStore, []string) *redis.IntCmd
    ZRange(string, int64, int64) *redis.StringSliceCmd
    ZRangeByLex(string, redis.ZRangeBy) *redis.StringSliceCmd
    ZRangeByScore(string, redis.ZRangeBy) *redis.StringSliceCmd
    ZRangeByScoreWithScores(string, redis.ZRangeBy) *redis.ZSliceCmd
    ZRangeWithScores(string, int64, int64) *redis.ZSliceCmd
    ZRank(string, string) *redis.IntCmd
    ZRem(string, []interface{}) *redis.IntCmd
    ZRemRangeByLex(string, string, string) *redis.IntCmd
    ZRemRangeByRank(string, int64, int64) *redis.IntCmd
    ZRemRangeByScore(string, string, string) *redis.IntCmd
    ZRevRange(string, int64, int64) *redis.StringSliceCmd
    ZRevRangeByLex(string, redis.ZRangeBy) *redis.StringSliceCmd
    ZRevRangeByScore(string, redis.ZRangeBy) *redis.StringSliceCmd
    ZRevRangeByScoreWithScores(string, redis.ZRangeBy) *redis.ZSliceCmd
    ZRevRangeWithScores(string, int64, int64) *redis.ZSliceCmd
    ZRevRank(string, string) *redis.IntCmd
    ZScan(string, uint64, string, int64) *redis.ScanCmd
    ZScore(string, string) *redis.FloatCmd
    ZUnionStore(string, redis.ZStore, []string) *redis.IntCmd
}