| /* |
| * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. |
| * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. |
| */ |
| |
| package test.collections |
| |
| import kotlin.test.* |
| |
| class IndexOverflowJVMTest { |
| |
| companion object { |
| fun <T> repeatCounted(value: T, count: Long = Int.MAX_VALUE + 1L): Sequence<T> = Sequence { |
| object : Iterator<T> { |
| var counter = count |
| override fun hasNext(): Boolean = counter > 0 |
| override fun next(): T = value.also { counter-- } |
| } |
| } |
| |
| val maxIndexSequence = repeatCounted("k", (Int.MAX_VALUE + 1L) + 1L) // here the last index is one greater than Int.MAX_VALUE |
| val maxIndexIterable = maxIndexSequence.asIterable() |
| |
| |
| val longCountSequence = Sequence { |
| object : Iterator<Long> { |
| var counter = 0L |
| override fun hasNext(): Boolean = true |
| override fun next(): Long = counter++ |
| } |
| } |
| |
| fun assertIndexOverflow(f: () -> Unit) { |
| val ex = assertFailsWith<ArithmeticException>(block = f) |
| assertTrue(ex.message!!.contains("index", ignoreCase = true)) |
| } |
| |
| fun assertCountOverflow(f: () -> Unit) { |
| val ex = assertFailsWith<ArithmeticException>(block = f) |
| assertTrue(ex.message!!.contains("count", ignoreCase = true)) |
| } |
| |
| fun checkIndexPositive(index: Int) { |
| if (index < 0) fail("Encountered negative index") |
| } |
| } |
| |
| @Test |
| fun indexOfOverflowSequence() { |
| assertIndexOverflow { maxIndexSequence.indexOf("j") } |
| assertIndexOverflow { maxIndexSequence.lastIndexOf("k") } |
| assertIndexOverflow { maxIndexSequence.indexOfFirst { false } } |
| assertIndexOverflow { maxIndexSequence.indexOfLast { false } } |
| } |
| |
| @Test |
| fun indexOfOverflowIterable() { |
| assertIndexOverflow { maxIndexIterable.indexOf("j") } |
| assertIndexOverflow { maxIndexIterable.lastIndexOf("k") } |
| assertIndexOverflow { maxIndexIterable.indexOfFirst { false } } |
| assertIndexOverflow { maxIndexIterable.indexOfLast { false } } |
| } |
| |
| |
| @Test |
| fun forEachIndexedOverflow() { |
| assertIndexOverflow { maxIndexSequence.forEachIndexed { index, _ -> checkIndexPositive(index) } } |
| assertIndexOverflow { maxIndexIterable.forEachIndexed { index, _ -> checkIndexPositive(index) } } |
| } |
| |
| @Test |
| fun withIndexOverflow() { |
| assertIndexOverflow { maxIndexSequence.withIndex().forEach { (index, _) -> checkIndexPositive(index) } } |
| assertIndexOverflow { maxIndexIterable.withIndex().forEach { (index, _) -> checkIndexPositive(index) } } |
| } |
| |
| |
| @Test |
| fun countOverflow() { |
| assertCountOverflow { repeatCounted("k").count() } |
| assertCountOverflow { repeatCounted("k").count { true } } |
| assertCountOverflow { repeatCounted("k").asIterable().count() } |
| assertCountOverflow { repeatCounted("k").asIterable().count { true } } |
| } |
| |
| @Test |
| fun averageCountOverflow() { |
| assertCountOverflow { repeatCounted(1.0).average() } |
| assertCountOverflow { repeatCounted(1L).asIterable().average() } |
| } |
| |
| |
| private class CountingCollection<T> : AbstractMutableCollection<T>() { |
| private var _size = 0 |
| |
| override fun add(element: T): Boolean { |
| if (_size < 0) error("Collection is too long") |
| _size++ |
| return true |
| } |
| |
| override val size: Int get() = _size |
| |
| override fun iterator(): MutableIterator<T> = error("not implemented") |
| } |
| |
| @Test |
| fun mapIndexedOverflow() { |
| assertIndexOverflow { maxIndexSequence.mapIndexed { index, _ -> checkIndexPositive(index) }.forEach { } } |
| assertIndexOverflow { maxIndexSequence.mapIndexedTo(CountingCollection()) { index, _ -> checkIndexPositive(index) } } |
| assertIndexOverflow { maxIndexIterable.mapIndexedTo(CountingCollection()) { index, _ -> checkIndexPositive(index) } } |
| } |
| |
| @Test |
| fun mapNotNullIndexedOverflow() { |
| assertIndexOverflow { maxIndexSequence.mapIndexedNotNull { index, _ -> checkIndexPositive(index) }.forEach { } } |
| assertIndexOverflow { maxIndexSequence.mapIndexedNotNullTo(CountingCollection()) { index, _ -> checkIndexPositive(index) } } |
| assertIndexOverflow { maxIndexIterable.mapIndexedNotNullTo(CountingCollection()) { index, _ -> checkIndexPositive(index) } } |
| } |
| |
| @Test |
| fun filterIndexedOverflow() { |
| assertIndexOverflow { maxIndexSequence.filterIndexed { index, _ -> checkIndexPositive(index); true }.forEach { } } |
| assertIndexOverflow { maxIndexSequence.filterIndexedTo(CountingCollection()) { index, _ -> checkIndexPositive(index); true } } |
| assertIndexOverflow { maxIndexIterable.filterIndexedTo(CountingCollection()) { index, _ -> checkIndexPositive(index); true } } |
| } |
| |
| |
| @Test |
| fun foldIndexedOverflow() { |
| assertIndexOverflow { maxIndexSequence.foldIndexed("") { index, _, s -> checkIndexPositive(index); s } } |
| assertIndexOverflow { maxIndexIterable.foldIndexed("") { index, _, s -> checkIndexPositive(index); s } } |
| } |
| |
| @Test |
| fun reduceIndexedOverflow() { |
| assertIndexOverflow { maxIndexSequence.reduceIndexed { index, _, s -> checkIndexPositive(index); s } } |
| assertIndexOverflow { maxIndexIterable.reduceIndexed { index, _, s -> checkIndexPositive(index); s } } |
| } |
| |
| |
| @Test |
| fun scanIndexedOverflow() { |
| assertIndexOverflow { maxIndexSequence.scanIndexed("") { index, _, s -> checkIndexPositive(index); s }.forEach { } } |
| } |
| |
| @Test |
| fun runningReduceIndexedOverflow() { |
| assertIndexOverflow { maxIndexSequence.runningReduceIndexed { index, _, s -> checkIndexPositive(index); s }.forEach { } } |
| } |
| |
| |
| @Test |
| fun dropTwiceMaxValue() { |
| |
| val halfMax = (1 shl 30) + 1 |
| |
| val dropOnce = longCountSequence.drop(halfMax) |
| val dropTwice = dropOnce.drop(halfMax) |
| |
| val expectedEnd = halfMax.toLong() * 2 |
| |
| assertEquals(expectedEnd, dropTwice.first()) |
| |
| val dropTake = dropOnce.take(halfMax + 1) |
| |
| assertEquals(expectedEnd, dropTake.last()) |
| } |
| |
| @Test |
| fun dropMaxValue() { |
| val range = 0L..Int.MAX_VALUE + 1L |
| assertEquals(listOf(Int.MAX_VALUE.toLong(), Int.MAX_VALUE + 1L), range.drop(Int.MAX_VALUE)) |
| } |
| |
| } |