Aravind Yarram
Aravind Yarram

Reputation: 80166

Defining a ScalaCheck generator in terms of another Gen

How do I define a generator in to produce random data for fields of a given Block. Following is the scaffolding code. I need help with an expression to replace the ???. This expression should generate Seq[Field], but the Field should be generated using defined genField function.

def blockGen(b: Block): Gen[Block] = for {
    id <- b.blockId //Use the same blockId as b
    fields <- ??? //Get the type from each field and call genField
} yield Block(id, fields)

ADT

trait Data {}

trait Field extends Data {
  val name: String
  val value: String
}

case class StringField(name: String, value: String) extends Field
case class NumberField(name: String, value: String) extends Field
case class Block(blockId: Field, fields: Seq[Field]) extends Data

Generators

def fieldGen(fieldType: Field): Gen[Field] = {
  for {
    f <-
    fieldType match {
      case _: NumberField => numGen
      case _: StringField => strGen
    }
  } yield f
}

val strGen: Gen[StringField] = for {
  name <- Gen.identifier
  value <- Gen.alphaStr
} yield StringField(name, value)

val numGen: Gen[NumberField] = for {
  name <- Gen.identifier
  value <- Gen.numStr
} yield NumberField(name, value)

Sample Block: myBlock

val cx = new StringField("blockId", "CX")
val seg = StringField("segmentation", "ABC")
val ver = NumberField("version", "1.0")

val myBlock = Block(cx, Seq(seg, ver))

Upvotes: 0

Views: 626

Answers (1)

Chris Martin
Chris Martin

Reputation: 30736

I believe what you're looking for is Gen.sequence.

Also, id doesn't need to come from a generator, since all you're doing is using a particular value directly.

def blockGen(b: Block): Gen[Block] =
  for {
    fields <- Gen.sequence[Seq[Field], Field](b.fields.map(fieldGen))
  } yield Block(b.blockId, fields)

By the way, Gen.sequence is very similar to Future.sequence and sequence in Haskell.

Upvotes: 3

Related Questions