diff --git a/.gitignore b/.gitignore index 4c19d3d8e4f..4581b4d5be5 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,4 @@ TAGS .sbtrc *.sublime-project *.sublime-workspace +tests.iml diff --git a/core/src/main/scala/cats/data/XorT.scala b/core/src/main/scala/cats/data/XorT.scala index d7ff05bf806..f3a94fa292c 100644 --- a/core/src/main/scala/cats/data/XorT.scala +++ b/core/src/main/scala/cats/data/XorT.scala @@ -51,6 +51,8 @@ final case class XorT[F[_], A, B](value: F[A Xor B]) { def exists(f: B => Boolean)(implicit F: Functor[F]): F[Boolean] = F.map(value)(_.exists(f)) + def ensure[AA >: A](ifLeft: => AA)(f: B => Boolean)(implicit F: Functor[F]): XorT[F, AA, B] = XorT(F.map(value)(_.ensure(ifLeft)(f))) + def toEither(implicit F: Functor[F]): F[Either[A, B]] = F.map(value)(_.toEither) def toOption(implicit F: Functor[F]): OptionT[F, B] = OptionT(F.map(value)(_.toOption)) diff --git a/tests/src/test/scala/cats/tests/XorTTests.scala b/tests/src/test/scala/cats/tests/XorTTests.scala index f75b14a7135..7ea4e9b3430 100644 --- a/tests/src/test/scala/cats/tests/XorTTests.scala +++ b/tests/src/test/scala/cats/tests/XorTTests.scala @@ -251,4 +251,28 @@ class XorTTests extends CatsSuite { x.toEither.map(_.right.toOption) should === (x.toOption.value) } } + + test("ensure on left is identity") { + forAll { (x: XorT[Id, String, Int], s: String, p: Int => Boolean) => + if (x.isLeft) { + x.ensure(s)(p) should === (x) + } + } + } + + test("ensure on right is identity if predicate satisfied") { + forAll { (x: XorT[Id, String, Int], s: String, p: Int => Boolean) => + if (x.isRight && p(x getOrElse 0)) { + x.ensure(s)(p) should === (x) + } + } + } + + test("ensure should fail if predicate not satisfied") { + forAll { (x: XorT[Id, String, Int], s: String, p: Int => Boolean) => + if (x.isRight && !p(x getOrElse 0)) { + x.ensure(s)(p) should === (XorT.left[Id, String, Int](s)) + } + } + } }