embracing-nondeterminism-code/src/test/scala/green/thisfieldwas/embracingnondeterminism/data/EitherSpec.scala

136 lines
3.2 KiB
Scala

package green.thisfieldwas.embracingnondeterminism.data
import green.thisfieldwas.embracingnondeterminism.control.ApplicativeLaws
import green.thisfieldwas.embracingnondeterminism.util._
import org.scalacheck.Arbitrary.arbitrary
import org.scalacheck.{Arbitrary, Gen}
import org.scalatest.Inside
import org.scalatest.matchers.should.Matchers
import org.scalatest.wordspec.AnyWordSpec
class EitherSpec extends AnyWordSpec with Matchers with Inside {
"Either" can {
"left" which {
"gets the desired term" when {
"it is a Left" in {
Left(1).left shouldBe 1
}
}
"faults" when {
"it is a Right" in {
inside(the[NoSuchElementException].thrownBy(Right("hello").left)) { case e: NoSuchElementException =>
e.getMessage shouldBe "Right.left"
}
}
}
}
"right" which {
"gets the desired term" when {
"it is a Right" in {
Right("hello").right shouldBe "hello"
}
}
"faults" when {
"it is a Left" in {
inside(the[NoSuchElementException].thrownBy(Left(1).right)) { case e: NoSuchElementException =>
e.getMessage shouldBe "Left.right"
}
}
}
}
"isLeft" which {
"is true" when {
"it is a Left" in {
Left(1).isLeft shouldBe true
}
}
"is false" when {
"it is a Right" in {
Right("hello").isLeft shouldBe false
}
}
}
"isRight" which {
"is true" when {
"it is a Right" in {
Right("hello").isRight shouldBe true
}
}
"is false" when {
"it is a Left" in {
Left(1).isRight shouldBe false
}
}
}
}
"Either object" can {
"left" which {
"creates a Left" in {
val left = Either.left[Int, String](1)
inside(left) { case Left(1) =>
}
}
}
"right" which {
"creates a Right" in {
val right = Either.right[Int, String]("hello")
inside(right) { case Right("hello") =>
}
}
}
}
"Either.EitherOps" can {
import green.thisfieldwas.embracingnondeterminism.syntax.either._
"toLeft" which {
"creates a left" in {
val left = 1.toLeft[String]
inside(left) { case Left(1) =>
}
}
}
"toRight" which {
"creates a right" in {
val right = "hello".toRight[Int]
inside(right) { case Right("hello") =>
}
}
}
}
}
/** Check that `Either` conforms to typeclass laws.
*/
class EitherLaws extends Laws with FunctorLaws with ApplicativeLaws {
/** Generate in roughly equal proportions either a `Left` of some arbitrary
* `X` or a `Right` of some generated `A` for law property checks.
*
* @tparam X
* The type of the `Left`
* @return
* A generator for the `Either`
*/
implicit def eitherLiftedGen[X: Arbitrary]: LiftedGen[Either[X, *]] = new LiftedGen[Either[X, *]] {
override def lift[A](gen: Gen[A]): Gen[Either[X, A]] =
Gen.lzy(
Gen.oneOf(
arbitrary[X].map(Left(_)),
gen.map(Right(_)),
)
)
}
checkFunctorLaws[Either[Exception, *]]()
checkApplicativeLaws[Either[Exception, *]]()
}