diff --git a/build.sbt b/build.sbt index 06f3581251..e080823f89 100644 --- a/build.sbt +++ b/build.sbt @@ -244,6 +244,7 @@ val binaryCompatibleExceptions = { exclude[UpdateForwarderBodyProblem]("cats.kernel.instances.MapInstances.catsKernelStdEqForMap"), exclude[UpdateForwarderBodyProblem]("cats.kernel.instances.MapInstances.catsKernelStdMonoidForMap"), exclude[ReversedMissingMethodProblem]("cats.kernel.instances.MapInstances.catsKernelStdHashForMap"), + exclude[UpdateForwarderBodyProblem]("cats.kernel.instances.OptionInstances0.catsKernelStdEqForOption"), exclude[UpdateForwarderBodyProblem]("cats.kernel.instances.TupleInstances.catsKernelStdEqForTuple12"), exclude[UpdateForwarderBodyProblem]("cats.kernel.instances.TupleInstances.catsKernelStdEqForTuple7"), exclude[UpdateForwarderBodyProblem]("cats.kernel.instances.TupleInstances.catsKernelStdPartialOrderForTuple4"), @@ -349,10 +350,13 @@ val binaryCompatibleExceptions = { exclude[InheritedNewAbstractMethodProblem]("cats.kernel.instances.EitherInstances0.catsStdPartialOrderForEither"), exclude[ReversedMissingMethodProblem]("cats.kernel.instances.OptionInstances1.catsKernelStdHashForOption"), exclude[ReversedMissingMethodProblem]("cats.kernel.instances.FunctionInstances0.catsKernelHashForFunction0"), + exclude[ReversedMissingMethodProblem]("cats.kernel.instances.OptionInstances0.catsKernelStdPartialOrderForOption"), exclude[ReversedMissingMethodProblem]("cats.kernel.instances.EitherInstances0.catsStdHashForEither"), + exclude[DirectMissingMethodProblem]("cats.kernel.instances.OptionInstances1.catsKernelStdPartialOrderForOption"), exclude[DirectMissingMethodProblem]("cats.kernel.instances.all.package.catsKernelStdPartialOrderForBitSet"), exclude[DirectMissingMethodProblem]("cats.kernel.instances.bitSet.package.catsKernelStdPartialOrderForBitSet"), - //todo: remove these once we release 1.0.0-RC1 + exclude[MissingTypesProblem]("cats.kernel.instances.OptionInstances1"), + exclude[InheritedNewAbstractMethodProblem]("cats.kernel.instances.OptionInstances1.catsKernelStdHashForOption"), exclude[InheritedNewAbstractMethodProblem]("cats.kernel.instances.QueueInstances.*"), exclude[InheritedNewAbstractMethodProblem]("cats.kernel.instances.QueueInstances1.*"), exclude[InheritedNewAbstractMethodProblem]("cats.kernel.instances.QueueInstances2.*"), diff --git a/docs/src/main/tut/typeclasses/lawtesting.md b/docs/src/main/tut/typeclasses/lawtesting.md index b8f1e4c490..56eea32d89 100644 --- a/docs/src/main/tut/typeclasses/lawtesting.md +++ b/docs/src/main/tut/typeclasses/lawtesting.md @@ -111,10 +111,8 @@ And voila, you've successfully proven that your data type upholds the Functor la ### Testing cats.kernel instances For most of the type classes included in cats, the above will work great. -However, the law tests for the type classes inside `cats.kernel` are structured a bit differently. -These include `Semigroup`, `Monoid`, `Group` and `Semilattice`. -Instead of importing the laws from `cats.laws.discipline.*`, we have to import `cats.kernel.laws.GroupLaws` -and then call the corresponding method, e.g. `GroupLaws[Foo].monoid`, or `GroupLaws[Foo].semigroup`. +However, the law tests for the type classes inside `cats.kernel` are located in `cats.kernel.laws.discipline.*` instead. +So we have to import from there to test type classes like `Semigroup`, `Monoid`, `Group` or `Semilattice`. Let's test it out, by defining a `Semigroup` instance for our `Tree` type. @@ -135,10 +133,10 @@ Then we can again test the instance inside our class extending `CatsSuite`: ```tut:book import cats.laws.discipline.FunctorTests -import cats.kernel.laws.GroupLaws +import cats.kernel.laws.discipline.SemigroupLawTests class TreeLawTests extends CatsSuite { - checkAll("Tree[Int].MonoidLaws", GroupLaws[Tree[Int]].semigroup) + checkAll("Tree[Int].SemigroupLaws", SemigroupLawTests[Tree[Int]].semigroup) checkAll("Tree.FunctorLaws", FunctorTests[Tree].functor[Int, Int, String]) } ``` diff --git a/js/src/test/scala/cats/tests/FutureTests.scala b/js/src/test/scala/cats/tests/FutureTests.scala index 61f4c1010d..574759537c 100644 --- a/js/src/test/scala/cats/tests/FutureTests.scala +++ b/js/src/test/scala/cats/tests/FutureTests.scala @@ -2,7 +2,7 @@ package cats package js package tests -import cats.kernel.laws.GroupLaws +import cats.kernel.laws.discipline.{MonoidLawTests, SemigroupLawTests} import cats.laws.discipline._ import cats.js.instances.Await import cats.js.instances.future.futureComonad @@ -58,8 +58,8 @@ class FutureTests extends CatsSuite { { implicit val F = ListWrapper.semigroup[Int] - checkAll("Future[ListWrapper[Int]]", GroupLaws[Future[ListWrapper[Int]]].semigroup) + checkAll("Future[ListWrapper[Int]]", SemigroupLawTests[Future[ListWrapper[Int]]].semigroup) } - checkAll("Future[Int]", GroupLaws[Future[Int]].monoid) + checkAll("Future[Int]", MonoidLawTests[Future[Int]].monoid) } diff --git a/jvm/src/test/scala/cats/tests/FutureTests.scala b/jvm/src/test/scala/cats/tests/FutureTests.scala index bf011071a8..2610fbb679 100644 --- a/jvm/src/test/scala/cats/tests/FutureTests.scala +++ b/jvm/src/test/scala/cats/tests/FutureTests.scala @@ -2,7 +2,7 @@ package cats package jvm package tests -import cats.kernel.laws.GroupLaws +import cats.kernel.laws.discipline.{MonoidLawTests, SemigroupLawTests} import cats.laws.discipline._ import cats.laws.discipline.arbitrary._ import cats.tests.{CatsSuite, ListWrapper} @@ -44,8 +44,8 @@ class FutureTests extends CatsSuite { { implicit val F = ListWrapper.semigroup[Int] - checkAll("Future[ListWrapper[Int]]", GroupLaws[Future[ListWrapper[Int]]].semigroup) + checkAll("Future[ListWrapper[Int]]", SemigroupLawTests[Future[ListWrapper[Int]]].semigroup) } - checkAll("Future[Int]", GroupLaws[Future[Int]].monoid) + checkAll("Future[Int]", MonoidLawTests[Future[Int]].monoid) } diff --git a/kernel-laws/src/main/scala/cats/kernel/laws/BandLaws.scala b/kernel-laws/src/main/scala/cats/kernel/laws/BandLaws.scala new file mode 100644 index 0000000000..a6e8f03180 --- /dev/null +++ b/kernel-laws/src/main/scala/cats/kernel/laws/BandLaws.scala @@ -0,0 +1,16 @@ +package cats.kernel.laws + +import cats.kernel.Band + +trait BandLaws[A] extends SemigroupLaws[A] { + override implicit def S: Band[A] + + def idempotence(x: A): IsEq[A] = + S.combine(x, x) <-> x + +} + +object BandLaws { + def apply[A](implicit ev: Band[A]): BandLaws[A] = + new BandLaws[A] { def S: Band[A] = ev } +} diff --git a/kernel-laws/src/main/scala/cats/kernel/laws/BaseLaws.scala b/kernel-laws/src/main/scala/cats/kernel/laws/BaseLaws.scala deleted file mode 100644 index bab672a933..0000000000 --- a/kernel-laws/src/main/scala/cats/kernel/laws/BaseLaws.scala +++ /dev/null @@ -1,27 +0,0 @@ -package cats.kernel.laws - -import cats.kernel._ - -import org.typelevel.discipline.Laws - -import org.scalacheck.{Arbitrary, Prop} - -object BaseLaws { - def apply[A : Eq : Arbitrary]: BaseLaws[A] = new BaseLaws[A] { - def Equ = Eq[A] - def Arb = implicitly[Arbitrary[A]] - } -} - -trait BaseLaws[A] extends Laws { - - implicit def Equ: Eq[A] - implicit def Arb: Arbitrary[A] - - class BaseRuleSet( - val name: String, - val parent: Option[RuleSet], - val bases: Seq[(String, Laws#RuleSet)], - val props: (String, Prop)* - ) extends RuleSet with HasOneParent -} diff --git a/kernel-laws/src/main/scala/cats/kernel/laws/BoundedSemilatticeLaws.scala b/kernel-laws/src/main/scala/cats/kernel/laws/BoundedSemilatticeLaws.scala new file mode 100644 index 0000000000..d55b64a380 --- /dev/null +++ b/kernel-laws/src/main/scala/cats/kernel/laws/BoundedSemilatticeLaws.scala @@ -0,0 +1,13 @@ +package cats.kernel.laws + +import cats.kernel.BoundedSemilattice + +trait BoundedSemilatticeLaws[A] extends CommutativeMonoidLaws[A] with SemilatticeLaws[A] { + override implicit def S: BoundedSemilattice[A] + +} + +object BoundedSemilatticeLaws { + def apply[A](implicit ev: BoundedSemilattice[A]): BoundedSemilatticeLaws[A] = + new BoundedSemilatticeLaws[A] { def S: BoundedSemilattice[A] = ev } +} diff --git a/kernel-laws/src/main/scala/cats/kernel/laws/CommutativeGroupLaws.scala b/kernel-laws/src/main/scala/cats/kernel/laws/CommutativeGroupLaws.scala new file mode 100644 index 0000000000..0a2d6ceee0 --- /dev/null +++ b/kernel-laws/src/main/scala/cats/kernel/laws/CommutativeGroupLaws.scala @@ -0,0 +1,13 @@ +package cats +package kernel +package laws + + +trait CommutativeGroupLaws[A] extends GroupLaws[A] with CommutativeMonoidLaws[A] { + override implicit def S: CommutativeGroup[A] +} + +object CommutativeGroupLaws { + def apply[A](implicit ev: CommutativeGroup[A]): CommutativeGroupLaws[A] = + new CommutativeGroupLaws[A] { def S: CommutativeGroup[A] = ev } +} diff --git a/kernel-laws/src/main/scala/cats/kernel/laws/CommutativeMonoidLaws.scala b/kernel-laws/src/main/scala/cats/kernel/laws/CommutativeMonoidLaws.scala new file mode 100644 index 0000000000..115962db14 --- /dev/null +++ b/kernel-laws/src/main/scala/cats/kernel/laws/CommutativeMonoidLaws.scala @@ -0,0 +1,13 @@ +package cats.kernel.laws + +import cats.kernel.CommutativeMonoid + +trait CommutativeMonoidLaws[A] extends MonoidLaws[A] with CommutativeSemigroupLaws[A] { + override implicit def S: CommutativeMonoid[A] + +} + +object CommutativeMonoidLaws { + def apply[A](implicit ev: CommutativeMonoid[A]): CommutativeMonoidLaws[A] = + new CommutativeMonoidLaws[A] { def S: CommutativeMonoid[A] = ev } +} diff --git a/kernel-laws/src/main/scala/cats/kernel/laws/CommutativeSemigroupLaws.scala b/kernel-laws/src/main/scala/cats/kernel/laws/CommutativeSemigroupLaws.scala new file mode 100644 index 0000000000..b183816e34 --- /dev/null +++ b/kernel-laws/src/main/scala/cats/kernel/laws/CommutativeSemigroupLaws.scala @@ -0,0 +1,16 @@ +package cats.kernel.laws + +import cats.kernel.CommutativeSemigroup + +trait CommutativeSemigroupLaws[A] extends SemigroupLaws[A] { + override implicit def S: CommutativeSemigroup[A] + + def commutative(x: A, y: A): IsEq[A] = + S.combine(x, y) <-> S.combine(y, x) + +} + +object CommutativeSemigroupLaws { + def apply[A](implicit ev: CommutativeSemigroup[A]): CommutativeSemigroupLaws[A] = + new CommutativeSemigroupLaws[A] { def S: CommutativeSemigroup[A] = ev } +} diff --git a/kernel-laws/src/main/scala/cats/kernel/laws/EqLaws.scala b/kernel-laws/src/main/scala/cats/kernel/laws/EqLaws.scala new file mode 100644 index 0000000000..4e02ff981e --- /dev/null +++ b/kernel-laws/src/main/scala/cats/kernel/laws/EqLaws.scala @@ -0,0 +1,26 @@ +package cats.kernel.laws + +import cats.kernel.Eq + +trait EqLaws[A] { + + implicit def E: Eq[A] + + def reflexitivityEq(x: A): IsEq[A] = + x <-> x + + def symmetryEq(x: A, y: A): IsEq[Boolean] = + E.eqv(x, y) <-> E.eqv(y, x) + + def antiSymmetryEq(x: A, y: A, f: A => A): IsEq[Boolean] = + (!E.eqv(x, y) || E.eqv(f(x), f(y))) <-> true + + def transitivityEq(x: A, y: A, z: A): IsEq[Boolean] = + (!(E.eqv(x, y) && E.eqv(y, z)) || E.eqv(x, z)) <-> true + +} + +object EqLaws { + def apply[A](implicit ev: Eq[A]): EqLaws[A] = + new EqLaws[A] { def E: Eq[A] = ev } +} diff --git a/kernel-laws/src/main/scala/cats/kernel/laws/GroupLaws.scala b/kernel-laws/src/main/scala/cats/kernel/laws/GroupLaws.scala index 92980a626f..340d24e9d7 100644 --- a/kernel-laws/src/main/scala/cats/kernel/laws/GroupLaws.scala +++ b/kernel-laws/src/main/scala/cats/kernel/laws/GroupLaws.scala @@ -1,101 +1,23 @@ package cats.kernel package laws -import cats.kernel._ -import cats.kernel.instances.option._ -import org.typelevel.discipline.Laws +trait GroupLaws[A] extends MonoidLaws[A] { + override implicit def S: Group[A] -import org.scalacheck.{Arbitrary, Prop} -import org.scalacheck.Prop._ + def leftInverse(x: A): IsEq[A] = + S.empty <-> S.combine(S.inverse(x), x) -object GroupLaws { - def apply[A : Eq : Arbitrary]: GroupLaws[A] = new GroupLaws[A] { - def Equ = Eq[A] - def Arb = implicitly[Arbitrary[A]] - } -} - -trait GroupLaws[A] extends Laws { - - implicit def Equ: Eq[A] - implicit def Arb: Arbitrary[A] - - // groups - - def semigroup(implicit A: Semigroup[A]): GroupProperties = new GroupProperties( - name = "semigroup", - parents = Nil, - Rules.serializable(A), - Rules.associativity(A.combine), - Rules.repeat1("combineN")(A.combineN), - Rules.repeat2("combineN", "|+|")(A.combineN)(A.combine), - "combineAllOption" -> forAll { (xs: Vector[A]) => - A.combineAllOption(xs) ?== xs.reduceOption(A.combine) - } - ) - - def band(implicit A: Band[A]): GroupProperties = new GroupProperties( - name = "band", - parents = List(semigroup), - Rules.idempotence(A.combine), - "isIdempotent" -> Semigroup.isIdempotent[A] - ) - - def commutativeSemigroup(implicit A: CommutativeSemigroup[A]): GroupProperties = new GroupProperties( - name = "commutative semigroup", - parents = List(semigroup), - Rules.commutative(A.combine) - ) + def rightInverse(x: A): IsEq[A] = + S.empty <-> S.combine(x, S.inverse(x)) - def semilattice(implicit A: Semilattice[A]): GroupProperties = new GroupProperties( - name = "semilattice", - parents = List(band, commutativeSemigroup) - ) - - def monoid(implicit A: Monoid[A]): GroupProperties = new GroupProperties( - name = "monoid", - parents = List(semigroup), - Rules.leftIdentity(A.empty)(A.combine), - Rules.rightIdentity(A.empty)(A.combine), - Rules.repeat0("combineN", "id", A.empty)(A.combineN), - Rules.collect0("combineAll", "id", A.empty)(A.combineAll), - Rules.isId("isEmpty", A.empty)(A.isEmpty), - "combineAll" -> forAll { (xs: Vector[A]) => - A.combineAll(xs) ?== (A.empty +: xs).reduce(A.combine) - } - ) - - def commutativeMonoid(implicit A: CommutativeMonoid[A]): GroupProperties = new GroupProperties( - name = "commutative monoid", - parents = List(monoid, commutativeSemigroup) - ) - - def boundedSemilattice(implicit A: BoundedSemilattice[A]): GroupProperties = new GroupProperties( - name = "boundedSemilattice", - parents = List(commutativeMonoid, semilattice) - ) - - def group(implicit A: Group[A]): GroupProperties = new GroupProperties( - name = "group", - parents = List(monoid), - Rules.leftInverse(A.empty)(A.combine)(A.inverse), - Rules.rightInverse(A.empty)(A.combine)(A.inverse), - Rules.consistentInverse("remove")(A.remove)(A.combine)(A.inverse) - ) + def consistentInverse(x: A, y: A): IsEq[A] = + S.remove(x, y) <-> S.combine(x, S.inverse(y)) +} - def commutativeGroup(implicit A: CommutativeGroup[A]): GroupProperties = new GroupProperties( - name = "commutative group", - parents = List(group, commutativeMonoid) - ) +object GroupLaws { + def apply[A](implicit ev: Group[A]): GroupLaws[A] = + new GroupLaws[A] { def S: Group[A] = ev } +} - // property classes - class GroupProperties( - val name: String, - val parents: Seq[GroupProperties], - val props: (String, Prop)* - ) extends RuleSet { - val bases = Nil - } -} diff --git a/kernel-laws/src/main/scala/cats/kernel/laws/HashLaws.scala b/kernel-laws/src/main/scala/cats/kernel/laws/HashLaws.scala index dade828729..a710a90e61 100644 --- a/kernel-laws/src/main/scala/cats/kernel/laws/HashLaws.scala +++ b/kernel-laws/src/main/scala/cats/kernel/laws/HashLaws.scala @@ -1,58 +1,27 @@ package cats.kernel package laws -import org.typelevel.discipline._ -import org.scalacheck._ -import org.scalacheck.Prop._ - import scala.util.hashing._ -object HashLaws { - def apply[A : Eq : Arbitrary]: HashLaws[A] = - new HashLaws[A] { - def Equ = implicitly[Eq[A]] - def Arb = implicitly[Arbitrary[A]] - } -} +trait HashLaws[A] extends EqLaws[A] { + override implicit def E: Hash[A] + + def hashCompatibility(x: A, y: A): IsEq[Boolean] = + (!E.eqv(x, y) || (Hash.hash(x) == Hash.hash(y))) <-> true + -/** - * @author Tongfei Chen - */ -trait HashLaws[A] extends Laws { - - implicit def Equ: Eq[A] - implicit def Arb: Arbitrary[A] - - def hash(implicit A: Hash[A]): HashProperties = new HashProperties( - name = "hash", - parent = None, - Rules.serializable(Equ), - "compatibility-hash" -> forAll { (x: A, y: A) => - !(A.eqv(x, y)) ?|| (Hash.hash(x) == Hash.hash(y)) - } - ) - - def sameAsUniversalHash(implicit A: Hash[A]): HashProperties = new HashProperties( - name = "sameAsUniversalHash", - parent = None, - Rules.serializable(Equ), - "same-as-universal-hash" -> forAll { (x: A, y: A) => - (A.hash(x) == x.hashCode) && (Hash.fromUniversalHashCode[A].hash(x) == x.hashCode()) && - (A.eqv(x, y) == Hash.fromUniversalHashCode[A].eqv(x, y)) - } - ) - - def sameAsScalaHashing(implicit catsHash: Hash[A], scalaHashing: Hashing[A]): HashProperties = new HashProperties( - name = "sameAsScalaHashing", - parent = None, - Rules.serializable(Equ), - "same-as-scala-hashing" -> forAll { (x: A, y: A) => - (catsHash.hash(x) == Hash.fromHashing(scalaHashing).hash(x)) && - (catsHash.eqv(x, y) == Hash.fromHashing(scalaHashing).eqv(x, y)) - } - ) - - class HashProperties(name: String, parent: Option[RuleSet], props: (String, Prop)*) - extends DefaultRuleSet(name, parent, props: _*) + def sameAsUniversalHash (x: A, y: A): IsEq[Boolean] = + ((E.hash(x) == x.hashCode) && (Hash.fromUniversalHashCode[A].hash(x) == x.hashCode()) && + (E.eqv(x, y) == Hash.fromUniversalHashCode[A].eqv(x, y))) <-> true + + def sameAsScalaHashing(x: A, y: A, scalaHashing: Hashing[A]): IsEq[Boolean] = + ((E.hash(x) == Hash.fromHashing(scalaHashing).hash(x)) && + (E.eqv(x, y) == Hash.fromHashing(scalaHashing).eqv(x, y))) <-> true + +} + +object HashLaws { + def apply[A](implicit ev: Hash[A]): HashLaws[A] = + new HashLaws[A] { def E: Hash[A] = ev } } diff --git a/laws/src/main/scala/cats/laws/IsEq.scala b/kernel-laws/src/main/scala/cats/kernel/laws/IsEq.scala similarity index 86% rename from laws/src/main/scala/cats/laws/IsEq.scala rename to kernel-laws/src/main/scala/cats/kernel/laws/IsEq.scala index a094f74f6f..0b8735e7b9 100644 --- a/laws/src/main/scala/cats/laws/IsEq.scala +++ b/kernel-laws/src/main/scala/cats/kernel/laws/IsEq.scala @@ -1,4 +1,4 @@ -package cats +package cats.kernel package laws /** Represents two values of the same type that are expected to be equal. */ diff --git a/kernel-laws/src/main/scala/cats/kernel/laws/IsSerializable.scala b/kernel-laws/src/main/scala/cats/kernel/laws/IsSerializable.scala deleted file mode 100644 index 6b06a7aed9..0000000000 --- a/kernel-laws/src/main/scala/cats/kernel/laws/IsSerializable.scala +++ /dev/null @@ -1,38 +0,0 @@ -package cats.kernel.laws - -import catalysts.Platform -import org.scalacheck.Prop -import org.scalacheck.Prop._ -import scala.util.control.NonFatal -import scala.util.DynamicVariable - -/** - * Object with a dynamic variable that allows users to skip the - * serialization tests for certain instances. - */ -private[laws] object IsSerializable { - val runTests = new DynamicVariable[Boolean](true) - def apply(): Boolean = (!Platform.isJs) && runTests.value - - def testSerialization[M](m: M): Prop.Result = - if (Platform.isJs) Result(status = Proof) else { - import java.io._ - val baos = new ByteArrayOutputStream() - val oos = new ObjectOutputStream(baos) - var ois: ObjectInputStream = null // scalastyle:ignore null - try { - oos.writeObject(m) - oos.close() - val bais = new ByteArrayInputStream(baos.toByteArray()) - ois = new ObjectInputStream(bais) - val m2 = ois.readObject() // just ensure we can read it back - ois.close() - Result(status = Proof) - } catch { case NonFatal(t) => - Result(status = Exception(t)) - } finally { - oos.close() - if (ois != null) ois.close() // scalastyle:ignore null - } - } -} diff --git a/kernel-laws/src/main/scala/cats/kernel/laws/MonoidLaws.scala b/kernel-laws/src/main/scala/cats/kernel/laws/MonoidLaws.scala new file mode 100644 index 0000000000..979d80ca0a --- /dev/null +++ b/kernel-laws/src/main/scala/cats/kernel/laws/MonoidLaws.scala @@ -0,0 +1,32 @@ +package cats.kernel.laws + +import cats.kernel.{Eq, Monoid} + +trait MonoidLaws[A] extends SemigroupLaws[A] { + override implicit def S: Monoid[A] + + def leftIdentity(x: A): IsEq[A] = + S.combine(S.empty, x) <-> x + + def rightIdentity(x: A): IsEq[A] = + S.combine(x, S.empty) <-> x + + def repeat0(x: A): IsEq[A] = + S.combineN(x, 0) <-> S.empty + + def collect0(x: A): IsEq[A] = + S.combineAll(Nil) <-> S.empty + + def combineAll(xs: Vector[A]): IsEq[A] = + S.combineAll(xs) <-> (S.empty +: xs).reduce(S.combine) + + def isId(x: A, eqv: Eq[A]): IsEq[Boolean] = { + eqv.eqv(x, S.empty) <-> S.isEmpty(x)(eqv) + } + +} + +object MonoidLaws { + def apply[A](implicit ev: Monoid[A]): MonoidLaws[A] = + new MonoidLaws[A] { def S: Monoid[A] = ev } +} diff --git a/kernel-laws/src/main/scala/cats/kernel/laws/OrderLaws.scala b/kernel-laws/src/main/scala/cats/kernel/laws/OrderLaws.scala index 402d4d9be0..dc7aa026c3 100644 --- a/kernel-laws/src/main/scala/cats/kernel/laws/OrderLaws.scala +++ b/kernel-laws/src/main/scala/cats/kernel/laws/OrderLaws.scala @@ -1,122 +1,40 @@ package cats.kernel package laws -import org.typelevel.discipline.Laws +import cats.kernel.Order -import org.scalacheck.{Arbitrary, Cogen, Prop} -import org.scalacheck.Prop._ +trait OrderLaws[A] extends PartialOrderLaws[A] { -import cats.kernel.instances.all._ + override implicit def E: Order[A] -object OrderLaws { - def apply[A: Eq: Arbitrary: Cogen]: OrderLaws[A] = - new OrderLaws[A] { - def Equ = Eq[A] - def Arb = implicitly[Arbitrary[A]] - def Cog = implicitly[Cogen[A]] - } -} - -trait OrderLaws[A] extends Laws { - - implicit def Equ: Eq[A] - implicit def Arb: Arbitrary[A] - implicit def Cog: Cogen[A] + def totality(x: A, y: A): IsEq[Boolean] = + (E.lteqv(x, y) || E.lteqv(y, x)) <-> true - def eqv: OrderProperties = new OrderProperties( - name = "eq", - parent = None, - Rules.serializable(Equ), - "reflexitivity-eq" -> forAll { (x: A) => - x ?== x - }, - "symmetry-eq" -> forAll { (x: A, y: A) => - Equ.eqv(x, y) ?== Equ.eqv(y, x) - }, - "antisymmetry-eq" -> forAll { (x: A, y: A, f: A => A) => - !Equ.eqv(x, y) ?|| Equ.eqv(f(x), f(y)) - }, - "transitivity-eq" -> forAll { (x: A, y: A, z: A) => - !(Equ.eqv(x, y) && Equ.eqv(y, z)) ?|| Equ.eqv(x, z) - } - ) + def compare(x: A, y: A): IsEq[Boolean] = { + val c = E.compare(x, y) + (((c < 0) == E.lt(x, y)) && ((c == 0) == E.eqv(x, y)) && ((c > 0) == E.gt(x, y))) <-> true + } - // scalastyle:off cyclomatic.complexity - def partialOrder(implicit A: PartialOrder[A]): OrderProperties = new OrderProperties( - name = "partialOrder", - parent = Some(eqv), - Rules.serializable(A), - "reflexitivity" -> forAll { (x: A) => - x ?<= x - }, - "antisymmetry" -> forAll { (x: A, y: A) => - !(A.lteqv(x, y) && A.lteqv(y, x)) ?|| A.eqv(x, y) - }, - "transitivity" -> forAll { (x: A, y: A, z: A) => - !(A.lteqv(x, y) && A.lteqv(y, z)) ?|| A.lteqv(x, z) - }, - "gteqv" -> forAll { (x: A, y: A) => - A.lteqv(x, y) ?== A.gteqv(y, x) - }, - "lt" -> forAll { (x: A, y: A) => - A.lt(x, y) ?== (A.lteqv(x, y) && A.neqv(x, y)) - }, - "gt" -> forAll { (x: A, y: A) => - A.lt(x, y) ?== A.gt(y, x) - }, - "partialCompare" -> forAll { (x: A, y: A) => - val c = A.partialCompare(x, y) - ((c < 0) ?== A.lt(x, y)) && ((c == 0) ?== A.eqv(x, y)) && ((c > 0) ?== A.gt(x, y)) - }, - "pmin" -> forAll { (x: A, y: A) => - val c = A.partialCompare(x, y) - val m = A.pmin(x, y) - if (c < 0) m ?== Some(x) - else if (c == 0) (m ?== Some(x)) && (m ?== Some(y)) - else if (c > 0) m ?== Some(y) - else m ?== None - }, - "pmax" -> forAll { (x: A, y: A) => - val c = A.partialCompare(x, y) - val m = A.pmax(x, y) - if (c < 0) m ?== Some(y) - else if (c == 0) (m ?== Some(x)) && (m ?== Some(y)) - else if (c > 0) m ?== Some(x) - else m ?== None - } - ) - // scalastyle:on cyclomatic.complexity + def min(x: A, y: A): IsEq[Boolean] = { + val c = E.compare(x, y) + val m = E.min(x, y) + if (c < 0) E.eqv(m, x) <-> true + else if (c == 0) (E.eqv(m, x) && (E.eqv(m, y))) <-> true + else E.eqv(m, y) <-> true + } - def order(implicit A: Order[A]): OrderProperties = new OrderProperties( - name = "order", - parent = Some(partialOrder), - "totality" -> forAll { (x: A, y: A) => - A.lteqv(x, y) ?|| A.lteqv(y, x) - }, - "compare" -> forAll { (x: A, y: A) => - val c = A.compare(x, y) - ((c < 0) ?== A.lt(x, y)) && ((c == 0) ?== A.eqv(x, y)) && ((c > 0) ?== A.gt(x, y)) - }, - "min" -> forAll { (x: A, y: A) => - val c = A.compare(x, y) - val m = A.min(x, y) - if (c < 0) m ?== x - else if (c == 0) (m ?== x) && (m ?== y) - else m ?== y - }, - "max" -> forAll { (x: A, y: A) => - val c = A.compare(x, y) - val m = A.max(x, y) - if (c < 0) m ?== y - else if (c == 0) (m ?== x) && (m ?== y) - else m ?== x - } - ) + def max(x: A, y: A): IsEq[Boolean] = { + val c = E.compare(x, y) + val m = E.max(x, y) + if (c < 0) E.eqv(m, y) <-> true + else if (c == 0) (E.eqv(m, x) && (E.eqv(m, y))) <-> true + else E.eqv(m, x) <-> true + } - class OrderProperties( - name: String, - parent: Option[RuleSet], - props: (String, Prop)* - ) extends DefaultRuleSet(name, parent, props: _*) +} +object OrderLaws { + def apply[A](implicit ev: Order[A]): OrderLaws[A] = + new OrderLaws[A] { def E: Order[A] = ev } } + diff --git a/kernel-laws/src/main/scala/cats/kernel/laws/PartialOrderLaws.scala b/kernel-laws/src/main/scala/cats/kernel/laws/PartialOrderLaws.scala new file mode 100644 index 0000000000..f8887d7c14 --- /dev/null +++ b/kernel-laws/src/main/scala/cats/kernel/laws/PartialOrderLaws.scala @@ -0,0 +1,59 @@ +package cats.kernel.laws + +import cats.kernel.{Eq, PartialOrder} +import cats.kernel.instances.option._ + +trait PartialOrderLaws[A] extends EqLaws[A] { + override implicit def E: PartialOrder[A] + + def reflexitivityLt(x: A): IsEq[Boolean] = + E.lteqv(x, x) <-> true + + def reflexitivityGt(x: A): IsEq[Boolean] = + E.gteqv(x, x) <-> true + + def antisymmetry(x: A, y: A): IsEq[Boolean] = + (!(E.lteqv(x, y) && E.lteqv(y, x)) || E.eqv(x, y)) <-> true + + def transitivity(x: A, y: A, z: A): IsEq[Boolean] = + (!(E.lteqv(x, y) && E.lteqv(y, z)) || E.lteqv(x, z)) <-> true + + def gteqv(x: A, y: A): IsEq[Boolean] = + E.lteqv(x, y) <-> E.gteqv(y, x) + + def lt(x: A, y: A): IsEq[Boolean] = + E.lt(x, y) <-> (E.lteqv(x, y) && E.neqv(x, y)) + + def gt(x: A, y: A): IsEq[Boolean] = + E.lt(x, y) <-> E.gt(y, x) + + def partialCompare(x: A, y: A): IsEq[Boolean] = { + val c = E.partialCompare(x, y) + (((c < 0) == E.lt(x, y)) && ((c == 0) == E.eqv(x, y)) && ((c > 0) == E.gt(x, y))) <-> true + } + + def pmin(x: A, y: A): IsEq[Boolean] = { + val c = E.partialCompare(x, y) + val m = E.pmin(x, y) + if (c < 0) Eq[Option[A]].eqv(m, Option(x)) <-> true + else if (c == 0) (Eq[Option[A]].eqv(m, Option(x)) && Eq[Option[A]].eqv(m, Option(y))) <-> true + else if (c > 0) Eq[Option[A]].eqv(m, Option(y)) <-> true + else Eq[Option[A]].eqv(m, None) <-> true + } + + def pmax(x: A, y: A): IsEq[Boolean] = { + val c = E.partialCompare(x, y) + val m = E.pmax(x, y) + if (c < 0) Eq[Option[A]].eqv(m, Option(y)) <-> true + else if (c == 0) (Eq[Option[A]].eqv(m, Option(x)) && Eq[Option[A]].eqv(m, Option(y))) <-> true + else if (c > 0) Eq[Option[A]].eqv(m, Option(x)) <-> true + else Eq[Option[A]].eqv(m, None) <-> true + } + + +} + +object PartialOrderLaws { + def apply[A](implicit ev: PartialOrder[A]): PartialOrderLaws[A] = + new PartialOrderLaws[A] { def E: PartialOrder[A] = ev } +} diff --git a/kernel-laws/src/main/scala/cats/kernel/laws/Rules.scala b/kernel-laws/src/main/scala/cats/kernel/laws/Rules.scala deleted file mode 100644 index f4cd717d2b..0000000000 --- a/kernel-laws/src/main/scala/cats/kernel/laws/Rules.scala +++ /dev/null @@ -1,104 +0,0 @@ -package cats.kernel -package laws - -import org.scalacheck.Prop -import org.scalacheck.Prop._ -import org.scalacheck.{Arbitrary, Prop} -import cats.kernel.instances.boolean._ - -object Rules { - - // Comparison operators for testing are supplied by CheckEqOps and - // CheckOrderOps in package.scala. They are: - // - // ?== Ensure that x equals y - // ?!= Ensure that x does not equal y - // ?< Ensure that x < y - // ?<= Ensure that x <= y - // ?> Ensure that x > y - // ?>= Ensure that x >= y - // - // The reason to prefer these operators is that when tests fail, we - // will get more detaild output about what the failing values were - // (in addition to the input values generated by ScalaCheck). - - def associativity[A: Arbitrary: Eq](f: (A, A) => A): (String, Prop) = - "associativity" -> forAll { (x: A, y: A, z: A) => - f(f(x, y), z) ?== f(x, f(y, z)) - } - - def leftIdentity[A: Arbitrary: Eq](id: A)(f: (A, A) => A): (String, Prop) = - "leftIdentity" -> forAll { (x: A) => - f(id, x) ?== x - } - - def rightIdentity[A: Arbitrary: Eq](id: A)(f: (A, A) => A): (String, Prop) = - "rightIdentity" -> forAll { (x: A) => - f(x, id) ?== x - } - - def leftInverse[A: Arbitrary: Eq](id: A)(f: (A, A) => A)(inv: A => A): (String, Prop) = - "left inverse" -> forAll { (x: A) => - id ?== f(inv(x), x) - } - - def rightInverse[A: Arbitrary: Eq](id: A)(f: (A, A) => A)(inv: A => A): (String, Prop) = - "right inverse" -> forAll { (x: A) => - id ?== f(x, inv(x)) - } - - def commutative[A: Arbitrary: Eq](f: (A, A) => A): (String, Prop) = - "commutative" -> forAll { (x: A, y: A) => - f(x, y) ?== f(y, x) - } - - def idempotence[A: Arbitrary: Eq](f: (A, A) => A): (String, Prop) = - "idempotence" -> forAll { (x: A) => - f(x, x) ?== x - } - - def consistentInverse[A: Arbitrary: Eq](name: String)(m: (A, A) => A)(f: (A, A) => A)(inv: A => A): (String, Prop) = - s"consistent $name" -> forAll { (x: A, y: A) => - m(x, y) ?== f(x, inv(y)) - } - - def repeat0[A: Arbitrary: Eq](name: String, sym: String, id: A)(r: (A, Int) => A): (String, Prop) = - s"$name(a, 0) == $sym" -> forAll { (a: A) => - r(a, 0) ?== id - } - - def repeat1[A: Arbitrary: Eq](name: String)(r: (A, Int) => A): (String, Prop) = - s"$name(a, 1) == a" -> forAll { (a: A) => - r(a, 1) ?== a - } - - def repeat2[A: Arbitrary: Eq](name: String, sym: String)(r: (A, Int) => A)(f: (A, A) => A): (String, Prop) = - s"$name(a, 2) == a $sym a" -> forAll { (a: A) => - r(a, 2) ?== f(a, a) - } - - def collect0[A: Arbitrary: Eq](name: String, sym: String, id: A)(c: Seq[A] => A): (String, Prop) = - s"$name(Nil) == $sym" -> forAll { (a: A) => - c(Nil) ?== id - } - - def isId[A: Arbitrary: Eq](name: String, id: A)(p: A => Boolean): (String, Prop) = - name -> forAll { (x: A) => - Eq.eqv(x, id) ?== p(x) - } - - def distributive[A: Arbitrary: Eq](a: (A, A) => A)(m: (A, A) => A): (String, Prop) = - "distributive" → forAll { (x: A, y: A, z: A) => - (m(x, a(y, z)) ?== a(m(x, y), m(x, z))) && - (m(a(x, y), z) ?== a(m(x, z), m(y, z))) - } - - // ugly platform-specific code follows - - def serializable[M](m: M): (String, Prop) = - "serializable" -> (if (IsSerializable()) { - Prop(_ => Result(status = Proof)) - } else { - Prop(_ => IsSerializable.testSerialization(m)) - }) -} diff --git a/kernel-laws/src/main/scala/cats/kernel/laws/SemigroupLaws.scala b/kernel-laws/src/main/scala/cats/kernel/laws/SemigroupLaws.scala new file mode 100644 index 0000000000..6c290b6ac8 --- /dev/null +++ b/kernel-laws/src/main/scala/cats/kernel/laws/SemigroupLaws.scala @@ -0,0 +1,25 @@ +package cats.kernel.laws + +import cats.kernel.Semigroup + +trait SemigroupLaws[A] { + implicit def S: Semigroup[A] + + def semigroupAssociative(x: A, y: A, z: A): IsEq[A] = + S.combine(S.combine(x, y), z) <-> S.combine(x, S.combine(y, z)) + + def repeat1(a: A, i: Int): IsEq[A] = + S.combineN(a, 1) <-> a + + def repeat2(a: A, i: Int): IsEq[A] = + S.combineN(a, 2) <-> S.combine(a, a) + + def combineAllOption(xs: Vector[A]): IsEq[Option[A]] = + S.combineAllOption(xs) <-> xs.reduceOption(S.combine) + +} + +object SemigroupLaws { + def apply[A](implicit ev: Semigroup[A]): SemigroupLaws[A] = + new SemigroupLaws[A] { def S: Semigroup[A] = ev } +} diff --git a/kernel-laws/src/main/scala/cats/kernel/laws/SemilatticeLaws.scala b/kernel-laws/src/main/scala/cats/kernel/laws/SemilatticeLaws.scala new file mode 100644 index 0000000000..3490a2dddf --- /dev/null +++ b/kernel-laws/src/main/scala/cats/kernel/laws/SemilatticeLaws.scala @@ -0,0 +1,12 @@ +package cats.kernel.laws + +import cats.kernel.Semilattice + +trait SemilatticeLaws[A] extends CommutativeSemigroupLaws[A] with BandLaws[A] { + implicit def S: Semilattice[A] +} + +object SemilatticeLaws { + def apply[A](implicit ev: Semilattice[A]): SemilatticeLaws[A] = + new SemilatticeLaws[A] { def S: Semilattice[A] = ev } +} diff --git a/laws/src/main/scala/cats/laws/SerializableLaws.scala b/kernel-laws/src/main/scala/cats/kernel/laws/SerializableLaws.scala similarity index 84% rename from laws/src/main/scala/cats/laws/SerializableLaws.scala rename to kernel-laws/src/main/scala/cats/kernel/laws/SerializableLaws.scala index 8835ffedf1..b05d3fd1d9 100644 --- a/laws/src/main/scala/cats/laws/SerializableLaws.scala +++ b/kernel-laws/src/main/scala/cats/kernel/laws/SerializableLaws.scala @@ -1,5 +1,4 @@ -package cats -package laws +package cats.kernel.laws import org.scalacheck.Prop import org.scalacheck.Prop.{ Exception, Proof, Result } @@ -9,12 +8,12 @@ import catalysts.Platform import scala.util.control.NonFatal /** - * Check for Java Serializability. - * - * This law is only applicable on the JVM, but is something we want - * to be sure to enforce. Therefore, we use bricks.Platform to do a - * runtime check rather than create a separate jvm-laws project. - */ + * Check for Java Serializability. + * + * This law is only applicable on the JVM, but is something we want + * to be sure to enforce. Therefore, we use bricks.Platform to do a + * runtime check rather than create a separate jvm-laws project. + */ object SerializableLaws { // This part is a bit tricky. Basically, we only want to test diff --git a/kernel-laws/src/main/scala/cats/kernel/laws/discipline/BandTests.scala b/kernel-laws/src/main/scala/cats/kernel/laws/discipline/BandTests.scala new file mode 100644 index 0000000000..213c8d8a8e --- /dev/null +++ b/kernel-laws/src/main/scala/cats/kernel/laws/discipline/BandTests.scala @@ -0,0 +1,24 @@ +package cats +package kernel +package laws +package discipline + +import org.scalacheck.Arbitrary +import org.scalacheck.Prop.forAll + +trait BandTests[A] extends SemigroupLawTests[A] { + + def laws: BandLaws[A] + + def band(implicit arbA: Arbitrary[A], eqA: Eq[A]): RuleSet = + new DefaultRuleSet( + "band", + Some(semigroup), + "idempotency" -> forAll(laws.idempotence _)) + +} + +object BandTests { + def apply[A: Band]: BandTests[A] = + new BandTests[A] { def laws: BandLaws[A] = BandLaws[A] } +} diff --git a/kernel-laws/src/main/scala/cats/kernel/laws/discipline/BoundedSemilatticeTests.scala b/kernel-laws/src/main/scala/cats/kernel/laws/discipline/BoundedSemilatticeTests.scala new file mode 100644 index 0000000000..80d646447a --- /dev/null +++ b/kernel-laws/src/main/scala/cats/kernel/laws/discipline/BoundedSemilatticeTests.scala @@ -0,0 +1,25 @@ +package cats +package kernel +package laws +package discipline + +import org.scalacheck.{Arbitrary, Prop} + +trait BoundedSemilatticeTests[A] extends CommutativeMonoidTests[A] with SemilatticeTests[A] { + + def laws: BoundedSemilatticeLaws[A] + + def boundedSemilattice(implicit arbA: Arbitrary[A], eqA: Eq[A]): RuleSet = + new RuleSet { + val name: String = "boundedSemilattice" + val bases: Seq[(String, RuleSet)] = Nil + val parents: Seq[RuleSet] = Seq(commutativeMonoid, semilattice) + val props: Seq[(String, Prop)] = Nil + } + +} + +object BoundedSemilatticeTests { + def apply[A: BoundedSemilattice]: BoundedSemilatticeTests[A] = + new BoundedSemilatticeTests[A] { def laws: BoundedSemilatticeLaws[A] = BoundedSemilatticeLaws[A] } +} diff --git a/kernel-laws/src/main/scala/cats/kernel/laws/discipline/CommutativeGroupTests.scala b/kernel-laws/src/main/scala/cats/kernel/laws/discipline/CommutativeGroupTests.scala new file mode 100644 index 0000000000..7028f92007 --- /dev/null +++ b/kernel-laws/src/main/scala/cats/kernel/laws/discipline/CommutativeGroupTests.scala @@ -0,0 +1,24 @@ +package cats +package kernel +package laws +package discipline + +import org.scalacheck.{Arbitrary, Prop} + +trait CommutativeGroupTests[A] extends CommutativeMonoidTests[A] with GroupLawTests[A] { + def laws: CommutativeGroupLaws[A] + + def commutativeGroup(implicit arbA: Arbitrary[A], eqA: Eq[A]): RuleSet = + new RuleSet { + val name: String = "commutativeGroup" + val bases: Seq[(String, RuleSet)] = Nil + val parents: Seq[RuleSet] = Seq(commutativeMonoid, group) + val props: Seq[(String, Prop)] = Nil + } + +} + +object CommutativeGroupTests { + def apply[A: CommutativeGroup]: CommutativeGroupTests[A] = + new CommutativeGroupTests[A] { def laws: CommutativeGroupLaws[A] = CommutativeGroupLaws[A] } +} diff --git a/kernel-laws/src/main/scala/cats/kernel/laws/discipline/CommutativeMonoidTests.scala b/kernel-laws/src/main/scala/cats/kernel/laws/discipline/CommutativeMonoidTests.scala new file mode 100644 index 0000000000..1e2a33eaca --- /dev/null +++ b/kernel-laws/src/main/scala/cats/kernel/laws/discipline/CommutativeMonoidTests.scala @@ -0,0 +1,24 @@ +package cats +package kernel +package laws +package discipline + +import org.scalacheck.{Arbitrary, Prop} + +trait CommutativeMonoidTests[A] extends CommutativeSemigroupTests[A] with MonoidLawTests[A] { + def laws: CommutativeMonoidLaws[A] + + def commutativeMonoid(implicit arbA: Arbitrary[A], eqA: Eq[A]): RuleSet = + new RuleSet { + val name: String = "commutativeMonoid" + val bases: Seq[(String, RuleSet)] = Nil + val parents: Seq[RuleSet] = Seq(commutativeSemigroup, monoid) + val props: Seq[(String, Prop)] = Nil + } + +} + +object CommutativeMonoidTests { + def apply[A: CommutativeMonoid]: CommutativeMonoidTests[A] = + new CommutativeMonoidTests[A] { def laws: CommutativeMonoidLaws[A] = CommutativeMonoidLaws[A] } +} diff --git a/kernel-laws/src/main/scala/cats/kernel/laws/discipline/CommutativeSemigroupTests.scala b/kernel-laws/src/main/scala/cats/kernel/laws/discipline/CommutativeSemigroupTests.scala new file mode 100644 index 0000000000..d1f4304604 --- /dev/null +++ b/kernel-laws/src/main/scala/cats/kernel/laws/discipline/CommutativeSemigroupTests.scala @@ -0,0 +1,24 @@ +package cats +package kernel +package laws +package discipline + +import org.scalacheck.Arbitrary +import org.scalacheck.Prop.forAll + +trait CommutativeSemigroupTests[A] extends SemigroupLawTests[A] { + + def laws: CommutativeSemigroupLaws[A] + + def commutativeSemigroup(implicit arbA: Arbitrary[A], eqA: Eq[A]): RuleSet = + new DefaultRuleSet( + "commutativeSemigroup", + Some(semigroup), + "commutative" -> forAll(laws.commutative _)) + +} + +object CommutativeSemigroupTests { + def apply[A: CommutativeSemigroup]: CommutativeSemigroupTests[A] = + new CommutativeSemigroupTests[A] { def laws: CommutativeSemigroupLaws[A] = CommutativeSemigroupLaws[A] } +} diff --git a/kernel-laws/src/main/scala/cats/kernel/laws/discipline/EqLawTests.scala b/kernel-laws/src/main/scala/cats/kernel/laws/discipline/EqLawTests.scala new file mode 100644 index 0000000000..fbf52ae50c --- /dev/null +++ b/kernel-laws/src/main/scala/cats/kernel/laws/discipline/EqLawTests.scala @@ -0,0 +1,28 @@ +package cats +package kernel +package laws +package discipline + +import cats.kernel.instances.boolean._ +import org.scalacheck.Arbitrary +import org.scalacheck.Prop.forAll +import org.typelevel.discipline.Laws + +trait EqLawTests[A] extends Laws { + def laws: EqLaws[A] + + def eqv(implicit arbA: Arbitrary[A], arbF: Arbitrary[A => A], eqA: Eq[A]): RuleSet = + new DefaultRuleSet( + "eq", + None, + "eq reflexitivity" -> forAll(laws.reflexitivityEq _), + "eq symmetry" -> forAll(laws.symmetryEq _), + "eq antisymmetry" -> forAll(laws.antiSymmetryEq _), + "eq transitivity" -> forAll(laws.transitivityEq _)) +} + +object EqLawTests { + def apply[A: Eq]: EqLawTests[A] = + new EqLawTests[A] { def laws: EqLaws[A] = EqLaws[A] } +} + diff --git a/kernel-laws/src/main/scala/cats/kernel/laws/discipline/GroupLawTests.scala b/kernel-laws/src/main/scala/cats/kernel/laws/discipline/GroupLawTests.scala new file mode 100644 index 0000000000..c2aa7ffedb --- /dev/null +++ b/kernel-laws/src/main/scala/cats/kernel/laws/discipline/GroupLawTests.scala @@ -0,0 +1,26 @@ +package cats +package kernel +package laws +package discipline + +import org.scalacheck.Arbitrary +import org.scalacheck.Prop.forAll + +trait GroupLawTests[A] extends MonoidLawTests[A] { + + def laws: GroupLaws[A] + + def group(implicit arbA: Arbitrary[A], eqA: Eq[A]): RuleSet = + new DefaultRuleSet( + "group", + Some(monoid), + "left inverse" -> forAll(laws.leftInverse _), + "right inverse" -> forAll(laws.rightInverse _), + "consistent inverse" -> forAll(laws.consistentInverse _)) + +} + +object GroupLawTests { + def apply[A: Group]: GroupLawTests[A] = + new GroupLawTests[A] { def laws: GroupLaws[A] = GroupLaws[A] } +} diff --git a/kernel-laws/src/main/scala/cats/kernel/laws/discipline/HashTests.scala b/kernel-laws/src/main/scala/cats/kernel/laws/discipline/HashTests.scala new file mode 100644 index 0000000000..c59544813b --- /dev/null +++ b/kernel-laws/src/main/scala/cats/kernel/laws/discipline/HashTests.scala @@ -0,0 +1,30 @@ +package cats +package kernel +package laws +package discipline + +import cats.kernel.instances.boolean._ +import org.scalacheck.Arbitrary +import org.scalacheck.Prop.forAll + +import scala.util.hashing.Hashing + +trait HashTests[A] extends EqLawTests[A] { + + def laws: HashLaws[A] + + def hash(implicit arbA: Arbitrary[A], arbF: Arbitrary[A => A], eqA: Eq[A], hashA: Hashing[A]): RuleSet = + new DefaultRuleSet( + "hash", + Some(eqv), + "hash compatibility" -> forAll(laws.hashCompatibility _), + "same as universal hash" -> forAll(laws.sameAsUniversalHash _), + "same as scala hashing" -> forAll((x: A, y: A) => laws.sameAsScalaHashing(x, y, hashA)) + ) + +} + +object HashTests { + def apply[A: Hash]: HashTests[A] = + new HashTests[A] { def laws: HashLaws[A] = HashLaws[A] } +} diff --git a/kernel-laws/src/main/scala/cats/kernel/laws/discipline/MonoidLawTests.scala b/kernel-laws/src/main/scala/cats/kernel/laws/discipline/MonoidLawTests.scala new file mode 100644 index 0000000000..7e8a4bb7fc --- /dev/null +++ b/kernel-laws/src/main/scala/cats/kernel/laws/discipline/MonoidLawTests.scala @@ -0,0 +1,30 @@ +package cats +package kernel +package laws +package discipline + +import cats.kernel.instances.boolean._ +import org.scalacheck.Arbitrary +import org.scalacheck.Prop.forAll + +trait MonoidLawTests[A] extends SemigroupLawTests[A] { + + def laws: MonoidLaws[A] + + def monoid(implicit arbA: Arbitrary[A], eqA: Eq[A]): RuleSet = + new DefaultRuleSet( + "monoid", + Some(semigroup), + "left identity" -> forAll(laws.leftIdentity _), + "right identity" -> forAll(laws.rightIdentity _), + "combine all" -> forAll(laws.combineAll _), + "collect0" -> forAll(laws.collect0 _), + "is id" -> forAll((a: A) => laws.isId(a, eqA)), + "repeat0" -> forAll(laws.repeat0 _)) + +} + +object MonoidLawTests { + def apply[A: Monoid]: MonoidLawTests[A] = + new MonoidLawTests[A] { def laws: MonoidLaws[A] = MonoidLaws[A] } +} diff --git a/kernel-laws/src/main/scala/cats/kernel/laws/discipline/OrderLawTests.scala b/kernel-laws/src/main/scala/cats/kernel/laws/discipline/OrderLawTests.scala new file mode 100644 index 0000000000..35b5a9c9b9 --- /dev/null +++ b/kernel-laws/src/main/scala/cats/kernel/laws/discipline/OrderLawTests.scala @@ -0,0 +1,29 @@ +package cats +package kernel +package laws +package discipline + +import cats.kernel.instances.boolean._ +import org.scalacheck.Arbitrary +import org.scalacheck.Prop.forAll + +trait OrderLawTests[A] extends PartialOrderLawTests[A] { + + def laws: OrderLaws[A] + + def order(implicit arbA: Arbitrary[A], arbF: Arbitrary[A => A], eqOA: Eq[Option[A]], eqA: Eq[A]): RuleSet = + new DefaultRuleSet( + "order", + Some(partialOrder), + "totality" -> forAll(laws.totality _), + "compare" -> forAll(laws.compare _), + "max" -> forAll(laws.max _), + "min" -> forAll(laws.min _) + ) + +} + +object OrderLawTests { + def apply[A: Order]: OrderLawTests[A] = + new OrderLawTests[A] { def laws: OrderLaws[A] = OrderLaws[A] } +} diff --git a/kernel-laws/src/main/scala/cats/kernel/laws/discipline/PartialOrderLawTests.scala b/kernel-laws/src/main/scala/cats/kernel/laws/discipline/PartialOrderLawTests.scala new file mode 100644 index 0000000000..2072336850 --- /dev/null +++ b/kernel-laws/src/main/scala/cats/kernel/laws/discipline/PartialOrderLawTests.scala @@ -0,0 +1,35 @@ +package cats +package kernel +package laws +package discipline + +import cats.kernel.instances.boolean._ +import org.scalacheck.Arbitrary +import org.scalacheck.Prop.forAll + +trait PartialOrderLawTests[A] extends EqLawTests[A] { + + def laws: PartialOrderLaws[A] + + def partialOrder(implicit arbA: Arbitrary[A], arbF: Arbitrary[A => A], eqOA: Eq[Option[A]], eqA: Eq[A]): RuleSet = + new DefaultRuleSet( + "partialOrder", + Some(eqv), + "transitivity" -> forAll(laws.transitivity _), + "reflexitivity lt" -> forAll(laws.reflexitivityLt _), + "reflexitivity gt" -> forAll(laws.reflexitivityGt _), + "antisymmetry" -> forAll(laws.antisymmetry _), + "gt" -> forAll(laws.gt _), + "gteqv" -> forAll(laws.gteqv _), + "lt" -> forAll(laws.lt _), + "partialCompare" -> forAll(laws.partialCompare _), + "pmax" -> forAll(laws.pmax _), + "pmin" -> forAll(laws.pmin _) + ) + +} + +object PartialOrderLawTests { + def apply[A: PartialOrder]: PartialOrderLawTests[A] = + new PartialOrderLawTests[A] { def laws: PartialOrderLaws[A] = PartialOrderLaws[A] } +} diff --git a/kernel-laws/src/main/scala/cats/kernel/laws/discipline/SemigroupLawTests.scala b/kernel-laws/src/main/scala/cats/kernel/laws/discipline/SemigroupLawTests.scala new file mode 100644 index 0000000000..1838767b2e --- /dev/null +++ b/kernel-laws/src/main/scala/cats/kernel/laws/discipline/SemigroupLawTests.scala @@ -0,0 +1,27 @@ +package cats +package kernel +package laws +package discipline + +import cats.kernel.instances.option._ +import org.scalacheck.Arbitrary +import org.scalacheck.Prop.forAll +import org.typelevel.discipline.Laws + +trait SemigroupLawTests[A] extends Laws { + def laws: SemigroupLaws[A] + + def semigroup(implicit arbA: Arbitrary[A], eqA: Eq[A]): RuleSet = + new DefaultRuleSet( + "semigroup", + None, + "semigroup associative" -> forAll(laws.semigroupAssociative _), + "semigroup repeat1" -> forAll(laws.repeat1 _), + "semigroup repeat2" -> forAll(laws.repeat2 _), + "semigroup combineAllOption" -> forAll(laws.combineAllOption _)) +} + +object SemigroupLawTests { + def apply[A: Semigroup]: SemigroupLawTests[A] = + new SemigroupLawTests[A] { def laws: SemigroupLaws[A] = SemigroupLaws[A] } +} diff --git a/kernel-laws/src/main/scala/cats/kernel/laws/discipline/SemilatticeTests.scala b/kernel-laws/src/main/scala/cats/kernel/laws/discipline/SemilatticeTests.scala new file mode 100644 index 0000000000..d4a697a52b --- /dev/null +++ b/kernel-laws/src/main/scala/cats/kernel/laws/discipline/SemilatticeTests.scala @@ -0,0 +1,27 @@ +package cats +package kernel +package laws +package discipline + +import org.scalacheck.{Arbitrary, Prop} + +trait SemilatticeTests[A] extends CommutativeSemigroupTests[A] with BandTests[A] { + + def laws: SemilatticeLaws[A] + + def semilattice(implicit arbA: Arbitrary[A], eqA: Eq[A]): RuleSet = + new RuleSet { + val name: String = "semilattice" + val bases: Seq[(String, RuleSet)] = Nil + val parents: Seq[RuleSet] = Seq(commutativeSemigroup, band) + val props: Seq[(String, Prop)] = Nil + } + +} + +object SemilatticeTests { + def apply[A: Semilattice]: SemilatticeTests[A] = + new SemilatticeTests[A] { def laws: SemilatticeLaws[A] = SemilatticeLaws[A] } +} + + diff --git a/laws/src/main/scala/cats/laws/discipline/SerializableTests.scala b/kernel-laws/src/main/scala/cats/kernel/laws/discipline/SerializableTests.scala similarity index 77% rename from laws/src/main/scala/cats/laws/discipline/SerializableTests.scala rename to kernel-laws/src/main/scala/cats/kernel/laws/discipline/SerializableTests.scala index 806161f2ba..a19d46c498 100644 --- a/laws/src/main/scala/cats/laws/discipline/SerializableTests.scala +++ b/kernel-laws/src/main/scala/cats/kernel/laws/discipline/SerializableTests.scala @@ -1,7 +1,6 @@ -package cats -package laws -package discipline +package cats.kernel.laws.discipline +import cats.kernel.laws.SerializableLaws import org.typelevel.discipline.Laws object SerializableTests extends Laws { diff --git a/kernel-laws/src/main/scala/cats/kernel/laws/discipline/package.scala b/kernel-laws/src/main/scala/cats/kernel/laws/discipline/package.scala new file mode 100644 index 0000000000..f5b0239b3b --- /dev/null +++ b/kernel-laws/src/main/scala/cats/kernel/laws/discipline/package.scala @@ -0,0 +1,9 @@ +package cats.kernel.laws + +import cats.kernel.Eq +import org.scalacheck.Prop + +package object discipline { + implicit def catsLawsIsEqToProp[A: Eq](isEq: IsEq[A])(implicit ev: Eq[A]): Prop = + ev.eqv(isEq.lhs, isEq.rhs) +} diff --git a/kernel-laws/src/main/scala/cats/kernel/laws/package.scala b/kernel-laws/src/main/scala/cats/kernel/laws/package.scala index f97de5ab1f..47a8f44621 100644 --- a/kernel-laws/src/main/scala/cats/kernel/laws/package.scala +++ b/kernel-laws/src/main/scala/cats/kernel/laws/package.scala @@ -1,38 +1,8 @@ package cats.kernel -import org.scalacheck._ -import org.scalacheck.util.Pretty -import Prop.{False, Proof, Result} - package object laws { - lazy val proved = Prop(Result(status = Proof)) - - lazy val falsified = Prop(Result(status = False)) - - object Ops { - def run[A](sym: String)(lhs: A, rhs: A)(f: (A, A) => Boolean): Prop = - if (f(lhs, rhs)) proved else falsified :| { - val exp = Pretty.pretty(lhs, Pretty.Params(0)) - val got = Pretty.pretty(rhs, Pretty.Params(0)) - s"($exp $sym $got) failed" - } - } - - implicit class CheckEqOps[A](lhs: A)(implicit ev: Eq[A], pp: A => Pretty) { - def ?==(rhs: A): Prop = Ops.run("?==")(lhs, rhs)(ev.eqv) - def ?!=(rhs: A): Prop = Ops.run("?!=")(lhs, rhs)(ev.neqv) - } - - implicit class CheckOrderOps[A](lhs: A)(implicit ev: PartialOrder[A], pp: A => Pretty) { - def ?<(rhs: A): Prop = Ops.run("?<")(lhs, rhs)(ev.lt) - def ?<=(rhs: A): Prop = Ops.run("?<=")(lhs, rhs)(ev.lteqv) - def ?>(rhs: A): Prop = Ops.run("?>")(lhs, rhs)(ev.gt) - def ?>=(rhs: A): Prop = Ops.run("?>=")(lhs, rhs)(ev.gteqv) - } - - implicit class BooleanOps[A](lhs: Boolean)(implicit pp: Boolean => Pretty) { - def ?&&(rhs: Boolean): Prop = Ops.run("?&&")(lhs, rhs)(_ && _) - def ?||(rhs: Boolean): Prop = Ops.run("?||")(lhs, rhs)(_ || _) + implicit final class IsEqArrow[A](val lhs: A) extends AnyVal { + def <->(rhs: A): IsEq[A] = IsEq(lhs, rhs) } } diff --git a/kernel-laws/src/test/scala/cats/kernel/laws/LawTests.scala b/kernel-laws/src/test/scala/cats/kernel/laws/LawTests.scala index c6623899ac..bc5f011e09 100644 --- a/kernel-laws/src/test/scala/cats/kernel/laws/LawTests.scala +++ b/kernel-laws/src/test/scala/cats/kernel/laws/LawTests.scala @@ -3,11 +3,11 @@ package laws import catalysts.Platform import catalysts.macros.TypeTagM - import cats.kernel.instances.all._ +import cats.kernel.laws.discipline._ -import org.typelevel.discipline.{ Laws } +import org.typelevel.discipline.Laws import org.typelevel.discipline.scalatest.Discipline import org.scalacheck.{ Arbitrary, Cogen, Gen } import Arbitrary.arbitrary @@ -21,19 +21,8 @@ import scala.util.Random import java.util.UUID import java.util.concurrent.TimeUnit.{DAYS, HOURS, MINUTES, SECONDS, MILLISECONDS, MICROSECONDS, NANOSECONDS} -class LawTests extends FunSuite with Discipline { +object KernelCheck { - // The scalacheck defaults (100,100) are too high for scala-js. - final val PropMaxSize: PosZInt = if (Platform.isJs) 10 else 100 - final val PropMinSuccessful: PosInt = if (Platform.isJs) 10 else 100 - - implicit override val generatorDrivenConfig: PropertyCheckConfiguration = - PropertyCheckConfiguration(minSuccessful = PropMinSuccessful, sizeRange = PropMaxSize) - - implicit def hashLaws[A: Cogen: Eq: Arbitrary]: HashLaws[A] = HashLaws[A] - - implicit def orderLaws[A: Cogen: Eq: Arbitrary]: OrderLaws[A] = OrderLaws[A] - implicit def groupLaws[A: Cogen: Eq: Arbitrary]: GroupLaws[A] = GroupLaws[A] implicit val arbitraryBitSet: Arbitrary[BitSet] = Arbitrary(arbitrary[List[Short]].map(ns => BitSet(ns.map(_ & 0xffff): _*))) @@ -89,162 +78,154 @@ class LawTests extends FunSuite with Discipline { case NANOSECONDS => 6128745701389500153L }) } +} + +class LawTests extends FunSuite with Discipline { + + import KernelCheck._ + + // The scalacheck defaults (100,100) are too high for scala-js. + final val PropMaxSize: PosZInt = if (Platform.isJs) 10 else 100 + final val PropMinSuccessful: PosInt = if (Platform.isJs) 10 else 100 + + implicit override val generatorDrivenConfig: PropertyCheckConfiguration = + PropertyCheckConfiguration(minSuccessful = PropMinSuccessful, sizeRange = PropMaxSize) + { // needed for Cogen[Map[...]] implicit val ohe: Ordering[HasEq[Int]] = Ordering[Int].on(_.a) - laws[OrderLaws, Map[String, HasEq[Int]]].check(_.eqv) + checkAll("Eq[Map[String, HasEq[Int]]]", EqLawTests[Map[String, HasEq[Int]]].eqv) } - laws[HashLaws, Unit].check(_.hash) - laws[HashLaws, Boolean].check(_.hash) - laws[HashLaws, String].check(_.hash) - laws[HashLaws, Symbol].check(_.hash) - laws[HashLaws, Byte].check(_.hash) - laws[HashLaws, Short].check(_.hash) - laws[HashLaws, Char].check(_.hash) - laws[HashLaws, Int].check(_.hash) - laws[HashLaws, Float].check(_.hash) - laws[HashLaws, Double].check(_.hash) - laws[HashLaws, Long].check(_.hash) - laws[HashLaws, BitSet].check(_.hash) - laws[HashLaws, BigDecimal].check(_.hash) - laws[HashLaws, BigInt].check(_.hash) - laws[HashLaws, UUID].check(_.hash) - laws[HashLaws, Duration].check(_.hash) - laws[HashLaws, List[Int]].check(_.hash) - laws[HashLaws, Option[String]].check(_.hash) - laws[HashLaws, List[String]].check(_.hash) - laws[HashLaws, Vector[Int]].check(_.hash) - laws[HashLaws, Queue[Int]].check(_.hash) - laws[HashLaws, Stream[Int]].check(_.hash) - laws[HashLaws, Set[Int]].check(_.hash) - laws[HashLaws, (Int, String)].check(_.hash) - laws[HashLaws, Either[Int, String]].check(_.hash) - laws[HashLaws, Map[Int, String]].check(_.hash) - - laws[HashLaws, Unit].check(_.sameAsUniversalHash) - laws[HashLaws, Boolean].check(_.sameAsUniversalHash) - laws[HashLaws, String].check(_.sameAsUniversalHash) - laws[HashLaws, Symbol].check(_.sameAsUniversalHash) - laws[HashLaws, Byte].check(_.sameAsUniversalHash) - laws[HashLaws, Short].check(_.sameAsUniversalHash) - laws[HashLaws, Char].check(_.sameAsUniversalHash) - laws[HashLaws, Int].check(_.sameAsUniversalHash) - laws[HashLaws, Float].check(_.sameAsUniversalHash) - laws[HashLaws, Double].check(_.sameAsUniversalHash) - laws[HashLaws, Long].check(_.sameAsUniversalHash) - laws[HashLaws, BitSet].check(_.sameAsUniversalHash) - laws[HashLaws, BigDecimal].check(_.sameAsUniversalHash) - laws[HashLaws, BigInt].check(_.sameAsUniversalHash) - laws[HashLaws, UUID].check(_.sameAsUniversalHash) - laws[HashLaws, List[Int]].check(_.sameAsUniversalHash) - laws[HashLaws, Option[String]].check(_.sameAsUniversalHash) - laws[HashLaws, List[String]].check(_.sameAsUniversalHash) - laws[HashLaws, Queue[Int]].check(_.sameAsUniversalHash) - laws[HashLaws, Vector[Int]].check(_.sameAsUniversalHash) - laws[HashLaws, Stream[Int]].check(_.sameAsUniversalHash) - laws[HashLaws, Set[Int]].check(_.sameAsUniversalHash) - laws[HashLaws, (Int, String)].check(_.sameAsUniversalHash) - laws[HashLaws, Either[Int, String]].check(_.sameAsUniversalHash) - laws[HashLaws, Map[Int, String]].check(_.sameAsUniversalHash) + + checkAll("Eq[List[HasEq[Int]]]", EqLawTests[List[HasEq[Int]]].eqv) + checkAll("Eq[Option[HasEq[Int]]]", EqLawTests[Option[HasEq[Int]]].eqv) + checkAll("Eq[Vector[HasEq[Int]]]", EqLawTests[Vector[HasEq[Int]]].eqv) + checkAll("Eq[Stream[HasEq[Int]]]", EqLawTests[Stream[HasEq[Int]]].eqv) + checkAll("Eq[Queue[HasEq[Int]]]", EqLawTests[Queue[HasEq[Int]]].eqv) + + checkAll("PartialOrder[Set[Int]]", PartialOrderLawTests[Set[Int]].partialOrder) + checkAll("PartialOrder[Set[Int]].reverse", PartialOrderLawTests(PartialOrder[Set[Int]].reverse).partialOrder) + checkAll("PartialOrder[Set[Int]].reverse.reverse", PartialOrderLawTests(PartialOrder[Set[Int]].reverse.reverse).partialOrder) + checkAll("PartialOrder[Option[HasPartialOrder[Int]]]", PartialOrderLawTests[Option[HasPartialOrder[Int]]].partialOrder) + checkAll("PartialOrder[List[HasPartialOrder[Int]]]", PartialOrderLawTests[List[HasPartialOrder[Int]]].partialOrder) + checkAll("PartialOrder[Vector[HasPartialOrder[Int]]]", PartialOrderLawTests[Vector[HasPartialOrder[Int]]].partialOrder) + checkAll("PartialOrder[Stream[HasPartialOrder[Int]]]", PartialOrderLawTests[Stream[HasPartialOrder[Int]]].partialOrder) + checkAll("PartialOrder[Queue[HasPartialOrder[Int]]]", PartialOrderLawTests[Queue[HasPartialOrder[Int]]].partialOrder) + checkAll("Semilattice.asMeetPartialOrder[Set[Int]]", PartialOrderLawTests(Semilattice.asMeetPartialOrder[Set[Int]]).partialOrder) + checkAll("Semilattice.asJoinPartialOrder[Set[Int]]", PartialOrderLawTests(Semilattice.asJoinPartialOrder[Set[Int]]).partialOrder) + + checkAll("Order[Unit]", OrderLawTests[Unit].order) + checkAll("Order[Boolean]", OrderLawTests[Boolean].order) + checkAll("Order[String]", OrderLawTests[String].order) + checkAll("Order[Symbol]", OrderLawTests[Symbol].order) + checkAll("Order[Byte]", OrderLawTests[Byte].order) + checkAll("Order[Short]", OrderLawTests[Short].order) + checkAll("Order[Char]", OrderLawTests[Char].order) + checkAll("Order[Int]", OrderLawTests[Int].order) + checkAll("Order[Long]", OrderLawTests[Long].order) + checkAll("PartialOrder[BitSet]", PartialOrderLawTests[BitSet].partialOrder) + checkAll("Order[BigInt]", OrderLawTests[BigInt].order) + checkAll("Order[Duration]", OrderLawTests[Duration].order) + checkAll("Order[UUID]", OrderLawTests[UUID].order) + checkAll("Order[List[Int]]", OrderLawTests[List[Int]] .order) + checkAll("Order[Option[String]]", OrderLawTests[Option[String]].order) + checkAll("Order[List[String]", OrderLawTests[List[String]].order) + checkAll("Order[Vector[Int]]", OrderLawTests[Vector[Int]].order) + checkAll("Order[Stream[Int]]", OrderLawTests[Stream[Int]].order) + checkAll("Order[Queue[Int]]", OrderLawTests[Queue[Int]].order) + checkAll("fromOrdering[Int]", OrderLawTests(Order.fromOrdering[Int]).order) + checkAll("Order[Int].reverse", OrderLawTests(Order[Int].reverse).order) + checkAll("Order[Int].reverse.reverse", OrderLawTests(Order[Int].reverse.reverse).order) + + checkAll("Monoid[String]", MonoidLawTests[String].monoid) + checkAll("Monoid[String]", SerializableTests.serializable(Monoid[String])) + checkAll("Monoid[Option[Int]]", MonoidLawTests[Option[Int]].monoid) + checkAll("Monoid[Option[Int]]", SerializableTests.serializable(Monoid[String])) + checkAll("Monoid[Option[String]]", MonoidLawTests[Option[String]].monoid) + checkAll("Monoid[Option[String]]", SerializableTests.serializable(Monoid[String])) + checkAll("Monoid[List[Int]]", MonoidLawTests[List[Int]].monoid) + checkAll("Monoid[List[Int]]", SerializableTests.serializable(Monoid[List[Int]])) + checkAll("Monoid[Vector[Int]]", MonoidLawTests[Vector[Int]].monoid) + checkAll("Monoid[Vector[Int]]", SerializableTests.serializable(Monoid[Vector[Int]])) + checkAll("Monoid[Stream[Int]]", MonoidLawTests[Stream[Int]].monoid) + checkAll("Monoid[Stream[Int]]", SerializableTests.serializable(Monoid[Stream[Int]])) + checkAll("Monoid[List[String]]", MonoidLawTests[List[String]].monoid) + checkAll("Monoid[List[String]]", SerializableTests.serializable(Monoid[List[String]])) + checkAll("Monoid[Map[String, Int]]", MonoidLawTests[Map[String, Int]].monoid) + checkAll("Monoid[Map[String, Int]]", SerializableTests.serializable(Monoid[Map[String, Int]])) + checkAll("Monoid[Queue[Int]]", MonoidLawTests[Queue[Int]].monoid) + checkAll("Monoid[Queue[Int]]", SerializableTests.serializable(Monoid[Queue[Int]])) + + checkAll("BoundedSemilattice[BitSet]", BoundedSemilatticeTests[BitSet].boundedSemilattice) + checkAll("BoundedSemilattice[BitSet]", SerializableTests.serializable(BoundedSemilattice[BitSet])) + checkAll("BoundedSemilattice[Set[Int]]", BoundedSemilatticeTests[Set[Int]].boundedSemilattice) + checkAll("BoundedSemilattice[Set[Int]]", SerializableTests.serializable(BoundedSemilattice[Set[Int]])) + + checkAll("CommutativeGroup[Unit]", CommutativeGroupTests[Unit].commutativeGroup) + checkAll("CommutativeGroup[Unit]", SerializableTests.serializable(CommutativeGroup[Unit])) + checkAll("CommutativeGroup[Byte]", CommutativeGroupTests[Byte].commutativeGroup) + checkAll("CommutativeGroup[Byte]", SerializableTests.serializable(CommutativeGroup[Byte])) + checkAll("CommutativeGroup[Short]", CommutativeGroupTests[Short].commutativeGroup) + checkAll("CommutativeGroup[Short]", SerializableTests.serializable(CommutativeGroup[Short])) + checkAll("CommutativeGroup[Int]", CommutativeGroupTests[Int].commutativeGroup) + checkAll("CommutativeGroup[Int]", SerializableTests.serializable(CommutativeGroup[Int])) + checkAll("CommutativeGroup[Long]", CommutativeGroupTests[Long].commutativeGroup) + checkAll("CommutativeGroup[Long]", SerializableTests.serializable(CommutativeGroup[Long])) + // checkAll("CommutativeGroup[Float]", CommutativeGroupTests[Float].commutativeGroup) // approximately associative + // checkAll("CommutativeGroup[Double]", CommutativeGroupTests[Double].commutativeGroup) // approximately associative + checkAll("CommutativeGroup[BigInt]", CommutativeGroupTests[BigInt].commutativeGroup) + checkAll("CommutativeGroup[BigInt]", SerializableTests.serializable(CommutativeGroup[BigInt])) + checkAll("CommutativeGroup[Duration]", CommutativeGroupTests[Duration].commutativeGroup) + checkAll("CommutativeGroup[Duration]", SerializableTests.serializable(CommutativeGroup[Duration])) + + + checkAll("Hash[Unit]" , HashTests[Unit].hash) + checkAll("Hash[Boolean]" , HashTests[Boolean].hash) + checkAll("Hash[String]" , HashTests[String].hash) + checkAll("Hash[Symbol]" , HashTests[Symbol].hash) + checkAll("Hash[Byte]" , HashTests[Byte].hash) + checkAll("Hash[Short]" , HashTests[Short].hash) + checkAll("Hash[Char]" , HashTests[Char].hash) + checkAll("Hash[Int]" , HashTests[Int].hash) + checkAll("Hash[Duration]", HashTests[Duration].hash) // NOTE: Do not test for Float/Double/Long. These types' // `##` is different from `hashCode`. See [[scala.runtime.Statics.anyHash]]. - laws[HashLaws, Unit].check(_.sameAsScalaHashing) - laws[HashLaws, Boolean].check(_.sameAsScalaHashing) - laws[HashLaws, String].check(_.sameAsScalaHashing) - laws[HashLaws, Symbol].check(_.sameAsScalaHashing) - laws[HashLaws, Byte].check(_.sameAsScalaHashing) - laws[HashLaws, Short].check(_.sameAsScalaHashing) - laws[HashLaws, Char].check(_.sameAsScalaHashing) - laws[HashLaws, Int].check(_.sameAsScalaHashing) - laws[HashLaws, BitSet].check(_.sameAsScalaHashing) - laws[HashLaws, BigDecimal].check(_.sameAsScalaHashing) - laws[HashLaws, BigInt].check(_.sameAsScalaHashing) - laws[HashLaws, UUID].check(_.sameAsScalaHashing) - laws[HashLaws, Duration].check(_.sameAsScalaHashing) - - laws[HashLaws, Option[HasHash[Int]]].check(_.hash) - laws[HashLaws, List[HasHash[Int]]].check(_.hash) - laws[HashLaws, Vector[HasHash[Int]]].check(_.hash) - laws[HashLaws, Stream[HasHash[Int]]].check(_.hash) - laws[HashLaws, Queue[HasHash[Int]]].check(_.hash) - - laws[OrderLaws, List[HasEq[Int]]].check(_.eqv) - laws[OrderLaws, Option[HasEq[Int]]].check(_.eqv) - laws[OrderLaws, Vector[HasEq[Int]]].check(_.eqv) - laws[OrderLaws, Stream[HasEq[Int]]].check(_.eqv) - laws[OrderLaws, Queue[HasEq[Int]]].check(_.eqv) - - laws[OrderLaws, Set[Int]].check(_.partialOrder) - laws[OrderLaws, Set[Int]]("reverse").check(_.partialOrder(PartialOrder[Set[Int]].reverse)) - laws[OrderLaws, Set[Int]]("reverse.reverse").check(_.partialOrder(PartialOrder[Set[Int]].reverse.reverse)) - laws[OrderLaws, Option[HasPartialOrder[Int]]].check(_.partialOrder) - laws[OrderLaws, List[HasPartialOrder[Int]]].check(_.partialOrder) - laws[OrderLaws, Vector[HasPartialOrder[Int]]].check(_.partialOrder) - laws[OrderLaws, Stream[HasPartialOrder[Int]]].check(_.partialOrder) - laws[OrderLaws, Queue[HasPartialOrder[Int]]].check(_.partialOrder) - laws[OrderLaws, Set[Int]]("asMeetPartialOrder").check(_.partialOrder(Semilattice.asMeetPartialOrder[Set[Int]])) - laws[OrderLaws, Set[Int]]("asJoinPartialOrder").check(_.partialOrder(Semilattice.asJoinPartialOrder[Set[Int]])) - - laws[OrderLaws, Unit].check(_.order) - laws[OrderLaws, Boolean].check(_.order) - laws[OrderLaws, String].check(_.order) - laws[OrderLaws, Symbol].check(_.order) - laws[OrderLaws, Byte].check(_.order) - laws[OrderLaws, Short].check(_.order) - laws[OrderLaws, Char].check(_.order) - laws[OrderLaws, Int].check(_.order) - laws[OrderLaws, Long].check(_.order) - laws[OrderLaws, BitSet].check(_.partialOrder) - laws[OrderLaws, BigInt].check(_.order) - laws[OrderLaws, Duration].check(_.order) - laws[OrderLaws, UUID].check(_.order) - laws[OrderLaws, List[Int]].check(_.order) - laws[OrderLaws, Option[String]].check(_.order) - laws[OrderLaws, List[String]].check(_.order) - laws[OrderLaws, Vector[Int]].check(_.order) - laws[OrderLaws, Stream[Int]].check(_.order) - laws[OrderLaws, Queue[Int]].check(_.order) - laws[OrderLaws, Int]("fromOrdering").check(_.order(Order.fromOrdering[Int])) - laws[OrderLaws, Int]("reverse").check(_.order(Order[Int].reverse)) - laws[OrderLaws, Int]("reverse.reverse").check(_.order(Order[Int].reverse.reverse)) - - laws[GroupLaws, String].check(_.monoid) - laws[GroupLaws, Option[Int]].check(_.monoid) - laws[GroupLaws, Option[String]].check(_.monoid) - laws[GroupLaws, List[Int]].check(_.monoid) - laws[GroupLaws, Vector[Int]].check(_.monoid) - laws[GroupLaws, Stream[Int]].check(_.monoid) - laws[GroupLaws, List[String]].check(_.monoid) - laws[GroupLaws, Map[String, Int]].check(_.monoid) - laws[GroupLaws, Queue[Int]].check(_.monoid) - - laws[GroupLaws, BitSet].check(_.boundedSemilattice) - laws[GroupLaws, Set[Int]].check(_.boundedSemilattice) - - laws[GroupLaws, Unit].check(_.commutativeGroup) - laws[GroupLaws, Byte].check(_.commutativeGroup) - laws[GroupLaws, Short].check(_.commutativeGroup) - laws[GroupLaws, Int].check(_.commutativeGroup) - laws[GroupLaws, Long].check(_.commutativeGroup) - //laws[GroupLaws, Float].check(_.commutativeGroup) // approximately associative - //laws[GroupLaws, Double].check(_.commutativeGroup) // approximately associative - laws[GroupLaws, BigInt].check(_.commutativeGroup) - laws[GroupLaws, Duration].check(_.commutativeGroup) + // checkAll("Hash[Float]" , HashTests[Float].hash) + // checkAll("Hash[Double]" , HashTests[Double].hash) + checkAll("Hash[BitSet]" , HashTests[BitSet].hash) + checkAll("Hash[BigDecimal]" , HashTests[BigDecimal].hash) + checkAll("Hash[BigInt]" , HashTests[BigInt].hash) + checkAll("Hash[UUID]" , HashTests[UUID].hash) + checkAll("Hash[List[Int]]" , HashTests[List[Int]].hash) + checkAll("Hash[Option[String]]" , HashTests[Option[String]].hash) + checkAll("Hash[List[String]]" , HashTests[List[String]].hash) + checkAll("Hash[Vector[Int]]" , HashTests[Vector[Int]].hash) + checkAll("Hash[Stream[Int]]" , HashTests[Stream[Int]].hash) + checkAll("Hash[Set[Int]]" , HashTests[Set[Int]].hash) + checkAll("Hash[(Int, String)]" , HashTests[(Int, String)].hash) + checkAll("Hash[Either[Int, String]]" , HashTests[Either[Int, String]].hash) + checkAll("Hash[Map[Int, String]]" , HashTests[Map[Int, String]].hash) + checkAll("Hash[Queue[Int]", HashTests[Queue[Int]].hash) + + { // default Arbitrary[BigDecimal] is a bit too intense :/ implicit val arbBigDecimal: Arbitrary[BigDecimal] = Arbitrary(arbitrary[Double].map(n => BigDecimal(n.toString))) - laws[OrderLaws, BigDecimal].check(_.order) - laws[GroupLaws, BigDecimal].check(_.commutativeGroup) + checkAll("Order[BigDecimal]", OrderLawTests[BigDecimal].order) + checkAll("CommutativeGroup[BigDecimal]", CommutativeGroupTests[BigDecimal].commutativeGroup) + checkAll("CommutativeGroup[BigDecimal]", SerializableTests.serializable(CommutativeGroup[BigDecimal])) } - laws[GroupLaws, (Int, Int)].check(_.band) + checkAll("Band[(Int, Int)]", BandTests[(Int, Int)].band) + checkAll("Band[(Int, Int)]", SerializableTests.serializable(Band[(Int, Int)])) - laws[GroupLaws, Unit].check(_.boundedSemilattice) + checkAll("BoundedSemilattice[Unit]", BoundedSemilatticeTests[Unit].boundedSemilattice) + checkAll("BoundedSemilattice[Unit]", SerializableTests.serializable(BoundedSemilattice[Unit])) // Comparison related @@ -257,7 +238,7 @@ class LawTests extends FunSuite with Discipline { else Double.NaN } - laws[OrderLaws, Set[Int]]("subset").check(_.partialOrder(subsetPartialOrder[Int])) + checkAll("subsetPartialOrder[Int]", PartialOrderLawTests(subsetPartialOrder[Int]).partialOrder) implicit val arbitraryComparison: Arbitrary[Comparison] = Arbitrary(Gen.oneOf(Comparison.GreaterThan, Comparison.EqualTo, Comparison.LessThan)) @@ -265,7 +246,7 @@ class LawTests extends FunSuite with Discipline { implicit val cogenComparison: Cogen[Comparison] = Cogen[Int].contramap(_.toInt) - laws[OrderLaws, Comparison].check(_.eqv) + checkAll("Eq[Comparison]", EqLawTests[Comparison].eqv) test("comparison") { val order = Order[Int] @@ -345,16 +326,16 @@ class LawTests extends FunSuite with Discipline { } implicit val monoidOrderN = Order.whenEqualMonoid[N] - laws[GroupLaws, Order[N]].check(_.monoid) - laws[GroupLaws, Order[N]].check(_.band) + checkAll("Monoid[Order[N]]", MonoidLawTests[Order[N]].monoid) + checkAll("Band[Order[N]]", BandTests[Order[N]].band) { implicit val bsEqN: BoundedSemilattice[Eq[N]] = Eq.allEqualBoundedSemilattice[N] - laws[GroupLaws, Eq[N]].check(_.boundedSemilattice) + checkAll("BoundedSemilattice[Eq[N]]", BoundedSemilatticeTests[Eq[N]].boundedSemilattice) } { implicit val sEqN: Semilattice[Eq[N]] = Eq.anyEqualSemilattice[N] - laws[GroupLaws, Eq[N]].check(_.semilattice) + checkAll("Semilattice[Eq[N]]", SemilatticeTests[Eq[N]].semilattice) } } diff --git a/kernel/src/main/scala/cats/kernel/instances/option.scala b/kernel/src/main/scala/cats/kernel/instances/option.scala index e0a497ad9e..ab324dabd8 100644 --- a/kernel/src/main/scala/cats/kernel/instances/option.scala +++ b/kernel/src/main/scala/cats/kernel/instances/option.scala @@ -3,22 +3,24 @@ package instances package object option extends OptionInstances -trait OptionInstances extends OptionInstances1 { +trait OptionInstances extends OptionInstances0 { implicit def catsKernelStdOrderForOption[A: Order]: Order[Option[A]] = new OptionOrder[A] implicit def catsKernelStdMonoidForOption[A: Semigroup]: Monoid[Option[A]] = new OptionMonoid[A] } -trait OptionInstances1 extends OptionInstances0 { +trait OptionInstances0 extends OptionInstances1 { implicit def catsKernelStdPartialOrderForOption[A: PartialOrder]: PartialOrder[Option[A]] = new OptionPartialOrder[A] +} +trait OptionInstances1 extends OptionInstances2 { implicit def catsKernelStdHashForOption[A: Hash]: Hash[Option[A]] = new OptionHash[A] } -trait OptionInstances0 { +trait OptionInstances2 { implicit def catsKernelStdEqForOption[A: Eq]: Eq[Option[A]] = new OptionEq[A] } diff --git a/laws/src/main/scala/cats/laws/discipline/CartesianTests.scala b/laws/src/main/scala/cats/laws/discipline/CartesianTests.scala index f1ab2a1455..38dd1b2614 100644 --- a/laws/src/main/scala/cats/laws/discipline/CartesianTests.scala +++ b/laws/src/main/scala/cats/laws/discipline/CartesianTests.scala @@ -16,6 +16,7 @@ trait CartesianTests[F[_]] extends Laws { ArbFA: Arbitrary[F[A]], ArbFB: Arbitrary[F[B]], ArbFC: Arbitrary[F[C]], + EqFA: Eq[F[A]], EqFABC: Eq[F[(A, B, C)]] ): RuleSet = { new DefaultRuleSet( @@ -31,24 +32,25 @@ object CartesianTests { new CartesianTests[F] { val laws: CartesianLaws[F] = CartesianLaws[F] } trait Isomorphisms[F[_]] { - def associativity[A, B, C](fs: (F[(A, (B, C))], F[((A, B), C)]))(implicit EqFABC: Eq[F[(A, B, C)]]): Prop - def leftIdentity[A](fs: (F[(Unit, A)], F[A]))(implicit EqFA: Eq[F[A]]): Prop - def rightIdentity[A](fs: (F[(A, Unit)], F[A]))(implicit EqFA: Eq[F[A]]): Prop + def associativity[A, B, C](fs: (F[(A, (B, C))], F[((A, B), C)])): IsEq[F[(A, B, C)]] + def leftIdentity[A](fs: (F[(Unit, A)], F[A])): IsEq[F[A]] + def rightIdentity[A](fs: (F[(A, Unit)], F[A])): IsEq[F[A]] } object Isomorphisms { + import cats.kernel.laws._ implicit def invariant[F[_]](implicit F: Invariant[F]): Isomorphisms[F] = new Isomorphisms[F] { - def associativity[A, B, C](fs: (F[(A, (B, C))], F[((A, B), C)]))(implicit EqFABC: Eq[F[(A, B, C)]]) = - F.imap(fs._1) { case (a, (b, c)) => (a, b, c) } { case (a, b, c) => (a, (b, c)) } ?== + def associativity[A, B, C](fs: (F[(A, (B, C))], F[((A, B), C)])): IsEq[F[(A, B, C)]] = + F.imap(fs._1) { case (a, (b, c)) => (a, b, c) } { case (a, b, c) => (a, (b, c)) } <-> F.imap(fs._2) { case ((a, b), c) => (a, b, c) } { case (a, b, c) => ((a, b), c) } - def leftIdentity[A](fs: (F[(Unit, A)], F[A]))(implicit EqFA: Eq[F[A]]): Prop = - F.imap(fs._1) { case (_, a) => a } { a => ((), a) } ?== fs._2 + def leftIdentity[A](fs: (F[(Unit, A)], F[A])): IsEq[F[A]] = + F.imap(fs._1) { case (_, a) => a } { a => ((), a) } <-> fs._2 - def rightIdentity[A](fs: (F[(A, Unit)], F[A]))(implicit EqFA: Eq[F[A]]): Prop = - F.imap(fs._1) { case (a, _) => a } { a => (a, ()) } ?== fs._2 + def rightIdentity[A](fs: (F[(A, Unit)], F[A])): IsEq[F[A]] = + F.imap(fs._1) { case (a, _) => a } { a => (a, ()) } <-> fs._2 } } diff --git a/laws/src/main/scala/cats/laws/discipline/package.scala b/laws/src/main/scala/cats/laws/discipline/package.scala index b4fb5ca831..b687bcdac4 100644 --- a/laws/src/main/scala/cats/laws/discipline/package.scala +++ b/laws/src/main/scala/cats/laws/discipline/package.scala @@ -1,11 +1,12 @@ package cats package laws -import cats.kernel.laws._ - import org.scalacheck.Prop package object discipline { + + val SerializableTests = cats.kernel.laws.discipline.SerializableTests + implicit def catsLawsIsEqToProp[A: Eq](isEq: IsEq[A]): Prop = - isEq.lhs ?== isEq.rhs + cats.kernel.laws.discipline.catsLawsIsEqToProp[A](isEq) } diff --git a/laws/src/main/scala/cats/laws/package.scala b/laws/src/main/scala/cats/laws/package.scala index fbfcfaf7d7..3b3a5d13d3 100644 --- a/laws/src/main/scala/cats/laws/package.scala +++ b/laws/src/main/scala/cats/laws/package.scala @@ -1,6 +1,10 @@ package cats package object laws { + + type IsEq[A] = cats.kernel.laws.IsEq[A] + val IsEq = cats.kernel.laws.IsEq + implicit final class IsEqArrow[A](val lhs: A) extends AnyVal { def <->(rhs: A): IsEq[A] = IsEq(lhs, rhs) } diff --git a/tests/src/test/scala/cats/tests/CategoryTests.scala b/tests/src/test/scala/cats/tests/CategoryTests.scala index a052e7c9fe..923e82184a 100644 --- a/tests/src/test/scala/cats/tests/CategoryTests.scala +++ b/tests/src/test/scala/cats/tests/CategoryTests.scala @@ -1,7 +1,7 @@ package cats package tests -import cats.kernel.laws.GroupLaws +import cats.kernel.laws.discipline.{MonoidLawTests} import cats.arrow.Category import cats.laws.discipline.{MonoidKTests, SerializableTests} @@ -15,5 +15,5 @@ class CategoryTest extends CatsSuite { checkAll("Category[Function1].algebraK", SerializableTests.serializable(functionCategory.algebraK)) val functionAlgebra = functionCategory.algebra[Int] - checkAll("Category[Function1].algebra[Int]", GroupLaws[Endo[Int]].monoid(functionAlgebra)) + checkAll("Category[Function1].algebra[Int]", MonoidLawTests[Endo[Int]](functionAlgebra).monoid) } diff --git a/tests/src/test/scala/cats/tests/ComposeTest.scala b/tests/src/test/scala/cats/tests/ComposeTest.scala index d848901f2c..0d0413ed5d 100644 --- a/tests/src/test/scala/cats/tests/ComposeTest.scala +++ b/tests/src/test/scala/cats/tests/ComposeTest.scala @@ -1,7 +1,7 @@ package cats package tests -import cats.kernel.laws.GroupLaws +import cats.kernel.laws.discipline.{SemigroupLawTests} import cats.arrow.Compose import cats.laws.discipline.{SemigroupKTests, SerializableTests} @@ -15,7 +15,7 @@ class ComposeTest extends CatsSuite { checkAll("Compose[Function1].algebraK", SerializableTests.serializable(functionCompose.algebraK)) val functionAlgebra = functionCompose.algebra[Int] - checkAll("Compose[Function1].algebra[Int]", GroupLaws[Endo[Int]].semigroup(functionAlgebra)) + checkAll("Compose[Function1].algebra[Int]", SemigroupLawTests[Endo[Int]](functionAlgebra).semigroup) test("syntax") { (((_: Int) + 1) <<< ((_: Int) / 2))(2) should be(2) diff --git a/tests/src/test/scala/cats/tests/ConstTests.scala b/tests/src/test/scala/cats/tests/ConstTests.scala index cb9687a1c3..7eb43fa952 100644 --- a/tests/src/test/scala/cats/tests/ConstTests.scala +++ b/tests/src/test/scala/cats/tests/ConstTests.scala @@ -1,8 +1,15 @@ package cats package tests + +import cats.kernel.laws.discipline.{ + MonoidLawTests, + SemigroupLawTests, + OrderLawTests, + PartialOrderLawTests, + EqLawTests +} import cats.Contravariant -import cats.kernel.laws.{GroupLaws, OrderLaws} import cats.data.{Const, NonEmptyList} import cats.laws.discipline._ import cats.laws.discipline.arbitrary._ @@ -29,17 +36,17 @@ class ConstTests extends CatsSuite { } // Algebra checks for Serializability of instances as part of the laws - checkAll("Monoid[Const[Int, String]]", GroupLaws[Const[Int, String]].monoid) + checkAll("Monoid[Const[Int, String]]", MonoidLawTests[Const[Int, String]].monoid) - checkAll("Const[NonEmptyList[Int], String]", GroupLaws[Const[NonEmptyList[Int], String]].semigroup) + checkAll("Const[NonEmptyList[Int], String]", SemigroupLawTests[Const[NonEmptyList[Int], String]].semigroup) // Note while Eq is a superclass of PartialOrder and PartialOrder a superclass // of Order, you can get different instances with different (more general) constraints. // For instance, you can get an Order for Const if the first type parameter has an Order, // but you can also get just an Eq for Const if the first type parameter has just an Eq - checkAll("Const[Map[Int, Int], String]", OrderLaws[Const[Map[Int, Int], String]].eqv) - checkAll("PartialOrder[Const[Set[Int], String]]", OrderLaws[Const[Set[Int], String]].partialOrder) - checkAll("Order[Const[Int, String]]", OrderLaws[Const[Int, String]].order) + checkAll("Const[Map[Int, Int], String]", EqLawTests[Const[Map[Int, Int], String]].eqv) + checkAll("PartialOrder[Const[Set[Int], String]]", PartialOrderLawTests[Const[Set[Int], String]].partialOrder) + checkAll("Order[Const[Int, String]]", OrderLawTests[Const[Int, String]].order) checkAll("Const[String, Int]", ContravariantTests[Const[String, ?]].contravariant[Int, Int, Int]) checkAll("Contravariant[Const[String, ?]]", SerializableTests.serializable(Contravariant[Const[String, ?]])) diff --git a/tests/src/test/scala/cats/tests/EitherKTests.scala b/tests/src/test/scala/cats/tests/EitherKTests.scala index d7a315a91c..112ec09234 100644 --- a/tests/src/test/scala/cats/tests/EitherKTests.scala +++ b/tests/src/test/scala/cats/tests/EitherKTests.scala @@ -1,7 +1,7 @@ package cats.tests import cats._ -import cats.kernel.laws.OrderLaws +import cats.kernel.laws.discipline.{EqLawTests} import cats.data.EitherK import cats.laws.discipline._ import cats.laws.discipline.arbitrary._ @@ -27,7 +27,7 @@ class EitherKTests extends CatsSuite { checkAll("CoflatMap[EitherK[Eval, Eval, ?]]", SerializableTests.serializable(CoflatMap[EitherK[Eval, Eval, ?]])) } - checkAll("EitherK[Option, Option, Int]", OrderLaws[EitherK[Option, Option, Int]].eqv) + checkAll("EitherK[Option, Option, Int]", EqLawTests[EitherK[Option, Option, Int]].eqv) checkAll("Eq[EitherK[Option, Option, Int]]", SerializableTests.serializable(Eq[EitherK[Option, Option, Int]])) checkAll("EitherK[Show, Show, ?]", ContravariantTests[EitherK[Show, Show, ?]].contravariant[Int, Int, Int]) diff --git a/tests/src/test/scala/cats/tests/EitherTTests.scala b/tests/src/test/scala/cats/tests/EitherTTests.scala index 2365ce4d4c..3c167e048d 100644 --- a/tests/src/test/scala/cats/tests/EitherTTests.scala +++ b/tests/src/test/scala/cats/tests/EitherTTests.scala @@ -6,7 +6,13 @@ import cats.data.EitherT import cats.laws.discipline._ import cats.laws.discipline.arbitrary._ -import cats.kernel.laws.{GroupLaws, OrderLaws} +import cats.kernel.laws.discipline.{ +MonoidLawTests, +SemigroupLawTests, +OrderLawTests, +PartialOrderLawTests, +EqLawTests +} class EitherTTests extends CatsSuite { @@ -20,7 +26,7 @@ class EitherTTests extends CatsSuite { { implicit val F = ListWrapper.order[Either[String, Int]] - checkAll("EitherT[List, String, Int]", OrderLaws[EitherT[ListWrapper, String, Int]].order) + checkAll("EitherT[List, String, Int]", OrderLawTests[EitherT[ListWrapper, String, Int]].order) checkAll("Order[EitherT[List, String, Int]]", SerializableTests.serializable(Order[EitherT[ListWrapper, String, Int]])) } @@ -100,14 +106,14 @@ class EitherTTests extends CatsSuite { { implicit val F = ListWrapper.partialOrder[Either[String, Int]] - checkAll("EitherT[ListWrapper, String, Int]", OrderLaws[EitherT[ListWrapper, String, Int]].partialOrder) + checkAll("EitherT[ListWrapper, String, Int]", PartialOrderLawTests[EitherT[ListWrapper, String, Int]].partialOrder) checkAll("PartialOrder[EitherT[ListWrapper, String, Int]]", SerializableTests.serializable(PartialOrder[EitherT[ListWrapper, String, Int]])) } { implicit val F = ListWrapper.semigroup[Either[String, Int]] - checkAll("EitherT[ListWrapper, String, Int]", GroupLaws[EitherT[ListWrapper, String, Int]].semigroup) + checkAll("EitherT[ListWrapper, String, Int]", SemigroupLawTests[EitherT[ListWrapper, String, Int]].semigroup) checkAll("Semigroup[EitherT[ListWrapper, String, Int]]", SerializableTests.serializable(Semigroup[EitherT[ListWrapper, String, Int]])) } @@ -116,14 +122,14 @@ class EitherTTests extends CatsSuite { Semigroup[EitherT[ListWrapper, String, Int]] - checkAll("EitherT[ListWrapper, String, Int]", GroupLaws[EitherT[ListWrapper, String, Int]].monoid) + checkAll("EitherT[ListWrapper, String, Int]", MonoidLawTests[EitherT[ListWrapper, String, Int]].monoid) checkAll("Monoid[EitherT[ListWrapper, String, Int]]", SerializableTests.serializable(Monoid[EitherT[ListWrapper, String, Int]])) } { implicit val F = ListWrapper.eqv[Either[String, Int]] - checkAll("EitherT[ListWrapper, String, Int]", OrderLaws[EitherT[ListWrapper, String, Int]].eqv) + checkAll("EitherT[ListWrapper, String, Int]", EqLawTests[EitherT[ListWrapper, String, Int]].eqv) checkAll("Eq[EitherT[ListWrapper, String, Int]]", SerializableTests.serializable(Eq[EitherT[ListWrapper, String, Int]])) } diff --git a/tests/src/test/scala/cats/tests/EitherTests.scala b/tests/src/test/scala/cats/tests/EitherTests.scala index 053887511c..72da1d6024 100644 --- a/tests/src/test/scala/cats/tests/EitherTests.scala +++ b/tests/src/test/scala/cats/tests/EitherTests.scala @@ -3,13 +3,19 @@ package tests import cats.data.{ EitherT, Validated } import cats.laws.discipline._ -import cats.kernel.laws.{GroupLaws, OrderLaws} +import cats.kernel.laws.discipline.{ + MonoidLawTests, + SemigroupLawTests, + OrderLawTests, + PartialOrderLawTests, + EqLawTests +} import scala.util.Try class EitherTests extends CatsSuite { implicit val iso = CartesianTests.Isomorphisms.invariant[Either[Int, ?]] - checkAll("Either[String, Int]", GroupLaws[Either[String, Int]].monoid) + checkAll("Either[String, Int]", MonoidLawTests[Either[String, Int]].monoid) checkAll("Monoid[Either[String, Int]]", SerializableTests.serializable(Monoid[Either[String, Int]])) checkAll("Either[Int, Int]", CartesianTests[Either[Int, ?]].cartesian[Int, Int, Int]) @@ -29,7 +35,7 @@ class EitherTests extends CatsSuite { checkAll("Either[ListWrapper[String], ?]", SemigroupKTests[Either[ListWrapper[String], ?]].semigroupK[Int]) checkAll("SemigroupK[Either[ListWrapper[String], ?]]", SerializableTests.serializable(SemigroupK[Either[ListWrapper[String], ?]])) - checkAll("Either[ListWrapper[String], Int]", GroupLaws[Either[ListWrapper[String], Int]].semigroup) + checkAll("Either[ListWrapper[String], Int]", SemigroupLawTests[Either[ListWrapper[String], Int]].semigroup) checkAll("Semigroup[Either[ListWrapper[String], Int]]", SerializableTests.serializable(Semigroup[Either[ListWrapper[String], Int]])) val partialOrder = catsStdPartialOrderForEither[Int, String] @@ -40,13 +46,12 @@ class EitherTests extends CatsSuite { { implicit val S = ListWrapper.eqv[String] implicit val I = ListWrapper.eqv[Int] - checkAll("Either[ListWrapper[String], ListWrapper[Int]]", OrderLaws[Either[ListWrapper[String], ListWrapper[Int]]].eqv) + checkAll("Either[ListWrapper[String], ListWrapper[Int]]", EqLawTests[Either[ListWrapper[String], ListWrapper[Int]]].eqv) checkAll("Eq[Either[ListWrapper[String], ListWrapper[Int]]]", SerializableTests.serializable(Eq[Either[ListWrapper[String], ListWrapper[Int]]])) } - val orderLaws = OrderLaws[Either[Int, String]] - checkAll("Either[Int, String]", orderLaws.partialOrder(partialOrder)) - checkAll("Either[Int, String]", orderLaws.order(order)) + checkAll("Either[Int, String]", PartialOrderLawTests[Either[Int, String]](partialOrder).partialOrder) + checkAll("Either[Int, String]", OrderLawTests[Either[Int, String]](order).order) test("Left/Right cast syntax") { forAll { (e: Either[Int, String]) => diff --git a/tests/src/test/scala/cats/tests/EvalTests.scala b/tests/src/test/scala/cats/tests/EvalTests.scala index a49ba4a3af..86ff9bee15 100644 --- a/tests/src/test/scala/cats/tests/EvalTests.scala +++ b/tests/src/test/scala/cats/tests/EvalTests.scala @@ -4,7 +4,7 @@ package tests import cats.laws.ComonadLaws import cats.laws.discipline.{BimonadTests, CartesianTests, ReducibleTests, SerializableTests} import cats.laws.discipline.arbitrary._ -import cats.kernel.laws.{GroupLaws, OrderLaws} +import cats.kernel.laws.discipline._ import org.scalacheck.{Arbitrary, Cogen, Gen} import org.scalacheck.Arbitrary.arbitrary import scala.annotation.tailrec @@ -98,31 +98,31 @@ class EvalTests extends CatsSuite { checkAll("Eval[Int]", ReducibleTests[Eval].reducible[Option, Int, Int]) checkAll("Reducible[Eval]", SerializableTests.serializable(Reducible[Eval])) - checkAll("Eval[Int]", GroupLaws[Eval[Int]].group) + checkAll("Eval[Int]", GroupLawTests[Eval[Int]].group) { implicit val A = ListWrapper.monoid[Int] - checkAll("Eval[ListWrapper[Int]]", GroupLaws[Eval[ListWrapper[Int]]].monoid) + checkAll("Eval[ListWrapper[Int]]", MonoidLawTests[Eval[ListWrapper[Int]]].monoid) } { implicit val A = ListWrapper.semigroup[Int] - checkAll("Eval[ListWrapper[Int]]", GroupLaws[Eval[ListWrapper[Int]]].semigroup) + checkAll("Eval[ListWrapper[Int]]", SemigroupLawTests[Eval[ListWrapper[Int]]].semigroup) } { implicit val A = ListWrapper.order[Int] - checkAll("Eval[ListWrapper[Int]]", OrderLaws[Eval[ListWrapper[Int]]].order) + checkAll("Eval[ListWrapper[Int]]", OrderLawTests[Eval[ListWrapper[Int]]].order) } { implicit val A = ListWrapper.partialOrder[Int] - checkAll("Eval[ListWrapper[Int]]", OrderLaws[Eval[ListWrapper[Int]]].partialOrder) + checkAll("Eval[ListWrapper[Int]]", PartialOrderLawTests[Eval[ListWrapper[Int]]].partialOrder) } { implicit val A = ListWrapper.eqv[Int] - checkAll("Eval[ListWrapper[Int]]", OrderLaws[Eval[ListWrapper[Int]]].eqv) + checkAll("Eval[ListWrapper[Int]]", EqLawTests[Eval[ListWrapper[Int]]].eqv) } // The following tests check laws which are a different formulation of diff --git a/tests/src/test/scala/cats/tests/FunctionTests.scala b/tests/src/test/scala/cats/tests/FunctionTests.scala index 5ca97373ac..36db548603 100644 --- a/tests/src/test/scala/cats/tests/FunctionTests.scala +++ b/tests/src/test/scala/cats/tests/FunctionTests.scala @@ -1,12 +1,12 @@ package cats package tests -import cats.Contravariant import cats.arrow.{Choice, CommutativeArrow} +import cats.kernel.laws.HashLaws +import cats.kernel.laws.discipline.{SerializableTests, _} import cats.laws.discipline._ import cats.laws.discipline.eq._ import cats.laws.discipline.arbitrary._ -import cats.kernel.laws._ import cats.kernel.{CommutativeGroup, CommutativeMonoid, CommutativeSemigroup} import cats.kernel.{Band, BoundedSemilattice, Semilattice} @@ -42,19 +42,25 @@ class FunctionTests extends CatsSuite { // law checks for the various Function0-related instances - checkAll("Function0[Eqed]", OrderLaws[Function0[Eqed]].eqv) - checkAll("Function0[POrd]", OrderLaws[Function0[POrd]].partialOrder) - checkAll("Function0[Ord]", OrderLaws[Function0[Ord]].order) - checkAll("Function0[Hsh]", HashLaws[Function0[Hsh]].hash) - checkAll("Function0[Semi]", GroupLaws[Function0[Semi]].semigroup) - checkAll("Function0[CSemi]", GroupLaws[Function0[CSemi]].commutativeSemigroup) - checkAll("Function0[Bnd]", GroupLaws[Function0[Bnd]].band) - checkAll("Function0[SL]", GroupLaws[Function0[SL]].semilattice) - checkAll("Function0[BSL]", GroupLaws[Function0[BSL]].boundedSemilattice) - checkAll("Function0[Mono]", GroupLaws[Function0[Mono]].monoid) - checkAll("Function0[CMono]", GroupLaws[Function0[CMono]].commutativeMonoid) - checkAll("Function0[Grp]", GroupLaws[Function0[Grp]].group) - checkAll("Function0[CGrp]", GroupLaws[Function0[CGrp]].commutativeGroup) + checkAll("Function0[Eqed]", EqLawTests[Function0[Eqed]].eqv) + checkAll("Function0[POrd]", PartialOrderLawTests[Function0[POrd]].partialOrder) + checkAll("Function0[Ord]", OrderLawTests[Function0[Ord]].order) + checkAll("Function0[Semi]", SemigroupLawTests[Function0[Semi]].semigroup) + checkAll("Function0[CSemi]", CommutativeSemigroupTests[Function0[CSemi]].commutativeSemigroup) + checkAll("Function0[Bnd]", BandTests[Function0[Bnd]].band) + checkAll("Function0[SL]", SemilatticeTests[Function0[SL]].semilattice) + checkAll("Function0[BSL]", BoundedSemilatticeTests[Function0[BSL]].boundedSemilattice) + checkAll("Function0[Mono]", MonoidLawTests[Function0[Mono]].monoid) + checkAll("Function0[CMono]", CommutativeMonoidTests[Function0[CMono]].commutativeMonoid) + checkAll("Function0[Grp]", GroupLawTests[Function0[Grp]].group) + checkAll("Function0[CGrp]", CommutativeGroupTests[Function0[CGrp]].commutativeGroup) + + test("Function0[Hsh]") { + forAll { (x: Function0[Hsh], y: Function0[Hsh]) => + HashLaws[Function0[Hsh]].hashCompatibility(x, y) + } + } + // serialization tests for the various Function0-related instances checkAll("Eq[() => Eqed]", SerializableTests.serializable(Eq[() => Eqed])) @@ -72,15 +78,15 @@ class FunctionTests extends CatsSuite { // law checks for the various Function1-related instances - checkAll("Function1[String, Semi]", GroupLaws[Function1[String, Semi]].semigroup) - checkAll("Function1[String, CSemi]", GroupLaws[Function1[String, CSemi]].commutativeSemigroup) - checkAll("Function1[String, Bnd]", GroupLaws[Function1[String, Bnd]].band) - checkAll("Function1[String, SL]", GroupLaws[Function1[String, SL]].semilattice) - checkAll("Function1[String, BSL]", GroupLaws[Function1[String, BSL]].boundedSemilattice) - checkAll("Function1[String, Mono]", GroupLaws[Function1[String, Mono]].monoid) - checkAll("Function1[String, CMono]", GroupLaws[Function1[String, CMono]].commutativeMonoid) - checkAll("Function1[String, Grp]", GroupLaws[Function1[String, Grp]].group) - checkAll("Function1[String, CGrp]", GroupLaws[Function1[String, CGrp]].commutativeGroup) + checkAll("Function1[String, Semi]", SemigroupLawTests[Function1[String, Semi]].semigroup) + checkAll("Function1[String, CSemi]", CommutativeSemigroupTests[Function1[String, CSemi]].commutativeSemigroup) + checkAll("Function1[String, Bnd]", BandTests[Function1[String, Bnd]].band) + checkAll("Function1[String, SL]", SemilatticeTests[Function1[String, SL]].semilattice) + checkAll("Function1[String, BSL]", BoundedSemilatticeTests[Function1[String, BSL]].boundedSemilattice) + checkAll("Function1[String, Mono]", MonoidLawTests[Function1[String, Mono]].monoid) + checkAll("Function1[String, CMono]", CommutativeMonoidTests[Function1[String, CMono]].commutativeMonoid) + checkAll("Function1[String, Grp]", GroupLawTests[Function1[String, Grp]].group) + checkAll("Function1[String, CGrp]", CommutativeGroupTests[Function1[String, CGrp]].commutativeGroup) // serialization tests for the various Function1-related instances checkAll("Semigroup[String => Semi]", SerializableTests.serializable(Semigroup[String => Semi])) diff --git a/tests/src/test/scala/cats/tests/GroupTests.scala b/tests/src/test/scala/cats/tests/GroupTests.scala index 03d80a5fc9..e3f4339649 100644 --- a/tests/src/test/scala/cats/tests/GroupTests.scala +++ b/tests/src/test/scala/cats/tests/GroupTests.scala @@ -1,7 +1,7 @@ package cats package tests -import cats.kernel.laws.GroupLaws +import cats.kernel.laws.discipline.{GroupLawTests} class GroupTests extends CatsSuite { test("combine minValue") { @@ -18,9 +18,9 @@ class GroupTests extends CatsSuite { Group[Int].remove(1, 2) should ===(-1) } - checkAll("Int", GroupLaws[Int].group) + checkAll("Int", GroupLawTests[Int].group) // float and double are *not* associative, and scalacheck knows // checkAll("Double", GroupLaws[Double].group) // checkAll("Float", GroupLaws[Float].group) - checkAll("Long", GroupLaws[Long].group) + checkAll("Long", GroupLawTests[Long].group) } diff --git a/tests/src/test/scala/cats/tests/IdTTests.scala b/tests/src/test/scala/cats/tests/IdTTests.scala index 24a0daf25c..1a2016f4fb 100644 --- a/tests/src/test/scala/cats/tests/IdTTests.scala +++ b/tests/src/test/scala/cats/tests/IdTTests.scala @@ -2,7 +2,10 @@ package cats package tests import cats.data.{IdT, NonEmptyList} -import cats.kernel.laws.OrderLaws +import cats.kernel.laws.discipline.{ + OrderLawTests, + EqLawTests +} import cats.laws.discipline._ import cats.laws.discipline.arbitrary._ @@ -13,14 +16,14 @@ class IdTTests extends CatsSuite { { implicit val F = ListWrapper.eqv[Option[Int]] - checkAll("IdT[ListWrapper, Int]", OrderLaws[IdT[ListWrapper, Int]].eqv) + checkAll("IdT[ListWrapper, Int]", EqLawTests[IdT[ListWrapper, Int]].eqv) checkAll("Eq[IdT[ListWrapper, Int]]", SerializableTests.serializable(Eq[IdT[ListWrapper, Int]])) } { implicit val F = ListWrapper.order[Int] - checkAll("IdT[ListWrapper, Int]", OrderLaws[IdT[ListWrapper, Int]].order) + checkAll("IdT[ListWrapper, Int]", OrderLawTests[IdT[ListWrapper, Int]].order) checkAll("Order[IdT[ListWrapper, Int]]", SerializableTests.serializable(Order[IdT[ListWrapper, Int]])) } diff --git a/tests/src/test/scala/cats/tests/IorTests.scala b/tests/src/test/scala/cats/tests/IorTests.scala index 2b6d4a30ed..c8e4415e45 100644 --- a/tests/src/test/scala/cats/tests/IorTests.scala +++ b/tests/src/test/scala/cats/tests/IorTests.scala @@ -1,7 +1,7 @@ package cats package tests -import cats.kernel.laws.GroupLaws +import cats.kernel.laws.discipline.{SemigroupLawTests} import cats.laws.discipline.{BifunctorTests, CartesianTests, MonadErrorTests, SerializableTests, TraverseTests} import cats.data.{Ior, NonEmptyList, EitherT} import cats.laws.discipline.arbitrary._ @@ -23,7 +23,7 @@ class IorTests extends CatsSuite { checkAll("Traverse[String Ior ?]", SerializableTests.serializable(Traverse[String Ior ?])) checkAll("? Ior ?", BifunctorTests[Ior].bifunctor[Int, Int, Int, String, String, String]) - checkAll("Semigroup[Ior[A: Semigroup, B: Semigroup]]", GroupLaws[Ior[List[Int], List[Int]]].semigroup) + checkAll("Semigroup[Ior[A: Semigroup, B: Semigroup]]", SemigroupLawTests[Ior[List[Int], List[Int]]].semigroup) checkAll("SerializableTest Semigroup[Ior[A: Semigroup, B: Semigroup]]", SerializableTests.serializable(Semigroup[Ior[List[Int], List[Int]]])) test("left Option is defined left and both") { diff --git a/tests/src/test/scala/cats/tests/KleisliTests.scala b/tests/src/test/scala/cats/tests/KleisliTests.scala index b8a78512aa..c032a9a425 100644 --- a/tests/src/test/scala/cats/tests/KleisliTests.scala +++ b/tests/src/test/scala/cats/tests/KleisliTests.scala @@ -8,8 +8,8 @@ import cats.laws.discipline._ import cats.laws.discipline.arbitrary._ import cats.laws.discipline.eq._ import org.scalacheck.Arbitrary -import cats.kernel.laws.GroupLaws -import cats.laws.discipline.{MonoidKTests, SemigroupKTests} +import cats.kernel.laws.discipline.{MonoidLawTests, SemigroupLawTests} +import cats.laws.discipline.{SemigroupKTests, MonoidKTests} class KleisliTests extends CatsSuite { implicit def kleisliEq[F[_], A, B](implicit A: Arbitrary[A], FB: Eq[F[B]]): Eq[Kleisli[F, A, B]] = @@ -107,13 +107,13 @@ class KleisliTests extends CatsSuite { { implicit val catsDataMonoidForKleisli = Kleisli.catsDataMonoidForKleisli[Option, Int, String] - checkAll("Kleisli[Option, Int, String]", GroupLaws[Kleisli[Option, Int, String]].monoid) + checkAll("Kleisli[Option, Int, String]", MonoidLawTests[Kleisli[Option, Int, String]].monoid) checkAll("Monoid[Kleisli[Option, Int, String]]", SerializableTests.serializable(catsDataMonoidForKleisli)) } { implicit val catsDataSemigroupForKleisli = Kleisli.catsDataSemigroupForKleisli[Option, Int, String] - checkAll("Kleisli[Option, Int, String]", GroupLaws[Kleisli[Option, Int, String]].semigroup) + checkAll("Kleisli[Option, Int, String]", SemigroupLawTests[Kleisli[Option, Int, String]].semigroup) checkAll("Semigroup[Kleisli[Option, Int, String]]", SerializableTests.serializable(catsDataSemigroupForKleisli)) } diff --git a/tests/src/test/scala/cats/tests/NonEmptyListTests.scala b/tests/src/test/scala/cats/tests/NonEmptyListTests.scala index 55261d2aa5..bc8c773d3d 100644 --- a/tests/src/test/scala/cats/tests/NonEmptyListTests.scala +++ b/tests/src/test/scala/cats/tests/NonEmptyListTests.scala @@ -1,7 +1,12 @@ package cats package tests -import cats.kernel.laws.{GroupLaws, OrderLaws} +import cats.kernel.laws.discipline.{ + SemigroupLawTests, + OrderLawTests, + PartialOrderLawTests, + EqLawTests +} import cats.data.{NonEmptyList, NonEmptyVector} import cats.laws.discipline.arbitrary._ @@ -12,7 +17,7 @@ class NonEmptyListTests extends CatsSuite { implicit override val generatorDrivenConfig: PropertyCheckConfiguration = PropertyCheckConfiguration(minSuccessful = 20, sizeRange = 5) - checkAll("NonEmptyList[Int]", OrderLaws[NonEmptyList[Int]].order) + checkAll("NonEmptyList[Int]", OrderLawTests[NonEmptyList[Int]].order) checkAll("NonEmptyList[Int] with Option", NonEmptyTraverseTests[NonEmptyList].nonEmptyTraverse[Option, Int, Int, Int, Int, Option, Option]) checkAll("NonEmptyTraverse[NonEmptyList[A]]", SerializableTests.serializable(NonEmptyTraverse[NonEmptyList])) @@ -26,18 +31,18 @@ class NonEmptyListTests extends CatsSuite { checkAll("NonEmptyList[Int]", SemigroupKTests[NonEmptyList].semigroupK[Int]) checkAll("SemigroupK[NonEmptyList[A]]", SerializableTests.serializable(SemigroupK[NonEmptyList])) - checkAll("NonEmptyList[Int]", GroupLaws[NonEmptyList[Int]].semigroup) + checkAll("NonEmptyList[Int]", SemigroupLawTests[NonEmptyList[Int]].semigroup) checkAll("Semigroup[NonEmptyList[Int]]", SerializableTests.serializable(Semigroup[NonEmptyList[Int]])) checkAll("NonEmptyList[Int]", ComonadTests[NonEmptyList].comonad[Int, Int, Int]) checkAll("Comonad[NonEmptyList]", SerializableTests.serializable(Comonad[NonEmptyList])) - checkAll("NonEmptyList[ListWrapper[Int]]", OrderLaws[NonEmptyList[ListWrapper[Int]]].eqv) + checkAll("NonEmptyList[ListWrapper[Int]]", EqLawTests[NonEmptyList[ListWrapper[Int]]].eqv) checkAll("Eq[NonEmptyList[ListWrapper[Int]]]", SerializableTests.serializable(Eq[NonEmptyList[ListWrapper[Int]]])) { implicit val A = ListWrapper.partialOrder[Int] - checkAll("NonEmptyList[ListWrapper[Int]]", OrderLaws[NonEmptyList[ListWrapper[Int]]].partialOrder) + checkAll("NonEmptyList[ListWrapper[Int]]", PartialOrderLawTests[NonEmptyList[ListWrapper[Int]]].partialOrder) checkAll("PartialOrder[NonEmptyList[ListWrapper[Int]]]", SerializableTests.serializable(PartialOrder[NonEmptyList[ListWrapper[Int]]])) Eq[NonEmptyList[ListWrapper[Int]]] @@ -45,7 +50,7 @@ class NonEmptyListTests extends CatsSuite { { implicit val A = ListWrapper.order[Int] - checkAll("NonEmptyList[ListWrapper[Int]]", OrderLaws[NonEmptyList[ListWrapper[Int]]].order) + checkAll("NonEmptyList[ListWrapper[Int]]", OrderLawTests[NonEmptyList[ListWrapper[Int]]].order) checkAll("Order[NonEmptyList[ListWrapper[Int]]]", SerializableTests.serializable(Order[NonEmptyList[ListWrapper[Int]]])) Eq[NonEmptyList[ListWrapper[Int]]] diff --git a/tests/src/test/scala/cats/tests/NonEmptyVectorTests.scala b/tests/src/test/scala/cats/tests/NonEmptyVectorTests.scala index 3b271e1b2f..6db3ffb5bc 100644 --- a/tests/src/test/scala/cats/tests/NonEmptyVectorTests.scala +++ b/tests/src/test/scala/cats/tests/NonEmptyVectorTests.scala @@ -3,7 +3,10 @@ package tests import catalysts.Platform -import cats.kernel.laws.{GroupLaws, OrderLaws} +import cats.kernel.laws.discipline.{ + SemigroupLawTests, + EqLawTests +} import cats.data.NonEmptyVector import cats.laws.discipline.{ComonadTests, SemigroupKTests, FoldableTests, SerializableTests, NonEmptyTraverseTests, ReducibleTests, MonadTests} @@ -16,7 +19,7 @@ class NonEmptyVectorTests extends CatsSuite { implicit override val generatorDrivenConfig: PropertyCheckConfiguration = PropertyCheckConfiguration(minSuccessful = 20, sizeRange = 5) - checkAll("NonEmptyVector[Int]", OrderLaws[NonEmptyVector[Int]].eqv) + checkAll("NonEmptyVector[Int]", EqLawTests[NonEmptyVector[Int]].eqv) checkAll("NonEmptyVector[Int] with Option", NonEmptyTraverseTests[NonEmptyVector].nonEmptyTraverse[Option, Int, Int, Int, Int, Option, Option]) checkAll("NonEmptyTraverse[NonEmptyVector[A]]", SerializableTests.serializable(NonEmptyTraverse[NonEmptyVector])) @@ -28,7 +31,7 @@ class NonEmptyVectorTests extends CatsSuite { // Test instances that have more general constraints checkAll("NonEmptyVector[Int]", SemigroupKTests[NonEmptyVector].semigroupK[Int]) - checkAll("NonEmptyVector[Int]", GroupLaws[NonEmptyVector[Int]].semigroup) + checkAll("NonEmptyVector[Int]", SemigroupLawTests[NonEmptyVector[Int]].semigroup) checkAll("SemigroupK[NonEmptyVector]", SerializableTests.serializable(SemigroupK[NonEmptyVector])) checkAll("Semigroup[NonEmptyVector[Int]]", SerializableTests.serializable(Semigroup[NonEmptyVector[Int]])) diff --git a/tests/src/test/scala/cats/tests/OneAndTests.scala b/tests/src/test/scala/cats/tests/OneAndTests.scala index bd0cd52359..f3028f861e 100644 --- a/tests/src/test/scala/cats/tests/OneAndTests.scala +++ b/tests/src/test/scala/cats/tests/OneAndTests.scala @@ -1,7 +1,10 @@ package cats package tests -import cats.kernel.laws.{GroupLaws, OrderLaws} +import cats.kernel.laws.discipline.{ + SemigroupLawTests, + EqLawTests +} import cats.instances.stream._ import cats.data.{NonEmptyStream, OneAnd} @@ -13,7 +16,7 @@ class OneAndTests extends CatsSuite { implicit override val generatorDrivenConfig: PropertyCheckConfiguration = PropertyCheckConfiguration(minSuccessful = 20, sizeRange = 5) - checkAll("OneAnd[Stream, Int]", OrderLaws[OneAnd[Stream, Int]].eqv) + checkAll("OneAnd[Stream, Int]", EqLawTests[OneAnd[Stream, Int]].eqv) checkAll("OneAnd[Stream, Int] with Option", NonEmptyTraverseTests[OneAnd[Stream, ?]].nonEmptyTraverse[Option, Int, Int, Int, Int, Option, Option]) checkAll("NonEmptyTraverse[OneAnd[Stream, A]]", SerializableTests.serializable(NonEmptyTraverse[OneAnd[Stream, ?]])) @@ -46,7 +49,7 @@ class OneAndTests extends CatsSuite { { implicit val alternative = ListWrapper.alternative checkAll("OneAnd[ListWrapper, Int]", SemigroupKTests[OneAnd[ListWrapper, ?]].semigroupK[Int]) - checkAll("OneAnd[Stream, Int]", GroupLaws[OneAnd[Stream, Int]].semigroup) + checkAll("OneAnd[Stream, Int]", SemigroupLawTests[OneAnd[Stream, Int]].semigroup) checkAll("SemigroupK[OneAnd[ListWrapper, A]]", SerializableTests.serializable(SemigroupK[OneAnd[ListWrapper, ?]])) checkAll("Semigroup[NonEmptyStream[Int]]", SerializableTests.serializable(Semigroup[OneAnd[Stream, Int]])) } diff --git a/tests/src/test/scala/cats/tests/OptionTTests.scala b/tests/src/test/scala/cats/tests/OptionTTests.scala index 450b4e915e..abf4db2907 100644 --- a/tests/src/test/scala/cats/tests/OptionTTests.scala +++ b/tests/src/test/scala/cats/tests/OptionTTests.scala @@ -2,7 +2,13 @@ package cats package tests import cats.data.OptionT -import cats.kernel.laws.{GroupLaws, OrderLaws} +import cats.kernel.laws.discipline.{ + MonoidLawTests, + SemigroupLawTests, + OrderLawTests, + PartialOrderLawTests, + EqLawTests +} import cats.laws.discipline._ import cats.laws.discipline.arbitrary._ @@ -12,14 +18,14 @@ class OptionTTests extends CatsSuite { { implicit val F = ListWrapper.eqv[Option[Int]] - checkAll("OptionT[ListWrapper, Int]", OrderLaws[OptionT[ListWrapper, Int]].eqv) + checkAll("OptionT[ListWrapper, Int]", EqLawTests[OptionT[ListWrapper, Int]].eqv) checkAll("Eq[OptionT[ListWrapper, Int]]", SerializableTests.serializable(Eq[OptionT[ListWrapper, Int]])) } { implicit val F = ListWrapper.partialOrder[Option[Int]] - checkAll("OptionT[ListWrapper, Int]", OrderLaws[OptionT[ListWrapper, Int]].partialOrder) + checkAll("OptionT[ListWrapper, Int]", PartialOrderLawTests[OptionT[ListWrapper, Int]].partialOrder) checkAll("PartialOrder[OptionT[ListWrapper, Int]]", SerializableTests.serializable(PartialOrder[OptionT[ListWrapper, Int]])) Eq[OptionT[ListWrapper, Int]] @@ -28,7 +34,7 @@ class OptionTTests extends CatsSuite { { implicit val F = ListWrapper.order[Option[Int]] - checkAll("OptionT[ListWrapper, Int]", OrderLaws[OptionT[ListWrapper, Int]].order) + checkAll("OptionT[ListWrapper, Int]", OrderLawTests[OptionT[ListWrapper, Int]].order) checkAll("Order[OptionT[ListWrapper, Int]]", SerializableTests.serializable(Order[OptionT[ListWrapper, Int]])) PartialOrder[OptionT[ListWrapper, Int]] @@ -108,7 +114,7 @@ class OptionTTests extends CatsSuite { // F[Option[A]] has a monoid implicit val FA: Monoid[ListWrapper[Option[Int]]] = ListWrapper.monoid[Option[Int]] - checkAll("OptionT[ListWrapper, Int]", GroupLaws[OptionT[ListWrapper, Int]].monoid) + checkAll("OptionT[ListWrapper, Int]", MonoidLawTests[OptionT[ListWrapper, Int]].monoid) checkAll("Monoid[OptionT[ListWrapper, Int]]", SerializableTests.serializable(Monoid[OptionT[ListWrapper, Int]])) Semigroup[OptionT[ListWrapper, Int]] @@ -118,7 +124,7 @@ class OptionTTests extends CatsSuite { // F[Option[A]] has a semigroup implicit val FA: Semigroup[ListWrapper[Option[Int]]] = ListWrapper.semigroup[Option[Int]] - checkAll("OptionT[ListWrapper, Int]", GroupLaws[OptionT[ListWrapper, Int]].semigroup) + checkAll("OptionT[ListWrapper, Int]", SemigroupLawTests[OptionT[ListWrapper, Int]].semigroup) checkAll("Semigroup[OptionT[ListWrapper, Int]]", SerializableTests.serializable(Semigroup[OptionT[ListWrapper, Int]])) } diff --git a/tests/src/test/scala/cats/tests/OrderTests.scala b/tests/src/test/scala/cats/tests/OrderTests.scala index 6903bc6a8e..1ff7638e46 100644 --- a/tests/src/test/scala/cats/tests/OrderTests.scala +++ b/tests/src/test/scala/cats/tests/OrderTests.scala @@ -2,7 +2,7 @@ package cats package tests -import cats.kernel.laws.OrderLaws +import cats.kernel.laws.discipline.{OrderLawTests} class OrderTests extends CatsSuite { { @@ -10,10 +10,10 @@ class OrderTests extends CatsSuite { Contravariant[Order] } - checkAll("Int", OrderLaws[Int].order) - checkAll("Double", OrderLaws[Double].order) - checkAll("Float", OrderLaws[Float].order) - checkAll("Long", OrderLaws[Long].order) + checkAll("Int", OrderLawTests[Int].order) + checkAll("Double", OrderLawTests[Double].order) + checkAll("Float", OrderLawTests[Float].order) + checkAll("Long", OrderLawTests[Long].order) } object OrderTests { diff --git a/tests/src/test/scala/cats/tests/SetTests.scala b/tests/src/test/scala/cats/tests/SetTests.scala index 3dfb705582..ba6b62d4d4 100644 --- a/tests/src/test/scala/cats/tests/SetTests.scala +++ b/tests/src/test/scala/cats/tests/SetTests.scala @@ -2,9 +2,9 @@ package cats package tests import cats.laws.discipline.{FoldableTests, MonoidKTests, SerializableTests} - +import cats.kernel.laws.discipline.{MonoidLawTests} class SetTests extends CatsSuite { - checkAll("Set[Int]", cats.kernel.laws.GroupLaws[Set[Int]].monoid) + checkAll("Set[Int]", MonoidLawTests[Set[Int]].monoid) checkAll("Set[Int]", MonoidKTests[Set].monoidK[Int]) checkAll("MonoidK[Set]", SerializableTests.serializable(MonoidK[Set])) diff --git a/tests/src/test/scala/cats/tests/TryTests.scala b/tests/src/test/scala/cats/tests/TryTests.scala index 7fe11c3293..b4ff873382 100644 --- a/tests/src/test/scala/cats/tests/TryTests.scala +++ b/tests/src/test/scala/cats/tests/TryTests.scala @@ -1,7 +1,10 @@ package cats package tests -import cats.kernel.laws.GroupLaws +import cats.kernel.laws.discipline.{ + SemigroupLawTests, + MonoidLawTests +} import cats.laws.{ApplicativeLaws, CoflatMapLaws, FlatMapLaws, MonadLaws} import cats.laws.discipline._ import cats.laws.discipline.arbitrary._ @@ -29,11 +32,11 @@ class TryTests extends CatsSuite { { implicit val F = ListWrapper.semigroup[Int] - checkAll("Try[ListWrapper[Int]]", GroupLaws[Try[ListWrapper[Int]]].semigroup) + checkAll("Try[ListWrapper[Int]]", SemigroupLawTests[Try[ListWrapper[Int]]].semigroup) checkAll("Semigroup[Try[ListWrapper[Int]]", SerializableTests.serializable(Semigroup[Try[ListWrapper[Int]]])) } - checkAll("Try[Int]", GroupLaws[Try[Int]].monoid) + checkAll("Try[Int]", MonoidLawTests[Try[Int]].monoid) checkAll("Monoid[Try[Int]]", SerializableTests.serializable(Monoid[Try[Int]])) test("show") { diff --git a/tests/src/test/scala/cats/tests/Tuple2KTests.scala b/tests/src/test/scala/cats/tests/Tuple2KTests.scala index 5309f4d093..d207c66f57 100644 --- a/tests/src/test/scala/cats/tests/Tuple2KTests.scala +++ b/tests/src/test/scala/cats/tests/Tuple2KTests.scala @@ -6,7 +6,11 @@ import cats.data.Tuple2K import cats.laws.discipline._ import cats.laws.discipline.arbitrary._ import cats.laws.discipline.eq._ -import cats.kernel.laws.OrderLaws +import cats.kernel.laws.discipline.{ + OrderLawTests, + PartialOrderLawTests, + EqLawTests +} class Tuple2KTests extends CatsSuite { implicit val iso = CartesianTests.Isomorphisms.invariant[Tuple2K[Option, List, ?]] @@ -77,9 +81,9 @@ class Tuple2KTests extends CatsSuite { implicit val O = ListWrapper.order[Int] implicit val P = ListWrapper.partialOrder[Int] - checkAll("Tuple2K[ListWrapper, ListWrapper, Int]", OrderLaws[Tuple2K[ListWrapper, ListWrapper, Int]].eqv) - checkAll("Tuple2K[ListWrapper, ListWrapper, Int]", OrderLaws[Tuple2K[ListWrapper, ListWrapper, Int]].order) - checkAll("Tuple2K[ListWrapper, ListWrapper, Int]", OrderLaws[Tuple2K[ListWrapper, ListWrapper, Int]].partialOrder) + checkAll("Tuple2K[ListWrapper, ListWrapper, Int]", EqLawTests[Tuple2K[ListWrapper, ListWrapper, Int]].eqv) + checkAll("Tuple2K[ListWrapper, ListWrapper, Int]", OrderLawTests[Tuple2K[ListWrapper, ListWrapper, Int]].order) + checkAll("Tuple2K[ListWrapper, ListWrapper, Int]", PartialOrderLawTests[Tuple2K[ListWrapper, ListWrapper, Int]].partialOrder) } test("show") { diff --git a/tests/src/test/scala/cats/tests/ValidatedTests.scala b/tests/src/test/scala/cats/tests/ValidatedTests.scala index dc152a5340..8a10682a1f 100644 --- a/tests/src/test/scala/cats/tests/ValidatedTests.scala +++ b/tests/src/test/scala/cats/tests/ValidatedTests.scala @@ -7,7 +7,13 @@ import cats.laws.discipline._ import org.scalacheck.Arbitrary._ import cats.laws.discipline.SemigroupKTests import cats.laws.discipline.arbitrary._ -import cats.kernel.laws.{GroupLaws, OrderLaws} +import cats.kernel.laws.discipline.{ + MonoidLawTests, + SemigroupLawTests, + OrderLawTests, + PartialOrderLawTests, + EqLawTests +} import scala.util.Try @@ -27,12 +33,12 @@ class ValidatedTests extends CatsSuite { checkAll("Validated[String, Int] with Option", TraverseTests[Validated[String,?]].traverse[Int, Int, Int, Int, Option, Option]) checkAll("Traverse[Validated[String, ?]]", SerializableTests.serializable(Traverse[Validated[String,?]])) - checkAll("Validated[String, Int]", OrderLaws[Validated[String, Int]].order) + checkAll("Validated[String, Int]", OrderLawTests[Validated[String, Int]].order) checkAll("Order[Validated[String, Int]]", SerializableTests.serializable(Order[Validated[String, Int]])) - checkAll("Validated[String, Int]", GroupLaws[Validated[String, Int]].monoid) + checkAll("Validated[String, Int]", MonoidLawTests[Validated[String, Int]].monoid) - checkAll("Validated[String, NonEmptyList[Int]]", GroupLaws[Validated[String, NonEmptyList[Int]]].semigroup) + checkAll("Validated[String, NonEmptyList[Int]]", SemigroupLawTests[Validated[String, NonEmptyList[Int]]].semigroup) { implicit val L = ListWrapper.semigroup[String] @@ -43,14 +49,14 @@ class ValidatedTests extends CatsSuite { { implicit val S = ListWrapper.partialOrder[String] implicit val I = ListWrapper.partialOrder[Int] - checkAll("Validated[ListWrapper[String], ListWrapper[Int]]", OrderLaws[Validated[ListWrapper[String], ListWrapper[Int]]].partialOrder) + checkAll("Validated[ListWrapper[String], ListWrapper[Int]]", PartialOrderLawTests[Validated[ListWrapper[String], ListWrapper[Int]]].partialOrder) checkAll("PartialOrder[Validated[ListWrapper[String], ListWrapper[Int]]]", SerializableTests.serializable(PartialOrder[Validated[ListWrapper[String], ListWrapper[Int]]])) } { implicit val S = ListWrapper.eqv[String] implicit val I = ListWrapper.eqv[Int] - checkAll("Validated[ListWrapper[String], ListWrapper[Int]]", OrderLaws[Validated[ListWrapper[String], ListWrapper[Int]]].eqv) + checkAll("Validated[ListWrapper[String], ListWrapper[Int]]", EqLawTests[Validated[ListWrapper[String], ListWrapper[Int]]].eqv) checkAll("Eq[Validated[ListWrapper[String], ListWrapper[Int]]]", SerializableTests.serializable(Eq[Validated[ListWrapper[String], ListWrapper[Int]]])) } diff --git a/tests/src/test/scala/cats/tests/WriterTTests.scala b/tests/src/test/scala/cats/tests/WriterTTests.scala index dd4f292935..321e8d8aed 100644 --- a/tests/src/test/scala/cats/tests/WriterTTests.scala +++ b/tests/src/test/scala/cats/tests/WriterTTests.scala @@ -7,7 +7,11 @@ import cats.laws.discipline._ import cats.laws.discipline.arbitrary._ import cats.laws.discipline.eq._ -import cats.kernel.laws.OrderLaws +import cats.kernel.laws.discipline.{ + MonoidLawTests, + SemigroupLawTests, + EqLawTests +} class WriterTTests extends CatsSuite { type Logged[A] = Writer[ListWrapper[Int], A] @@ -18,7 +22,7 @@ class WriterTTests extends CatsSuite { implicit override val generatorDrivenConfig: PropertyCheckConfiguration = checkConfiguration.copy(sizeRange = 5) - checkAll("WriterT[List, Int, Int]", OrderLaws[WriterT[List, Int, Int]].eqv) + checkAll("WriterT[List, Int, Int]", EqLawTests[WriterT[List, Int, Int]].eqv) checkAll("Eq[WriterT[List, Int, Int]]", SerializableTests.serializable(Eq[WriterT[List, Int, Int]])) checkAll("WriterT[Show, Int, Int]", ContravariantTests[WriterT[Show, Int, ?]].contravariant[Int, Int, Int]) @@ -290,11 +294,11 @@ class WriterTTests extends CatsSuite { implicit val FLV: Monoid[ListWrapper[(Int, Int)]] = ListWrapper.monoid[(Int, Int)] Monoid[WriterT[ListWrapper, Int, Int]] - checkAll("WriterT[ListWrapper, Int, Int]", kernel.laws.GroupLaws[WriterT[ListWrapper, Int, Int]].monoid) + checkAll("WriterT[ListWrapper, Int, Int]", MonoidLawTests[WriterT[ListWrapper, Int, Int]].monoid) checkAll("Monoid[WriterT[ListWrapper, Int, Int]]", SerializableTests.serializable(Monoid[WriterT[ListWrapper, Int, Int]])) Monoid[Writer[Int, Int]] - checkAll("Writer[Int, Int]", kernel.laws.GroupLaws[Writer[Int, Int]].monoid) + checkAll("Writer[Int, Int]", MonoidLawTests[Writer[Int, Int]].monoid) } { @@ -302,11 +306,11 @@ class WriterTTests extends CatsSuite { implicit val FLV: Semigroup[ListWrapper[(Int, Int)]] = ListWrapper.semigroup[(Int, Int)] Semigroup[WriterT[ListWrapper, Int, Int]] - checkAll("WriterT[ListWrapper, Int, Int]", kernel.laws.GroupLaws[WriterT[ListWrapper, Int, Int]].semigroup) + checkAll("WriterT[ListWrapper, Int, Int]", SemigroupLawTests[WriterT[ListWrapper, Int, Int]].semigroup) checkAll("Semigroup[WriterT[ListWrapper, Int, Int]]", SerializableTests.serializable(Semigroup[WriterT[ListWrapper, Int, Int]])) Semigroup[Writer[Int, Int]] - checkAll("Writer[Int, Int]", kernel.laws.GroupLaws[Writer[Int, Int]].semigroup) + checkAll("Writer[Int, Int]", SemigroupLawTests[Writer[Int, Int]].semigroup) } {