Skip to content

Commit

Permalink
Merge pull request #656 from ceedubs/fix-streamingt-drop
Browse files Browse the repository at this point in the history
Add StreamingT tests and fix some uncovered bugs
  • Loading branch information
stew committed Nov 16, 2015
2 parents 4ff969e + 6bd6152 commit f4db3c4
Show file tree
Hide file tree
Showing 2 changed files with 115 additions and 4 deletions.
11 changes: 7 additions & 4 deletions core/src/main/scala/cats/data/StreamingT.scala
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ sealed abstract class StreamingT[F[_], A] extends Product with Serializable { lh
* element to be calculated.
*/
def isEmpty(implicit ev: Monad[F]): F[Boolean] =
uncons.map(_.isDefined)
uncons.map(_.isEmpty)

/**
* Return true if the stream is non-empty, false otherwise.
Expand All @@ -116,7 +116,7 @@ sealed abstract class StreamingT[F[_], A] extends Product with Serializable { lh
* element to be calculated.
*/
def nonEmpty(implicit ev: Monad[F]): F[Boolean] =
uncons.map(_.isEmpty)
uncons.map(_.isDefined)

/**
* Prepend an A value to the current stream.
Expand Down Expand Up @@ -205,7 +205,7 @@ sealed abstract class StreamingT[F[_], A] extends Product with Serializable { lh
*/
def drop(n: Int)(implicit ev: Functor[F]): StreamingT[F, A] =
if (n <= 0) this else this match {
case Cons(a, ft) => Wait(ft.map(_.take(n - 1)))
case Cons(a, ft) => Wait(ft.map(_.drop(n - 1)))
case Wait(ft) => Wait(ft.map(_.drop(n)))
case Empty() => Empty()
}
Expand Down Expand Up @@ -249,7 +249,7 @@ sealed abstract class StreamingT[F[_], A] extends Product with Serializable { lh
*/
def dropWhile(f: A => Boolean)(implicit ev: Functor[F]): StreamingT[F, A] =
this match {
case Cons(a, ft) => if (f(a)) Empty() else Cons(a, ft.map(_.takeWhile(f)))
case Cons(a, ft) => if (f(a)) Empty() else Cons(a, ft.map(_.dropWhile(f)))
case Wait(ft) => Wait(ft.map(_.dropWhile(f)))
case Empty() => Empty()
}
Expand Down Expand Up @@ -439,6 +439,9 @@ private[data] sealed trait StreamingTInstances extends StreamingTInstances1 {
fa.filter(f)
def coflatMap[A, B](fa: StreamingT[F, A])(f: StreamingT[F, A] => B): StreamingT[F, B] =
fa.coflatMap(f)

override def map[A, B](fa: StreamingT[F, A])(f: A => B): StreamingT[F, B] =
fa.map(f)
}

implicit def streamingTOrder[F[_], A](implicit ev: Monad[F], eva: Order[F[List[A]]]): Order[StreamingT[F, A]] =
Expand Down
108 changes: 108 additions & 0 deletions tests/src/test/scala/cats/tests/StreamingTTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import algebra.laws.OrderLaws
import cats.data.StreamingT
import cats.laws.discipline.{CoflatMapTests, MonadCombineTests, SerializableTests}
import cats.laws.discipline.arbitrary._
import cats.laws.discipline.eq._

class StreamingTTests extends CatsSuite {

Expand All @@ -23,6 +24,113 @@ class StreamingTTests extends CatsSuite {
checkAll("StreamingT[List, ?]", CoflatMapTests[StreamingT[List, ?]].coflatMap[Int, Int, Int])
checkAll("StreamingT[List, Int]", OrderLaws[StreamingT[List, Int]].order)
checkAll("Monad[StreamingT[List, ?]]", SerializableTests.serializable(Monad[StreamingT[List, ?]]))

test("uncons with Id consistent with List headOption/tail") {
forAll { (s: StreamingT[Id, Int]) =>
val sList = s.toList
s.uncons.map{ case (h, t) =>
(h, t.toList)
} should === (sList.headOption.map{ h =>
(h, sList.tail)
})
}
}

test("map with Id consistent with List.map") {
forAll { (s: StreamingT[Id, Int], f: Int => Long) =>
s.map(f).toList should === (s.toList.map(f))
}
}

test("flatMap with Id consistent with List.flatMap") {
forAll { (s: StreamingT[Id, Int], f: Int => StreamingT[Id, Long]) =>
s.flatMap(f).toList should === (s.toList.flatMap(f(_).toList))
}
}

test("filter with Id consistent with List.filter") {
forAll { (s: StreamingT[Id, Int], f: Int => Boolean) =>
s.filter(f).toList should === (s.toList.filter(f))
}
}

test("foldLeft with Id consistent with List.foldLeft") {
forAll { (s: StreamingT[Id, Int], l: Long, f: (Long, Int) => Long) =>
s.foldLeft(l)(f) should === (s.toList.foldLeft(l)(f))
}
}

test("find with Id consistent with List.find") {
forAll { (s: StreamingT[Id, Int], f: Int => Boolean) =>
s.find(f) should === (s.toList.find(f))
}
}

test("isEmpty with Id consistent with List.isEmpty") {
forAll { (s: StreamingT[Id, Int]) =>
s.isEmpty should === (s.toList.isEmpty)
}
}

test("nonEmpty with Id consistent with List.nonEmpty") {
forAll { (s: StreamingT[Id, Int]) =>
s.nonEmpty should === (s.toList.nonEmpty)
}
}

test("%:: with Id consistent with List.::") {
forAll { (i: Int, s: StreamingT[Id, Int]) =>
(i %:: s).toList should === (i :: s.toList)
}
}

test("%::: with Id consistent with List.:::") {
forAll { (s1: StreamingT[Id, Int], s2: StreamingT[Id, Int]) =>
(s1 %::: s2).toList should === (s1.toList ::: s2.toList)
}
}

test("concat with Id consistent with List.++") {
forAll { (s1: StreamingT[Id, Int], s2: StreamingT[Id, Int]) =>
(s1 concat s2).toList should === (s1.toList ++ s2.toList)
}
}

test("exists with Id consistent with List.exists") {
forAll { (s: StreamingT[Id, Int], f: Int => Boolean) =>
s.exists(f) should === (s.toList.exists(f))
}
}

test("forall with Id consistent with List.forall") {
forAll { (s: StreamingT[Id, Int], f: Int => Boolean) =>
s.forall(f) should === (s.toList.forall(f))
}
}

test("takeWhile with Id consistent with List.takeWhile") {
forAll { (s: StreamingT[Id, Int], f: Int => Boolean) =>
s.takeWhile(f).toList should === (s.toList.takeWhile(f))
}
}

test("dropWhile with Id consistent with List.dropWhile") {
forAll { (s: StreamingT[Id, Int], f: Int => Boolean) =>
s.dropWhile(f).toList should === (s.toList.dropWhile(f))
}
}

test("take with Id consistent with List.take") {
forAll { (s: StreamingT[Id, Int], i: Int) =>
s.take(i).toList should === (s.toList.take(i))
}
}

test("drop with Id consistent with List.drop") {
forAll { (s: StreamingT[Id, Int], i: Int) =>
s.drop(i).toList should === (s.toList.drop(i))
}
}
}

class SpecificStreamingTTests extends CatsSuite {
Expand Down

0 comments on commit f4db3c4

Please sign in to comment.