22

I am trying to generate optional parameters in ScalaCheck, without success.

There seems to be no direct mechanism for this. Gen.containerOf[Option, Thing](thingGenerator) fails because it cannot find an implicit Buildable[Thing, Option].

I tried

for {
  thing <- Gen.listOfN[Thing](1, thingGenerator)
} yield thing.headOption

But this doesn't work because listOfN produces a list that is always of length N. As a result I always get a Some[Thing]. Similarly, listOf1 does not work, because (a) it doesn't produce empty lists, but also (b) it is inefficient because I can't set a max limit on the number of elements.

How can I generate Option[Thing] that includes Nones?

EDIT: I have found a solution, but it is not succinct. Is there a better way than this?

for {
  thing <- for {
    qty <- Gen.choose(0,1)
    things <- Gen.listOfN[Thing](qty, thingGenerator)
  } yield things.headOption
} yield thing

EDIT 2: I generalised this to

def optional[T](g: Gen[T]) = 
  for (qty <- Gen.choose(0, 1); xs <- Gen.listOfN[T](qty, g)) yield xs.headOption

So I don't have to write it more than once. But surely this is in the library already and I just missed it?

Synesso
  • 37,610
  • 35
  • 136
  • 207
  • 1
    About EDIT 2. I just found out that `Gen#option[T]` was introduced with version 1.11.5 of scalacheck - see [here](https://github.com/rickynils/scalacheck/commit/35c8309e7b52eff910dbc6bb1bc727c31ffed07d). The method will return either an instance of `Some[T]` or `None` with equal probability. – erasing Sep 18 '14 at 10:11

2 Answers2

31

Now you can just use:

Gen.option(yourGen)
douglaz
  • 1,306
  • 2
  • 13
  • 17
9

You can use pick to randomly choose between a Some and a None generator:

val someThing = thingGenerator.map( Some.apply )
val noThing = Gen.value( None:Option[Thing] )
val optThing = Gen.oneOf( someThing, noThing )
Caoilte
  • 2,381
  • 1
  • 21
  • 27
paradigmatic
  • 40,153
  • 18
  • 88
  • 147
  • See new solution using Gen.option – douglaz May 25 '15 at 17:21
  • 1
    @douglaz Nice update. The [actual implementation](https://github.com/rickynils/scalacheck/blob/master/src/main/scala/org/scalacheck/Gen.scala#L376) of `Gen.option` is the one-line version of my answer, so I'll let it for the sake of learning scalacheck. However, your answer is certainly better. – paradigmatic May 26 '15 at 07:34