or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

alternative-laws.mdbifunctor-laws.mdcategory-laws.mdcommutative-laws.mdcomonad-laws.mdcore-laws.mderror-laws.mdindex.mdparallel-laws.mdtesting-utilities.mdtraversal-laws.md
tile.json

testing-utilities.mddocs/

Testing Utilities

Utility classes and objects for property-based testing and law verification in cats-laws.

Imports

import cats.laws.discipline._
import org.scalacheck.{Arbitrary, Gen, Cogen}
import org.scalacheck.Prop._

IsEq Type and Utilities

The core type for expressing law equations.

// Type alias from cats.kernel.laws
type IsEq[A] = cats.kernel.laws.IsEq[A]

// Value reference
val IsEq = cats.kernel.laws.IsEq

// Implicit class for creating IsEq instances
implicit final class IsEqArrow[A](private val lhs: A) extends AnyVal {
  def <->(rhs: A): IsEq[A] = IsEq(lhs, rhs)
}

ExhaustiveCheck

Trait for exhaustive property checking with finite domains.

trait ExhaustiveCheck[A] {
  def allValues: List[A]
}

object ExhaustiveCheck {
  // Instances for common types
  implicit val booleanExhaustiveCheck: ExhaustiveCheck[Boolean]
  implicit def tuple2ExhaustiveCheck[A: ExhaustiveCheck, B: ExhaustiveCheck]: ExhaustiveCheck[(A, B)]
  implicit def tuple3ExhaustiveCheck[A: ExhaustiveCheck, B: ExhaustiveCheck, C: ExhaustiveCheck]: ExhaustiveCheck[(A, B, C)]
  implicit def eitherExhaustiveCheck[A: ExhaustiveCheck, B: ExhaustiveCheck]: ExhaustiveCheck[Either[A, B]]
  implicit def optionExhaustiveCheck[A: ExhaustiveCheck]: ExhaustiveCheck[Option[A]]
  implicit def setExhaustiveCheck[A: ExhaustiveCheck]: ExhaustiveCheck[Set[A]]
}

MiniInt

A small domain integer type for efficient property testing. Similar to Int, but with a 4-bit domain (-8 to 7) that provides integer overflow characteristics for fast testing.

final class MiniInt private (val intBits: Int) extends AnyVal with Serializable {
  def toInt: Int
  def +(o: MiniInt): MiniInt
  def *(o: MiniInt): MiniInt  
  def |(o: MiniInt): MiniInt
  def /(o: MiniInt): MiniInt
  def unary_- : MiniInt
}

object MiniInt {
  val bitCount: Int = 4
  val minIntValue: Int = -8
  val maxIntValue: Int = 7
  val minValue: MiniInt
  val maxValue: MiniInt
  val zero: MiniInt
  val one: MiniInt
  val negativeOne: MiniInt
  
  val allValues: List[MiniInt]
  
  def isInDomain(i: Int): Boolean
  def fromInt(i: Int): Option[MiniInt]
  def wrapped(intBits: Int): MiniInt
  def unsafeFromInt(i: Int): MiniInt
  
  // Algebra instances for MiniInt
  val miniIntAddition: CommutativeGroup[MiniInt]
  val miniIntMultiplication: CommutativeMonoid[MiniInt]
  val miniIntOr: BoundedSemilattice[MiniInt]
  
  // Typeclass instances
  implicit val catsLawsEqInstancesForMiniInt: Order[MiniInt] with Hash[MiniInt]
  implicit val catsLawsExhaustiveCheckForMiniInt: ExhaustiveCheck[MiniInt]
}

Eq Instances

Comprehensive collection of Eq instances for higher-order types and functions.

object eq {
  // Function equality instances
  implicit def function1Eq[A, B](implicit A: ExhaustiveCheck[A], B: Eq[B]): Eq[A => B]
  implicit def function2Eq[A, B, C](implicit A: ExhaustiveCheck[A], B: ExhaustiveCheck[B], C: Eq[C]): Eq[(A, B) => C]
  
  // Kleisli arrow equality
  implicit def kleisliEq[F[_], A, B](implicit FA: ExhaustiveCheck[A], FB: Eq[F[B]]): Eq[Kleisli[F, A, B]]
  
  // Cokleisli arrow equality  
  implicit def cokleisliEq[F[_], A, B](implicit FB: ExhaustiveCheck[F[B]], A: Eq[A]): Eq[Cokleisli[F, A, B]]
  
  // Type class instances equality
  implicit def semigroupEq[A](implicit A: ExhaustiveCheck[A], eq: Eq[A]): Eq[Semigroup[A]]
  implicit def monoidEq[A](implicit A: ExhaustiveCheck[A], eq: Eq[A]): Eq[Monoid[A]]
  implicit def groupEq[A](implicit A: ExhaustiveCheck[A], eq: Eq[A]): Eq[Group[A]]
  
  // Higher-order type class equality
  implicit def functorEq[F[_]](implicit F: ExhaustiveCheck[Int => F[Int]]): Eq[Functor[F]]
  implicit def applicativeEq[F[_]](implicit F: ExhaustiveCheck[Int => F[Int]], FA: ExhaustiveCheck[F[Int => Int]]): Eq[Applicative[F]]
  implicit def monadEq[F[_]](implicit arbFInt: ExhaustiveCheck[F[Int]], eqFInt: Eq[F[Int]]): Eq[Monad[F]]
  
  // Many more instances for cats data types...
}

Arbitrary Instances

Comprehensive collection of Arbitrary and Cogen instances for ScalaCheck.

object arbitrary {
  // Basic cats.data types
  implicit def evalArbitrary[A: Arbitrary]: Arbitrary[Eval[A]]
  implicit def evalCogen[A: Cogen]: Cogen[Eval[A]]
  
  implicit def nonEmptyListArbitrary[A: Arbitrary]: Arbitrary[NonEmptyList[A]]
  implicit def nonEmptyListCogen[A: Cogen]: Cogen[NonEmptyList[A]]
  
  implicit def nonEmptyVectorArbitrary[A: Arbitrary]: Arbitrary[NonEmptyVector[A]] 
  implicit def nonEmptyVectorCogen[A: Cogen]: Cogen[NonEmptyVector[A]]
  
  implicit def chainArbitrary[A: Arbitrary]: Arbitrary[Chain[A]]
  implicit def chainCogen[A: Cogen]: Cogen[Chain[A]]
  
  implicit def nonEmptyChainArbitrary[A: Arbitrary]: Arbitrary[NonEmptyChain[A]]
  implicit def nonEmptyChainCogen[A: Cogen]: Cogen[NonEmptyChain[A]]
  
  // Monad transformers
  implicit def optionTArbitrary[F[_]: Arbitrary, A: Arbitrary]: Arbitrary[OptionT[F, A]]
  implicit def optionTCogen[F[_]: Cogen, A: Cogen]: Cogen[OptionT[F, A]]
  
  implicit def eitherTArbitrary[F[_]: Arbitrary, A: Arbitrary, B: Arbitrary]: Arbitrary[EitherT[F, A, B]]
  implicit def eitherTCogen[F[_]: Cogen, A: Cogen, B: Cogen]: Cogen[EitherT[F, A, B]]
  
  implicit def kleisliArbitrary[F[_]: Arbitrary, A: Arbitrary, B: Arbitrary]: Arbitrary[Kleisli[F, A, B]]
  implicit def kleisliCogen[F[_]: Cogen, A: Cogen, B: Cogen]: Cogen[Kleisli[F, A, B]]
  
  implicit def cokleisliArbitrary[F[_]: Arbitrary, A: Arbitrary, B: Arbitrary]: Arbitrary[Cokleisli[F, A, B]]
  implicit def cokleisliCogen[F[_]: Cogen, A: Cogen, B: Cogen]: Cogen[Cokleisli[F, A, B]]
  
  // Validated and Ior  
  implicit def validatedArbitrary[A: Arbitrary, B: Arbitrary]: Arbitrary[Validated[A, B]]
  implicit def validatedCogen[A: Cogen, B: Cogen]: Cogen[Validated[A, B]]
  
  implicit def iorArbitrary[A: Arbitrary, B: Arbitrary]: Arbitrary[Ior[A, B]]
  implicit def iorCogen[A: Cogen, B: Cogen]: Cogen[Ior[A, B]]
  
  // And many more for all cats.data types...
}

RuleSet

The fundamental type for organizing property-based tests.

trait RuleSet {
  def name: String
  def bases: Seq[(String, RuleSet)]
  def props: Seq[(String, Prop)]
}

// Common implementations
class DefaultRuleSet(
  val name: String,
  val parent: Option[RuleSet],
  val props: (String, Prop)*
) extends RuleSet {
  val bases: Seq[(String, RuleSet)] = parent.toSeq.map(p => (p.name, p))
}

class SimpleRuleSet(
  val name: String,
  val props: (String, Prop)*
) extends RuleSet {
  val bases: Seq[(String, RuleSet)] = Seq.empty
}

ScalaVersionSpecific

Version-specific arbitrary instances for different Scala versions.

Scala 2.12

object ScalaVersionSpecific {
  implicit def zipStreamArbitrary[A: Arbitrary]: Arbitrary[ZipStream[A]]
  implicit def zipStreamCogen[A: Cogen]: Cogen[ZipStream[A]]
}

Scala 2.13+

object ScalaVersionSpecific {
  implicit def zipLazyListArbitrary[A: Arbitrary]: Arbitrary[ZipLazyList[A]]
  implicit def zipLazyListCogen[A: Cogen]: Cogen[ZipLazyList[A]]
  
  implicit def nonEmptyLazyListArbitrary[A: Arbitrary]: Arbitrary[NonEmptyLazyList[A]]
  implicit def nonEmptyLazyListCogen[A: Cogen]: Cogen[NonEmptyLazyList[A]]
}

Usage Examples

Using ExhaustiveCheck

import cats.laws.discipline.ExhaustiveCheck

// Get all boolean values for testing
val allBooleans = ExhaustiveCheck[Boolean].allValues
// List(true, false)

// Test all combinations of Either[Boolean, Boolean]
val allEithers = ExhaustiveCheck[Either[Boolean, Boolean]].allValues
// List(Left(true), Left(false), Right(true), Right(false))

Using MiniInt for Efficient Testing

import cats.laws.discipline.MiniInt
import cats.laws.discipline.eq._

// Test ring laws with small domain
class MiniIntRingTest extends AnyFunSuite with Checkers {
  checkAll("MiniInt.RingLaws", RingTests[MiniInt].ring)
}

Creating Custom RuleSets

import cats.laws.discipline.{RuleSet, DefaultRuleSet}
import org.scalacheck.Prop._

def customLaws[F[_]: Functor]: RuleSet = new DefaultRuleSet(
  name = "custom functor laws",
  parent = Some(FunctorTests[F].functor[Int, String, Double]),
  "custom property" -> forAll { (fa: F[Int]) =>
    // Custom property test
    fa.map(identity) == fa
  }
)

Converting IsEq to Prop

import cats.laws.discipline.catsLawsIsEqToProp

val law: IsEq[List[Int]] = List(1, 2).map(identity) <-> List(1, 2)
val prop: Prop = law  // Automatic conversion via implicit