Skip to content

Commit

Permalink
Issue davegurnell#1: Add some more context combining tests.
Browse files Browse the repository at this point in the history
  • Loading branch information
rpiaggio committed Aug 20, 2018
1 parent 36188b1 commit 8f7bcdd
Show file tree
Hide file tree
Showing 2 changed files with 107 additions and 12 deletions.
3 changes: 2 additions & 1 deletion build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ lazy val core = crossProject(JSPlatform, JVMPlatform)
"org.typelevel" %%% "cats-testkit" % "1.1.0" % Test,
"com.github.julien-truffaut" %%% "monocle-core" % "1.5.1-cats",
"com.github.julien-truffaut" %%% "monocle-macro" % "1.5.1-cats",
"org.scalatest" %%% "scalatest" % "3.0.4" % Test
"org.scalatest" %%% "scalatest" % "3.0.4" % Test,
"io.monix" %%% "monix" % "3.0.0-RC1" % Test
),
)

Expand Down
116 changes: 105 additions & 11 deletions core/src/test/scala/checklist/ContextSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,119 @@ package checklist

import cats._
import cats.data.Ior
import cats.effect.IO
import cats.implicits._
import org.scalatest.{FreeSpec, Matchers}
import checklist.Message.errors
import monix.eval.Task
import monix.execution.Scheduler
import org.scalatest.{AsyncFreeSpec, Matchers}

import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global
import scala.collection.immutable.HashSet
import scala.concurrent.{ExecutionContext, Future}

class ContextSpec extends FreeSpec with Matchers {
class ContextSpec extends AsyncFreeSpec with Matchers {

"pass" in {
val rule1 = Rule.pass[Int]
val rule2 = rule1.liftTo[Future]
val rule1 = Rule.pass[Int]
val rule2 = rule1.liftTo[Future]

val db = HashSet("[email protected]", "[email protected]")
def existsInDBFuture(email: String): Future[Boolean] = Future.successful(db.contains(email))
def existsInDBTask(email: String): Task[Boolean] = Task(db.contains(email))
def existsInDBIO(email: String): IO[Boolean] = IO(db.contains(email))

val isUniqueFuture =
Rule.test(Message.errors("Email is already registered")) { email: String => existsInDBFuture(email).map(!_) }
val isUniqueTask =
Rule.test(Message.errors("Email is already registered")) { email: String => existsInDBTask(email).map(!_) }
val isUniqueIO =
Rule.test(Message.errors("Email is already registered")) { email: String => existsInDBIO(email).map(!_) }

val isEmail = Rule.matchesRegexStrict("^[^@]+@[^@]+$".r, Message.errors("Must be an email"))
val isEmailFuture = isEmail.liftTo[Future]

val futureToTask: Future ~> Task = new (Future ~> Task) {
override def apply[A](f: Future[A]): Task[A] = Task.deferFuture(f)
}

def taskToFuture(implicit ec: ExecutionContext, sch: Scheduler): Task ~> Future = new (Task ~> Future) {
override def apply[A](t: Task[A]): Future[A] = t.runAsync
}

val ioToFuture: IO ~> Future = new (IO ~> Future) {
override def apply[A](i: IO[A]): Future[A] = i.unsafeToFuture
}

"and: lift id to future" in {
val combined1 = rule1 and rule2
val combined2 = rule2 and rule1
val combined3 = rule1 andThen rule2
val combined4 = rule2 andThen rule1
combined1(+1) map (_ should be(Ior.right(+1)))
combined2(+1) map (_ should be(Ior.right(+1)))
combined3(+1) map (_ should be(Ior.right(+1)))
combined4(+1) map (_ should be(Ior.right(+1)))
}

"andThen: lift id to future" in {
val combined1 = rule1 andThen rule2
val combined2 = rule2 andThen rule1
combined1(+1) map (_ should be(Ior.right(+1)))
combined2(+1) map (_ should be(Ior.right(+1)))
}

"zip: lift id to future" in {
val combined1 = rule1 zip rule2
val combined2 = rule2 zip rule1
combined1(+1) map (_ should be(Ior.right((+1, +1))))
combined2(+1) map (_ should be(Ior.right((+1, +1))))
}

"Future unique email" in {
val validator = isEmail and isUniqueFuture
validator("[email protected]") map (_ should be(Ior.right("[email protected]")))
validator("[email protected]") map (_ should be(Ior.left(errors("Email is already registered"))))
validator("hello@") map (_ should be(Ior.left(errors("Must be an email"))))
}

"Task unique email" in {
import monix.execution.Scheduler.Implicits.global

val validator = isEmail and isUniqueTask
validator("[email protected]").runAsync map (_ should be(Ior.right("[email protected]")))
validator("[email protected]").runAsync map (_ should be(Ior.left(errors("Email is already registered"))))
validator("hello@").runAsync map (_ should be(Ior.left(errors("Must be an email"))))
}

"Id, Future and Task unique non-empty email (as Task)" in {
import monix.execution.Scheduler.Implicits.global

implicit val transformation: Future ~> Task = futureToTask

val validator = Rule.nonEmpty[String] and isUniqueTask and isEmailFuture
validator("[email protected]").runAsync map (_ should be(Ior.right("[email protected]")))
validator("[email protected]").runAsync map (_ should be(Ior.left(errors("Email is already registered"))))
validator("hello@").runAsync map (_ should be(Ior.left(errors("Must be an email"))))
validator("").runAsync map (_ should be(Ior.left(errors("Must not be empty", "Must be an email"))))
}

"Id, Future and Task unique non-empty email (as Future)" in {
import monix.execution.Scheduler.Implicits.global

implicit val transformation: Task ~> Future = taskToFuture

val validator = isUniqueTask and isEmailFuture and Rule.nonEmpty[String]
validator("[email protected]") map (_ should be(Ior.right("[email protected]")))
validator("[email protected]") map (_ should be(Ior.left(errors("Email is already registered"))))
validator("hello@") map (_ should be(Ior.left(errors("Must be an email"))))
validator("") map (_ should be(Ior.left(errors("Must be an email", "Must not be empty"))))
}

"IO, Future and Task unique non-empty email (as Future)" in {
import monix.execution.Scheduler.Implicits.global

implicit val transformation1: Task ~> Future = taskToFuture
implicit val transformation2: IO ~> Future = ioToFuture

val validator = isUniqueTask and isEmailFuture and Rule.nonEmpty[String].liftTo[IO]
validator("[email protected]") map (_ should be(Ior.right("[email protected]")))
validator("[email protected]") map (_ should be(Ior.left(errors("Email is already registered"))))
validator("hello@") map (_ should be(Ior.left(errors("Must be an email"))))
validator("") map (_ should be(Ior.left(errors("Must be an email", "Must not be empty"))))
}
}

0 comments on commit 8f7bcdd

Please sign in to comment.