PageRenderTime 17ms CodeModel.GetById 2ms app.highlight 12ms RepoModel.GetById 1ms app.codeStats 0ms

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