package laws
The laws
package provides functionality for describing laws as values.
The fundamental abstraction is a set of ZLaws[Caps, R]
. These laws model
the laws that instances having a capability of type Caps
are expected to
satisfy. A capability Caps[_]
is an abstraction describing some
functionality that is common across different data types and obeys certain
laws. For example, we can model the capability of two values of a type
being compared for equality as follows:
trait Equal[-A] { def equal(a1: A, a2: A): Boolean }
Definitions of equality are expected to obey certain laws:
- Reflexivity -
a1 === a1
2. Symmetry -a1 === a2 ==> a2 === a1
3. Transitivity - (a1 === a2) && (a2 === a3) ==> (a1 === a3)
These laws define what the capabilities mean and ensure that it is safe to abstract across different instances with the same capability.
Using ZIO Test, we can represent these laws as values. To do so, we define
each law using one of the ZLaws
constructors. For example:
val transitivityLaw = ZLaws.Laws3[Equal]("transitivityLaw") { def apply[A: Equal](a1: A, a2: A, a3: A): TestResult = ??? }
We can then combine laws using the +
operator:
val reflexivityLaw: = ??? val symmetryLaw: = ??? val equalLaws = reflexivityLaw + symmetryLaw + transitivityLaw
Laws have a run
method that takes a generator of values of type A
and
checks that those values satisfy the laws. In addition, objects can extend
ZLawful
to provide an even more convenient syntax for users to check that
instances satisfy certain laws.
object Equal extends Lawful[Equal] object Hash extends Lawful[Hash] object Ord extends Lawful[Ord] checkAllLaws(Equal + Hash + Ord)(Gen.anyInt)
Note that capabilities compose seamlessly because of contravariance. We can combine laws describing different capabilities to construct a set of laws requiring that instances having all of the capabilities satisfy each of the laws.
- Alphabetic
- By Inheritance
- laws
- AnyRef
- Any
- Hide All
- Show All
- Public
- All
Type Members
-
trait
GenF[-R, F[_]] extends AnyRef
A
GenF
knows how to construct a generator ofF[A]
values given a generator ofA
values for anyA
.A
GenF
knows how to construct a generator ofF[A]
values given a generator ofA
values for anyA
. For example, aGenF
ofList
values knows how to generate lists with elements given a generator of elements of that type. You can think ofGenF
as a "recipe" for building generators for parameterized types. - type Lawful[-Caps[_]] = ZLawful[Caps, Any]
- type Lawful2[-CapsBoth[_, _], -CapsLeft[_], -CapsRight[_]] = ZLawful2[CapsBoth, CapsLeft, CapsRight, Any]
- type Laws[-Caps[_]] = ZLaws[Caps, Any]
- type Laws2[-CapsBoth[_, _], -CapsLeft[_], -CapsRight[_]] = ZLaws2[CapsBoth, CapsLeft, CapsRight, Any]
-
trait
ZLawful[-Caps[_], -R] extends AnyRef
ZLawful[Caps, R]
describes a capability that is expected to satisfy a set of laws.ZLawful[Caps, R]
describes a capability that is expected to satisfy a set of laws. Lawful instances can be combined using+
to describe a set of capabilities and all of the laws that those capabilities are expected to satisfy.trait Equal[-A] { def equal(a1: A, a2: A): Boolean } object Equal extends Lawful[Equal] { val laws = ??? }
- trait ZLawful2[-CapsBoth[_, _], -CapsLeft[_], -CapsRight[_], -R] extends AnyRef
-
trait
ZLaws[-Caps[_], -R] extends AnyRef
ZLaws[Caps, R]
represents a set of laws that values with capabilitiesCaps
are expected to satisfy.ZLaws[Caps, R]
represents a set of laws that values with capabilitiesCaps
are expected to satisfy. Laws can be run by providing a generator of values of a typeA
with the required capabilities to return a test result. Laws can be combined using+
to produce a set of laws that require both sets of laws to be satisfied. - trait ZLaws2[-CapsBoth[_, _], -CapsLeft[_], -CapsRight[_], -R] extends AnyRef
Value Members
-
def
checkAllLaws[CapsF[_[_]], Caps[_], R, R1 <: R, F[_], A](lawful: Invariant[CapsF, Caps, R])(genF: GenF[R1, F], gen: Gen[R1, A])(implicit arg0: CapsF[F], arg1: Caps[A]): ZIO[R1, Nothing, TestResult]
Checks that all values generated by a the specified generator satisfy the expected behavior of the lawful instance.
-
def
checkAllLaws[CapsF[_[-_]], Caps[_], R, R1 <: R, F[-_], A](lawful: Contravariant[CapsF, Caps, R])(genF: GenF[R1, F], gen: Gen[R1, A])(implicit arg0: CapsF[F], arg1: Caps[A]): ZIO[R1, Nothing, TestResult]
Checks that all values generated by a the specified generator satisfy the expected behavior of the lawful instance.
- def checkAllLaws[CapsF[_[+_]], Caps[_], R, R1 <: R, F[+_], A](lawful: Covariant[CapsF, Caps, R])(genF: GenF[R1, F], gen: Gen[R1, A])(implicit arg0: CapsF[F], arg1: Caps[A]): ZIO[R1, Nothing, TestResult]
-
def
checkAllLaws[CapsBoth[_, _], CapsLeft[_], CapsRight[_], R, R1 <: R, A, B](lawful: ZLawful2[CapsBoth, CapsLeft, CapsRight, R])(a: Gen[R1, A], b: Gen[R1, B])(implicit arg0: CapsLeft[A], arg1: CapsRight[B], CapsBoth: CapsBoth[A, B]): ZIO[R1, Nothing, TestResult]
Checks that all values generated by a the specified generator satisfy the expected behavior of the lawful instance.
-
def
checkAllLaws[Caps[_], R, R1 <: R, A](lawful: ZLawful[Caps, R])(gen: Gen[R1, A])(implicit arg0: Caps[A]): ZIO[R1, Nothing, TestResult]
Checks that all values generated by a the specified generator satisfy the expected behavior of the lawful instance.
- object GenF
- object LawfulF
- object Laws
- object Laws2
- object LawsF
-
object
ZLawfulF
ZLawful[CapsF, Caps, R]
describes a set of laws that a parameterized typeF[A]
with capabilitiesCapsF
is expected to satisfy with respect to all typesA
that have capabilitiesCaps
.ZLawful[CapsF, Caps, R]
describes a set of laws that a parameterized typeF[A]
with capabilitiesCapsF
is expected to satisfy with respect to all typesA
that have capabilitiesCaps
. Lawful instances can be combined using+
to describe a set of capabilities and all of the laws that those capabilities are expected to satisfy. - object ZLaws
- object ZLaws2
-
object
ZLawsF
ZLaws[CapsF, Caps, R]
describes a set of laws that a parameterized typeF[A]
with capabilitiesCapsF
is expected to satisfy with respect to all typesA
that have capabilitiesCaps
.ZLaws[CapsF, Caps, R]
describes a set of laws that a parameterized typeF[A]
with capabilitiesCapsF
is expected to satisfy with respect to all typesA
that have capabilitiesCaps
. Laws can be run by providing aGenF
that is capable of generatingF[A]
values given a generator ofA
values and a generatoro of values of some typeA
. Laws can be combined using+
to produce a set of laws that require both sets of laws to be satisfied.