Skip to content

Commit

Permalink
Improve test coverage IdT
Browse files Browse the repository at this point in the history
  • Loading branch information
peterneyens committed May 20, 2017
1 parent cc4080c commit 5697f2f
Show file tree
Hide file tree
Showing 3 changed files with 122 additions and 33 deletions.
67 changes: 46 additions & 21 deletions core/src/main/scala/cats/data/IdT.scala
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,24 @@ object IdT extends IdTInstances {
private[data] sealed trait IdTFunctor[F[_]] extends Functor[IdT[F, ?]] {
implicit val F0: Functor[F]

def map[A, B](fa: IdT[F, A])(f: A => B): IdT[F, B] =
override def map[A, B](fa: IdT[F, A])(f: A => B): IdT[F, B] =
fa.map(f)
}

private[data] sealed trait IdTMonad[F[_]] extends Monad[IdT[F, ?]] {
implicit val F0: Monad[F]
private[data] sealed trait IdTApply[F[_]] extends Apply[IdT[F, ?]] with IdTFunctor[F] {
implicit val F0: Apply[F]

override def ap[A, B](ff: IdT[F, A => B])(fa: IdT[F, A]): IdT[F, B] = fa.ap(ff)
}

def pure[A](a: A): IdT[F, A] =
IdT.pure(a)
private[data] sealed trait IdTApplicative[F[_]] extends Applicative[IdT[F, ?]] with IdTApply[F] {
implicit val F0: Applicative[F]

def pure[A](a: A): IdT[F, A] = IdT.pure(a)
}

private[data] sealed trait IdTFlatMap[F[_]] extends FlatMap[IdT[F, ?]] with IdTApply[F] {
implicit val F0: FlatMap[F]

def flatMap[A, B](fa: IdT[F, A])(f: A => IdT[F, B]): IdT[F, B] =
fa.flatMap(f)
Expand All @@ -55,6 +64,10 @@ private[data] sealed trait IdTMonad[F[_]] extends Monad[IdT[F, ?]] {
IdT(F0.tailRecM(a)(f(_).value))
}

private[data] sealed trait IdTMonad[F[_]] extends Monad[IdT[F, ?]] with IdTApplicative[F] with IdTFlatMap[F] {
implicit val F0: Monad[F]
}

private[data] sealed trait IdTFoldable[F[_]] extends Foldable[IdT[F, ?]] {
implicit val F0: Foldable[F]

Expand All @@ -71,46 +84,58 @@ private[data] sealed trait IdTFoldable[F[_]] extends Foldable[IdT[F, ?]] {
F0.get(fa.value)(idx)
}

private[data] sealed trait IdTTraverse[F[_]] extends Traverse[IdT[F, ?]] with IdTFoldable[F] {
private[data] sealed trait IdTTraverse[F[_]] extends Traverse[IdT[F, ?]] with IdTFoldable[F] with IdTFunctor[F] {
implicit val F0: Traverse[F]

def traverse[G[_]: Applicative, A, B](fa: IdT[F, A])(f: A => G[B]): G[IdT[F, B]] =
fa.traverse(f)
}

private[data] sealed abstract class IdTInstances1 {
private[data] sealed abstract class IdTInstances4 {
implicit def catsDataFunctorForIdT[F[_]](implicit F: Functor[F]): Functor[IdT[F, ?]] =
new IdTFunctor[F] {
implicit val F0: Functor[F] = F
}
new IdTFunctor[F] { implicit val F0: Functor[F] = F }
}

private[data] sealed abstract class IdTInstances3 extends IdTInstances4 {
implicit def catsDataApplyForIdT[F[_]](implicit F: Apply[F]): Apply[IdT[F, ?]] =
new IdTApply[F] { implicit val F0: Apply[F] = F }
}

private[data] sealed abstract class IdTInstances2 extends IdTInstances3 {
implicit def catsDataApplicativeForIdT[F[_]](implicit F: Applicative[F]): Applicative[IdT[F, ?]] =
new IdTApplicative[F] { implicit val F0: Applicative[F] = F }
}

private[data] sealed abstract class IdTInstances1 extends IdTInstances2 {
implicit def catsDataFlatMapForIdT[F[_]](implicit F: FlatMap[F]): FlatMap[IdT[F, ?]] =
new IdTFlatMap[F] { implicit val F0: FlatMap[F] = F }
}

private[data] sealed abstract class IdTInstances0 extends IdTInstances1 {

implicit def catsDataMonadForIdT[F[_]](implicit F: Monad[F]): Monad[IdT[F, ?]] =
new IdTMonad[F] {
implicit val F0: Monad[F] = F
}
new IdTMonad[F] { implicit val F0: Monad[F] = F }

implicit def catsDataFoldableForIdT[F[_]](implicit F: Foldable[F]): Foldable[IdT[F, ?]] =
new IdTFoldable[F] {
implicit val F0: Foldable[F] = F
}
new IdTFoldable[F] { implicit val F0: Foldable[F] = F }

implicit def catsDataOrderForIdT[F[_], A](implicit F: Order[F[A]]): Order[IdT[F, A]] =
implicit def catsDataEqForIdT[F[_], A](implicit F: Eq[F[A]]): Eq[IdT[F, A]] =
F.on(_.value)
}

private[data] sealed abstract class IdTInstances extends IdTInstances0 {

implicit def catsDataTraverseForIdT[F[_]](implicit F: Traverse[F]): Traverse[IdT[F, ?]] =
new IdTTraverse[F] {
implicit val F0: Traverse[F] = F
}
new IdTTraverse[F] { implicit val F0: Traverse[F] = F }

implicit def catsDataEqForIdT[F[_], A](implicit F: Eq[F[A]]): Eq[IdT[F, A]] =
implicit def catsDataOrderForIdT[F[_], A](implicit F: Order[F[A]]): Order[IdT[F, A]] =
F.on(_.value)

implicit def catsDataShowForIdT[F[_], A](implicit F: Show[F[A]]): Show[IdT[F, A]] =
functor.Contravariant[Show].contramap(F)(_.value)

implicit def catsDataMonadTransForIdT: MonadTrans[IdT] =
new MonadTrans[IdT] {
def liftT[M[_]: Monad, A](ma: M[A]): IdT[M, A] = IdT(ma)
}
}
86 changes: 74 additions & 12 deletions tests/src/test/scala/cats/tests/IdTTests.scala
Original file line number Diff line number Diff line change
@@ -1,24 +1,86 @@
package cats.tests
package cats
package tests

import cats.{Foldable, Functor, Monad, Traverse}
import cats.data.IdT
import cats.laws.discipline.{CartesianTests, FoldableTests, FunctorTests, MonadTests, SerializableTests, TraverseTests}
import cats.kernel.laws.OrderLaws
import cats.laws.discipline._
import cats.laws.discipline.arbitrary._

class IdTTests extends CatsSuite {

implicit val iso = CartesianTests.Isomorphisms.invariant[IdT[List, ?]]
implicit val iso = CartesianTests.Isomorphisms.invariant[IdT[ListWrapper, ?]](IdT.catsDataFunctorForIdT(ListWrapper.functor))

checkAll("IdT[Functor, Int]", FunctorTests[IdT[List, ?]].functor[Int, Int, Int])
checkAll("Functor[IdT[List, ?]]", SerializableTests.serializable(Functor[IdT[List, ?]]))
{
implicit val F = ListWrapper.eqv[Option[Int]]

checkAll("IdT[List, Int]", MonadTests[IdT[List, ?]].monad[Int, Int, Int])
checkAll("Monad[IdT[List, ?]]", SerializableTests.serializable(Monad[IdT[List, ?]]))
checkAll("IdT[ListWrapper, Int]", OrderLaws[IdT[ListWrapper, Int]].eqv)
checkAll("Eq[IdT[ListWrapper, Int]]", SerializableTests.serializable(Eq[IdT[ListWrapper, Int]]))
}

checkAll("IdT[Option, Int]", FoldableTests[IdT[Option, ?]].foldable[Int, Int])
checkAll("Foldable[IdT[Option, ?]]", SerializableTests.serializable(Foldable[IdT[Option, ?]]))
{
implicit val F = ListWrapper.order[Int]

checkAll("IdT[Option, Int]", TraverseTests[IdT[Option, ?]].traverse[Int, Int, Int, Int, Option, Option])
checkAll("Traverse[IdT[Option, ?]]", SerializableTests.serializable(Traverse[IdT[Option, ?]]))
checkAll("IdT[ListWrapper, Int]", OrderLaws[IdT[ListWrapper, Int]].order)
checkAll("Order[IdT[ListWrapper, Int]]", SerializableTests.serializable(Order[IdT[ListWrapper, Int]]))
}

{
implicit val F = ListWrapper.functor

checkAll("IdT[ListWrapper, Int]", FunctorTests[IdT[ListWrapper, ?]].functor[Int, Int, Int])
checkAll("Functor[IdT[ListWrapper, ?]]", SerializableTests.serializable(Functor[IdT[ListWrapper, ?]]))
}

{
implicit val F = ListWrapper.applyInstance

checkAll("IdT[ListWrapper, Int]", ApplyTests[IdT[ListWrapper, ?]].apply[Int, Int, Int])
checkAll("Apply[IdT[ListWrapper, ?]]", SerializableTests.serializable(Apply[IdT[ListWrapper, ?]]))
}

{
implicit val F = ListWrapper.applicative

checkAll("IdT[ListWrapper, Int]", ApplicativeTests[IdT[ListWrapper, ?]].applicative[Int, Int, Int])
checkAll("Applicative[IdT[ListWrapper, ?]]", SerializableTests.serializable(Applicative[IdT[ListWrapper, ?]]))
}

{
implicit val F = ListWrapper.flatMap

checkAll("IdT[ListWrapper, Int]", FlatMapTests[IdT[ListWrapper, ?]].flatMap[Int, Int, Int])
checkAll("FlatMap[IdT[ListWrapper, ?]]", SerializableTests.serializable(FlatMap[IdT[ListWrapper, ?]]))
}

{
implicit val F = ListWrapper.monad

checkAll("IdT[ListWrapper, Int]", MonadTests[IdT[ListWrapper, ?]].monad[Int, Int, Int])
checkAll("Monad[IdT[ListWrapper, ?]]", SerializableTests.serializable(Monad[IdT[ListWrapper, ?]]))

checkAll("IdT[ListWrapper, Int]", MonadTransTests[IdT].monadTrans[ListWrapper, Int, Int])
checkAll("MonadTrans[IdT]", SerializableTests.serializable(MonadTrans[IdT]))
}

{
implicit val F = ListWrapper.foldable

checkAll("IdT[ListWrapper, Int]", FoldableTests[IdT[ListWrapper, ?]].foldable[Int, Int])
checkAll("Foldable[IdT[ListWrapper, ?]]", SerializableTests.serializable(Foldable[IdT[ListWrapper, ?]]))
}

{
implicit val F = ListWrapper.traverse

checkAll("IdT[ListWrapper, Int] with Option", TraverseTests[IdT[ListWrapper, ?]].traverse[Int, Int, Int, Int, Option, Option])
checkAll("Traverse[IdT[ListWrapper, ?]]", SerializableTests.serializable(Traverse[IdT[ListWrapper, ?]]))
}


test("flatMap and flatMapF consistent") {
forAll { (idT: IdT[Option, Int], f: Int => IdT[Option, Int]) =>
idT.flatMap(f) should === (idT.flatMapF(f(_).value))
}
}

}
2 changes: 2 additions & 0 deletions tests/src/test/scala/cats/tests/ListWrapper.scala
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,8 @@ object ListWrapper {

val monad: Monad[ListWrapper] = monadCombine

val flatMap: FlatMap[ListWrapper] = monadCombine

val applicative: Applicative[ListWrapper] = monadCombine

/** apply is taken due to ListWrapper being a case class */
Expand Down

0 comments on commit 5697f2f

Please sign in to comment.