package test.collections import test.collections.behaviors.listBehavior import test.collections.behaviors.mapBehavior import test.collections.behaviors.setBehavior import kotlin.test.* class ContainerBuilderTest { private fun mutableCollectionOperations(present: E, absent: E) = listOf.() -> Unit>>( "add(present)" to { add(present) }, "add(absent)" to { add(absent) }, "addAll(listOf(present))" to { addAll(listOf(present)) }, "addAll(listOf(absent))" to { addAll(listOf(absent)) }, "addAll(emptyList())" to { addAll(emptyList()) }, "remove(present)" to { remove(present) }, "remove(absent)" to { remove(absent) }, "removeAll(listOf(present))" to { removeAll(listOf(present)) }, "removeAll(emptyList())" to { removeAll(emptyList()) }, "removeAll(this.toList())" to { removeAll(this.toList()) }, "retainAll(listOf(present))" to { retainAll(listOf(present)) }, "retainAll(emptyList())" to { retainAll(emptyList()) }, "retainAll(this.toList())" to { retainAll(this.toList()) }, "clear()" to { clear() }, "iterator().apply { next() }.remove()" to { iterator().apply { next() }.remove() } ) private fun mutableListOperations(present: E, absent: E) = mutableCollectionOperations(present, absent) + listOf.() -> Unit>>( "add(0, present)" to { add(0, present) }, "addAll(0, listOf(present))" to { addAll(0, listOf(present)) }, "addAll(0, emptyList())" to { addAll(0, emptyList()) }, "removeAt(0)" to { removeAt(0) }, "set(0, present)" to { set(0, present) }, "listIterator().apply { next() }.remove()" to { listIterator().apply { next() }.remove() }, "listIterator(0).apply { next() }.remove()" to { listIterator(0).apply { next() }.remove() }, "listIterator().apply { next() }.set(present)" to { listIterator().apply { next() }.set(present) }, "listIterator().add(present)" to { listIterator().add(present) } ) private fun mutableSetOperations(present: E, absent: E) = mutableCollectionOperations(present, absent) + listOf.() -> Unit>>( // check java.util.AbstractSet.removeAll optimisation "removeAll(List(this.size) { absent })" to { removeAll(List(this.size) { absent }) } ) private fun mutableMapOperations(k: K, v: V) = listOf.() -> Unit>>( "put(k, v)" to { put(k, v) }, "remove(k)" to { remove(k) }, "putAll(mapOf(k to v))" to { putAll(mapOf(k to v)) }, "putAll(emptyMap())" to { putAll(emptyMap()) }, "clear()" to { clear() }, "entries.first().setValue(v)" to { entries.first().setValue(v) }, "entries.iterator().next().setValue(v)" to { entries.iterator().next().setValue(v) } ) @Test fun buildList() { val x = buildList { add('b') add('c') } val subList: MutableList val y = buildList(4) { add('a') addAll(x) add('d') subList = subList(0, 4) } compare(listOf('a', 'b', 'c', 'd'), y) { listBehavior() } compare(listOf('a', 'b', 'c', 'd'), y.subList(0, 4)) { listBehavior() } compare(listOf('b', 'c'), y.subList(1, 4).subList(0, 2)) { listBehavior() } assertEquals(listOf(1), buildList(0) { add(1) }) assertFailsWith { buildList(-1) { add(0) } } assertTrue(y is MutableList) for ((fName, operation) in mutableListOperations('b', 'x')) { assertFailsWith("y.$fName") { y.operation() } assertFailsWith("y.subList(1, 3).$fName") { y.subList(1, 3).operation() } assertFailsWith("subList.$fName") { subList.operation() } } } @Test fun listBuilderSubList() { buildList { addAll(listOf('a', 'b', 'c', 'd', 'e')) val subList = subList(1, 4) compare(listOf('a', 'b', 'c', 'd', 'e'), this) { listBehavior() } compare(listOf('b', 'c', 'd'), subList) { listBehavior() } set(2, '1') compare(listOf('a', 'b', '1', 'd', 'e'), this) { listBehavior() } compare(listOf('b', '1', 'd'), subList) { listBehavior() } subList[2] = '2' compare(listOf('a', 'b', '1', '2', 'e'), this) { listBehavior() } compare(listOf('b', '1', '2'), subList) { listBehavior() } subList.add('3') compare(listOf('a', 'b', '1', '2', '3', 'e'), this) { listBehavior() } compare(listOf('b', '1', '2', '3'), subList) { listBehavior() } val subSubList = subList.subList(2, 4) // buffer reallocation should happen repeat(20) { subSubList.add('x') } repeat(20) { subSubList.add(subSubList.size - 2 * it, 'y') } val addedChars = "xy".repeat(20) compare("ab123${addedChars}e".toList(), this) { listBehavior() } compare("b123$addedChars".toList(), subList) { listBehavior() } compare("23$addedChars".toList(), subSubList) { listBehavior() } } } @Test fun buildSet() { val x = buildSet { add('b') add('c') } val y = buildSet(4) { add('c') addAll(x) add('d') } compare(setOf('c', 'b', 'd'), y) { setBehavior() } assertEquals(setOf(1), buildSet(0) { add(1) }) assertFailsWith { buildSet(-1) { add(0) } } assertTrue(y is MutableSet) for ((fName, operation) in mutableSetOperations('b', 'x')) { assertFailsWith("y.$fName") { y.operation() } } } @Test fun buildMap() { val x = buildMap { put('b', 2) put('c', 3) } val y = buildMap(4) { put('a', 1) put('c', 0) putAll(x) put('d', 4) } compare(mapOf('a' to 1, 'c' to 3, 'b' to 2, 'd' to 4), y) { mapBehavior() } assertEquals(mapOf("a" to 1), buildMap(0) { put("a", 1) }) assertFailsWith { buildMap(-1) { put("x", 1) } } assertTrue(y is MutableMap) for ((fName, operation) in mutableMapOperations('a', 1) + mutableMapOperations('x', 10)) { assertFailsWith("y.$fName") { y.operation() } } for ((fName, operation) in mutableSetOperations('a', 'x')) { assertFailsWith("y.keys.$fName") { y.keys.operation() } } for ((fName, operation) in mutableCollectionOperations(1, 10)) { assertFailsWith("y.values.$fName") { y.values.operation() } } val presentEntry = y.entries.first() val absentEntry: MutableMap.MutableEntry = object : MutableMap.MutableEntry { override val key: Char get() = 'x' override val value: Int get() = 10 override fun setValue(newValue: Int): Int = fail("Unreachable") } for ((fName, operation) in mutableSetOperations(presentEntry, absentEntry)) { assertFailsWith("y.entries.$fName") { y.entries.operation() } } } }