package test.collections import org.junit.Test import java.util.ArrayList import java.util.LinkedHashSet import kotlin.test.* fun iterableOf(vararg items: T): Iterable = IterableWrapper(items.toList()) class IterableWrapper(collection: Iterable) : Iterable { private val collection = collection override fun iterator(): Iterator { return collection.iterator() } } class IterableTest : OrderedIterableTests>(iterableOf("foo", "bar"), iterableOf()) class SetTest : IterableTests>(setOf("foo", "bar"), setOf()) class LinkedSetTest : IterableTests>(linkedSetOf("foo", "bar"), linkedSetOf()) class ListTest : OrderedIterableTests>(listOf("foo", "bar"), listOf()) class ArrayListTest : OrderedIterableTests>(arrayListOf("foo", "bar"), arrayListOf()) abstract class OrderedIterableTests>(data: T, empty: T) : IterableTests(data, empty) { @Test fun indexOf() { expect(0) { data.indexOf("foo") } expect(-1) { empty.indexOf("foo") } expect(1) { data.indexOf("bar") } expect(-1) { data.indexOf("zap") } } @Test fun lastIndexOf() { expect(0) { data.lastIndexOf("foo") } expect(-1) { empty.lastIndexOf("foo") } expect(1) { data.lastIndexOf("bar") } expect(-1) { data.lastIndexOf("zap") } } @Test fun indexOfFirst() { expect(-1) { data.indexOfFirst { it.contains("p") } } expect(0) { data.indexOfFirst { it.startsWith('f') } } expect(-1) { empty.indexOfFirst { it.startsWith('f') } } } @Test fun indexOfLast() { expect(-1) { data.indexOfLast { it.contains("p") } } expect(1) { data.indexOfLast { it.length() == 3 } } expect(-1) { empty.indexOfLast { it.startsWith('f') } } } @Test fun elementAt() { expect("foo") { data.elementAt(0) } expect("bar") { data.elementAt(1) } assertFails { data.elementAt(2) } assertFails { data.elementAt(-1) } assertFails { empty.elementAt(0) } expect("foo") { data.elementAtOrElse(0, {""} )} expect("zoo") { data.elementAtOrElse(-1, { "zoo" })} expect("zoo") { data.elementAtOrElse(2, { "zoo" })} expect("zoo") { empty.elementAtOrElse(0) { "zoo" }} expect(null) { empty.elementAtOrNull(0) } } @Test fun first() { expect("foo") { data.first() } assertFails { data.first { it.startsWith("x") } } assertFails { empty.first() } expect("foo") { data.first { it.startsWith("f") } } } @Test fun firstOrNull() { expect(null) { data.firstOrNull { it.startsWith("x") } } expect(null) { empty.firstOrNull() } val f = data.firstOrNull { it.startsWith("f") } assertEquals("foo", f) } @Test fun last() { assertEquals("bar", data.last()) assertFails { data.last { it.startsWith("x") } } assertFails { empty.last() } expect("foo") { data.last { it.startsWith("f") } } } @Test fun lastOrNull() { expect(null) { data.lastOrNull { it.startsWith("x") } } expect(null) { empty.lastOrNull() } expect("foo") { data.lastOrNull { it.startsWith("f") } } } } abstract class IterableTests>(val data: T, val empty: T) { @Test fun any() { expect(true) { data.any() } expect(false) { empty.any() } expect(true) { data.any { it.startsWith("f") } } expect(false) { data.any { it.startsWith("x") } } expect(false) { empty.any { it.startsWith("x") } } } @Test fun all() { expect(true) { data.all { it.length() == 3 } } expect(false) { data.all { it.startsWith("b") } } expect(true) { empty.all { it.startsWith("b") } } } @Test fun none() { expect(false) { data.none() } expect(true) { empty.none() } expect(false) { data.none { it.length() == 3 } } expect(false) { data.none { it.startsWith("b") } } expect(true) { data.none { it.startsWith("x") } } expect(true) { empty.none { it.startsWith("b") } } } @Test fun filter() { val foo = data.filter { it.startsWith("f") } expect(true) { foo is List } expect(true) { foo.all { it.startsWith("f") } } expect(1) { foo.size } assertEquals(listOf("foo"), foo) } @Test fun drop() { val foo = data.drop(1) expect(true) { foo is List } expect(true) { foo.all { it.startsWith("b") } } expect(1) { foo.size } assertEquals(listOf("bar"), foo) } @Test fun dropWhile() { val foo = data.dropWhile { it[0] == 'f' } expect(true) { foo is List } expect(true) { foo.all { it.startsWith("b") } } expect(1) { foo.size } assertEquals(listOf("bar"), foo) } @Test fun filterNot() { val notFoo = data.filterNot { it.startsWith("f") } expect(true) { notFoo is List } expect(true) { notFoo.none { it.startsWith("f") } } expect(1) { notFoo.size } assertEquals(listOf("bar"), notFoo) } @Test fun forEach() { var count = 0 data.forEach { count += it.length() } assertEquals(6, count) } @Test fun contains() { assertTrue(data.contains("foo")) assertTrue("bar" in data) assertTrue("baz" !in data) assertFalse("baz" in empty) } @Test fun single() { assertFails { data.single() } assertFails { empty.single() } expect("foo") { data.single { it.startsWith("f") } } expect("bar") { data.single { it.startsWith("b") } } assertFails { data.single { it.length() == 3 } } } @Test fun singleOrNull() { expect(null) { data.singleOrNull() } expect(null) { empty.singleOrNull() } expect("foo") { data.singleOrNull { it.startsWith("f") } } expect("bar") { data.singleOrNull { it.startsWith("b") } } expect(null) { data.singleOrNull { it.length() == 3 } } } @Test fun map() { val lengths = data.map { it.length() } assertTrue { lengths.all { it == 3 } } assertEquals(2, lengths.size) assertEquals(listOf(3, 3), lengths) } @Test fun flatten() { assertEquals(listOf(0, 1, 2, 3, 0, 1, 2, 3), data.map { 0..it.length() }.flatten()) } @Test fun mapIndexed() { val shortened = data.mapIndexed { index, value -> value.substring(0..index) } assertEquals(2, shortened.size) assertEquals(listOf("f", "ba"), shortened) } @Test fun withIndex() { val indexed = data.withIndex().map { it.value.substring(0..it.index) } assertEquals(2, indexed.size) assertEquals(listOf("f", "ba"), indexed) } @Test fun max() { expect("foo") { data.max() } expect("bar") { data.maxBy { it.last() } } } @Test fun min() { expect("bar") { data.min() } expect("foo") { data.minBy { it.last() } } } @Test fun count() { expect(2) { data.count() } expect(0) { empty.count() } expect(1) { data.count { it.startsWith("f") } } expect(0) { empty.count { it.startsWith("f") } } expect(0) { data.count { it.startsWith("x") } } expect(0) { empty.count { it.startsWith("x") } } } @Test fun sumBy() { expect(6) { data.sumBy { it.length() } } expect(0) { empty.sumBy { it.length() } } expect(3.0) { data.sumByDouble { it.length().toDouble() / 2 } } expect(0.0) { empty.sumByDouble { it.length().toDouble() / 2 } } } @Test fun withIndices() { var index = 0 for ((i, d) in data.withIndex()) { assertEquals(i, index) assertEquals(d, data.elementAt(index)) index++ } assertEquals(data.count(), index) } @Test fun fold() { expect(231) { data.fold(1, { a, b -> a + if (b == "foo") 200 else 30 }) } } @Test fun reduce() { val reduced = data.reduce { a, b -> a + b } assertEquals(6, reduced.length()) assertTrue(reduced == "foobar" || reduced == "barfoo") } @Test fun mapAndJoinToString() { val result = data.joinToString(separator = "-") { it.toUpperCase() } assertEquals("FOO-BAR", result) } fun testPlus(doPlus: (Iterable) -> List) { val result: List = doPlus(data) assertEquals(listOf("foo", "bar", "zoo", "g"), result) assertFalse(result === data) } @Test fun plusElement() = testPlus { it + "zoo" + "g" } @Test fun plusCollection() = testPlus { it + listOf("zoo", "g") } @Test fun plusArray() = testPlus { it + arrayOf("zoo", "g") } @Test fun plusSequence() = testPlus { it + sequenceOf("zoo", "g") } @Test fun plusAssign() { // lets use a mutable variable var result: Iterable = data result += "foo" result += listOf("beer") result += arrayOf("cheese", "wine") result += sequenceOf("zoo", "g") assertEquals(listOf("foo", "bar", "foo", "beer", "cheese", "wine", "zoo", "g"), result) } @Test fun minusElement() { val result = data - "foo" - "g" assertEquals(listOf("bar"), result) } @Test fun minusCollection() { val result = data - listOf("foo", "g") assertEquals(listOf("bar"), result) } @Test fun minusArray() { val result = data - arrayOf("foo", "g") assertEquals(listOf("bar"), result) } @Test fun minusSequence() { val result = data - sequenceOf("foo", "g") assertEquals(listOf("bar"), result) } @Test fun minusAssign() { // lets use a mutable variable var result: Iterable = data result -= "foo" assertEquals(listOf("bar"), result) result = data result -= listOf("beer", "bar") assertEquals(listOf("foo"), result) result = data result -= arrayOf("bar", "foo") assertEquals(emptyList(), result) result = data result -= sequenceOf("foo", "g") assertEquals(listOf("bar"), result) } } fun Iterable.assertSorted(isInOrder: (T, T) -> Boolean): Unit { this.iterator().assertSorted(isInOrder) } fun Iterator.assertSorted(isInOrder: (T, T) -> Boolean) { if (!hasNext()) return var index = 0 var prev = next() while (hasNext()) { index += 1 val next = next() assertTrue(isInOrder(prev, next), "Not in order at position $index, element[${index-1}]: $prev, element[$index]: $next") prev = next } return }