Prop.forAll turns a generator and a predicate into a property: `def forAll[A](a: Gen[A])(f: A => Boolean): Prop`. Rather than checking one hand-picked value, it states that every value supplied by `Gen[A]` should satisfy `A => Boolean`. The result is a `Prop`, not a Boolean, so it can be run later and combined with other properties. section 8.1 section 8.1.2
This separation matters because a generator describes how to obtain test data, while a property describes the test to perform. A list generator can produce lists of varying lengths and values; one predicate can assert that reversing twice returns the original list, while another relates `headOption` to the reversed list’s `lastOption`. Combining the resulting properties with `&&` forms a partial specification: both claims must resist falsification. section 8.1 section 8.1.2
Expressing laws over generated lists
```scala val intList = Gen.listOf(Gen.choose(0, 100)) val prop = Prop.forAll(intList)(ns => ns.reverse.reverse == ns) && Prop.forAll(intList)(ns => ns.headOption == ns.reverse.lastOption) val failingProp = Prop.forAll(intList)(ns => ns.reverse == ns) ``` The first two predicates express stable relationships rather than particular expected outputs. The last makes a deliberately false universal claim, so a test run can report a generated counterexample such as `List(0, 1)`. section 8.1
A useful `Prop` must preserve the outcome of testing instead of merely printing it. If checking returned `Unit`, combining two properties would only run two independent side effects and discard the information needed to control composition. Returning a result permits `&&` to stop on a failure and `||` to try its alternative after a failure; failures can retain both the failing case and the number of prior successes. section 8.1.3 section 8.6
To implement `forAll`, a property needs more than its generator and predicate at construction time. Running it requires a test-case count and a source of randomness. It repeatedly draws generated values, evaluates the predicate, returns `Passed` if none fail, and returns `Falsified` with diagnostic information at the first false result. Exceptions from the predicate are also converted into failures so the triggering input is retained. section 8.1.6
Listing 8.3 Implementing forAll
def forAll[A](as: Gen[A])(f: A => Boolean): Prop =
(n, rng) =>
randomLazyList(as)(rng)
.zip(LazyList.from(0))
.take(n)
.map: #1
case (a, i) =>
try
if f(a) then Passed
else Falsified(a.toString, i) #2
catch
case e: Exception =>
Falsified(buildMsg(a, e), i) #3
.find(_.isFalsified)
.getOrElse(Passed)
}
def randomLazyList[A](g: Gen[A])(rng: RNG): LazyList[A] =
LazyList.unfold(rng)(rng => Some(g.run(rng))) #4
def buildMsg[A](s: A, e: Exception): String =
s"test case: $s\n" + #5
s"generated an exception: ${e.getMessage}\n" +
s"stack trace:\n ${e.getStackTrace.mkString("\n")}"
Inspect the complete loop: it creates a lazy stream of generated values, limits it to the requested test count, records the first falsification, and turns predicate exceptions into diagnostic failures. section 8.1.6
A later refinement distinguishes a property that is merely unfalsified from one proven over an exhaustively enumerated finite domain. `forAll` first consumes available exhaustive cases within its budget, then uses random samples when enumeration is incomplete. The result can therefore say whether all domain elements were checked or only whether no tested value falsified the predicate. section 8.6
When writing a property with `forAll`, make each part explicit:
- Choose a `Gen[A]` that represents the inputs whose behavior is under test. section 8.1
- Write an `A => Boolean` law that relates observable behavior instead of encoding a single example. section 8.1
- Compose independent laws with `&&` when both must hold, and retain failure information for debugging. section 8.1.3 section 8.6

