Scalacheck收缩

时间:2017-03-03 14:48:38

标签: scala scalacheck

我对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)

如何为此编写缩小方法?

1 个答案:

答案 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)
}