PageRenderTime 77ms CodeModel.GetById 32ms app.highlight 40ms RepoModel.GetById 1ms app.codeStats 0ms

/tests/src/test/scala/scalaz/TraverseTest.scala

http://github.com/scalaz/scalaz
Scala | 164 lines | 135 code | 24 blank | 5 comment | 35 complexity | fcc52526bdd579c8fad1793ea2aacaad MD5 | raw file
  1package scalaz
  2import org.scalacheck.Prop.forAll
  3
  4
  5object TraverseTest extends SpecLite {
  6
  7  import scalaz._
  8  import scalaz.State._
  9  import std.AllInstances._
 10  import std.AllFunctions._
 11  import syntax.traverse._
 12
 13  "list" should {
 14    // ghci> import Data.Traversable
 15    // ghci> import Control.Monad.Writer
 16    // ghci> let (|>) = flip ($)
 17    // ghci> traverse (\x -> writer (x, x)) ["1", "2", "3"] |> runWriter
 18    // (["1","2","3"],"123")
 19    "apply effects in order" in {
 20      val s: Writer[String, List[Int]] = List(1, 2, 3).traverseU(x => Writer(x.toString, x))
 21      s.run must_===(("123", List(1, 2, 3)))
 22    }
 23
 24    "indexed" ! forAll { xs: List[Byte] =>
 25      Traverse[List].indexed(xs) must_=== xs.zipWithIndex.map{case (a, b) => (b, a)}
 26    }
 27
 28    "traverse through option effect" in {
 29      val s: Option[List[Int]] = List(1, 2, 3).traverseU((x: Int) => if (x < 3) some(x) else none)
 30      s must_===(none[List[Int]])
 31    }
 32
 33    "traverse int function as monoidal applicative" in {
 34      val s: Const[Int, _] = List(1, 2, 3) traverseU {a => Const(a + 1)}
 35      s.getConst must_===(9)
 36    }
 37
 38    "not blow the stack" in {
 39      val s: Option[List[Int]] = List.range(0, 32 * 1024).traverseU(x => some(x))
 40      s.map(_.take(3)) must_===(some(List(0, 1, 2)))
 41    }
 42
 43    "be stack-safe and short-circuiting" in {
 44      val N = 10000
 45      val s: Maybe[List[Int]] = List.range(0, N) traverse { x =>
 46        if(x < N-2) Maybe.just(x)
 47        else if(x == N-2) Maybe.empty
 48        else sys.error("BOOM!")
 49      }
 50      s must_=== Maybe.empty
 51    }
 52
 53    "state traverse agrees with regular traverse" in {
 54      val N = 10
 55      List.range(0,N).traverseS(x => modify((x: Int) => x+1))(0) must_=== (
 56      List.range(0,N).traverseU(x => modify((x: Int) => x+1)).apply(0))
 57    }
 58
 59    "state traverse does not blow stack" in {
 60      val N = 10000
 61      val s = List.range(0,N).traverseS(x => modify((x: Int) => x+1))
 62      s.exec(0) must_=== (N)
 63    }
 64
 65  }
 66
 67  "ilist" should {
 68    "be stack-safe and short-circuiting" in {
 69      val N = 10000
 70      val s: Maybe[IList[Int]] = IList.fromList(List.range(0, N)) traverse { x =>
 71        if(x < N-2) Maybe.just(x)
 72        else if(x == N-2) Maybe.empty
 73        else sys.error("BOOM!")
 74      }
 75      s must_=== Maybe.empty
 76    }
 77  }
 78
 79  "stream" should {
 80    "apply effects in order" in {
 81      val s: Writer[String, Stream[Int]] = Stream(1, 2, 3).traverseU(x => Writer(x.toString, x))
 82      s.run must_===(("123", Stream(1, 2, 3)))
 83    }
 84
 85    "be stack-safe and short-circuiting" in {
 86      val N = 10000
 87      val s: Maybe[Stream[Int]] = Stream.from(0) traverse { x =>
 88        if(x < N-2) Maybe.just(x)
 89        else if(x == N-2) Maybe.empty
 90        else sys.error("BOOM!")
 91      }
 92      s must_=== Maybe.empty
 93    }
 94  }
 95
 96  "ephemeralstream" should {
 97    "be stack-safe and short-circuiting" in {
 98      val N = 10000
 99      val s: Maybe[EphemeralStream[Int]] = EphemeralStream.fromStream(Stream.from(0)) traverse { x =>
100        if(x < N-2) Maybe.just(x)
101        else if(x == N-2) Maybe.empty
102        else sys.error("BOOM!")
103      }
104      s must_=== Maybe.empty
105    }
106  }
107
108  "nonemptylist" should {
109    "be stack-safe and short-circuiting" in {
110      val N = 10000
111      val fa = NonEmptyList.nel(0, IList.fromList(List.range(1, N)))
112      val s: Maybe[NonEmptyList[Int]] = Traverse1[NonEmptyList].traverse1 (fa) ({ x =>
113        if(x < N-2) Maybe.just(x)
114        else if(x == N-2) Maybe.empty
115        else sys.error("BOOM!")
116      })
117      s must_=== Maybe.empty
118    }
119  }
120
121  "combos" should {
122    "traverse with monadic join" in {
123      val s: Writer[String, List[Int]] = List(1, 2, 3).traverseM[Writer[String, *], Int](x => Writer(x.toString, List(x, x * 2)))
124      s.run must_===(("123", List(1, 2, 2, 4, 3, 6)))
125    }
126  }
127
128  "derived functions" should {
129    "sequence" in {
130      some(List(1, 2, 3)).sequence must_===(List(some(1), some(2), some(3)))
131      List(some(1), some(2)).sequence must_===(some(List(1, 2)))
132      List(some(1), none[Int]).sequence must_===(none)
133
134      val states: List[State[Int, Int]] = List(State.modify[Int](_ + 1).map(_ => 0), for {
135          i <- State.get[Int]
136          _ <- State.put(i + 1)
137        } yield i)
138      val state: State[Int, List[Int]] = states.sequenceU
139      state.run(0) must_===(2 -> List(0, 1))
140
141      List(some(List(1, 2)), some(List(3, 4, 5))).sequenceM must_===(some(List(1, 2, 3, 4, 5)))
142      List(some(List(1, 2)), none[List[Int]]).sequenceM must_===(none)
143    }
144
145    "reverse" in {
146      Traverse[List].reverse(List(1, 2, 3)) must_===(List(3, 2, 1))
147    }
148
149    "mapAccumL/R" ! forAll {
150      val L = Traverse[List]; import L.traverseSyntax._
151      (l: List[Int]) => {
152        val (acc, l2) = l.mapAccumL(List[Int]())((acc,a) => (a :: acc, a))
153        val (acc2, l3) = l.mapAccumR(List[Int]())((acc,a) => (a :: acc, a))
154        acc == l.reverse && l2 == l && acc2 == l3 && l3 == l
155      }
156    }
157
158    "double reverse" ! forAll {
159      (is: List[Int]) =>
160        import syntax.monoid._
161        Endo(Traverse[List].reverse[Int]).multiply(2).apply(is) must_===(is)
162    }
163  }
164}