Add tests for windowed and chunked, fix precondition checks
This commit is contained in:
@@ -1524,6 +1524,7 @@ public fun <T> Sequence<T>.windowed(size: Int, step: Int): Sequence<List<T>> {
|
||||
|
||||
@SinceKotlin("1.2")
|
||||
public fun <T, R> Sequence<T>.windowed(size: Int, step: Int, transform: (List<T>) -> R): Sequence<R> {
|
||||
require(size > 0 && step > 0) { "size $size and step $step both must be greater than zero" }
|
||||
return Sequence { windowForwardOnlySequenceImpl(iterator(), size, step, dropTrailing = false).iterator() }.map(transform)
|
||||
}
|
||||
|
||||
|
||||
@@ -18,8 +18,7 @@ package kotlin.collections
|
||||
|
||||
|
||||
internal fun windowIndices(sourceSize: Int, size: Int, step: Int, dropTrailing: Boolean): Sequence<IntRange> {
|
||||
require(size >= 0) { "size should not be negative" }
|
||||
require(step != 0) { "step shouldn't be zero" }
|
||||
require(size > 0 && step > 0) { "size $size and step $step both must be greater than zero" }
|
||||
|
||||
if (sourceSize == 0 || (size > sourceSize && dropTrailing)) {
|
||||
return emptySequence()
|
||||
@@ -54,8 +53,7 @@ internal fun windowIndices(sourceSize: Int, size: Int, step: Int, dropTrailing:
|
||||
}
|
||||
|
||||
internal fun <T> windowForwardOnlySequenceImpl(iterator: Iterator<T>, size: Int, step: Int, dropTrailing: Boolean): Sequence<List<T>> {
|
||||
require(size >= 0) { "size should not be negative" }
|
||||
require(step > 0) { "step should be positive non zero" }
|
||||
require(size > 0 && step > 0) { "size $size and step $step both must be greater than zero" }
|
||||
|
||||
return if (step >= size) {
|
||||
windowForwardWithGap(iterator, size, step, dropTrailing)
|
||||
@@ -278,8 +276,9 @@ internal class RingBuffer<T>(val capacity: Int): Iterable<T> {
|
||||
return if (this < n) (this - n + capacity) else this - n
|
||||
}
|
||||
|
||||
// TODO: replace with Array.fill from stdlib when available in common
|
||||
private fun <T> Array<T>.fill(element: T, fromIndex: Int = 0, toIndex: Int = size): Unit {
|
||||
for (idx in fromIndex .. toIndex) {
|
||||
for (idx in fromIndex .. toIndex-1) {
|
||||
this[idx] = element
|
||||
}
|
||||
}
|
||||
|
||||
@@ -135,6 +135,67 @@ abstract class OrderedIterableTests<T : Iterable<String>>(createFrom: (Array<out
|
||||
assertEquals(listOf("a" to "b"), createFrom("a", "b").pairwise())
|
||||
assertEquals(listOf("a" to "b", "b" to "c"), createFrom("a", "b", "c").pairwise())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun chunked() {
|
||||
val size = 7
|
||||
val data = createFrom(Array(size) { "$it" })
|
||||
val result = data.chunked(4)
|
||||
assertEquals(listOf(
|
||||
listOf("0", "1", "2", "3"),
|
||||
listOf("4", "5", "6")
|
||||
), result)
|
||||
|
||||
val result2 = data.chunked(3) { it.joinToString("") }
|
||||
assertEquals(listOf("012", "345", "6"), result2)
|
||||
|
||||
data.toList().let { expectedSingleChunk ->
|
||||
assertEquals(expectedSingleChunk, data.chunked(size).single())
|
||||
assertEquals(expectedSingleChunk, data.chunked(size + 3).single())
|
||||
}
|
||||
|
||||
assertTrue(empty.chunked(3).isEmpty())
|
||||
|
||||
for (illegalValue in listOf(Int.MIN_VALUE, -1, 0)) {
|
||||
assertFailsWith<IllegalArgumentException>("size $illegalValue") { data.chunked(illegalValue) }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
fun windowed() {
|
||||
val size = 7
|
||||
val data = createFrom(Array(size) { "$it" })
|
||||
val result = data.windowed(4, 2)
|
||||
assertEquals(listOf(
|
||||
listOf("0", "1", "2", "3"),
|
||||
listOf("2", "3", "4", "5"),
|
||||
listOf("4", "5", "6"),
|
||||
listOf("6")
|
||||
), result)
|
||||
|
||||
val result2 = data.windowed(2, 3) { it.joinToString("") }
|
||||
assertEquals(listOf("01", "34", "6"), result2)
|
||||
|
||||
assertEquals(data.chunked(2), data.windowed(2, 2))
|
||||
|
||||
assertEquals(data.take(2), data.windowed(2, size).single())
|
||||
assertEquals(data.take(3), data.windowed(3, size + 3).single())
|
||||
|
||||
val result3 = data.windowed(size, 1)
|
||||
result3.forEachIndexed { index, window ->
|
||||
assertEquals(size - index, window.size, "size of window#$index")
|
||||
}
|
||||
|
||||
assertTrue(empty.windowed(3, 2).isEmpty())
|
||||
|
||||
for (illegalValue in listOf(Int.MIN_VALUE, -1, 0)) {
|
||||
assertFailsWith<IllegalArgumentException>("size $illegalValue") { data.windowed(illegalValue, 1) }
|
||||
assertFailsWith<IllegalArgumentException>("step $illegalValue") { data.windowed(1, illegalValue) }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
abstract class IterableTests<T : Iterable<String>>(val createFrom: (Array<out String>) -> T, val empty: T) {
|
||||
|
||||
@@ -216,6 +216,79 @@ public class SequenceTest {
|
||||
ensureIsIntermediate(source = sequenceOf(1, 2)) { it.pairwise() }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun chunked() {
|
||||
val infiniteSeq = generateSequence(0) { it + 1 }
|
||||
val result = infiniteSeq.chunked(4)
|
||||
assertEquals(listOf(
|
||||
listOf(0, 1, 2, 3),
|
||||
listOf(4, 5, 6, 7)
|
||||
), result.take(2).toList())
|
||||
|
||||
val size = 7
|
||||
val seq = infiniteSeq.take(7)
|
||||
|
||||
val result2 = seq.chunked(3) { it.joinToString("") }
|
||||
assertEquals(listOf("012", "345", "6"), result2.toList())
|
||||
|
||||
seq.toList().let { expectedSingleChunk ->
|
||||
assertEquals(expectedSingleChunk, seq.chunked(size).single())
|
||||
assertEquals(expectedSingleChunk, seq.chunked(size + 3).single())
|
||||
}
|
||||
|
||||
assertTrue(emptySequence<String>().chunked(3).none())
|
||||
|
||||
for (illegalValue in listOf(Int.MIN_VALUE, -1, 0)) {
|
||||
assertFailsWith<IllegalArgumentException>("size $illegalValue") { infiniteSeq.chunked(illegalValue) }
|
||||
}
|
||||
|
||||
ensureIsIntermediate(source = sequenceOf(1, 2, 3)) { it.chunked(2) }
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
fun windowed() {
|
||||
val infiniteSeq = generateSequence(0) { it + 1 }
|
||||
val result = infiniteSeq.windowed(5, 3)
|
||||
result.take(10).forEachIndexed { windowIndex, window ->
|
||||
val startElement = windowIndex * 3
|
||||
assertEquals((startElement until startElement + 5).toList(), window)
|
||||
}
|
||||
|
||||
val size = 7
|
||||
val seq = infiniteSeq.take(7)
|
||||
|
||||
val result1 = seq.windowed(4, 2)
|
||||
assertEquals(listOf(
|
||||
listOf(0, 1, 2, 3),
|
||||
listOf(2, 3, 4, 5),
|
||||
listOf(4, 5, 6),
|
||||
listOf(6)
|
||||
), result1.toList())
|
||||
|
||||
val result2 = seq.windowed(2, 3) { it.joinToString("") }
|
||||
assertEquals(listOf("01", "34", "6"), result2.toList())
|
||||
|
||||
assertEquals(seq.chunked(2).toList(), seq.windowed(2, 2).toList())
|
||||
|
||||
assertEquals(seq.take(2).toList(), seq.windowed(2, size).single())
|
||||
assertEquals(seq.take(3).toList(), seq.windowed(3, size + 3).single())
|
||||
|
||||
val result3 = seq.windowed(size, 1)
|
||||
result3.forEachIndexed { index, window ->
|
||||
assertEquals(size - index, window.size, "size of window#$index")
|
||||
}
|
||||
|
||||
assertTrue(emptySequence<String>().windowed(3, 2).none())
|
||||
|
||||
for (illegalValue in listOf(Int.MIN_VALUE, -1, 0)) {
|
||||
assertFailsWith<IllegalArgumentException>("size $illegalValue") { seq.windowed(illegalValue, 1) }
|
||||
assertFailsWith<IllegalArgumentException>("step $illegalValue") { seq.windowed(1, illegalValue) }
|
||||
}
|
||||
|
||||
ensureIsIntermediate(source = sequenceOf(1, 2, 3)) { it.windowed(2, 1) }
|
||||
}
|
||||
|
||||
@Test fun zip() {
|
||||
expect(listOf("ab", "bc", "cd")) {
|
||||
sequenceOf("a", "b", "c").zip(sequenceOf("b", "c", "d")) { a, b -> a + b }.toList()
|
||||
|
||||
@@ -19,6 +19,8 @@ package test.text
|
||||
import kotlin.test.*
|
||||
import test.*
|
||||
import org.junit.Test
|
||||
import test.collections.behaviors.iteratorBehavior
|
||||
import test.collections.compare
|
||||
|
||||
|
||||
fun createString(content: String): CharSequence = content
|
||||
@@ -849,6 +851,67 @@ class StringTest {
|
||||
assertTrue(arg1("a").pairwise().isEmpty())
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
fun chunked() = withOneCharSequenceArg { arg1 ->
|
||||
val size = 7
|
||||
val data = arg1("abcdefg")
|
||||
val result = data.chunked(4)
|
||||
assertEquals(listOf("abcd", "efg"), result)
|
||||
|
||||
val result2 = data.chunked(3) { it.reversed().toString() }
|
||||
assertEquals(listOf("cba", "fed", "g"), result2)
|
||||
|
||||
data.toString().let { expectedSingleChunk ->
|
||||
assertEquals(expectedSingleChunk, data.chunked(size).single())
|
||||
assertEquals(expectedSingleChunk, data.chunked(size + 3).single())
|
||||
}
|
||||
|
||||
assertTrue(arg1("").chunked(3).isEmpty())
|
||||
|
||||
for (illegalValue in listOf(Int.MIN_VALUE, -1, 0)) {
|
||||
assertFailsWith<IllegalArgumentException>("size $illegalValue") { data.chunked(illegalValue) }
|
||||
}
|
||||
|
||||
for (chunkSize in 1..size + 1) {
|
||||
compare(data.chunked(chunkSize).iterator(), data.chunkedSequence(chunkSize).iterator()) { iteratorBehavior() }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
fun windowed() = withOneCharSequenceArg { arg1 ->
|
||||
val size = 7
|
||||
val data = arg1("abcdefg")
|
||||
val result = data.windowed(4, 2)
|
||||
assertEquals(listOf("abcd", "cdef", "efg", "g"), result)
|
||||
|
||||
val result2 = data.windowed(2, 3) { it.reversed().toString() }
|
||||
assertEquals(listOf("ba", "ed", "g"), result2)
|
||||
|
||||
assertEquals(data.chunked(2), data.windowed(2, 2))
|
||||
|
||||
assertEquals(data.take(2), data.windowed(2, size).single())
|
||||
assertEquals(data.take(3), data.windowed(3, size + 3).single())
|
||||
|
||||
val result3 = data.windowed(size, 1)
|
||||
result3.forEachIndexed { index, window ->
|
||||
assertEquals(size - index, window.length, "size of window#$index")
|
||||
}
|
||||
|
||||
assertTrue(arg1("").windowed(3, 2).isEmpty())
|
||||
|
||||
for (illegalValue in listOf(Int.MIN_VALUE, -1, 0)) {
|
||||
assertFailsWith<IllegalArgumentException>("size $illegalValue") { data.windowed(illegalValue, 1) }
|
||||
assertFailsWith<IllegalArgumentException>("step $illegalValue") { data.windowed(1, illegalValue) }
|
||||
}
|
||||
|
||||
for (window in 1..size + 1) {
|
||||
for (step in 1..size + 1)
|
||||
compare(data.windowed(window, step).iterator(), data.windowedSequence(window, step).iterator()) { iteratorBehavior() }
|
||||
}
|
||||
}
|
||||
|
||||
@Test fun map() = withOneCharSequenceArg { arg1 ->
|
||||
assertEquals(listOf('a', 'b', 'c'), arg1("abc").map { it })
|
||||
|
||||
|
||||
Reference in New Issue
Block a user