Skip to content

Instantly share code, notes, and snippets.

@Dnomyar
Last active October 14, 2019 13:25
Show Gist options
  • Save Dnomyar/42e95c6911ca5c09c6aafe871df420b4 to your computer and use it in GitHub Desktop.
Save Dnomyar/42e95c6911ca5c09c6aafe871df420b4 to your computer and use it in GitHub Desktop.
package example
import cats.effect.{IO, Sync}
import cats.kernel.laws._
import cats.kernel.laws.discipline._
import cats.{Eq, Monad}
import org.scalacheck.Gen._
import org.scalacheck.Prop._
import org.scalacheck._
import org.scalatest._
import org.scalatest.flatspec.AnyFlatSpec
import org.typelevel.discipline.Laws
import org.typelevel.discipline.scalatest.Discipline
import scala.language.higherKinds
case class User(id: String)
trait UserService[F[_]] {
def save(user: User): F[User]
def getUser(id: String): F[Option[User]]
def delete(user: User): F[Boolean]
}
object UserService {
// def service[F[_]]: UserService[F] = new UserService[F] {
def service[F[_]](implicit F: Sync[F]): UserService[F] = new UserService[F] {
override def save(user: User): F[User] = F.pure(User("id"))
override def getUser(id: String): F[Option[User]] = F.pure(Some(User("iddd")))
override def delete(user: User): F[Boolean] = F.pure(true)
}
}
trait UserServiceLaws[F[_]] {
def algebra: UserService[F]
implicit def M: Monad[F]
import cats.syntax.flatMap._
def saveGetComposition(user: User): IsEq[F[Option[User]]] =
algebra.save(user) >> algebra.getUser(user.id) <-> M.pure(Some(user))
}
object UserServiceLaws {
def apply[F[_]](instance: UserService[F])(implicit ev: Monad[F]): UserServiceLaws[F] =
new UserServiceLaws[F] {
override val algebra = instance
override implicit val M: Monad[F] = ev
}
}
trait UserServiceAlgebraTests[F[_]] extends Laws {
def laws: UserServiceLaws[F]
def algebra(implicit arbUserService: Arbitrary[User],
eqFOptUserService: Eq[F[Option[User]]]) =
new SimpleRuleSet(
name = "UserServices",
"find and get compose" -> forAll(laws.saveGetComposition _)
)
}
object UserServiceAlgebraTests {
def apply[F[_] : Monad](instance: UserService[F]): UserServiceAlgebraTests[F] = new UserServiceAlgebraTests[F] {
override val laws: UserServiceLaws[F] = UserServiceLaws(instance)
}
}
class BinarySearchTreeSpec
extends AnyFlatSpec
with Matchers
with Discipline {
final val UserGen: Gen[User] = (for {
id <- nonEmptyListOf(alphaNumChar).map(_.mkString)
} yield id) suchThat (_.length <= 254) map User
implicit final val ArbitraryEmail: Arbitrary[User] = Arbitrary(UserGen)
implicit val eqUser: Eq[User] = new Eq[User] {
override def eqv(x: User, y: User): Boolean = x == y
}
implicit def eqOption[A](implicit aEq: Eq[A]): Eq[Option[A]] = new Eq[Option[A]] {
override def eqv(x: Option[A], y: Option[A]): Boolean = {
for{
f1 <- x
f2 <- y
} yield f1 === f2
}.getOrElse(false)
}
implicit def eqIO[A](implicit aEq: Eq[A]): Eq[IO[A]] = new Eq[IO[A]] {
override def eqv(x: IO[A], y: IO[A]): Boolean = {
(x.unsafeRunSync, y.unsafeRunSync) match {
case (xx, yy) =>
println(s"$xx == $yy = ${xx == yy}")
xx == yy
}
}
}
checkAll("UserService", UserServiceAlgebraTests(UserService.service[IO]).algebra)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment