From da60dda202f386ed85fa15bf8fe02252d4dfb911 Mon Sep 17 00:00:00 2001 From: Som Snytt Date: Fri, 5 Sep 2014 00:24:27 -0700 Subject: SI-8835 Iterator tests can be junit Without loss of generality or convenience, but helps reduce the number of files in test/files and may reduce compile times for test suite. This commit includes the fix from #3963 and an extra test of that fix that ensures the stack doesn't grow on chained drops. --- src/library/scala/collection/Iterator.scala | 4 +- test/files/run/iterator-concat.check | 4 - test/files/run/iterator-concat.scala | 15 --- test/files/run/iterator-iterate-lazy.scala | 5 - test/files/run/iterators.check | 14 -- test/files/run/iterators.scala | 168 ------------------------ test/files/run/t3516.check | 3 - test/files/run/t3516.scala | 13 -- test/junit/scala/collection/IteratorTest.scala | 148 ++++++++++++++++++++- test/junit/scala/tools/testing/AssertUtil.scala | 20 ++- 10 files changed, 167 insertions(+), 227 deletions(-) delete mode 100644 test/files/run/iterator-concat.check delete mode 100644 test/files/run/iterator-concat.scala delete mode 100644 test/files/run/iterator-iterate-lazy.scala delete mode 100644 test/files/run/iterators.check delete mode 100644 test/files/run/iterators.scala delete mode 100644 test/files/run/t3516.check delete mode 100644 test/files/run/t3516.scala diff --git a/src/library/scala/collection/Iterator.scala b/src/library/scala/collection/Iterator.scala index 0115cc154c..20712f918c 100644 --- a/src/library/scala/collection/Iterator.scala +++ b/src/library/scala/collection/Iterator.scala @@ -322,8 +322,8 @@ trait Iterator[+A] extends TraversableOnce[A] { */ def drop(n: Int): Iterator[A] = { var j = 0 - while (j < n && this.hasNext) { - this.next + while (j < n && hasNext) { + next() j += 1 } this diff --git a/test/files/run/iterator-concat.check b/test/files/run/iterator-concat.check deleted file mode 100644 index 23835b07ae..0000000000 --- a/test/files/run/iterator-concat.check +++ /dev/null @@ -1,4 +0,0 @@ -100 -1000 -10000 -100000 diff --git a/test/files/run/iterator-concat.scala b/test/files/run/iterator-concat.scala deleted file mode 100644 index f11363410f..0000000000 --- a/test/files/run/iterator-concat.scala +++ /dev/null @@ -1,15 +0,0 @@ -object Test { - // Create `size` Function0s, each of which evaluates to an Iterator - // which produces 1. Then fold them over ++ to get a single iterator, - // which should sum to "size". - def mk(size: Int): Iterator[Int] = { - val closures = (1 to size).toList.map(x => (() => Iterator(1))) - closures.foldLeft(Iterator.empty: Iterator[Int])((res, f) => res ++ f()) - } - def main(args: Array[String]): Unit = { - println(mk(100).sum) - println(mk(1000).sum) - println(mk(10000).sum) - println(mk(100000).sum) - } -} diff --git a/test/files/run/iterator-iterate-lazy.scala b/test/files/run/iterator-iterate-lazy.scala deleted file mode 100644 index 92b170062e..0000000000 --- a/test/files/run/iterator-iterate-lazy.scala +++ /dev/null @@ -1,5 +0,0 @@ -object Test { - def main(args: Array[String]): Unit = { - Iterator.iterate((1 to 5).toList)(_.tail).takeWhile(_.nonEmpty).map(_.head).toList - } -} diff --git a/test/files/run/iterators.check b/test/files/run/iterators.check deleted file mode 100644 index abaf80ff38..0000000000 --- a/test/files/run/iterators.check +++ /dev/null @@ -1,14 +0,0 @@ -test check_from was successful -test check_range was successful -test check_range2 was successful -test check_range3 was successful -test check_take was successful -test check_drop was successful -test check_slice was successful -test check_foreach was successful -test check_forall was successful -test check_fromArray was successful -test check_toSeq was successful -test check_indexOf was successful -test check_findIndexOf was successful - diff --git a/test/files/run/iterators.scala b/test/files/run/iterators.scala deleted file mode 100644 index d54da3d3ba..0000000000 --- a/test/files/run/iterators.scala +++ /dev/null @@ -1,168 +0,0 @@ -//############################################################################ -// Iterators -//############################################################################ - -//############################################################################ - -import scala.language.postfixOps - -object Test { - - def check_from: Int = { - val it1 = Iterator.from(-1) - val it2 = Iterator.from(0, -1) - it1.next + it2.next - } - - def check_range: Int = { - val xs1 = Iterator.range(0, 10, 2) toList; - val xs2 = Iterator.range(0, 10, -2) toList; - val xs3 = Iterator.range(10, 0, -2) toList; - val xs4 = Iterator.range(10, 0, 2) toList; - val xs5 = Iterator.range(0, 10, 11) toList; - xs1.length + xs2.length + xs3.length + xs4.length + xs5.length - } - - def check_range2: Int = { - val r1start = 0 - val r1end = 10 - val r1step = 1 - val r1 = Iterator.range(r1start, r1end, r1step) toList; - val r2 = Iterator.range(r1start, r1end, r1step + 1) toList; - val r3 = Iterator.range(r1end, r1start, -r1step) toList; - val r4 = Iterator.range(0, 10, 11) toList; - // 10 + 5 + 10 + 1 - r1.length + r2.length + r3.length + r4.length - } - - def check_range3: Int = { - def trues(xs: List[Boolean]) = xs.foldLeft(0)((a, b) => if (b) a+1 else a) - val r1 = Iterator.range(0, 10) - val xs1 = List(r1 contains 5, r1 contains 6) - val r2a = Iterator.range(0, 10, 2) - val r2b = Iterator.range(0, 10, 2) - val xs2 = List(r2a contains 5, r2b contains 6) - val r3 = Iterator.range(0, 10, 11) - val xs3 = List(r3 contains 5, r3 contains 6) - // 2 + 1 + 0 - trues(xs1) + trues(xs2) + trues(xs3) - } - - def check_take: Int = { - val it1 = Iterator.from(0) - val xs1 = it1 take 10 toList; - xs1.length - } - - def check_drop: Int = { - val tests = Array( - Iterator.from(0).take(5).drop(1).toSeq sameElements Seq(1, 2, 3, 4), - Iterator.from(0).take(5).drop(3).toSeq sameElements Seq(3, 4), - - Iterator.from(0).take(5).drop(5).toSeq sameElements Seq(), - Iterator.from(0).take(5).drop(10).toSeq sameElements Seq(), - - Iterator.from(0).take(5).drop(0).toSeq sameElements Seq(0, 1, 2, 3, 4), - Iterator.from(0).take(5).drop(-1).toSeq sameElements Seq(0, 1, 2, 3, 4), - - Iterator.from(0).take(5).drop(1).map(2 * _).toSeq sameElements Seq(2, 4, 6, 8), - Iterator.from(0).take(5).map(2 * _).drop(1).toSeq sameElements Seq(2, 4, 6, 8), - - Iterator.from(0).take(5).drop(1).drop(2).toSeq sameElements Seq(3, 4), - Iterator.from(0).take(5).drop(2).drop(1).toSeq sameElements Seq(3, 4) - ) - tests.count(result => result) - } - - def check_slice: Int = { - val tests = Array( - Iterator.from(0).slice(3, 7).toSeq sameElements Seq(3, 4, 5, 6), - Iterator.from(0).slice(3, 3).toSeq sameElements Seq(), - Iterator.from(0).slice(-1, 3).toSeq sameElements Seq(0, 1, 2), - Iterator.from(0).slice(3, -1).toSeq sameElements Seq(), - - Iterator.from(0).slice(3, 7).map(2 * _).toSeq sameElements Seq(6, 8, 10, 12), - Iterator.from(0).map(2 * _).slice(3, 7).toSeq sameElements Seq(6, 8, 10, 12), - - Iterator.from(0).slice(3, 7).drop(1).toSeq sameElements Seq(4, 5, 6), - Iterator.from(0).drop(1).slice(3, 7).toSeq sameElements Seq(4, 5, 6, 7), - - Iterator.from(0).slice(3, 7).slice(1, 3).toSeq sameElements Seq(4, 5), - Iterator.from(0).slice(3, 7).slice(1, 10).toSeq sameElements Seq(4, 5, 6) - ) - tests.count(result => result) - } - - def check_foreach: Int = { - val it1 = Iterator.from(0) take 20 - var n = 0 - it1 foreach { n += _ } - n - } - - def check_forall: Int = { - val it1 = Iterator.from(0) - val it2 = Iterator.from(1) - 0 - } - - def check_fromArray: Int = { // ticket #429 - val a = List(1, 2, 3, 4).toArray - var xs0 = a.iterator.toList; - var xs1 = a.slice(0, 1).iterator.toList; - var xs2 = a.slice(0, 2).iterator.toList; - var xs3 = a.slice(0, 3).iterator.toList; - var xs4 = a.slice(0, 4).iterator.toList; - xs0.length + xs1.length + xs2.length + xs3.length + xs4.length - } - - def check_toSeq: String = - List(1, 2, 3, 4, 5).iterator.toSeq.mkString("x") - - def check_indexOf: String = { - val i = List(1, 2, 3, 4, 5).indexOf(4) - val j = List(1, 2, 3, 4, 5).indexOf(16) - "" + i + "x" + j - } - - def check_findIndexOf: String = { - val i = List(1, 2, 3, 4, 5).indexWhere { x: Int => x >= 4 } - val j = List(1, 2, 3, 4, 5).indexWhere { x: Int => x >= 16 } - "" + i + "x" + j - } - - def check_success[A](name: String, closure: => A, expected: A) { - print("test " + name) - try { - val actual: A = closure - if (actual == expected) - print(" was successful") - else - print(" failed: expected "+ expected +", found "+ actual) - } - catch { - case exception: Throwable => - print(" raised exception " + exception) - } - println() - } - - def main(args: Array[String]) { - check_success("check_from", check_from, -1) - check_success("check_range", check_range, 11) - check_success("check_range2", check_range2, 26) - check_success("check_range3", check_range3, 3) - check_success("check_take", check_take, 10) - check_success("check_drop", check_drop, 10) - check_success("check_slice", check_slice, 10) - check_success("check_foreach", check_foreach, 190) - check_success("check_forall", check_forall, 0) - check_success("check_fromArray",check_fromArray, 14) - check_success("check_toSeq", check_toSeq, "1x2x3x4x5") - check_success("check_indexOf", check_indexOf, "3x-1") - check_success("check_findIndexOf", check_findIndexOf, "3x-1") - println() - } -} - -//############################################################################ diff --git a/test/files/run/t3516.check b/test/files/run/t3516.check deleted file mode 100644 index d0d10d82fa..0000000000 --- a/test/files/run/t3516.check +++ /dev/null @@ -1,3 +0,0 @@ -1 -1 -21 diff --git a/test/files/run/t3516.scala b/test/files/run/t3516.scala deleted file mode 100644 index aa302ce85a..0000000000 --- a/test/files/run/t3516.scala +++ /dev/null @@ -1,13 +0,0 @@ -object Test { - def mkIterator = (1 to 5).iterator map (x => { println(x) ; x }) - def mkInfinite = Iterator continually { println(1) ; 1 } - - def main(args: Array[String]): Unit = { - // Stream is strict in its head so we should see 1 from each of them. - val s1 = mkIterator.toStream - val s2 = mkInfinite.toStream - // back and forth without slipping into nontermination. - println((Stream from 1).toIterator.drop(10).toStream.drop(10).toIterator.next) - () - } -} diff --git a/test/junit/scala/collection/IteratorTest.scala b/test/junit/scala/collection/IteratorTest.scala index b7a9805c9f..04af074ac7 100644 --- a/test/junit/scala/collection/IteratorTest.scala +++ b/test/junit/scala/collection/IteratorTest.scala @@ -6,11 +6,12 @@ import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.JUnit4 +import scala.tools.testing.AssertUtil._ + @RunWith(classOf[JUnit4]) class IteratorTest { - @Test - def groupedIteratorShouldNotAskForUnneededElement(): Unit = { + @Test def groupedIteratorShouldNotAskForUnneededElement(): Unit = { var counter = 0 val it = new Iterator[Int] { var i = 0 ; def hasNext = { counter = i; true } ; def next = { i += 1; i } } val slidingIt = it sliding 2 @@ -25,4 +26,147 @@ class IteratorTest { slidingIt.next assertEquals("Counter should be one, that means we didn't look further than needed", 1, counter) } + + @Test def dropDoesNotGrowStack(): Unit = { + def it = new Iterator[Throwable] { def hasNext = true ; def next = new Throwable } + + assertEquals(it.drop(1).next.getStackTrace.length, it.drop(1).drop(1).next.getStackTrace.length) + } + + @Test def dropIsChainable(): Unit = { + assertSameElements(1 to 4, Iterator.from(0).take(5).drop(1).toList) + assertSameElements(3 to 4, Iterator.from(0).take(5).drop(3).toList) + assertSameElements(Seq.empty, Iterator.from(0).take(5).drop(5).toList) + assertSameElements(Seq.empty, Iterator.from(0).take(5).drop(10).toList) + assertSameElements(0 to 4, Iterator.from(0).take(5).drop(0).toList) + assertSameElements(0 to 4, Iterator.from(0).take(5).drop(-1).toList) + assertSameElements(2 to 8 by 2, (Iterator from 0 take 5 drop 1 map (2 * _)).toList) + assertSameElements(2 to 8 by 2, (Iterator from 0 take 5 map (2 * _) drop 1).toList) + assertSameElements(3 to 4, (Iterator from 0 take 5 drop 1 drop 2).toList) + assertSameElements(3 to 4, (Iterator from 0 take 5 drop 2 drop 1).toList) + } + + @Test def sliceIsChainable(): Unit = { + assertSameElements(3 to 6, Iterator from 0 slice (3, 7)) + assertSameElements(Seq.empty, Iterator from 0 slice (3, 3)) + assertSameElements(0 to 2, Iterator from 0 slice (-1, 3)) + assertSameElements(Seq.empty, Iterator from 0 slice (3, -1)) + assertSameElements(6 to 12 by 2, Iterator from 0 slice (3, 7) map (2 * _)) + assertSameElements(6 to 12 by 2, Iterator from 0 map (2 * _) slice (3, 7)) + assertSameElements(4 to 6, Iterator from 0 slice (3, 7) drop 1) + assertSameElements(4 to 7, Iterator from 0 drop 1 slice (3, 7)) + assertSameElements(4 to 5, Iterator from 0 slice (3, 7) slice (1, 3)) + assertSameElements(4 to 6, Iterator from 0 slice (3, 7) slice (1, 10)) + } + + // test/files/run/iterator-concat.scala + @Test def concatIsStackFriendly(): Unit = { + // Create `size` Function0s, each of which evaluates to an Iterator + // which produces 1. Then fold them over ++ to get a single iterator, + // which should sum to "size". + def mk(size: Int): Iterator[Int] = { + //val closures = (1 to size).toList.map(x => (() => Iterator(1))) + //closures.foldLeft(Iterator.empty: Iterator[Int])((res, f) => res ++ f()) + List.fill(size)(() => Iterator(1)).foldLeft(Iterator.empty: Iterator[Int])((res, f) => res ++ f()) + } + assertEquals(100, mk(100).sum) + assertEquals(1000, mk(1000).sum) + assertEquals(10000, mk(10000).sum) + assertEquals(100000, mk(100000).sum) + } + + @Test def from(): Unit = { + val it1 = Iterator.from(-1) + val it2 = Iterator.from(0, -1) + assertEquals(-1, it1.next() + it2.next()) + } + @Test def range(): Unit = { + val xs1 = Iterator.range(0, 10, 2) + val xs2 = Iterator.range(0, 10, -2) + val xs3 = Iterator.range(10, 0, -2) + val xs4 = Iterator.range(10, 0, 2) + val xs5 = Iterator.range(0, 10, 11) + assertEquals(11, xs1.size + xs2.size + xs3.size + xs4.size + xs5.size) + } + @Test def range2(): Unit = { + val r1start = 0 + val r1end = 10 + val r1step = 1 + val r1 = Iterator.range(r1start, r1end, r1step) + val r2 = Iterator.range(r1start, r1end, r1step + 1) + val r3 = Iterator.range(r1end, r1start, -r1step) + val r4 = Iterator.range(0, 10, 11) + // 10 + 5 + 10 + 1 + assertEquals(10 + 5 + 10 + 1, r1.size + r2.size + r3.size + r4.size) + } + @Test def range3(): Unit = { + def trues(xs: List[Boolean]) = xs.foldLeft(0)((a, b) => if (b) a+1 else a) + val r1 = Iterator.range(0, 10) + val xs1 = List(r1 contains 5, r1 contains 6) + val r2a = Iterator.range(0, 10, 2) + val r2b = Iterator.range(0, 10, 2) + val xs2 = List(r2a contains 5, r2b contains 6) + val r3 = Iterator.range(0, 10, 11) + val xs3 = List(r3 contains 5, r3 contains 6) + // 2 + 1 + 0 + assertEquals(2 + 1 + 0, trues(xs1) + trues(xs2) + trues(xs3)) + } + @Test def take(): Unit = { + val it1 = Iterator.from(0) + val xs1 = it1 take 10 + assertEquals(10, xs1.size) + } + @Test def foreach(): Unit = { + val it1 = Iterator.from(0) take 20 + var n = 0 + it1 foreach { n += _ } + assertEquals(190, n) + } + /* ??? + @Test def forall(): Unit = { + val it1 = Iterator.from(0) + val it2 = Iterator.from(1) + 0 + } + */ + // ticket #429 + @Test def fromArray(): Unit = { + val a = List(1, 2, 3, 4).toArray + var xs0 = a.iterator.toList; + var xs1 = a.slice(0, 1).iterator + var xs2 = a.slice(0, 2).iterator + var xs3 = a.slice(0, 3).iterator + var xs4 = a.slice(0, 4).iterator + assertEquals(14, xs0.size + xs1.size + xs2.size + xs3.size + xs4.size) + } + @Test def toSeq(): Unit = { + assertEquals("1x2x3x4x5", List(1, 2, 3, 4, 5).iterator.mkString("x")) + } + @Test def indexOf(): Unit = { + assertEquals(3, List(1, 2, 3, 4, 5).indexOf(4)) + assertEquals(-1, List(1, 2, 3, 4, 5).indexOf(16)) + } + @Test def indexWhere(): Unit = { + assertEquals(3, List(1, 2, 3, 4, 5).indexWhere { x: Int => x >= 4 }) + assertEquals(-1, List(1, 2, 3, 4, 5).indexWhere { x: Int => x >= 16 }) + } + // iterator-iterate-lazy.scala + // was java.lang.UnsupportedOperationException: tail of empty list + @Test def iterateIsSufficientlyLazy(): Unit = { + //Iterator.iterate((1 to 5).toList)(_.tail).takeWhile(_.nonEmpty).toList // suffices + Iterator.iterate((1 to 5).toList)(_.tail).takeWhile(_.nonEmpty).map(_.head).toList + } + // SI-3516 + @Test def toStreamIsSufficientlyLazy(): Unit = { + val results = collection.mutable.ListBuffer.empty[Int] + def mkIterator = (1 to 5).iterator map (x => { results += x ; x }) + def mkInfinite = Iterator continually { results += 1 ; 1 } + + // Stream is strict in its head so we should see 1 from each of them. + val s1 = mkIterator.toStream + val s2 = mkInfinite.toStream + // back and forth without slipping into nontermination. + results += (Stream from 1).toIterator.drop(10).toStream.drop(10).toIterator.next() + assertSameElements(List(1,1,21), results) + } } diff --git a/test/junit/scala/tools/testing/AssertUtil.scala b/test/junit/scala/tools/testing/AssertUtil.scala index 9b4833d46b..83a637783f 100644 --- a/test/junit/scala/tools/testing/AssertUtil.scala +++ b/test/junit/scala/tools/testing/AssertUtil.scala @@ -1,6 +1,11 @@ package scala.tools package testing +import org.junit.Assert +import Assert.fail +import scala.runtime.ScalaRunTime.stringOf +import scala.collection.{ GenIterable, IterableLike } + /** This module contains additional higher-level assert statements * that are ultimately based on junit.Assert primitives. */ @@ -21,6 +26,19 @@ object AssertUtil { throw e else return } - throw new AssertionError("Expression did not throw!") + fail("Expression did not throw!") } + + /** JUnit-style assertion for `IterableLike.sameElements`. + */ + def assertSameElements[A, B >: A](expected: IterableLike[A, _], actual: GenIterable[B], message: String = ""): Unit = + if (!(expected sameElements actual)) + fail( + f"${ if (message.nonEmpty) s"$message " else "" }expected:<${ stringOf(expected) }> but was:<${ stringOf(actual) }>" + ) + + /** Convenient for testing iterators. + */ + def assertSameElements[A, B >: A](expected: IterableLike[A, _], actual: Iterator[B]): Unit = + assertSameElements(expected, actual.toList, "") } -- cgit v1.2.3