CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-org-typelevel--cats-testkit

Testing utilities and helpers for the Cats functional programming library with controlled type class instances for property-based testing

Overview
Eval results
Files

helper-types.mddocs/

Helper Types for Type Class Testing

The Helper Types capability provides concrete data types where you can control exactly which type class instances are available. This enables precise testing of algebraic laws and type class behaviors.

Overview

All helper types extend the base N trait and have controlled type class instances:

  • All types include Arbitrary[T] and Cogen[T] for ScalaCheck property testing
  • Each type provides exactly one primary algebraic type class instance
  • Additional comparison instances (Eq, Order, etc.) are provided where appropriate

Base Types and Traits

abstract class N {
  def n: Int
}

abstract class Arb[E <: N](f: Int => E) {
  implicit val earb: Arbitrary[E]
  implicit val ccog: Cogen[E]
}

trait Q[E] {
  implicit val eeq: Eq[E]
}

abstract class Companion[E <: N](f: Int => E) extends Arb[E](f) with Q[E]

Equality and Ordering Types

Eqed - Equality Only

For testing types that only need equality comparison.

case class Eqed(n: Int) extends N
object Eqed extends Companion(new Eqed(_))

Usage example:

import cats.tests.Helpers.Eqed
import cats.kernel.laws.discipline.EqTests

checkAll("Eq[Eqed]", EqTests[Eqed].eqv)

POrd - Partial Order

For testing partial ordering laws where not all elements are comparable.

case class POrd(n: Int) extends N
object POrd extends Arb(new POrd(_)) {
  implicit object O extends PartialOrder[POrd] {
    def partialCompare(x: POrd, y: POrd): Double
  }
}

Usage example:

import cats.tests.Helpers.POrd
import cats.kernel.laws.discipline.PartialOrderTests

checkAll("PartialOrder[POrd]", PartialOrderTests[POrd].partialOrder)

Ord - Total Order

For testing total ordering laws.

case class Ord(n: Int) extends N
object Ord extends Arb(new Ord(_)) {
  implicit object O extends Order[Ord] {
    def compare(x: Ord, y: Ord): Int
  }
}

Usage example:

import cats.tests.Helpers.Ord
import cats.kernel.laws.discipline.OrderTests

checkAll("Order[Ord]", OrderTests[Ord].order)

Hsh - Hash

For testing hash-based equality.

case class Hsh(n: Int) extends N
object Hsh extends Arb(new Hsh(_)) {
  implicit object O extends Hash[Hsh] {
    def hash(x: Hsh): Int
    def eqv(x: Hsh, y: Hsh): Boolean
  }
}

Algebraic Structure Types

Band - Idempotent Semigroup

For testing idempotent semigroup laws (where x combine x = x).

case class Bnd(n: Int) extends N
object Bnd extends Companion(new Bnd(_)) {
  implicit object Alg extends Band[Bnd] {
    def combine(x: Bnd, y: Bnd): Bnd
  }
}

Semilattice

For testing semilattice laws (idempotent and commutative semigroup).

case class SL(n: Int) extends N
object SL extends Companion(new SL(_)) {
  implicit object Alg extends Semilattice[SL] {
    def combine(x: SL, y: SL): SL
  }
}

BoundedSemilattice

For testing bounded semilattice laws (semilattice with identity element).

case class BSL(n: Int) extends N
object BSL extends Companion(new BSL(_)) {
  implicit object Alg extends BoundedSemilattice[BSL] {
    def empty: BSL
    def combine(x: BSL, y: BSL): BSL
  }
}

Semigroup

For testing basic semigroup laws (associativity).

case class Semi(n: Int) extends N
object Semi extends Companion(new Semi(_)) {
  implicit object Alg extends Semigroup[Semi] {
    def combine(x: Semi, y: Semi): Semi
  }
}

CommutativeSemigroup

For testing commutative semigroup laws.

case class CSemi(n: Int) extends N
object CSemi extends Companion(new CSemi(_)) {
  implicit object Alg extends CommutativeSemigroup[CSemi] {
    def combine(x: CSemi, y: CSemi): CSemi
  }
}

Monoid

For testing monoid laws (semigroup with identity).

case class Mono(n: Int) extends N
object Mono extends Companion(new Mono(_)) {
  implicit object Alg extends Monoid[Mono] {
    def empty: Mono
    def combine(x: Mono, y: Mono): Mono
  }
}

Usage example:

import cats.tests.Helpers.Mono
import cats.kernel.laws.discipline.MonoidTests

checkAll("Monoid[Mono]", MonoidTests[Mono].monoid)

CommutativeMonoid

For testing commutative monoid laws.

case class CMono(n: Int) extends N
object CMono extends Companion(new CMono(_)) {
  implicit object Alg extends CommutativeMonoid[CMono] {
    def empty: CMono
    def combine(x: CMono, y: CMono): CMono
  }
}

Group

For testing group laws (monoid with inverse).

case class Grp(n: Int) extends N
object Grp extends Companion(new Grp(_)) {
  implicit object Alg extends Group[Grp] {
    def empty: Grp
    def combine(x: Grp, y: Grp): Grp
    def inverse(x: Grp): Grp
  }
}

Usage example:

import cats.tests.Helpers.Grp
import cats.kernel.laws.discipline.GroupTests

checkAll("Group[Grp]", GroupTests[Grp].group)

CommutativeGroup

For testing commutative group laws.

case class CGrp(n: Int) extends N
object CGrp extends Companion(new CGrp(_)) {
  implicit object Alg extends CommutativeGroup[CGrp] {
    def empty: CGrp
    def combine(x: CGrp, y: CGrp): CGrp
    def inverse(x: CGrp): CGrp
  }
}

Testing Pattern

The typical pattern for using helper types in property-based testing:

import cats.tests.Helpers._
import cats.kernel.laws.discipline._
import org.scalatest.funsuite.AnyFunSuite
import org.scalatestplus.scalacheck.Checkers

class AlgebraicLawTests extends AnyFunSuite with Checkers {
  
  test("semigroup laws") {
    checkAll("Semigroup[Semi]", SemigroupTests[Semi].semigroup)
  }
  
  test("monoid laws") {
    checkAll("Monoid[Mono]", MonoidTests[Mono].monoid)
  }
  
  test("group laws") {
    checkAll("Group[Grp]", GroupTests[Grp].group)
  }
}

Each helper type provides exactly the type class instances needed for testing specific algebraic laws, ensuring that tests focus on the intended algebraic structure without interference from additional instances.

Install with Tessl CLI

npx tessl i tessl/maven-org-typelevel--cats-testkit

docs

helper-types.md

index.md

list-wrapper.md

tile.json