You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

170 lines
4.3 KiB

package green.thisfieldwas.embracingnondeterminism.data
import green.thisfieldwas.embracingnondeterminism.util._
import org.scalacheck.Gen
import org.scalatest.Inside
import org.scalatest.matchers.should.Matchers
import org.scalatest.wordspec.AnyWordSpec
class ListSpec extends AnyWordSpec with Matchers with Inside {
"List" can {
"head" which {
"faults" when {
"the list is empty" in {
inside(the[NoSuchElementException].thrownBy(Nil.head)) { case e: NoSuchElementException =>
e.getMessage shouldBe "Nil.head"
}
}
}
"gets the first element" when {
"the list is not empty" in {
List(1, 2, 3).head shouldBe 1
}
}
}
"tail" which {
"faults" when {
"list list is empty" in {
inside(the[NoSuchElementException].thrownBy(Nil.tail)) { case e: NoSuchElementException =>
e.getMessage shouldBe "Nil.tail"
}
}
}
"gets all but the first element" when {
"the list is not empty" in {
List(1, 2, 3).tail shouldBe List(2, 3)
}
}
}
"isEmpty" which {
"is true" when {
"the list is empty" in {
List[Int]().isEmpty shouldBe true
}
}
"is false" when {
"the list is not empty" in {
List(1, 2, 3).isEmpty shouldBe false
}
}
}
"foldLeft" which {
"returns the accumulator" when {
"the list is empty" in {
List[Int]().foldLeft(0)(_ + _) shouldBe 0
}
}
"applies the function" when {
"the list is non-empty" in {
List(1, 2, 3).foldLeft("$")(_ + _.toString) shouldBe "$123"
}
}
}
"foldRight" which {
"returns the accumulator" when {
"the list is empty" in {
List[Int]().foldRight(0)(_ + _) shouldBe 0
}
}
"applies the function" when {
"the list is non-empty" in {
List(1, 2, 3).foldRight("$")(_.toString + _) shouldBe "123$"
}
}
}
"reverse" which {
"reverses the order of instances in the list" in {
List(1, 2, 3, 4, 5).reverse shouldBe List(5, 4, 3, 2, 1)
}
}
"zip" which {
"zips two lists of equal length together" in {
List(1, 2, 3, 4).zip(List("a", "b", "c", "d")) shouldBe List((1, "a"), (2, "b"), (3, "c"), (4, "d"))
}
"zips two lists with the left list being shorter" in {
List(1, 2, 3).zip(List("a", "b", "c", "d")) shouldBe List((1, "a"), (2, "b"), (3, "c"))
}
"zips two lists with the right list being shorter" in {
List(1, 2, 3, 4).zip(List("a", "b", "c")) shouldBe List((1, "a"), (2, "b"), (3, "c"))
}
}
"::" which {
"prepends an element to the list" in {
0 :: List(1, 2, 3) shouldBe List(0, 1, 2, 3)
0 :: Nil shouldBe List(0)
}
}
"|:" which {
"creates a NonEmptyList" in {
0 |: List(1, 2, 3) shouldBe NonEmptyList(0, List(1, 2, 3))
0 |: Nil shouldBe NonEmptyList(0)
}
}
"toSeq" which {
"converts the List to a Seq" in {
List(1, 2, 3).toSeq shouldBe Seq(1, 2, 3)
}
}
}
"List object" can {
"apply" which {
"creates an empty list" when {
"given no arguments" in {
List[Int]() shouldBe Nil
}
}
"creates a list with elements" when {
"given arguments" in {
List(1, 2, 3) shouldBe (1 :: 2 :: 3 :: Nil)
}
}
}
"unapply" which {
"matches the length of a list" when {
"the list has no elements" in {
List[Int]() match {
case List() => succeed
case _ => fail("List should be empty")
}
}
"the list has one element" in {
List(1) match {
case List(x) => x shouldBe 1
case _ => fail("List should have one element")
}
}
}
}
}
}
/** Check that `List` conforms to typeclass laws.
*/
class ListLaws extends Laws with FunctorLaws {
/** From a generator for some type `A`, generate a `List` of some length of
* `A`.
*/
implicit val listLiftedGen: LiftedGen[List] = new LiftedGen[List] {
override def lift[A](gen: Gen[A]): Gen[List[A]] =
Gen.sized(Gen.listOfN(_, gen).map(List(_: _*)))
}
checkFunctorLaws[List]()
}