Skip to content

Commit

Permalink
Port tests for InjectK to new tests for Inject
Browse files Browse the repository at this point in the history
  • Loading branch information
andyscott committed Jun 15, 2017
1 parent a4b4fba commit b56e92a
Show file tree
Hide file tree
Showing 3 changed files with 119 additions and 0 deletions.
20 changes: 20 additions & 0 deletions laws/src/main/scala/cats/laws/InjectLaws.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package cats
package laws

trait InjectLaws[A, B] {
def inject: Inject[A, B]

def injectRoundTripInj(a: A): IsEq[Option[A]] =
(inject.prj compose inject.inj).apply(a) <-> Some(a)

def injectRoundTripPrj(b: B): IsEq[Option[B]] =
inject.prj(b) match {
case Some(a) => (Some(inject.inj(a)): Option[B]) <-> Some(b)
case None => (None: Option[B]) <-> None
}
}

object InjectLaws {
def apply[A, B](implicit ev: Inject[A, B]): InjectLaws[A, B] =
new InjectLaws[A, B]{ val inject: Inject[A, B] = ev }
}
31 changes: 31 additions & 0 deletions laws/src/main/scala/cats/laws/discipline/InjectTests.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package cats
package laws
package discipline

import org.scalacheck.Arbitrary
import org.scalacheck.Prop
import Prop._
import org.typelevel.discipline.Laws

trait InjectTests[A, B] extends Laws {
def laws: InjectLaws[A, B]

def inject(implicit
ArbA: Arbitrary[A],
EqOptionA: Eq[Option[A]],
ArbB: Arbitrary[B],
EqOptionB: Eq[Option[B]]
): RuleSet =
new DefaultRuleSet(
"inject",
None,
"inject round trip inj" -> forAll((a: A) => laws.injectRoundTripInj(a)),
"inject round trip prj" -> forAll((b: B) => laws.injectRoundTripPrj(b))
)

}

object InjectTests {
def apply[A, B](implicit ev: Inject[A, B]): InjectTests[A, B] =
new InjectTests[A, B] { val laws: InjectLaws[A, B] = InjectLaws[A, B] }
}
68 changes: 68 additions & 0 deletions tests/src/test/scala/cats/tests/InjectTests.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package cats

import cats.laws.discipline.{ InjectTests => InjectTypeclassTests }
import cats.tests.CatsSuite

class InjectTests extends CatsSuite {

type StringOrInt = Either[String, Int]

test("inj & prj") {
def distr[F](f1: F, f2: F)
(implicit
I0: Inject[String, F],
I1: Inject[Int, F]
): Option[String] =
for {
x <- I0.prj(f1)
y <- I1.prj(f2)
} yield s"$x $y"

forAll { (x: String, y: Int) =>
val expr1: StringOrInt = Inject[String, StringOrInt].inj(x)
val expr2: StringOrInt = Inject[Int, StringOrInt].inj(y)
val res = distr(expr1, expr2)
res should ===(Some(s"$x $y"))
}
}

test("apply & unapply") {
def distr[F](f1: F, f2: F)
(implicit
I0: Inject[String, F],
I1: Inject[Int, F]
): Option[String] =
for {
x <- I0.unapply(f1)
y <- I1.unapply(f2)
} yield s"$x $y"

forAll { (x: String, y: Int) =>
val expr1: StringOrInt = Inject[String, StringOrInt].apply(x)
val expr2: StringOrInt = Inject[Int, StringOrInt].apply(y)
val res = distr(expr1, expr2)
res should ===(Some(s"$x $y"))
}
}

test("apply in left") {
forAll { (y: String) =>
Inject[String, StringOrInt].inj(y) == Left(y) should ===(true)
}
}

test("apply in right") {
forAll { (y: Int) =>
Inject[Int, StringOrInt].inj(y) == Right(y) should ===(true)
}
}

test("null identity") {
val stringNull = null.asInstanceOf[String]
Inject.catsReflexiveInjectInstance[String].inj(stringNull) should ===(stringNull)
Inject.catsReflexiveInjectInstance[String].prj(stringNull) should ===(Some(stringNull))
}

checkAll("Inject[String, StringOrInt]", InjectTypeclassTests[String, StringOrInt].inject)
checkAll("Inject[Int, StringOrInt]", InjectTypeclassTests[Int, StringOrInt].inject)
}

0 comments on commit b56e92a

Please sign in to comment.