# Combining ScalaCheck generators


[ScalaCheck](https://www.scalacheck.org/) library comes with a wide variety of [built-in generators](https://github.com/rickynils/scalacheck/blob/master/doc/UserGuide.md#generators), but let me show you how to combine them to make the library even more powerful.

<!-- more -->

## Map on generator

**Generator** comes with a method `map` which allows you to transform obtained data. Let's create a generator which generates only positive, even integers:

```scala
val evenNumberGenerator: Gen[Int] = Gen.posNum[Int].map(_ * 2)
````

In this case map accepts a function `Int => U`, since the generator on which the map is called returns `Int`. You can chain maps even further:

```scala
val oddNumberGenerator: Gen[Int] = evenNumberGenerator.map(_ + 1)
```

## FlatMap on generator

Let's suppose that you wold like to generate `Either[String, Int]`. We can use `flatMap` to handle this case. We will create `Right` if generated number is even and left if it's odd:

```scala
  val leftOrRightFiftyFifty: Gen[Either[String, Int]] = Gen.posNum[Int].flatMap{ i =>
    if(i % 2 == 0) Gen.posNum[Int].map(Right[String, Int])
    else Gen.alphaLowerStr.map(Left[String, Int])
  }
```

FlatMap called on generator accepts a function `T => Gen[U]`. This allows you to combine generators further and further, leading to the generator which exactly suits your needs.


## Frequency generator
FlatMap is a very powerful tool, but requires a lot of boilerplate. What would happen if we wanted to obtain right 40% of time? What if we would have more and more possibilities? There is a nice built-in solution for this case. Take a look at `frequency` combinator:

```scala
val leftOrRight: Gen[Either[String, Int]] = Gen.frequency(
    4 -> Gen.posNum[Int].map(Right[String, Int]),
    6 -> Gen.alphaLowerStr.map(Left[String, Int])
)
```

## Options here and options there
Option generators are well represented in **ScalaCheck**. If you want to always generate `Some[T]` you can use `Gen.some` like this:

```scala
val someOfIntGenerator: Gen[Option[Int]] = Gen.some(Gen.posNum[Int])
```

In case you would like to have `Some` and `None` you can use `Gen.option`, to have both of the possibilities. It's used in exactly the same way as `Gen.some`:

```scala
val optionalIntegerGenerator: Gen[Option[Int]] = Gen.option(Gen.posNum[Int])
```

What is interesting `Gen.option` is implemented using `Gen.frequency`. Check it out [here](https://github.com/rickynils/scalacheck/blob/master/src/main/scala/org/scalacheck/Gen.scala#L542).

## Exclusive ranges
There might be a possibility that you want to generate a number from non overlapping ranges. Again you can use a nice built-in generator - `Gen.oneOf`. In this example we will generate numbers greater than 10 and smaller than 20 or bigger than 40 and smaller than 50. It's as simple as this:

```scala
val oneOfRanges: Gen[Int] = Gen.oneOf(
    Gen.chooseNum(10, 20),
    Gen.chooseNum(40, 50)
)
 ```

 ## Conclusion

Hopefully i managed to show you that ScalaCheck generators are easily combined, leading to code which can fit your exact needs.

Keep in mind that the examples I shown above are rather simple, but I hope you can already see usages which will fit your domain requirements.
