jeudi 11 août 2016

Generate a tree of structs with testing/quick, respecting invariants

I have a tree of structs which I'd like to test using testing/quick, but constraining it to within my invariants.

This example code works:

var rnd = rand.New(rand.NewSource(time.Now().UnixNano()))
type X struct {
    HasChildren bool
    Children    []*X
}
func TestSomething(t *testing.T) {
    x, _ := quick.Value(reflect.TypeOf(X{}), rnd)
    _ = x
    // test some stuff here
}

But we hold HasChildren = true whenever len(Children) > 0 as an invariant, so it'd be better to ensure that whatever quick.Value() generates respects that (rather than finding "bugs" that don't actually exist).

I figured I could define a Generate function which uses quick.Value() to populate all the variable members:

func (X) Generate(rand *rand.Rand, size int) reflect.Value {
    x := X{}

    throwaway, _ := quick.Value(reflect.TypeOf([]*X{}), rand)
    x.Children = throwaway.Interface().([]*X)

    if len(x.Children) > 0 {
        x.HasChildren = true
    } else {
        x.HasChildren = false
    }

    return reflect.ValueOf(x)
}

But this is panicking:

panic: value method main.X.Generate called using nil *X pointer [recovered]

And when I change Children from []*X to []X, it dies with a stack overflow.

The documentation is very thin on examples, and I'm finding almost nothing in web searches either.

How can this be done?

Aucun commentaire:

Enregistrer un commentaire