diff --git a/core/src/main/scala/cats/Bitraverse.scala b/core/src/main/scala/cats/Bitraverse.scala index a9a5f9c285..90804d364b 100644 --- a/core/src/main/scala/cats/Bitraverse.scala +++ b/core/src/main/scala/cats/Bitraverse.scala @@ -14,7 +14,7 @@ trait Bitraverse[F[_, _]] extends Bifoldable[F] with Bifunctor[F] { self => bitraverse(fab)(identity, identity) /** If F and G are both [[cats.Bitraverse]] then so is their composition F[G[_, _], G[_, _]] */ - def compose[G[_, _]](implicit ev: Bitraverse[G]): Bifoldable[Lambda[(A, B) => F[G[A, B], G[A, B]]]] = + def compose[G[_, _]](implicit ev: Bitraverse[G]): Bitraverse[Lambda[(A, B) => F[G[A, B], G[A, B]]]] = new CompositeBitraverse[F, G] { val F = self val G = ev diff --git a/laws/src/main/scala/cats/laws/discipline/Eq.scala b/laws/src/main/scala/cats/laws/discipline/Eq.scala index d79a1a6a84..ed5879bb22 100644 --- a/laws/src/main/scala/cats/laws/discipline/Eq.scala +++ b/laws/src/main/scala/cats/laws/discipline/Eq.scala @@ -3,6 +3,7 @@ package laws package discipline import algebra.Eq +import cats.std.string._ import org.scalacheck.Arbitrary object eq { @@ -21,6 +22,12 @@ object eq { } } + /** Create an approximation of Eq[Show[A]] by using function1Eq[A, String] */ + implicit def showEq[A: Arbitrary]: Eq[Show[A]] = + Eq.by[Show[A], A => String] { showInstance => + (a: A) => showInstance.show(a) + } + // Temporary, see https://github.com/non/algebra/pull/82 implicit def tuple2Eq[A, B](implicit A: Eq[A], B: Eq[B]): Eq[(A, B)] = new Eq[(A, B)] { diff --git a/tests/src/test/scala/cats/tests/BifoldableTests.scala b/tests/src/test/scala/cats/tests/BifoldableTests.scala new file mode 100644 index 0000000000..2c121909bd --- /dev/null +++ b/tests/src/test/scala/cats/tests/BifoldableTests.scala @@ -0,0 +1,15 @@ +package cats +package tests + +import cats.data.Xor +import cats.laws.discipline.{BifoldableTests, SerializableTests} +import cats.laws.discipline.arbitrary._ + +class BifoldableTest extends CatsSuite { + type EitherXor[A, B] = Either[Xor[A, B], Xor[A, B]] + val eitherComposeXor: Bifoldable[EitherXor] = + Bifoldable[Either].compose[Xor] + + checkAll("Either compose Xor", BifoldableTests(eitherComposeXor).bifoldable[Int, Int, Int]) + checkAll("Bifoldable[Either compose Xor]", SerializableTests.serializable(eitherComposeXor)) +} diff --git a/tests/src/test/scala/cats/tests/BitraverseTests.scala b/tests/src/test/scala/cats/tests/BitraverseTests.scala new file mode 100644 index 0000000000..e981925d80 --- /dev/null +++ b/tests/src/test/scala/cats/tests/BitraverseTests.scala @@ -0,0 +1,16 @@ +package cats +package tests + +import cats.data.Xor +import cats.laws.discipline.{BitraverseTests, SerializableTests} +import cats.laws.discipline.arbitrary._ +import cats.laws.discipline.eq.tuple2Eq + +class BitraverseTest extends CatsSuite { + type XorTuple2[A, B] = Xor[(A, B), (A, B)] + val xorComposeTuple2: Bitraverse[XorTuple2] = + Bitraverse[Xor].compose[Tuple2] + + checkAll("Xor compose Tuple2", BitraverseTests(xorComposeTuple2).bitraverse[Option, Int, Int, Int, String, String, String]) + checkAll("Bitraverse[Xor compose Tuple2]", SerializableTests.serializable(xorComposeTuple2)) +} diff --git a/tests/src/test/scala/cats/tests/CategoryTests.scala b/tests/src/test/scala/cats/tests/CategoryTests.scala new file mode 100644 index 0000000000..b93cc732d6 --- /dev/null +++ b/tests/src/test/scala/cats/tests/CategoryTests.scala @@ -0,0 +1,19 @@ +package cats +package tests + +import algebra.laws.GroupLaws + +import cats.arrow.Category +import cats.laws.discipline.{MonoidKTests, SerializableTests} +import cats.laws.discipline.eq.function1Eq + +class CategoryTest extends CatsSuite { + val functionCategory = Category[Function1] + type Endo[A] = Function1[A, A] + + checkAll("Category[Function1].algebraK", MonoidKTests[Endo](functionCategory.algebraK).monoidK[Int]) + checkAll("Category[Function1].algebraK", SerializableTests.serializable(functionCategory.algebraK)) + + val functionAlgebra = functionCategory.algebra[Int] + checkAll("Category[Function1].algebra[Int]", GroupLaws[Endo[Int]].monoid(functionAlgebra)) +} diff --git a/tests/src/test/scala/cats/tests/ComposeTest.scala b/tests/src/test/scala/cats/tests/ComposeTest.scala new file mode 100644 index 0000000000..74019444bb --- /dev/null +++ b/tests/src/test/scala/cats/tests/ComposeTest.scala @@ -0,0 +1,19 @@ +package cats +package tests + +import algebra.laws.GroupLaws + +import cats.arrow.Compose +import cats.laws.discipline.{SemigroupKTests, SerializableTests} +import cats.laws.discipline.eq.function1Eq + +class ComposeTest extends CatsSuite { + val functionCompose = Compose[Function1] + type Endo[A] = Function1[A, A] + + checkAll("Compose[Function1].algebraK", SemigroupKTests[Endo](functionCompose.algebraK).semigroupK[Int]) + checkAll("Compose[Function1].algebraK", SerializableTests.serializable(functionCompose.algebraK)) + + val functionAlgebra = functionCompose.algebra[Int] + checkAll("Compose[Function1].algebra[Int]", GroupLaws[Endo[Int]].semigroup(functionAlgebra)) +} diff --git a/tests/src/test/scala/cats/tests/FunctorTests.scala b/tests/src/test/scala/cats/tests/FunctorTests.scala new file mode 100644 index 0000000000..40ee82e96c --- /dev/null +++ b/tests/src/test/scala/cats/tests/FunctorTests.scala @@ -0,0 +1,23 @@ +package cats +package tests + +import cats.data.Xor +import cats.functor.Contravariant +import cats.laws.discipline.{ContravariantTests, FunctorTests, SerializableTests} +import cats.laws.discipline.arbitrary._ +import cats.laws.discipline.eq.showEq + +class FunctorTest extends CatsSuite { + type OptionXor[A] = Option[Xor[String, A]] + + val optionXorFunctor: Functor[OptionXor] = + Functor[Option].compose[Xor[String, ?]] + checkAll("Option compose Xor", FunctorTests(optionXorFunctor).functor[Int, Int, Int]) + checkAll("Functor[Option compose Xor]", SerializableTests.serializable(optionXorFunctor)) + + type OptionShow[A] = Option[Show[A]] + val optionShowContravariant: Contravariant[OptionShow] = + Functor[Option].composeWithContravariant[Show] + checkAll("Option composeWithContravariant Show", ContravariantTests(optionShowContravariant).contravariant[Int, Int, Int]) + checkAll("Contravariant[Option composeWithContravariant Show]", SerializableTests.serializable(optionShowContravariant)) +} diff --git a/tests/src/test/scala/cats/tests/MonadStateTests.scala b/tests/src/test/scala/cats/tests/MonadStateTests.scala new file mode 100644 index 0000000000..3c9d825b28 --- /dev/null +++ b/tests/src/test/scala/cats/tests/MonadStateTests.scala @@ -0,0 +1,22 @@ +package cats +package tests + +import cats.data.State + +class MonadStateTest extends CatsSuite { + val testInstance = MonadState[State[Int, ?], Int] + + test("MonadState#modify identity does not modify the state") { + forAll { (i: Int) => + val x = testInstance.modify(identity).runS(i).value + x should === (i) + } + } + + test("MonadState#inspect identity does not modify the state") { + forAll { (i: Int) => + val x = testInstance.inspect(identity).runA(i).value + x should === (i) + } + } +}