leanovate / gopter

GOlang Property TestER
MIT License
599 stars 40 forks source link

Trying to use a concrete generator to fill an interface variable panics #54

Closed philandstuff closed 5 years ago

philandstuff commented 5 years ago

The following test panics:

package main_test

import (
    "reflect"
    "testing"

    "github.com/leanovate/gopter"
    "github.com/leanovate/gopter/gen"
    "github.com/leanovate/gopter/prop"
)

type Box struct {
    Content interface{}
}

func BoxOf(inner gopter.Gen) gopter.Gen {
    return gen.Struct(reflect.TypeOf(Box{}), map[string]gopter.Gen{
        "Content": inner,
    })
}

func TestPanics(t *testing.T) {
    properties := gopter.NewProperties(nil)

    properties.Property("Should not panic",
        prop.ForAll(
            func(e Box) bool {
                return reflect.DeepEqual(e, Box{0})
            },
            BoxOf(gen.Int()),
        ))

    properties.TestingRun(t)
}

What seems to be happening is that I can't use a generator of int to fill a variable of type interface{} in Box. What I expected to happen is for this to be fine. After all, there's nothing wrong with var i interface{} = 3 so why is there a problem with BoxOf(gen.Int())?

I can work around by using an explicit Map() to change the type of the Int() generator to interface{}:

            func(e Box) bool {
                return reflect.DeepEqual(e, Box{0})
            },
-           BoxOf(gen.Int()),
+           BoxOf(
+               gen.Int().Map(func(in *gopter.GenResult) *gopter.GenResult {
+                   in.ResultType = reflect.TypeOf((*interface{})(nil)).Elem()
+                   return in
+               }),
+           ),
        ))

    properties.TestingRun(t)

but this feels pretty heavyweight. Is it possible to get structs to accept concrete generators for interface types?