/tests/src/test/scala/scalaz/FingerTreeTest.scala

http://github.com/scalaz/scalaz · Scala · 135 lines · 104 code · 31 blank · 0 comment · 10 complexity · 860b06791301d0517232e97ff279d2a7 MD5 · raw file

  1. package scalaz
  2. import org.scalacheck.Prop._
  3. import scalacheck.ScalazArbitrary._
  4. import scalacheck.ScalazProperties._
  5. import std.anyVal._
  6. import std.stream._
  7. import std.string._
  8. import std.tuple._
  9. import std.option._
  10. import syntax.equal._
  11. import WriterT._
  12. import org.scalacheck.Prop.forAll
  13. object FingerTreeTest extends SpecLite {
  14. type SequenceTree[A] = FingerTree[Int, A]
  15. implicit def SizeReducer[A]: Reducer[A, Int] = UnitReducer(x => 1)
  16. import FingerTree._
  17. checkAll(monoid.laws[SequenceTree[String]])
  18. checkAll(equal.laws[SequenceTree[String]])
  19. checkAll("FingerTree", foldable.laws[SequenceTree])
  20. checkAll("Finger", foldable.laws[Finger[Int, *]])
  21. checkAll("Node", foldable.laws[Node[Int, *]])
  22. checkAll("IndSeq", equal.laws[IndSeq[Int]])
  23. checkAll("IndSeq", monadPlus.strongLaws[IndSeq])
  24. checkAll("IndSeq", traverse.laws[IndSeq])
  25. checkAll("IndSeq", isEmpty.laws[IndSeq])
  26. checkAll("IndSeq", alt.laws[IndSeq])
  27. val intStream = Stream.from(1)
  28. def streamToTree[A](stream: Stream[A]): SequenceTree[A] = stream.foldLeft(FingerTree.empty[Int, A]) {
  29. case (t, x) => (t :+ x)
  30. }
  31. "append one element works correctly" ! forAll {(tree: SequenceTree[Int], x: Int) =>
  32. (tree :+ x).toStream must_===(tree.toStream :+ x)
  33. }
  34. "prepending one element works correctly" ! forAll {(tree: SequenceTree[Int], x: Int) =>
  35. (x +: tree).toStream must_===(x +: tree.toStream)
  36. }
  37. "converting a stream to a finger-tree and back produces an equal stream" ! forAll {(stream: Stream[Int]) =>
  38. streamToTree(stream).toStream must_===(stream)
  39. }
  40. "appending two trees works correctly" ! forAll {(tree1: SequenceTree[Int], tree2: SequenceTree[Int]) =>
  41. (tree1 <++> tree2).toStream must_===(tree1.toStream ++ tree2.toStream)
  42. }
  43. "splitting a tree works the same as splitting a stream" ! forAll {(tree: SequenceTree[Int], index: Int) =>
  44. val asStream = tree.toStream
  45. val splitTree = tree.split(_ > index)
  46. (splitTree._1.toStream, splitTree._2.toStream) must_===(asStream.splitAt(index))
  47. }
  48. "replacing last element works correctly" ! forAll{(tree: SequenceTree[Int], x: Int) =>
  49. !tree.isEmpty ==> ((tree :-| x).toStream must_===(tree.toStream.init :+ x))
  50. }
  51. "replacing first element works correctly" ! forAll {(tree: SequenceTree[Int], x: Int) =>
  52. !tree.isEmpty ==> ((x |-: tree).toStream must_=== (x +: tree.toStream.tail))
  53. }
  54. "head and tail work correctly" ! forAll {(tree: SequenceTree[Int]) =>
  55. !tree.isEmpty ==> ((tree.head === tree.toStream.head) && (tree.tail.toStream === tree.toStream.tail))
  56. }
  57. "last and init work correctly" ! forAll {(tree: SequenceTree[Int]) =>
  58. !tree.isEmpty ==> ((tree.last === tree.toStream.last) && (tree.init.toStream === tree.toStream.init))
  59. }
  60. "foldLeft snoc is identity" ! forAll {
  61. (tree: SequenceTree[Int]) => tree.foldLeft(FingerTree.empty[Int, Int])(_ :+ _).toStream must_==(tree.toStream)
  62. }
  63. "foldLeft cons is reverse" ! forAll {(tree: SequenceTree[Int]) => tree.foldLeft(FingerTree.empty[Int, Int])((x, y) => y +: x).toStream must_==(tree.toStream.reverse)}
  64. "Fingertree" should {
  65. "apply effects in order" in {
  66. val s: Writer[String, FingerTree[Int, Int]] = streamToTree(intStream.take(5)).traverseTree[Writer[String, *], Int, Int](x => Writer(x.toString, x))
  67. s.run must_===("12345" -> streamToTree(intStream.take(5)))
  68. }
  69. "traverseTree through the option effect yielding result" in {
  70. val tree = streamToTree(intStream.take(20)).traverseTree[Option, Int, Int](i => Some(i * 2))
  71. tree.map(_.toStream) getOrElse(Stream.empty) must_===(streamToTree(intStream.take(20).map(_ * 2)).toStream)
  72. }
  73. "traverseTree through the option effect yielding none" in {
  74. val tree = streamToTree(intStream.take(20)).traverseTree[Option, Int, Int](i => if (i < 10) Some(i * 2) else None)
  75. tree must_===(None)
  76. }
  77. "not blow the stack" in {
  78. val tree: Option[FingerTree[Int, Int]] = streamToTree(intStream.take(32 * 1024)).traverseTree[Option, Int, Int](x => Some(x))
  79. tree.map(_.toStream.take(100)) getOrElse Stream.empty must_===(intStream.take(100))
  80. }
  81. }
  82. "OrdSeq is ordered" ! forAll { xs: List[Int] => OrdSeq(xs:_*).toList == xs.sorted }
  83. "IndSeq" should {
  84. import org.scalacheck._
  85. import Arbitrary.arbitrary
  86. case class TestInstance(arr: Array[Int], index: Int)
  87. implicit def myGen: Arbitrary[TestInstance] = Arbitrary(for {
  88. arr <- arbitrary[Array[Int]] if arr.nonEmpty
  89. m <- Gen.choose(0, arr.length-1)
  90. } yield TestInstance(arr,m))
  91. "have a length" ! forAll { xs: Array[Int] => IndSeq(xs: _*).length == xs.length }
  92. "allow random access" ! forAll { ti: TestInstance =>
  93. IndSeq(ti.arr: _*)(ti.index) == ti.arr(ti.index)
  94. }
  95. }
  96. "viewl works correctly" ! forAll {(tree: SequenceTree[Int]) =>
  97. val asStream = tree.toStream
  98. tree.viewl.fold[Boolean](true, (x, t) => (x === asStream.head) && (t.toStream === asStream.tail))
  99. }
  100. "viewr works correctly" ! forAll {(tree: SequenceTree[Int]) =>
  101. val asStream = tree.toStream
  102. tree.viewr.fold[Boolean](true, (i, x) => (i.toStream asStream.init) && (x asStream.last))
  103. }
  104. }