/*
* Copyright (c) 2018, 2020. Phasmid Software
*/
package edu.neu.coe.csye7200.asstll
import org.scalatest.flatspec
import org.scalatest.matchers.should
import scala.language.postfixOps
class MyLazyListSpec extends flatspec.AnyFlatSpec with should.Matchers {
behavior of Cons
it should produce a single of 1 in {
val x: ListLike[Int] = MyLazyList(1, () => EmptyList)
x.head shouldBe 1
x.tail shouldBe EmptyList
}
it should produce a stream of xs using Cons directly in {
lazy val x: ListLike[String] = MyLazyList(x, () => x)
val y = x.take(3).toSeq
y.size shouldBe 3
y.head shouldBe x
y shouldBe Seq(x, x, x)
}
behavior of toSeq
it should produce a single 1 in {
val x: ListLike[Int] = MyLazyList(1, () => EmptyList)
x.toSeq shouldBe Seq(1)
}
it should produce a sequence of 1, 2 in {
val x = MyLazyList(1, () => MyLazyList(2, () => EmptyList))
x.toSeq shouldBe Seq(1, 2)
}
behavior of ones
it should produce a stream of 1s in {
val x: ListLike[Int] = MyLazyList.ones
val y = x.take(3).toSeq
y.size shouldBe 3
y.head shouldBe 1
y shouldBe Seq(1, 1, 1)
}
behavior of take
it should take zero from a finite stream in {
MyLazyList(1).take(0).toSeq shouldBe Nil
}
it should take zero from an infinite stream in {
MyLazyList.continually(1).take(0).toSeq shouldBe Nil
}
it should take 3 from a finite stream of actual length 1 in {
(MyLazyList(1) take 3).toSeq shouldBe Seq(1)
}
it should take 3 from an infinite stream in {
(MyLazyList.continually(1) take 3).toSeq shouldBe Seq(1, 1, 1)
}
it should take 3 from an infinite stream of 1s that counts in {
var count = 0
def incrementCountAndProvideValue: Int = {
count = count + 1
1
}
val lazyList = MyLazyList.continually(incrementCountAndProvideValue) take 3
count shouldBe 1
lazyList.toSeq shouldBe Seq(1, 1, 1)
// LazyList is not memorizing the elements that have been evaluated already.
count shouldBe 4
}
it should take 3 from an infinite incrementing stream that counts in {
var count = 0
def incrementCountAndProvideValue: Int = {
count = count + 1
count
}
val lazyList = MyLazyList.continually(incrementCountAndProvideValue) take 3
count shouldBe 1
lazyList.toSeq shouldBe Seq(1, 2, 3)
// LazyList is not memorizing the elements that have been evaluated already.
count shouldBe 4
}
behavior of drop
it should work correctly in {
val x = MyLazyList.from(1)
val y = x drop 3 take 3
y.toSeq shouldBe Seq(4, 5, 6)
}
behavior of ++
it should join two Empty streams together in {
val x = EmptyList
val y = x.++(EmptyList)
y shouldBe x
}
it should join a stream with an Empty stream in {
val empty = EmptyList
val ones = MyLazyList.continually(1)
val y = ones.++(empty)
val z = y.take(3).toSeq
z.size shouldBe 3
z shouldBe Seq(1, 1, 1)
}
it should join an Empty stream with a stream in {
val x: ListLike[Int] = EmptyList.asInstanceOf[ListLike[Int]]
val ones = MyLazyList.continually(1)
val y = x.++(ones)
(y take 3).toSeq shouldBe Seq(1, 1, 1)
}
behavior of map
it should produce a stream of 2s in {
lazy val x: ListLike[Int] = MyLazyList(1, () => x)
val y = x map (_ * 2)
assert(y.head == 2)
assert(y.tail.head == 2)
(y take 4).toSeq shouldBe Seq(2, 2, 2, 2)
}
behavior of flatMap
it should produce a stream of 2s from a single element 1 in {
val x = MyLazyList(1)
val y = x flatMap (z => MyLazyList.continually(z * 2))
assert(y.head == 2)
assert(y.tail.head == 2)
(y take 4).toSeq shouldBe Seq(2, 2, 2, 2)
}
it should produce a stream of 2s from a stream of 1s in {
lazy val x: ListLike[Int] = MyLazyList(1, () => x)
val y = x flatMap (z => MyLazyList.continually(z * 2))
assert(y.head == 2)
assert(y.tail.head == 2)
(y take 4).toSeq shouldBe Seq(2, 2, 2, 2)
}
behavior of from
it should get a Seq(2, 4, 6, 8) in {
val x = MyLazyList.from(2, 2)
(x take 4 toSeq) shouldBe Seq(2, 4, 6, 8)
}
it should get a Seq(1, -1, -3, -5) in {
val x = MyLazyList.from(1, -2)
(x take 4 toSeq) shouldBe Seq(1, -1, -3, -5)
}
behavior of filter
it should produce a stream of even numbers using from(1) in {
def even(x: Int): Boolean = x % 2 == 0
val y = MyLazyList.from(1) filter even
assert(y.head == 2)
assert(y.tail.head == 4)
(y take 4).toSeq shouldBe Seq(2, 4, 6, 8)
}
it should produce a stream of even numbers using from(2,2) in {
def even(x: Int): Boolean = x % 2 == 0
val y = MyLazyList.from(2, 2) filter even
assert(y.head == 2)
assert(y.tail.head == 4)
(y take 4).toSeq shouldBe Seq(2, 4, 6, 8)
}
behavior of filterNot
it should produce a stream of even numbers using from(1) in {
def odd(x: Int): Boolean = x % 2 != 0
val y = MyLazyList.from(1) filterNot odd
assert(y.head == 2)
assert(y.tail.head == 4)
(y take 4).toSeq shouldBe Seq(2, 4, 6, 8)
}
it should produce a stream of even numbers using from(2,2) in {
def odd(x: Int): Boolean = x % 2 != 0
val y = MyLazyList.from(2, 2) filterNot odd
assert(y.head == 2)
assert(y.tail.head == 4)
(y take 4).toSeq shouldBe Seq(2, 4, 6, 8)
}
behavior of zip
it should zip together two empty streams in {
EmptyList.zip(EmptyList) shouldBe EmptyList
}
it should zip together a stream and an empty stream in {
MyLazyList.continually(1).zip(EmptyList) shouldBe EmptyList
}
it should zip together an empty stream and a stream in {
EmptyList.zip(MyLazyList.continually(1)) shouldBe EmptyList
}
it should zip together two non-empty streams in {
val x = MyLazyList.from(1).zip(MyLazyList.from(2))
x.head shouldBe(1, 2)
x.tail.head shouldBe(2, 3)
}
behavior of apply
it should produce a stream of a single 1 in {
val y = MyLazyList(1) take 3
y.toSeq shouldBe Seq(1)
}
behavior of continually
it should produce a stream of 1s in {
val y = MyLazyList.continually(1) take 3
y.toSeq shouldBe Seq(1, 1, 1)
}
it should produce a stream of 1 thru 3 in {
val x = MyLazyList.from(1)
val y = x take 3
y.toSeq shouldBe Seq(1, 2, 3)
}
behavior of MyLazyList as a monad
it should support a for-comprehension in {
val zs = for (x <- MyLazyList.from(1); y <- MyLazyList(Seq(1, 2, 3))) yield (x, y)(zs take 5).toSeq shouldBe Seq(1 -> 1, 1 -> 2, 1 -> 3, 2 -> 1, 2 -> 2)
}
it should support a for-comprehension with filter in {
val zs = for (x <- MyLazyList.from(1); if x > 1; y <- MyLazyList(Seq(1, 2, 3)); if y == 2) yield (x, y)(zs take 3).toSeq shouldBe Seq(2 -> 2, 3 -> 2, 4 -> 2)
}
behavior of singleton
it should allow for 1 in {
val x = MyLazyList.singleton(1)
x.toSeq shouldBe Seq(1)
}
behavior of Iterator
it should support EmptyList in {
val x = EmptyList
val i = x.iterator
i.hasNext shouldBe false
}
it should support from in {
val x = MyLazyList.from(1)
val i = x.iterator
i.hasNext shouldBe true
i.next() shouldBe 1
i.hasNext shouldBe true
i.next() shouldBe 2
}
it should support singleton in {
val x = MyLazyList.singleton(1)
val i = x.iterator
i.hasNext shouldBe true
i.next() shouldBe 1
i.hasNext shouldBe false
}
}
Reviews
There are no reviews yet.