我发现scalacheck存在一个非常明显的bug,如果真的存在这个问题,我无法理解人们如何在递归数据结构中使用它。
在构造
更奇怪的是,一些本应该不影响程序运行的修改似乎会让程序正常工作。例如,如果您将
在构造
Arbitrary
值时,此程序在scalacheck接管之前因StackOverflowError
而失败。请注意,Tree
类型和Tree
的生成器直接从这个scalacheck教程中取出。package treegen
import org.scalacheck._
import Prop._
class TreeProperties extends Properties("Tree") {
trait Tree
case class Node(left: Tree, right: Tree) extends Tree
case class Leaf(x: Int) extends Tree
val ints = Gen.choose(-100, 100)
def leafs: Gen[Leaf] = for {
x <- ints
} yield Leaf(x)
def nodes: Gen[Node] = for {
left <- trees
right <- trees
} yield Node(left, right)
def trees: Gen[Tree] = Gen.oneOf(leafs, nodes)
implicit lazy val arbTree: Arbitrary[Tree] = Arbitrary(trees)
property("vacuous") = forAll { t: Tree => true }
}
object Main extends App {
(new TreeProperties).check
}
更奇怪的是,一些本应该不影响程序运行的修改似乎会让程序正常工作。例如,如果您将
trees
的定义更改为以下内容,则可以顺利通过: def trees: Gen[Tree] = for {
x <- Gen.oneOf(0, 1)
t <- if (x == 0) {leafs} else {nodes}
} yield t
更奇怪的是,如果您改变二叉树结构,使得值存储在节点
上而不是叶子
上,并修改叶子
和节点
的定义为:
def leafs: Gen[Leaf] = Gen.value(Leaf())
def nodes: Gen[Node] = for {
x <- ints // Note: be sure to ask for x first, or it'll StackOverflow later, inside scalacheck code!
left <- trees
right <- trees
} yield Node(left, right, x)
它之后能够正常工作。
这是怎么回事?为什么构建Arbitrary
值最初会导致堆栈溢出?为什么看起来scalacheck生成器对微小的更改如此敏感,而这些更改不应影响生成器的控制流?
为什么我的表达式oneOf(0,1)
与原始的oneOf(leafs, nodes)
没有完全等价?