dqxboe2628 2016-08-11 22:16
浏览 50
已采纳

遵循不变式生成带有测试/快速结构的结构树

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?

  • 写回答

1条回答 默认 最新

  • douzen1880 2016-08-12 00:41
    关注

    Looking at the testing/quick source code it seems that you can't create recursive custom generators and at the same time reuse the quick library facilities to generate the array part of the struct, because the size parameter, that is designed to limit the number of recursive calls, cannot be passed back into quick.Value(...)

    https://golang.org/src/testing/quick/quick.go (see around line 50)

    in your case this lead to an infinite tree that quickly "explodes" with 1..50 leafs at each level (that's the reason for the stack overflow).

    If the function quick.sizedValue() had been public we could have used it to accomplish your task, but unfortunately this is not the case.

    BTW since HasChildren is an invariant, can't you simply make it a struct method?

    type X struct {
        Children    []*X
    }
    
    func (me *X) HasChildren() bool {
        return len(me.Children) > 0
    }
    
    func main() {
        .... generate X ....
        if x.HasChildren() {
            .....
        }
    }
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 BP神经网络控制倒立摆
  • ¥20 要这个数学建模编程的代码 并且能完整允许出来结果 完整的过程和数据的结果
  • ¥15 html5+css和javascript有人可以帮吗?图片要怎么插入代码里面啊
  • ¥30 Unity接入微信SDK 无法开启摄像头
  • ¥20 有偿 写代码 要用特定的软件anaconda 里的jvpyter 用python3写
  • ¥20 cad图纸,chx-3六轴码垛机器人
  • ¥15 移动摄像头专网需要解vlan
  • ¥20 access多表提取相同字段数据并合并
  • ¥20 基于MSP430f5529的MPU6050驱动,求出欧拉角
  • ¥20 Java-Oj-桌布的计算