Last active
          June 25, 2020 19:19 
        
      - 
      
- 
        Save kryptt/db57189b411323beaeaf76b9d07a0468 to your computer and use it in GitHub Desktop. 
    power of higher kinded types...
  
        
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
  | import cats.{Bifoldable, Eq, Foldable, Show} | |
| import cats.data.Ior | |
| import cats.instances.either._ | |
| import cats.instances.option._ | |
| import cats.instances.list._ | |
| import cats.syntax.bifoldable._ | |
| import cats.syntax.foldable._ | |
| import cats.syntax.align._ | |
| object DiffExample { | |
| trait Diffable[T] extends Eq[T] with Show[T] { | |
| def diff(value: T, expected: T): Option[String] = | |
| if (eqv(value, expected)) None | |
| else Some(s"was: ${show(value)}; expected: ${show(expected)}") | |
| } | |
| trait LowerPriorityDiffable { | |
| implicit def defaultDiffable[T](implicit EqT: Eq[T], ShowT: Show[T]): Diffable[T] = new Diffable[T] { | |
| override def eqv(x: T, y: T): Boolean = EqT.eqv(x, y) | |
| override def show(t: T): String = ShowT.show(t) | |
| } | |
| protected def listEqv[T](xs: List[T], ys: List[T])(implicit EqT: Eq[T]): Boolean = | |
| xs.alignWith(ys)(eqvAlign(_)(EqT)).forall(identity) | |
| protected def eqvAlign[T](x: Ior[T, T])(implicit EqT: Eq[T]): Boolean = x match { | |
| case Ior.Both(a, b) => EqT.eqv(a, b) | |
| case _ => false | |
| } | |
| } | |
| object Diffable extends LowerPriorityDiffable { | |
| def apply[T](implicit diffable: Diffable[T]): Diffable[T] = diffable | |
| implicit def bifoldableDiffable[F[_, _]: Bifoldable, T: Eq, V: Eq]( | |
| implicit ShowF: Show[F[T, V]]): Diffable[F[T, V]] = | |
| new Diffable[F[T, V]] { | |
| override def eqv(x: F[T, V], y: F[T, V]): Boolean = | |
| listEqv(toList(x), toList(y))(catsStdEqForEither(Eq[T], Eq[V])) | |
| override def show(ftv: F[T, V]): String = ShowF.show(ftv) | |
| private def toList(x: F[T, V]): List[Either[T, V]] = | |
| x.bifoldLeft(List.empty[Either[T, V]])((l, t) => Left(t) :: l, (l, v) => Right(v) :: l) | |
| } | |
| } | |
| def expectNone[T: Diffable](received: Option[T]): String = | |
| expect(received, None, note => s"Failed to match None.\n$note") | |
| def expectSome[T: Diffable](received: Option[T], expected: T): String = | |
| expect(received, Some(expected), note => s"Failed to match Some(${Diffable[T].show(expected)}).\n$note") | |
| def expectLeft[T: Diffable, V: Diffable](received: Either[T, V], expected: T): String = | |
| expect(received, Left(expected), note => s"Failed to match Left(${Diffable[T].show(expected)}.\b$note") | |
| def expectRight[T: Diffable, V: Diffable](received: Either[T, V], expected: V): String = | |
| expect(received, Right(expected), note => s"Failed to match Right(${Diffable[V].show(expected)}.\b$note") | |
| private def expect[T: Diffable](received: T, expected: T, msgBuilder: String => String): String = | |
| Diffable[T] | |
| .diff(received, expected) | |
| .fold("Values matched")(msgBuilder) | |
| } | 
  
    Sign up for free
    to join this conversation on GitHub.
    Already have an account?
    Sign in to comment