我对ScalaCheck(完全是Scala)相当新,所以这可能是一个相当简单的解决方案
我正在使用ScalaCheck为AST生成测试并验证编写器/解析器是否正常工作。我有这些文件
AST.scala
package com.test
object Operator extends Enumeration {
val Add, Subtract, Multiply, Divide = Value
}
sealed trait AST
case class Operation(left: AST, op: Operator.Value, right: AST) extends AST
case class Literal(value: Int) extends AST
GenOperation.scala
import com.test.{AST, Literal}
import org.scalacheck._
import Shrink._
import Prop._
import Arbitrary.arbitrary
object GenLiteral extends Properties("AST::Literal") {
property("Verify parse/write") = forAll(genLiteral){ (node) =>
// val string_version = node.writeToString() // AST -> String
// val result = Parse(string_version) // String -> AST
true
}
def genLiteral: Gen[Literal] = for {
value <- arbitrary[Int]
} yield Literal(value)
implicit def shrinkLiteral: Shrink[AST] = Shrink {
case Literal(value) =>
for {
reduced <- shrink(value)
} yield Literal(reduced)
}
}
GenOperation.scala
import com.test.{AST, Operation}
import org.scalacheck._
import Gen._
import Shrink._
import Prop._
import GenLiteral._
object GenOperation extends Properties("AST::Operation") {
property("Verify parse/write") = forAll(genOperation){ (node) =>
// val string_version = node.writeToString() // AST -> String
// val result = Parse(string_version) // String -> AST
true
}
def genOperation: Gen[Operation] = for {
left <- oneOf(genOperation, genLiteral)
right <- oneOf(genOperation, genLiteral)
op <- oneOf(Operator.values.toSeq)
} yield Operation(left,op,right)
implicit def shrinkOperation: Shrink[AST] = Shrink {
case Operation(l,o,r) =>
(
for {
ls <- shrink(l)
rs <- shrink(r)
} yield Operation(ls, o, rs)
) append (
for {
ls <- shrink(l)
} yield Operation(ls, o, r)
) append (
for {
rs <- shrink(r)
} yield Operation(l, o, rs)
) append shrink(l) append shrink(r)
}
}
在我编写的示例代码中(上面粘贴的内容)我收到了错误
ambiguous implicit values:
both method shrinkLiteral in object GenLiteral of type => org.scalacheck.Shrink[com.test.AST]
and method shrinkOperation in object GenOperation of type => org.scalacheck.Shrink[com.test.AST]
match expected type org.scalacheck.Shrink[com.test.AST]
ls <- shrink(l)
如何为此编写缩小方法?
答案 0 :(得分:4)
你有Shrink[AST]
的两个隐式实例,因此编译器会抱怨含糊不清的隐含值。
您可以将代码重写为:
implicit def shrinkLiteral: Shrink[Literal] = Shrink {
case Literal(value) => shrink(value).map(Literal)
}
implicit def shrinkOperation: Shrink[Operation] = Shrink {
case Operation(l,o,r) =>
shrink(l).map(Operation(_, o, r)) append
shrink(r).map(Operation(l, o, _)) append ???
}
implicit def shrinkAST: Shrink[AST] = Shrink {
case o: Operation => shrink(o)
case l: Literal => shrink(l)
}