ScalaCheckのGenを試してみる

## 概要

ScalaCheckの`Gen`は、プロパティベーステストで使用するテストデータを生成するためのジェネレーターです。
この記事では、Genの様々なメソッドを呼び出した結果について共有します。

## const

`Gen#const`は、引数で指定した値を生成するジェネレータを返します。

```scala
scala> Gen.const(1).sample
val res0: Option[Int] = Some(1)
```

## choose

`Gen#choose[T]`は、第一引数`min`および第二引数`max`で閉区間を指定して、
`T`型の値をランダムに生成するジェネレータを返します。

```scala
scala> Gen.choose(0, 10).sample
val res4: Option[Int] = Some(10)

scala> Gen.choose(0, 10).sample
val res8: Option[Int] = Some(2)
                                                                                
scala> Gen.choose(0, 10).sample
val res9: Option[Int] = Some(6)
                                                                                
scala> Gen.choose(0, 10).sample
val res10: Option[Int] = Some(9)
                                                                                
scala> Gen.choose(0, 10).sample
val res11: Option[Int] = Some(0)
```

## fail

`Gen#fail`は、値を絶対に生成しないジェネレータを返します。

```scala
scala> Gen.fail.sample
val res2: Option[Nothing] = None
                                                                                
scala> Gen.fail[Int].sample
val res3: Option[Int] = None
```

個人的に捻り出した`Gen#fail`の使い道ですが、
以下のように無効なケースを明示的に扱う場合に使えるかもしれないです。
(他に何かいい使い方があれば教えてくださいm(_ _)m)

```scala:無効なケースを明示的に扱う
import org.scalacheck.Prop.forAll
import org.scalacheck.Gen

val validGen: Gen[Int] = Gen.choose(0, 10)
val invalidGen: Gen[Int] = Gen.fail // 0から10までの数字以外はインプットとして想定しないことを強調する

val prop = forAll(Gen.oneOf(validGen, invalidGen)) { n =>
  n >= 0 && n <= 10
}

prop.check()
```

## sequence

`Gen#sequence`は、複数のジェネレータを組み合わせて、
それらのジェネレータが生成する値のコレクション（リスト、配列など）を生成するための関数です。

```scala
scala> Gen.sequence(List(org.scalacheck.Gen.alphaStr)).sample
val res27: Option[java.util.ArrayList[String]] = Some([ijdWdpIQdxGkKYINKJQ])
```

```scala
scala> import org.scalacheck.Gen.{alphaUpperStr, hexStr}
scala> Gen.sequence(Seq(alphaUpperStr, hexStr)).sample
val res30: Option[java.util.ArrayList[String]] = Some([PJBQKOMHSVFPHPIIVJXOKWPUGHSPLSQDJEFCKC, 76dB30803c6D6C3803404D9Ae44B4B45898B14B6cEce06d2A08Fa42b9c7C233c52B8ec28])
```

## oneOf

`Gen.oneOf`は、引数として与えられたジェネレータの中からランダムに1つを選び、
そのジェネレータを使って値を生成するジェネレータを返します。

```scala
scala> Gen.oneOf(1, 10, 100).sample
val res33: Option[Int] = Some(1)
                                                                                                                                                                                                                                                                                
scala> Gen.oneOf(1, 10, 100).sample
val res34: Option[Int] = Some(100)

scala> Gen.oneOf(Gen.const(1), Gen.const(2)).sample
val res1: Option[Int] = Some(1)
```

## option

`Gen.option`は、オプション型の値を生成するためのジェネレータを返します。

```scala
scala> Gen.option(1).sample
val res35: Option[Option[Int]] = Some(None)
                                                                                                                                                                                                                                                                                
scala> Gen.option(1).sample
val res36: Option[Option[Int]] = Some(Some(1))
```

## either

`Gen.either`は、Either型の値を生成するためのジェネレータを返します。

```scala
scala> Gen.either(100, "aaa").sample
val res41: Option[Either[Int, String]] = Some(Left(100))
                                                                                                                                                                                                                                                                                
scala> Gen.either(100, "aaa").sample
val res42: Option[Either[Int, String]] = Some(Right(aaa))
```

## frequency

`Gen.frequency`は、複数のジェネレータとその生成確率をペアにしたリストを受け取り、
指定された確率に従ってジェネレータを選択し、値を生成するジェネレータ返します。

```scala
scala> Gen.frequency(
  |   (20, Gen.const(20)),
  |   (80, Gen.const(80))
    | ).sample
val res44: Option[Int] = Some(80)

scala> Gen.frequency(
  |   (20, Gen.const(20)),
  |   (80, Gen.const(80))
    | ).sample
val res45: Option[Int] = Some(80)

scala> Gen.frequency(
  |   (20, Gen.const(20)),
  |   (80, Gen.const(80))
    | ).sample
val res46: Option[Int] = Some(80)

scala> Gen.frequency(
  |   (20, Gen.const(20)),
  |   (80, Gen.const(80))
    | ).sample
val res47: Option[Int] = Some(80)

scala> Gen.frequency(
  |   (20, Gen.const(20)),
  |   (80, Gen.const(80))
    | ).sample
val res48: Option[Int] = Some(20)
```

## listOf

`Gen#listOf`は、指定されたジェネレータを使って要素を生成し、それらの要素からなるリストを生成するジェネレータを返します。

```scala
scala> Gen.listOf(Gen.const(1)).sample
val res2: Option[List[Int]] = Some(List(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1))

scala> Gen.listOf(
     |   Gen.frequency(
     |     (20, Gen.const(20)),
     |     (80, Gen.const(80))
     |   )
     | ).sample
val res4: Option[List[Int]] = Some(List(80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 20, 80, 20, 20, 80, 20, 20, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 20, 80, 20, 80, 80, 80, 80, 20, 20, 20, 80, 80, 20, 80))

scala> res4.get.filter(_ == 20).size.toDouble / res4.get.size
val res6: Double = 0.22916666666666666                                                                         
```

## listOfN

`Gen#listOfN`は、`Gen#listOf`とほぼ同じですが、生成するリストの長さを引数で指定できます。

```scala
scala> Gen.listOfN(3, Gen.const(1)).sample
val res7: Option[List[Int]] = Some(List(1, 1, 1))
```