136 lines
3.2 KiB
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, *]]()
|
|
}
|