Skip to content

Commit

Permalink
Refined tests to isolate Invariant instances
Browse files Browse the repository at this point in the history
  • Loading branch information
barambani committed Oct 4, 2018
1 parent ec2ef44 commit b5249ee
Show file tree
Hide file tree
Showing 5 changed files with 75 additions and 16 deletions.
15 changes: 15 additions & 0 deletions core/src/main/scala/cats/data/OptionT.scala
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@ final case class OptionT[F[_], A](value: F[Option[A]]) {
def map[B](f: A => B)(implicit F: Functor[F]): OptionT[F, B] =
OptionT(F.map(value)(_.map(f)))

def imap[B](f: A => B)(g: B => A)(implicit F: Invariant[F]): OptionT[F, B] =
OptionT {
F.imap(value)(_ map f)(_ map g)
}

def contramap[B](f: B => A)(implicit F: Contravariant[F]): OptionT[F, B] =
OptionT {
F.contramap(value)(_ map f)
Expand Down Expand Up @@ -302,6 +307,9 @@ private[data] sealed abstract class OptionTInstances1 extends OptionTInstances2
private[data] sealed abstract class OptionTInstances2 extends OptionTInstances3 {
implicit def catsDataFoldableForOptionT[F[_]](implicit F0: Foldable[F]): Foldable[OptionT[F, ?]] =
new OptionTFoldable[F] { implicit val F = F0 }

implicit def catsDataInvariantForOptionT[F[_]](implicit F0: Invariant[F]): Invariant[OptionT[F, ?]] =
new OptionTInvariant[F] { implicit val F = F0 }
}

private[data] sealed abstract class OptionTInstances3 {
Expand All @@ -315,6 +323,13 @@ private[data] trait OptionTFunctor[F[_]] extends Functor[OptionT[F, ?]] {
override def map[A, B](fa: OptionT[F, A])(f: A => B): OptionT[F, B] = fa.map(f)
}

private[data] sealed trait OptionTInvariant[F[_]] extends Invariant[OptionT[F, ?]] {
implicit def F: Invariant[F]

override def imap[A, B](fa: OptionT[F, A])(f: A => B)(g: B => A): OptionT[F, B] =
fa.imap(f)(g)
}

private[data] sealed trait OptionTContravariant[F[_]] extends Contravariant[OptionT[F, ?]] {
implicit def F: Contravariant[F]

Expand Down
22 changes: 19 additions & 3 deletions core/src/main/scala/cats/data/WriterT.scala
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@ final case class WriterT[F[_], L, V](run: F[(L, V)]) {
functorF.map(run) { z => (z._1, fn(z._2)) }
}

def imap[Z](f: V => Z)(g: Z => V)(implicit F: Invariant[F]): WriterT[F, L, Z] =
WriterT {
F.imap(run)(z => (z._1, f(z._2)))(z => (z._1, g(z._2)))
}

/**
* Modify the context `F` using transformation `f`.
*/
Expand Down Expand Up @@ -253,9 +258,10 @@ private[data] sealed abstract class WriterTInstances8 extends WriterTInstances9
implicit val L0: Semigroup[L] = L
}

implicit def catsDataContravariantForWriterT[F[_], L](implicit F: Contravariant[F]): Contravariant[WriterT[F, L, ?]] = new WriterTContravariant[F, L] {
implicit val F0: Contravariant[F] = F
}
implicit def catsDataContravariantForWriterT[F[_], L](implicit F: Contravariant[F]): Contravariant[WriterT[F, L, ?]] =
new WriterTContravariant[F, L] {
implicit val F0: Contravariant[F] = F
}
}

private[data] sealed abstract class WriterTInstances9 extends WriterTInstances10 {
Expand All @@ -269,6 +275,9 @@ private[data] sealed abstract class WriterTInstances9 extends WriterTInstances10
implicit val F0: Applicative[F] = F
implicit val L0: Monoid[L] = L
}

implicit def catsDataInvariantForWriterT[F[_], L](implicit F0: Invariant[F]): Invariant[WriterT[F, L, ?]] =
new WriterTInvariant[F, L] { implicit val F = F0 }
}

private[data] sealed abstract class WriterTInstances10 extends WriterTInstances11 {
Expand Down Expand Up @@ -307,6 +316,13 @@ private[data] sealed trait WriterTContravariant[F[_], L] extends Contravariant[W
fa.contramap(f)
}

private[data] sealed trait WriterTInvariant[F[_], L] extends Invariant[WriterT[F, L, ?]] {
implicit def F: Invariant[F]

override def imap[A, B](fa: WriterT[F, L, A])(f: A => B)(g: B => A): WriterT[F, L, B] =
fa.imap(f)(g)
}

private[data] sealed trait WriterTApply[F[_], L] extends WriterTFunctor[F, L] with Apply[WriterT[F, L, ?]] {
override implicit def F0: Apply[F]
implicit def L0: Semigroup[L]
Expand Down
30 changes: 29 additions & 1 deletion laws/src/main/scala/cats/laws/discipline/Arbitrary.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@ package discipline

import cats.data.NonEmptyList.ZipNonEmptyList
import cats.data.NonEmptyVector.ZipNonEmptyVector

import scala.util.{Failure, Success, Try}
import scala.collection.immutable.{SortedMap, SortedSet}
import cats.data._
import cats.kernel.Semigroup
import org.scalacheck.{Arbitrary, Cogen, Gen}
import org.scalacheck.Arbitrary.{arbitrary => getArbitrary}

Expand Down Expand Up @@ -319,7 +321,7 @@ object arbitrary extends ArbitraryInstances0 {

}

private[discipline] sealed trait ArbitraryInstances0 {
private[discipline] sealed trait ArbitraryInstances0 extends ArbitraryInstances1 {

implicit def catsLawArbitraryForIndexedStateT[F[_], SA, SB, A](implicit F: Arbitrary[F[SA => F[(SB, A)]]]): Arbitrary[IndexedStateT[F, SA, SB, A]] =
Arbitrary(F.arbitrary.map(IndexedStateT.applyF))
Expand All @@ -336,3 +338,29 @@ private[discipline] sealed trait ArbitraryInstances0 {
implicit def catsLawsArbitraryForCokleisli[F[_], A, B](implicit AFA: Arbitrary[F[A]], CFA: Cogen[F[A]], B: Arbitrary[B]): Arbitrary[Cokleisli[F, A, B]] =
Arbitrary(Arbitrary.arbitrary[F[A] => B].map(Cokleisli(_)))
}

private[discipline] sealed trait ArbitraryInstances1 {

implicit def catsLawsArbitraryForSemigroupOfOption[A](implicit ev: Semigroup[A]): Arbitrary[Semigroup[Option[A]]] =
Arbitrary {
Gen.const(
new Semigroup[Option[A]] {
def combine(x: Option[A], y: Option[A]): Option[A] =
(x, y) match {
case (Some(a1), Some(a2)) => Some(ev.combine(a1, a2))
case _ => None
}
}
)
}

implicit def catsLawsArbitraryForSemigroupOfTuple[L, V](implicit ev1: Semigroup[L], ev2: Semigroup[V]): Arbitrary[Semigroup[(L, V)]] =
Arbitrary {
Gen.const(
new Semigroup[(L, V)] {
def combine(x: (L, V), y: (L, V)): (L, V) =
ev1.combine(x._1, y._1) -> ev2.combine(x._2, y._2)
}
)
}
}
11 changes: 6 additions & 5 deletions tests/src/test/scala/cats/tests/OptionTSuite.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ package cats
package tests

import cats.data.{Const, OptionT}
import cats.kernel.laws.discipline.{MonoidTests, SemigroupTests, OrderTests, PartialOrderTests, EqTests}
import cats.kernel.{Monoid, Semigroup}
import cats.kernel.laws.discipline.{EqTests, MonoidTests, OrderTests, PartialOrderTests, SemigroupTests}
import cats.laws.discipline._
import cats.laws.discipline.arbitrary._
import cats.laws.discipline.eq._
Expand Down Expand Up @@ -73,11 +74,11 @@ class OptionTSuite extends CatsSuite {

{
// F has an Invariant
Invariant[Show]
Invariant[OptionT[Show, ?]]
Invariant[Semigroup]
Invariant[OptionT[Semigroup, ?]]

checkAll("OptionT[Show, ?]", InvariantTests[OptionT[Show, ?]].invariant[Int, Int, Int])
checkAll("Invariant[OptionT[Show, ?]]", SerializableTests.serializable(Invariant[OptionT[Show, ?]]))
checkAll("OptionT[Semigroup, ?]", InvariantTests[OptionT[Semigroup, ?]].invariant[Int, Int, Int])
checkAll("Invariant[OptionT[Semigroup, ?]]", SerializableTests.serializable(Invariant[OptionT[Semigroup, ?]]))
}

{
Expand Down
13 changes: 6 additions & 7 deletions tests/src/test/scala/cats/tests/WriterTSuite.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,11 @@ package cats
package tests

import cats.data.{Const, EitherT, Validated, Writer, WriterT}

import cats.kernel.Semigroup
import cats.laws.discipline._
import cats.laws.discipline.arbitrary._
import cats.laws.discipline.eq._

import cats.kernel.laws.discipline.{MonoidTests, SemigroupTests, EqTests}
import cats.kernel.laws.discipline.{EqTests, MonoidTests, SemigroupTests}

class WriterTSuite extends CatsSuite {
type Logged[A] = Writer[ListWrapper[Int], A]
Expand Down Expand Up @@ -373,11 +372,11 @@ class WriterTSuite extends CatsSuite {

{
// F has an Invariant
Invariant[Show]
Invariant[WriterT[Show, Int, ?]]
Invariant[Semigroup]
Invariant[WriterT[Semigroup, Int, ?]]

checkAll("WriterT[Show, Int, ?]", InvariantTests[WriterT[Show, Int, ?]].invariant[Int, Int, Int])
checkAll("Invariant[WriterT[Show, Int, ?]]", SerializableTests.serializable(Invariant[WriterT[Show, Int, ?]]))
checkAll("WriterT[Semigroup, Int, ?]", InvariantTests[WriterT[Semigroup, Int, ?]].invariant[Int, Int, Int])
checkAll("Invariant[WriterT[Semigroup, Int, ?]]", SerializableTests.serializable(Invariant[WriterT[Semigroup, Int, ?]]))
}

{
Expand Down

0 comments on commit b5249ee

Please sign in to comment.