Initial.
This commit is contained in:
@@ -0,0 +1,19 @@
|
||||
package collections
|
||||
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertFalse
|
||||
|
||||
class HashmapTests : ImperialMutableMapTestsParent() {
|
||||
override fun emptyCustomMutableMapStringInt(): ImperialMutableMap<String, Int> =
|
||||
Hashmap(::SinglyLinkedList)
|
||||
|
||||
override fun emptyCustomMutableMapCollidingStringInt(): ImperialMutableMap<CollidingString, Int> =
|
||||
Hashmap(::SinglyLinkedList)
|
||||
|
||||
// This test is present merely to ensure that at least one concrete test case exists.
|
||||
// The real tests are inherited from the abstract superclass.
|
||||
@Test
|
||||
fun `trivial test`() {
|
||||
assertFalse(emptyCustomMutableMapStringInt().iterator().hasNext())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package collections
|
||||
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
class ImperialMutableListUtilitiesTests {
|
||||
|
||||
@Test
|
||||
fun `removeAll matching list types`() {
|
||||
val list1: ImperialMutableList<String> = SinglyLinkedList()
|
||||
list1.add(0, "a")
|
||||
list1.add(0, "b")
|
||||
list1.add(0, "c")
|
||||
list1.add(0, "d")
|
||||
list1.add(0, "e")
|
||||
val list2: ImperialMutableList<String> = SinglyLinkedList()
|
||||
list2.add(0, "a")
|
||||
list2.add(0, "b")
|
||||
list2.add(0, "c")
|
||||
list1.removeAll(list2)
|
||||
assertEquals(2, list1.size)
|
||||
assertEquals("e", list1[0])
|
||||
assertEquals("d", list1[1])
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `removeAll different list types`() {
|
||||
val list1: ImperialMutableList<Any> = SinglyLinkedList()
|
||||
list1.add(0, "a")
|
||||
list1.add(0, "b")
|
||||
list1.add(0, "c")
|
||||
list1.add(0, 1)
|
||||
list1.add(0, 2)
|
||||
list1.add(0, 3)
|
||||
val list2: ImperialMutableList<String> = SinglyLinkedList()
|
||||
list2.add(0, "a")
|
||||
list2.add(0, "b")
|
||||
list2.add(0, "c")
|
||||
list1.removeAll(list2)
|
||||
assertEquals(3, list1.size)
|
||||
assertEquals(3, list1[0])
|
||||
assertEquals(2, list1[1])
|
||||
assertEquals(1, list1[2])
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,257 @@
|
||||
package collections
|
||||
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertFalse
|
||||
import kotlin.test.assertNotNull
|
||||
import kotlin.test.assertNull
|
||||
import kotlin.test.assertTrue
|
||||
import kotlin.test.fail
|
||||
|
||||
abstract class ImperialMutableMapTestsParent {
|
||||
abstract fun emptyCustomMutableMapStringInt(): ImperialMutableMap<String, Int>
|
||||
|
||||
abstract fun emptyCustomMutableMapCollidingStringInt(): ImperialMutableMap<CollidingString, Int>
|
||||
|
||||
@Test
|
||||
fun `test contains when empty`() {
|
||||
val map = emptyCustomMutableMapStringInt()
|
||||
assertFalse(map.contains("Hello"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test remove when empty`() {
|
||||
val map = emptyCustomMutableMapStringInt()
|
||||
assertNull(map.remove("Hello"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test size when empty`() {
|
||||
val map = emptyCustomMutableMapStringInt()
|
||||
assertEquals(0, map.size)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test contains after put`() {
|
||||
val map = emptyCustomMutableMapStringInt()
|
||||
map.put("Hello", 3)
|
||||
assertTrue(map.contains("Hello"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test remove after put`() {
|
||||
val map = emptyCustomMutableMapStringInt()
|
||||
map.put("Hello", 3)
|
||||
assertNull(map.remove("World"))
|
||||
assertEquals(3, map.remove("Hello"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test size after put`() {
|
||||
val map = emptyCustomMutableMapStringInt()
|
||||
map.put("Hello", 3)
|
||||
assertEquals(1, map.size)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test get returns null`() {
|
||||
val map = emptyCustomMutableMapStringInt()
|
||||
map.put("Hello", 3)
|
||||
map.put("World", 4)
|
||||
assertNull(map["You"])
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test get returns latest value`() {
|
||||
val map = emptyCustomMutableMapStringInt()
|
||||
map["Hello"] = 3
|
||||
map["World"] = 4
|
||||
map["Hello"] = 10
|
||||
map["Hello"] = 11
|
||||
assertEquals(11, map["Hello"])
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test entries initially empty`() {
|
||||
val map = emptyCustomMutableMapStringInt()
|
||||
for (e in map) {
|
||||
fail("Map entries should be empty")
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test entries after some putting`() {
|
||||
val map = emptyCustomMutableMapStringInt()
|
||||
val entries = (1..100).map {
|
||||
ImperialMutableMap.Entry(it.toString(), it)
|
||||
}
|
||||
entries.forEach {
|
||||
map.put(it.key, it.value)
|
||||
}
|
||||
assertEquals(entries.size, map.size)
|
||||
assertEquals(entries, map.toSet().sortedBy { it.value })
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test entries after some setting`() {
|
||||
val map = emptyCustomMutableMapStringInt()
|
||||
val expected: List<ImperialMutableMap.Entry<String, Int>> = (1..100).map {
|
||||
ImperialMutableMap.Entry(it.toString(), it)
|
||||
}
|
||||
expected.forEach {
|
||||
map[it.key] = it.value
|
||||
}
|
||||
assertEquals(expected.size, map.size)
|
||||
assertEquals(expected, map.toList().sortedBy { it.value })
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test entries after some putting, removing and setting`() {
|
||||
val map = createCustomMutableMapByPuttingRemovingAndSetting()
|
||||
val expected = createExpectedEntriesFromPuttingRemovingAndSetting()
|
||||
assertEquals(expected.size, map.size)
|
||||
assertEquals(expected, map.toList().sortedBy { it.value })
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test entries after some putting (collision prone)`() {
|
||||
val map = emptyCustomMutableMapCollidingStringInt()
|
||||
val expected = (1..100).map {
|
||||
ImperialMutableMap.Entry(CollidingString(it.toString()), it)
|
||||
}
|
||||
expected.forEach {
|
||||
map.put(it.key, it.value)
|
||||
}
|
||||
assertEquals(expected.size, map.size)
|
||||
assertEquals(expected, map.toList().sortedBy { it.value })
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test entries after some setting (collision prone)`() {
|
||||
val map = emptyCustomMutableMapCollidingStringInt()
|
||||
val expected = (1..100).map {
|
||||
ImperialMutableMap.Entry(CollidingString(it.toString()), it)
|
||||
}
|
||||
expected.forEach {
|
||||
map[it.key] = it.value
|
||||
}
|
||||
assertEquals(expected.size, map.size)
|
||||
assertEquals(expected, map.toList().sortedBy { it.value })
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test entries after some putting, removing and setting (collision prone)`() {
|
||||
val map = createCollisionProneMapByPuttingRemovingAndSetting()
|
||||
val expected = createCollisionProneExpectedEntriesFromPuttingRemovingAndSetting()
|
||||
assertEquals(expected.size, map.size)
|
||||
assertEquals(expected, map.toList().sortedBy { it.value })
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `performance test 1`() {
|
||||
println("Performance test started.")
|
||||
val map = emptyCustomMutableMapStringInt()
|
||||
for (i in 0..<1000000) {
|
||||
if (i.mod(10000) == 0) {
|
||||
println("Added $i elements out of 1000000. These messages should fly by if performance is adequate.")
|
||||
}
|
||||
map.put(i.toString(), i)
|
||||
}
|
||||
assertEquals(1000000, map.size)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `performance test 2`() {
|
||||
println("Performance test started.")
|
||||
val map = emptyCustomMutableMapCollidingStringInt()
|
||||
for (i in 0..<20000) {
|
||||
if (i.mod(100) == 0) {
|
||||
println("Added $i elements out of 20000. These messages should fly by if performance is adequate.")
|
||||
}
|
||||
map.put(CollidingString(i.toString()), i)
|
||||
}
|
||||
assertEquals(20000, map.size)
|
||||
}
|
||||
|
||||
class CollidingString(val string: String) : Comparable<CollidingString> {
|
||||
override fun hashCode(): Int = 5
|
||||
override fun compareTo(other: CollidingString): Int = string.compareTo(other.string)
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (other is CollidingString) {
|
||||
return string == other.string
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
private fun createCustomMutableMapByPuttingRemovingAndSetting(): ImperialMutableMap<String, Int> {
|
||||
val map = emptyCustomMutableMapStringInt()
|
||||
for (i in 1..100) {
|
||||
assertFalse(map.contains(i.toString()))
|
||||
assertNull(map[i.toString()])
|
||||
assertNull(map.put(i.toString(), i))
|
||||
}
|
||||
for (i in 1..100) {
|
||||
assertTrue(map.contains(i.toString()))
|
||||
assertEquals(i, map[i.toString()])
|
||||
if (i % 2 == 0) {
|
||||
val previous = map.remove(i.toString())
|
||||
assertNotNull(previous)
|
||||
assertEquals(i, previous)
|
||||
}
|
||||
}
|
||||
for (i in 1..100) {
|
||||
if (i % 4 == 0) {
|
||||
assertNull(map[i.toString()])
|
||||
assertFalse(map.contains(i.toString()))
|
||||
assertNull(map.set(i.toString(), i))
|
||||
}
|
||||
}
|
||||
return map
|
||||
}
|
||||
|
||||
private fun createExpectedEntriesFromPuttingRemovingAndSetting(): List<ImperialMutableMap.Entry<String, Int>> {
|
||||
val entries = (1..100).map {
|
||||
ImperialMutableMap.Entry(it.toString(), it)
|
||||
}.filter {
|
||||
it.value % 2 != 0 || it.value % 4 == 0
|
||||
}
|
||||
return entries
|
||||
}
|
||||
|
||||
private fun createCollisionProneMapByPuttingRemovingAndSetting(): ImperialMutableMap<CollidingString, Int> {
|
||||
val map = emptyCustomMutableMapCollidingStringInt()
|
||||
for (i in 1..100) {
|
||||
assertFalse(map.contains(CollidingString(i.toString())))
|
||||
assertNull(map[CollidingString(i.toString())])
|
||||
assertNull(map.put(CollidingString(i.toString()), i))
|
||||
}
|
||||
for (i in 1..100) {
|
||||
assertTrue(map.contains(CollidingString(i.toString())))
|
||||
assertEquals(i, map[CollidingString(i.toString())])
|
||||
if (i % 2 == 0) {
|
||||
val previous = map.remove(CollidingString(i.toString()))
|
||||
assertNotNull(previous)
|
||||
assertEquals(i, previous)
|
||||
}
|
||||
}
|
||||
for (i in 1..100) {
|
||||
if (i % 4 == 0) {
|
||||
assertNull(map.get(CollidingString(i.toString())))
|
||||
assertFalse(map.contains(CollidingString(i.toString())))
|
||||
assertNull(map.set(CollidingString(i.toString()), i))
|
||||
}
|
||||
}
|
||||
return map
|
||||
}
|
||||
|
||||
private fun createCollisionProneExpectedEntriesFromPuttingRemovingAndSetting(): List<ImperialMutableMap.Entry<CollidingString, Int>> {
|
||||
val entries = (1..100).map {
|
||||
ImperialMutableMap.Entry(CollidingString(it.toString()), it)
|
||||
}.filter {
|
||||
it.value % 2 != 0 || it.value % 4 == 0
|
||||
}
|
||||
return entries
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,423 @@
|
||||
package collections
|
||||
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertFalse
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
private val exampleStrings: Array<String> = arrayOf(
|
||||
"cat",
|
||||
"dog",
|
||||
"frog",
|
||||
"horse",
|
||||
"zebra",
|
||||
"wildebeest",
|
||||
"vulture",
|
||||
"hyena",
|
||||
"warthog",
|
||||
"hyrax",
|
||||
)
|
||||
|
||||
class ResizingArrayListTests {
|
||||
|
||||
@Test
|
||||
fun `test get (String)`() {
|
||||
val list = ResizingArrayList<String>(10)
|
||||
for (i in 0..<10) {
|
||||
list.add(i, exampleStrings[i])
|
||||
assertEquals(i + 1, list.size)
|
||||
}
|
||||
for (i in 0..<10) {
|
||||
assertEquals(exampleStrings[i], list[i])
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test add (String)`() {
|
||||
val list = ResizingArrayList<String>(10)
|
||||
for (i in 1..10) {
|
||||
list.add(i - 1, exampleStrings[i - 1])
|
||||
assertEquals(i, list.size)
|
||||
}
|
||||
assertEquals(
|
||||
exampleStrings.joinToString(prefix = "[", postfix = "]"),
|
||||
list.toString(),
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test add (String) with zero initial capacity`() {
|
||||
val list = ResizingArrayList<String>(0)
|
||||
for (i in 1..10) {
|
||||
list.add(i - 1, exampleStrings[i - 1])
|
||||
assertEquals(i, list.size)
|
||||
}
|
||||
assertEquals(
|
||||
exampleStrings.joinToString(prefix = "[", postfix = "]"),
|
||||
list.toString(),
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test add with resize (String)`() {
|
||||
val list = ResizingArrayList<String>(1)
|
||||
for (i in 0..256) {
|
||||
list.add(i, i.toString())
|
||||
}
|
||||
for (i in 0..256) {
|
||||
assertEquals(i.toString(), list[i])
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test add at start with resize (String)`() {
|
||||
val list = ResizingArrayList<String>(1)
|
||||
for (i in 0..256) {
|
||||
list.add(0, i.toString())
|
||||
}
|
||||
for (i in 0..256) {
|
||||
assertEquals(i.toString(), list[256 - i])
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test add in middle (String)`() {
|
||||
val list = ResizingArrayList<String>(10)
|
||||
for (i in 1..5) {
|
||||
list.add(i - 1, exampleStrings[i])
|
||||
assertEquals(i, list.size)
|
||||
}
|
||||
assertEquals(5, list.size)
|
||||
list.add(3, "blob")
|
||||
assertEquals(6, list.size)
|
||||
assertEquals("[dog, frog, horse, blob, zebra, wildebeest]", list.toString())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test add at end (String)`() {
|
||||
val list = ResizingArrayList<String>(10)
|
||||
for (i in 1..5) {
|
||||
list.add(i - 1, exampleStrings[i])
|
||||
assertEquals(i, list.size)
|
||||
}
|
||||
list.add(5, "blob")
|
||||
assertEquals(6, list.size)
|
||||
assertEquals("[dog, frog, horse, zebra, wildebeest, blob]", list.toString())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test resize in add-at-index if list is full (String)`() {
|
||||
val list = ResizingArrayList<String>(1)
|
||||
list.add(0, "blob")
|
||||
list.add(0, "blib")
|
||||
assertEquals("blib", list[0])
|
||||
assertEquals("blob", list[1])
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test clear (String)`() {
|
||||
val list = ResizingArrayList<String>(10)
|
||||
for (i in 1..5) {
|
||||
list.add(i - 1, exampleStrings[i])
|
||||
assertEquals(i, list.size)
|
||||
}
|
||||
list.clear()
|
||||
assertEquals(0, list.size)
|
||||
assertEquals("[]", list.toString())
|
||||
list.clear()
|
||||
assertEquals(0, list.size)
|
||||
assertEquals("[]", list.toString())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test toString empty (String)`() {
|
||||
val list = ResizingArrayList<String>()
|
||||
assertEquals(0, list.size)
|
||||
assertEquals("[]", list.toString())
|
||||
val trivialList = ResizingArrayList<String>(0)
|
||||
assertEquals(0, trivialList.size)
|
||||
assertEquals("[]", trivialList.toString())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test set (String)`() {
|
||||
val list = ResizingArrayList<String>()
|
||||
list.add(0, "one")
|
||||
list.add(1, "two")
|
||||
list.add(2, "three")
|
||||
assertEquals("one", list.set(0, "forty two"))
|
||||
assertEquals("two", list.set(1, "forty three"))
|
||||
assertEquals("three", list.set(2, "forty four"))
|
||||
assertEquals(3, list.size)
|
||||
assertEquals("[forty two, forty three, forty four]", list.toString())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test get (Int)`() {
|
||||
val list = ResizingArrayList<Int>(10)
|
||||
for (i in 1..10) {
|
||||
list.add(i - 1, i)
|
||||
assertEquals(i, list.size)
|
||||
}
|
||||
for (i in 1..10) {
|
||||
assertEquals(i, list[i - 1])
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test add (Int)`() {
|
||||
val list = ResizingArrayList<Int>(10)
|
||||
for (i in 1..10) {
|
||||
list.add(i - 1, i)
|
||||
assertEquals(i, list.size)
|
||||
}
|
||||
assertEquals("[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]", list.toString())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test add with resize (Int)`() {
|
||||
val list = ResizingArrayList<Int>(1)
|
||||
for (i in 0..256) {
|
||||
list.add(i, i)
|
||||
}
|
||||
for (i in 0..256) {
|
||||
assertEquals(i, list[i])
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test add in middle (Int)`() {
|
||||
val list = ResizingArrayList<Int>(10)
|
||||
for (i in 1..5) {
|
||||
list.add(i - 1, i)
|
||||
assertEquals(i, list.size)
|
||||
}
|
||||
assertEquals(5, list.size)
|
||||
list.add(3, 42)
|
||||
assertEquals(6, list.size)
|
||||
assertEquals("[1, 2, 3, 42, 4, 5]", list.toString())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test add at end (Int)`() {
|
||||
val list = ResizingArrayList<Int>(10)
|
||||
for (i in 1..5) {
|
||||
list.add(i - 1, i)
|
||||
assertEquals(i, list.size)
|
||||
}
|
||||
list.add(5, 42)
|
||||
assertEquals(6, list.size)
|
||||
assertEquals("[1, 2, 3, 4, 5, 42]", list.toString())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test resize in add-at-index if list is full (Int)`() {
|
||||
val list = ResizingArrayList<Int>(1)
|
||||
list.add(0, 1)
|
||||
list.add(0, 2)
|
||||
assertEquals(2, list[0])
|
||||
assertEquals(1, list[1])
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test clear (Int)`() {
|
||||
val list = ResizingArrayList<Int>(10)
|
||||
for (i in 1..5) {
|
||||
list.add(i - 1, i)
|
||||
assertEquals(i, list.size)
|
||||
}
|
||||
list.clear()
|
||||
assertEquals(0, list.size)
|
||||
assertEquals("[]", list.toString())
|
||||
list.clear()
|
||||
assertEquals(0, list.size)
|
||||
assertEquals("[]", list.toString())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test toString empty (Int)`() {
|
||||
val list = ResizingArrayList<Int>(10)
|
||||
assertEquals(0, list.size)
|
||||
assertEquals("[]", list.toString())
|
||||
val trivialList = ResizingArrayList<Int>(0)
|
||||
assertEquals(0, trivialList.size)
|
||||
assertEquals("[]", trivialList.toString())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test set (Int)`() {
|
||||
val list = ResizingArrayList<Int>(10)
|
||||
list.add(0, 1)
|
||||
list.add(1, 2)
|
||||
list.add(2, 3)
|
||||
assertEquals(1, list.set(0, 42))
|
||||
assertEquals(2, list.set(1, 43))
|
||||
assertEquals(3, list.set(2, 44))
|
||||
assertEquals(3, list.size)
|
||||
assertEquals("[42, 43, 44]", list.toString())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test addAll to zero-capacity list`() {
|
||||
val initiallyEmptyList: ImperialMutableList<Int> = ResizingArrayList(0)
|
||||
val smallList: ImperialMutableList<Int> = ResizingArrayList(2)
|
||||
for (i in 1..10) {
|
||||
smallList.add(i - 1, i)
|
||||
}
|
||||
initiallyEmptyList.addAll(0, smallList)
|
||||
assertEquals(10, initiallyEmptyList.size)
|
||||
assertEquals(1, initiallyEmptyList[0])
|
||||
assertEquals(2, initiallyEmptyList[1])
|
||||
assertEquals(3, initiallyEmptyList[2])
|
||||
assertEquals(4, initiallyEmptyList[3])
|
||||
assertEquals(5, initiallyEmptyList[4])
|
||||
assertEquals(6, initiallyEmptyList[5])
|
||||
assertEquals(7, initiallyEmptyList[6])
|
||||
assertEquals(8, initiallyEmptyList[7])
|
||||
assertEquals(9, initiallyEmptyList[8])
|
||||
assertEquals(10, initiallyEmptyList[9])
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test addAll small`() {
|
||||
val firstSmallList: ImperialMutableList<Int> = ResizingArrayList(2)
|
||||
val secondSmallList: ImperialMutableList<Int> = ResizingArrayList(2)
|
||||
for (i in 1..10) {
|
||||
firstSmallList.add(i - 1, i)
|
||||
secondSmallList.add(i - 1, -i)
|
||||
}
|
||||
firstSmallList.addAll(firstSmallList.size, secondSmallList)
|
||||
assertEquals(20, firstSmallList.size)
|
||||
assertEquals(1, firstSmallList[0])
|
||||
assertEquals(2, firstSmallList[1])
|
||||
assertEquals(3, firstSmallList[2])
|
||||
assertEquals(4, firstSmallList[3])
|
||||
assertEquals(5, firstSmallList[4])
|
||||
assertEquals(6, firstSmallList[5])
|
||||
assertEquals(7, firstSmallList[6])
|
||||
assertEquals(8, firstSmallList[7])
|
||||
assertEquals(9, firstSmallList[8])
|
||||
assertEquals(10, firstSmallList[9])
|
||||
assertEquals(-1, firstSmallList[10])
|
||||
assertEquals(-2, firstSmallList[11])
|
||||
assertEquals(-3, firstSmallList[12])
|
||||
assertEquals(-4, firstSmallList[13])
|
||||
assertEquals(-5, firstSmallList[14])
|
||||
assertEquals(-6, firstSmallList[15])
|
||||
assertEquals(-7, firstSmallList[16])
|
||||
assertEquals(-8, firstSmallList[17])
|
||||
assertEquals(-9, firstSmallList[18])
|
||||
assertEquals(-10, firstSmallList[19])
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test addAll at index small`() {
|
||||
val firstSmallList: ImperialMutableList<Int> = ResizingArrayList(2)
|
||||
val secondSmallList: ImperialMutableList<Int> = ResizingArrayList(2)
|
||||
for (i in 1..10) {
|
||||
firstSmallList.add(i - 1, i)
|
||||
secondSmallList.add(i - 1, -i)
|
||||
}
|
||||
firstSmallList.addAll(5, secondSmallList)
|
||||
assertEquals(20, firstSmallList.size)
|
||||
assertEquals(1, firstSmallList[0])
|
||||
assertEquals(2, firstSmallList[1])
|
||||
assertEquals(3, firstSmallList[2])
|
||||
assertEquals(4, firstSmallList[3])
|
||||
assertEquals(5, firstSmallList[4])
|
||||
assertEquals(-1, firstSmallList[5])
|
||||
assertEquals(-2, firstSmallList[6])
|
||||
assertEquals(-3, firstSmallList[7])
|
||||
assertEquals(-4, firstSmallList[8])
|
||||
assertEquals(-5, firstSmallList[9])
|
||||
assertEquals(-6, firstSmallList[10])
|
||||
assertEquals(-7, firstSmallList[11])
|
||||
assertEquals(-8, firstSmallList[12])
|
||||
assertEquals(-9, firstSmallList[13])
|
||||
assertEquals(-10, firstSmallList[14])
|
||||
assertEquals(6, firstSmallList[15])
|
||||
assertEquals(7, firstSmallList[16])
|
||||
assertEquals(8, firstSmallList[17])
|
||||
assertEquals(9, firstSmallList[18])
|
||||
assertEquals(10, firstSmallList[19])
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test addAll at start`() {
|
||||
val list1: ImperialMutableList<Int> = ResizingArrayList()
|
||||
val list2: ImperialMutableList<Int> = ResizingArrayList()
|
||||
list1.add(0, 1)
|
||||
list1.add(1, 2)
|
||||
list1.add(2, 3)
|
||||
list2.add(0, 4)
|
||||
list2.add(1, 5)
|
||||
list2.add(2, 6)
|
||||
list1.addAll(0, list2)
|
||||
assertEquals(6, list1.size)
|
||||
assertEquals(4, list1[0])
|
||||
assertEquals(5, list1[1])
|
||||
assertEquals(6, list1[2])
|
||||
assertEquals(1, list1[3])
|
||||
assertEquals(2, list1[4])
|
||||
assertEquals(3, list1[5])
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test addAll at end`() {
|
||||
val list1: ImperialMutableList<Int> = ResizingArrayList()
|
||||
val list2: ImperialMutableList<Int> = ResizingArrayList()
|
||||
list1.add(0, 1)
|
||||
list1.add(1, 2)
|
||||
list1.add(2, 3)
|
||||
list2.add(0, 4)
|
||||
list2.add(1, 5)
|
||||
list2.add(2, 6)
|
||||
list1.addAll(3, list2)
|
||||
assertEquals(6, list1.size)
|
||||
assertEquals(1, list1[0])
|
||||
assertEquals(2, list1[1])
|
||||
assertEquals(3, list1[2])
|
||||
assertEquals(4, list1[3])
|
||||
assertEquals(5, list1[4])
|
||||
assertEquals(6, list1[5])
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `size is 0`() {
|
||||
assertEquals(0, ResizingArrayList<Int>().size)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `iterator has next when empty`() {
|
||||
assertFalse(ResizingArrayList<Int>().iterator().hasNext())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `iterate over elements`() {
|
||||
val list: ImperialMutableList<String> = ResizingArrayList()
|
||||
list.add(0, "a")
|
||||
list.add(1, "b")
|
||||
list.add(2, "c")
|
||||
val iterator = list.iterator()
|
||||
assertTrue(iterator.hasNext())
|
||||
assertEquals("a", iterator.next())
|
||||
assertTrue(iterator.hasNext())
|
||||
assertEquals("b", iterator.next())
|
||||
assertTrue(iterator.hasNext())
|
||||
assertEquals("c", iterator.next())
|
||||
assertFalse(iterator.hasNext())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `concatenate with iterator`() {
|
||||
val list: ImperialMutableList<String> = ResizingArrayList()
|
||||
list.add(0, "a")
|
||||
list.add(1, "b")
|
||||
list.add(2, "c")
|
||||
val concatenation = StringBuilder()
|
||||
for (string in list) {
|
||||
concatenation.append(string)
|
||||
}
|
||||
assertEquals("abc", concatenation.toString())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
package collections
|
||||
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.fail
|
||||
|
||||
// These are examples of the kinds of imports that may be useful when writing tests.
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertFalse
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
class SinglyLinkedListExtraTests {
|
||||
|
||||
/* TODO - replace this placeholder test with a number of your own tests.
|
||||
@Test
|
||||
fun `placeholder test`() {
|
||||
fail()
|
||||
}
|
||||
• The tests you write for remove should confirm that the method behaves correctly
|
||||
when invoked with an element that does appear in the list, and when invoked with
|
||||
an element that does not appear in the list.
|
||||
• Each test should be designed with a specific purpose, and the name of the test should
|
||||
reflect this purpose.
|
||||
• Think about “edge case” inputs to these functions when deciding on test inputs.
|
||||
*/
|
||||
@Test
|
||||
fun `remove element in list`() {
|
||||
val list: ImperialMutableList<String> = SinglyLinkedList()
|
||||
list.add(0, "a")
|
||||
list.add(1, "b")
|
||||
list.add(2, "c")
|
||||
assertEquals(list.remove("b"),true)
|
||||
assertEquals(list.remove("c"),true)
|
||||
assertEquals(list.remove("a"),true)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `removeAt in list`() {
|
||||
val list: ImperialMutableList<String> = SinglyLinkedList()
|
||||
list.add(0, "a")
|
||||
list.add(1, "b")
|
||||
list.add(2, "c")
|
||||
assertEquals(list.removeAt(1),"b")
|
||||
assertEquals(list.removeAt(1),"c")
|
||||
assertEquals(list.removeAt(0),"a")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `remove element not in list`() {
|
||||
val list: ImperialMutableList<String> = SinglyLinkedList()
|
||||
list.add(0, "a")
|
||||
list.add(1, "b")
|
||||
list.add(2, "c")
|
||||
assertEquals(list.remove("d"),false)
|
||||
assertEquals(list.remove("a"),true)
|
||||
assertEquals(list.remove("b"),true)
|
||||
assertEquals(list.remove("c"),true)
|
||||
assertEquals(list.remove("d"),false)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `remove empty list throws`() {
|
||||
val list: ImperialMutableList<String> = SinglyLinkedList()
|
||||
list.add(0, "a")
|
||||
list.add(1, "b")
|
||||
list.add(2, "c")
|
||||
assertEquals(list.removeAt(1),"b")
|
||||
assertEquals(list.removeAt(1),"c")
|
||||
assertEquals(list.removeAt(0),"a")
|
||||
try {
|
||||
list.removeAt(0)
|
||||
} catch (exception: IndexOutOfBoundsException) {
|
||||
// yay
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `remove list out of bounds`() {
|
||||
val list: ImperialMutableList<String> = SinglyLinkedList()
|
||||
list.add(0, "a")
|
||||
list.add(1, "b")
|
||||
list.add(2, "c")
|
||||
try {
|
||||
list.removeAt(3)
|
||||
} catch (exception: IndexOutOfBoundsException) {
|
||||
// yay
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,335 @@
|
||||
package collections
|
||||
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertFalse
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
private val exampleStrings: Array<String> = arrayOf(
|
||||
"cat",
|
||||
"dog",
|
||||
"frog",
|
||||
"horse",
|
||||
"zebra",
|
||||
"wildebeest",
|
||||
"vulture",
|
||||
"hyena",
|
||||
"warthog",
|
||||
"hyrax",
|
||||
)
|
||||
|
||||
class SinglyLinkedListJavaTests {
|
||||
|
||||
@Test
|
||||
fun `test get (String)`() {
|
||||
val list = SinglyLinkedListJava<String>()
|
||||
for (i in 0..<10) {
|
||||
list.add(i, exampleStrings[i])
|
||||
assertEquals(i + 1, list.size)
|
||||
}
|
||||
for (i in 0..<10) {
|
||||
assertEquals(exampleStrings[i], list[i])
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test add (String)`() {
|
||||
val list = SinglyLinkedListJava<String>()
|
||||
for (i in 1..10) {
|
||||
list.add(i - 1, exampleStrings[i - 1])
|
||||
assertEquals(i, list.size)
|
||||
}
|
||||
assertEquals(
|
||||
exampleStrings.joinToString(prefix = "[", postfix = "]"),
|
||||
list.toString(),
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test add in middle (String)`() {
|
||||
val list = SinglyLinkedListJava<String>()
|
||||
for (i in 1..5) {
|
||||
list.add(i - 1, exampleStrings[i])
|
||||
assertEquals(i, list.size)
|
||||
}
|
||||
assertEquals(5, list.size)
|
||||
list.add(3, "blob")
|
||||
assertEquals(6, list.size)
|
||||
assertEquals("[dog, frog, horse, blob, zebra, wildebeest]", list.toString())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test add at end (String)`() {
|
||||
val list = SinglyLinkedListJava<String>()
|
||||
for (i in 1..5) {
|
||||
list.add(i - 1, exampleStrings[i])
|
||||
assertEquals(i, list.size)
|
||||
}
|
||||
list.add(5, "blob")
|
||||
assertEquals(6, list.size)
|
||||
assertEquals("[dog, frog, horse, zebra, wildebeest, blob]", list.toString())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test clear (String)`() {
|
||||
val list = SinglyLinkedListJava<String>()
|
||||
for (i in 1..5) {
|
||||
list.add(i - 1, exampleStrings[i])
|
||||
assertEquals(i, list.size)
|
||||
}
|
||||
list.clear()
|
||||
assertEquals(0, list.size)
|
||||
assertEquals("[]", list.toString())
|
||||
list.clear()
|
||||
assertEquals(0, list.size)
|
||||
assertEquals("[]", list.toString())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test toString empty (String)`() {
|
||||
val list = SinglyLinkedListJava<String>()
|
||||
assertEquals(0, list.size)
|
||||
assertEquals("[]", list.toString())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test set (String)`() {
|
||||
val list = SinglyLinkedListJava<String>()
|
||||
list.add(0, "one")
|
||||
list.add(1, "two")
|
||||
list.add(2, "three")
|
||||
assertEquals("one", list.set(0, "forty two"))
|
||||
assertEquals("two", list.set(1, "forty three"))
|
||||
assertEquals("three", list.set(2, "forty four"))
|
||||
assertEquals(3, list.size)
|
||||
assertEquals("[forty two, forty three, forty four]", list.toString())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test get (Int)`() {
|
||||
val list = SinglyLinkedListJava<Int>()
|
||||
for (i in 1..10) {
|
||||
list.add(i - 1, i)
|
||||
assertEquals(i, list.size)
|
||||
}
|
||||
for (i in 1..10) {
|
||||
assertEquals(i, list[i - 1])
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test add (Int)`() {
|
||||
val list = SinglyLinkedListJava<Int>()
|
||||
for (i in 1..10) {
|
||||
list.add(i - 1, i)
|
||||
assertEquals(i, list.size)
|
||||
}
|
||||
assertEquals("[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]", list.toString())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test add in middle (Int)`() {
|
||||
val list = SinglyLinkedListJava<Int>()
|
||||
for (i in 1..5) {
|
||||
list.add(i - 1, i)
|
||||
assertEquals(i, list.size)
|
||||
}
|
||||
assertEquals(5, list.size)
|
||||
list.add(3, 42)
|
||||
assertEquals(6, list.size)
|
||||
assertEquals("[1, 2, 3, 42, 4, 5]", list.toString())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test add at end (Int)`() {
|
||||
val list = SinglyLinkedListJava<Int>()
|
||||
for (i in 1..5) {
|
||||
list.add(i - 1, i)
|
||||
assertEquals(i, list.size)
|
||||
}
|
||||
list.add(5, 42)
|
||||
assertEquals(6, list.size)
|
||||
assertEquals("[1, 2, 3, 4, 5, 42]", list.toString())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test clear (Int)`() {
|
||||
val list = SinglyLinkedListJava<Int>()
|
||||
for (i in 1..5) {
|
||||
list.add(i - 1, i)
|
||||
assertEquals(i, list.size)
|
||||
}
|
||||
list.clear()
|
||||
assertEquals(0, list.size)
|
||||
assertEquals("[]", list.toString())
|
||||
list.clear()
|
||||
assertEquals(0, list.size)
|
||||
assertEquals("[]", list.toString())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test toString empty (Int)`() {
|
||||
val list = SinglyLinkedListJava<Int>()
|
||||
assertEquals(0, list.size)
|
||||
assertEquals("[]", list.toString())
|
||||
val trivialList = SinglyLinkedListJava<Int>()
|
||||
assertEquals(0, trivialList.size)
|
||||
assertEquals("[]", trivialList.toString())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test set (Int)`() {
|
||||
val list = SinglyLinkedListJava<Int>()
|
||||
list.add(0, 1)
|
||||
list.add(1, 2)
|
||||
list.add(2, 3)
|
||||
assertEquals(1, list.set(0, 42))
|
||||
assertEquals(2, list.set(1, 43))
|
||||
assertEquals(3, list.set(2, 44))
|
||||
assertEquals(3, list.size)
|
||||
assertEquals("[42, 43, 44]", list.toString())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test addAll small`() {
|
||||
val firstSmallList: ImperialMutableList<Int> = SinglyLinkedListJava()
|
||||
val secondSmallList: ImperialMutableList<Int> = SinglyLinkedListJava()
|
||||
for (i in 1..10) {
|
||||
firstSmallList.add(i - 1, i)
|
||||
secondSmallList.add(i - 1, -i)
|
||||
}
|
||||
firstSmallList.addAll(firstSmallList.size, secondSmallList)
|
||||
assertEquals(20, firstSmallList.size)
|
||||
assertEquals(1, firstSmallList[0])
|
||||
assertEquals(2, firstSmallList[1])
|
||||
assertEquals(3, firstSmallList[2])
|
||||
assertEquals(4, firstSmallList[3])
|
||||
assertEquals(5, firstSmallList[4])
|
||||
assertEquals(6, firstSmallList[5])
|
||||
assertEquals(7, firstSmallList[6])
|
||||
assertEquals(8, firstSmallList[7])
|
||||
assertEquals(9, firstSmallList[8])
|
||||
assertEquals(10, firstSmallList[9])
|
||||
assertEquals(-1, firstSmallList[10])
|
||||
assertEquals(-2, firstSmallList[11])
|
||||
assertEquals(-3, firstSmallList[12])
|
||||
assertEquals(-4, firstSmallList[13])
|
||||
assertEquals(-5, firstSmallList[14])
|
||||
assertEquals(-6, firstSmallList[15])
|
||||
assertEquals(-7, firstSmallList[16])
|
||||
assertEquals(-8, firstSmallList[17])
|
||||
assertEquals(-9, firstSmallList[18])
|
||||
assertEquals(-10, firstSmallList[19])
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test addAll at index small`() {
|
||||
val firstSmallList: ImperialMutableList<Int> = SinglyLinkedListJava()
|
||||
val secondSmallList: ImperialMutableList<Int> = SinglyLinkedListJava()
|
||||
for (i in 1..10) {
|
||||
firstSmallList.add(i - 1, i)
|
||||
secondSmallList.add(i - 1, -i)
|
||||
}
|
||||
firstSmallList.addAll(5, secondSmallList)
|
||||
assertEquals(20, firstSmallList.size)
|
||||
assertEquals(1, firstSmallList[0])
|
||||
assertEquals(2, firstSmallList[1])
|
||||
assertEquals(3, firstSmallList[2])
|
||||
assertEquals(4, firstSmallList[3])
|
||||
assertEquals(5, firstSmallList[4])
|
||||
assertEquals(-1, firstSmallList[5])
|
||||
assertEquals(-2, firstSmallList[6])
|
||||
assertEquals(-3, firstSmallList[7])
|
||||
assertEquals(-4, firstSmallList[8])
|
||||
assertEquals(-5, firstSmallList[9])
|
||||
assertEquals(-6, firstSmallList[10])
|
||||
assertEquals(-7, firstSmallList[11])
|
||||
assertEquals(-8, firstSmallList[12])
|
||||
assertEquals(-9, firstSmallList[13])
|
||||
assertEquals(-10, firstSmallList[14])
|
||||
assertEquals(6, firstSmallList[15])
|
||||
assertEquals(7, firstSmallList[16])
|
||||
assertEquals(8, firstSmallList[17])
|
||||
assertEquals(9, firstSmallList[18])
|
||||
assertEquals(10, firstSmallList[19])
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test addAll at start`() {
|
||||
val list1: ImperialMutableList<Int> = SinglyLinkedListJava()
|
||||
val list2: ImperialMutableList<Int> = SinglyLinkedListJava()
|
||||
list1.add(0, 1)
|
||||
list1.add(1, 2)
|
||||
list1.add(2, 3)
|
||||
list2.add(0, 4)
|
||||
list2.add(1, 5)
|
||||
list2.add(2, 6)
|
||||
list1.addAll(0, list2)
|
||||
assertEquals(6, list1.size)
|
||||
assertEquals(4, list1[0])
|
||||
assertEquals(5, list1[1])
|
||||
assertEquals(6, list1[2])
|
||||
assertEquals(1, list1[3])
|
||||
assertEquals(2, list1[4])
|
||||
assertEquals(3, list1[5])
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test addAll at end`() {
|
||||
val list1: ImperialMutableList<Int> = SinglyLinkedListJava()
|
||||
val list2: ImperialMutableList<Int> = SinglyLinkedListJava()
|
||||
list1.add(0, 1)
|
||||
list1.add(1, 2)
|
||||
list1.add(2, 3)
|
||||
list2.add(0, 4)
|
||||
list2.add(1, 5)
|
||||
list2.add(2, 6)
|
||||
list1.addAll(3, list2)
|
||||
assertEquals(6, list1.size)
|
||||
assertEquals(1, list1[0])
|
||||
assertEquals(2, list1[1])
|
||||
assertEquals(3, list1[2])
|
||||
assertEquals(4, list1[3])
|
||||
assertEquals(5, list1[4])
|
||||
assertEquals(6, list1[5])
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `size is 0`() {
|
||||
assertEquals(0, SinglyLinkedListJava<Int>().size)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `iterator has next when empty`() {
|
||||
assertFalse(SinglyLinkedListJava<Int>().iterator().hasNext())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `iterate over elements`() {
|
||||
val list: ImperialMutableList<String> = SinglyLinkedListJava()
|
||||
list.add(0, "a")
|
||||
list.add(1, "b")
|
||||
list.add(2, "c")
|
||||
val iterator = list.iterator()
|
||||
assertTrue(iterator.hasNext())
|
||||
assertEquals("a", iterator.next())
|
||||
assertTrue(iterator.hasNext())
|
||||
assertEquals("b", iterator.next())
|
||||
assertTrue(iterator.hasNext())
|
||||
assertEquals("c", iterator.next())
|
||||
assertFalse(iterator.hasNext())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `concatenate with iterator`() {
|
||||
val list: ImperialMutableList<String> = SinglyLinkedListJava()
|
||||
list.add(0, "a")
|
||||
list.add(1, "b")
|
||||
list.add(2, "c")
|
||||
val concatenation = StringBuilder()
|
||||
for (string in list) {
|
||||
concatenation.append(string)
|
||||
}
|
||||
assertEquals("abc", concatenation.toString())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,335 @@
|
||||
package collections
|
||||
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertFalse
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
private val exampleStrings: Array<String> = arrayOf(
|
||||
"cat",
|
||||
"dog",
|
||||
"frog",
|
||||
"horse",
|
||||
"zebra",
|
||||
"wildebeest",
|
||||
"vulture",
|
||||
"hyena",
|
||||
"warthog",
|
||||
"hyrax",
|
||||
)
|
||||
|
||||
class SinglyLinkedListTests {
|
||||
|
||||
@Test
|
||||
fun `test get (String)`() {
|
||||
val list = SinglyLinkedList<String>()
|
||||
for (i in 0..<10) {
|
||||
list.add(i, exampleStrings[i])
|
||||
assertEquals(i + 1, list.size)
|
||||
}
|
||||
for (i in 0..<10) {
|
||||
assertEquals(exampleStrings[i], list[i])
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test add (String)`() {
|
||||
val list = SinglyLinkedList<String>()
|
||||
for (i in 1..10) {
|
||||
list.add(i - 1, exampleStrings[i - 1])
|
||||
assertEquals(i, list.size)
|
||||
}
|
||||
assertEquals(
|
||||
exampleStrings.joinToString(prefix = "[", postfix = "]"),
|
||||
list.toString(),
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test add in middle (String)`() {
|
||||
val list = SinglyLinkedList<String>()
|
||||
for (i in 1..5) {
|
||||
list.add(i - 1, exampleStrings[i])
|
||||
assertEquals(i, list.size)
|
||||
}
|
||||
assertEquals(5, list.size)
|
||||
list.add(3, "blob")
|
||||
assertEquals(6, list.size)
|
||||
assertEquals("[dog, frog, horse, blob, zebra, wildebeest]", list.toString())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test add at end (String)`() {
|
||||
val list = SinglyLinkedList<String>()
|
||||
for (i in 1..5) {
|
||||
list.add(i - 1, exampleStrings[i])
|
||||
assertEquals(i, list.size)
|
||||
}
|
||||
list.add(5, "blob")
|
||||
assertEquals(6, list.size)
|
||||
assertEquals("[dog, frog, horse, zebra, wildebeest, blob]", list.toString())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test clear (String)`() {
|
||||
val list = SinglyLinkedList<String>()
|
||||
for (i in 1..5) {
|
||||
list.add(i - 1, exampleStrings[i])
|
||||
assertEquals(i, list.size)
|
||||
}
|
||||
list.clear()
|
||||
assertEquals(0, list.size)
|
||||
assertEquals("[]", list.toString())
|
||||
list.clear()
|
||||
assertEquals(0, list.size)
|
||||
assertEquals("[]", list.toString())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test toString empty (String)`() {
|
||||
val list = SinglyLinkedList<String>()
|
||||
assertEquals(0, list.size)
|
||||
assertEquals("[]", list.toString())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test set (String)`() {
|
||||
val list = SinglyLinkedList<String>()
|
||||
list.add(0, "one")
|
||||
list.add(1, "two")
|
||||
list.add(2, "three")
|
||||
assertEquals("one", list.set(0, "forty two"))
|
||||
assertEquals("two", list.set(1, "forty three"))
|
||||
assertEquals("three", list.set(2, "forty four"))
|
||||
assertEquals(3, list.size)
|
||||
assertEquals("[forty two, forty three, forty four]", list.toString())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test get (Int)`() {
|
||||
val list = SinglyLinkedList<Int>()
|
||||
for (i in 1..10) {
|
||||
list.add(i - 1, i)
|
||||
assertEquals(i, list.size)
|
||||
}
|
||||
for (i in 1..10) {
|
||||
assertEquals(i, list[i - 1])
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test add (Int)`() {
|
||||
val list = SinglyLinkedList<Int>()
|
||||
for (i in 1..10) {
|
||||
list.add(i - 1, i)
|
||||
assertEquals(i, list.size)
|
||||
}
|
||||
assertEquals("[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]", list.toString())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test add in middle (Int)`() {
|
||||
val list = SinglyLinkedList<Int>()
|
||||
for (i in 1..5) {
|
||||
list.add(i - 1, i)
|
||||
assertEquals(i, list.size)
|
||||
}
|
||||
assertEquals(5, list.size)
|
||||
list.add(3, 42)
|
||||
assertEquals(6, list.size)
|
||||
assertEquals("[1, 2, 3, 42, 4, 5]", list.toString())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test add at end (Int)`() {
|
||||
val list = SinglyLinkedList<Int>()
|
||||
for (i in 1..5) {
|
||||
list.add(i - 1, i)
|
||||
assertEquals(i, list.size)
|
||||
}
|
||||
list.add(5, 42)
|
||||
assertEquals(6, list.size)
|
||||
assertEquals("[1, 2, 3, 4, 5, 42]", list.toString())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test clear (Int)`() {
|
||||
val list = SinglyLinkedList<Int>()
|
||||
for (i in 1..5) {
|
||||
list.add(i - 1, i)
|
||||
assertEquals(i, list.size)
|
||||
}
|
||||
list.clear()
|
||||
assertEquals(0, list.size)
|
||||
assertEquals("[]", list.toString())
|
||||
list.clear()
|
||||
assertEquals(0, list.size)
|
||||
assertEquals("[]", list.toString())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test toString empty (Int)`() {
|
||||
val list = SinglyLinkedList<Int>()
|
||||
assertEquals(0, list.size)
|
||||
assertEquals("[]", list.toString())
|
||||
val trivialList = SinglyLinkedList<Int>()
|
||||
assertEquals(0, trivialList.size)
|
||||
assertEquals("[]", trivialList.toString())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test set (Int)`() {
|
||||
val list = SinglyLinkedList<Int>()
|
||||
list.add(0, 1)
|
||||
list.add(1, 2)
|
||||
list.add(2, 3)
|
||||
assertEquals(1, list.set(0, 42))
|
||||
assertEquals(2, list.set(1, 43))
|
||||
assertEquals(3, list.set(2, 44))
|
||||
assertEquals(3, list.size)
|
||||
assertEquals("[42, 43, 44]", list.toString())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test addAll small`() {
|
||||
val firstSmallList: ImperialMutableList<Int> = SinglyLinkedList()
|
||||
val secondSmallList: ImperialMutableList<Int> = SinglyLinkedList()
|
||||
for (i in 1..10) {
|
||||
firstSmallList.add(i - 1, i)
|
||||
secondSmallList.add(i - 1, -i)
|
||||
}
|
||||
firstSmallList.addAll(firstSmallList.size, secondSmallList)
|
||||
assertEquals(20, firstSmallList.size)
|
||||
assertEquals(1, firstSmallList[0])
|
||||
assertEquals(2, firstSmallList[1])
|
||||
assertEquals(3, firstSmallList[2])
|
||||
assertEquals(4, firstSmallList[3])
|
||||
assertEquals(5, firstSmallList[4])
|
||||
assertEquals(6, firstSmallList[5])
|
||||
assertEquals(7, firstSmallList[6])
|
||||
assertEquals(8, firstSmallList[7])
|
||||
assertEquals(9, firstSmallList[8])
|
||||
assertEquals(10, firstSmallList[9])
|
||||
assertEquals(-1, firstSmallList[10])
|
||||
assertEquals(-2, firstSmallList[11])
|
||||
assertEquals(-3, firstSmallList[12])
|
||||
assertEquals(-4, firstSmallList[13])
|
||||
assertEquals(-5, firstSmallList[14])
|
||||
assertEquals(-6, firstSmallList[15])
|
||||
assertEquals(-7, firstSmallList[16])
|
||||
assertEquals(-8, firstSmallList[17])
|
||||
assertEquals(-9, firstSmallList[18])
|
||||
assertEquals(-10, firstSmallList[19])
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test addAll at index small`() {
|
||||
val firstSmallList: ImperialMutableList<Int> = SinglyLinkedList()
|
||||
val secondSmallList: ImperialMutableList<Int> = SinglyLinkedList()
|
||||
for (i in 1..10) {
|
||||
firstSmallList.add(i - 1, i)
|
||||
secondSmallList.add(i - 1, -i)
|
||||
}
|
||||
firstSmallList.addAll(5, secondSmallList)
|
||||
assertEquals(20, firstSmallList.size)
|
||||
assertEquals(1, firstSmallList[0])
|
||||
assertEquals(2, firstSmallList[1])
|
||||
assertEquals(3, firstSmallList[2])
|
||||
assertEquals(4, firstSmallList[3])
|
||||
assertEquals(5, firstSmallList[4])
|
||||
assertEquals(-1, firstSmallList[5])
|
||||
assertEquals(-2, firstSmallList[6])
|
||||
assertEquals(-3, firstSmallList[7])
|
||||
assertEquals(-4, firstSmallList[8])
|
||||
assertEquals(-5, firstSmallList[9])
|
||||
assertEquals(-6, firstSmallList[10])
|
||||
assertEquals(-7, firstSmallList[11])
|
||||
assertEquals(-8, firstSmallList[12])
|
||||
assertEquals(-9, firstSmallList[13])
|
||||
assertEquals(-10, firstSmallList[14])
|
||||
assertEquals(6, firstSmallList[15])
|
||||
assertEquals(7, firstSmallList[16])
|
||||
assertEquals(8, firstSmallList[17])
|
||||
assertEquals(9, firstSmallList[18])
|
||||
assertEquals(10, firstSmallList[19])
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test addAll at start`() {
|
||||
val list1: ImperialMutableList<Int> = SinglyLinkedList()
|
||||
val list2: ImperialMutableList<Int> = SinglyLinkedList()
|
||||
list1.add(0, 1)
|
||||
list1.add(1, 2)
|
||||
list1.add(2, 3)
|
||||
list2.add(0, 4)
|
||||
list2.add(1, 5)
|
||||
list2.add(2, 6)
|
||||
list1.addAll(0, list2)
|
||||
assertEquals(6, list1.size)
|
||||
assertEquals(4, list1[0])
|
||||
assertEquals(5, list1[1])
|
||||
assertEquals(6, list1[2])
|
||||
assertEquals(1, list1[3])
|
||||
assertEquals(2, list1[4])
|
||||
assertEquals(3, list1[5])
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test addAll at end`() {
|
||||
val list1: ImperialMutableList<Int> = SinglyLinkedList()
|
||||
val list2: ImperialMutableList<Int> = SinglyLinkedList()
|
||||
list1.add(0, 1)
|
||||
list1.add(1, 2)
|
||||
list1.add(2, 3)
|
||||
list2.add(0, 4)
|
||||
list2.add(1, 5)
|
||||
list2.add(2, 6)
|
||||
list1.addAll(3, list2)
|
||||
assertEquals(6, list1.size)
|
||||
assertEquals(1, list1[0])
|
||||
assertEquals(2, list1[1])
|
||||
assertEquals(3, list1[2])
|
||||
assertEquals(4, list1[3])
|
||||
assertEquals(5, list1[4])
|
||||
assertEquals(6, list1[5])
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `size is 0`() {
|
||||
assertEquals(0, SinglyLinkedList<Int>().size)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `iterator has next when empty`() {
|
||||
assertFalse(SinglyLinkedList<Int>().iterator().hasNext())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `iterate over elements`() {
|
||||
val list: ImperialMutableList<String> = SinglyLinkedList()
|
||||
list.add(0, "a")
|
||||
list.add(1, "b")
|
||||
list.add(2, "c")
|
||||
val iterator = list.iterator()
|
||||
assertTrue(iterator.hasNext())
|
||||
assertEquals("a", iterator.next())
|
||||
assertTrue(iterator.hasNext())
|
||||
assertEquals("b", iterator.next())
|
||||
assertTrue(iterator.hasNext())
|
||||
assertEquals("c", iterator.next())
|
||||
assertFalse(iterator.hasNext())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `concatenate with iterator`() {
|
||||
val list: ImperialMutableList<String> = SinglyLinkedList()
|
||||
list.add(0, "a")
|
||||
list.add(1, "b")
|
||||
list.add(2, "c")
|
||||
val concatenation = StringBuilder()
|
||||
for (string in list) {
|
||||
concatenation.append(string)
|
||||
}
|
||||
assertEquals("abc", concatenation.toString())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package collections
|
||||
/*
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertFalse
|
||||
|
||||
class StripedHashmapTests : ThreadSafeImperialMutableMapTestsParent() {
|
||||
|
||||
override fun emptyThreadSafeMapIntString(): ImperialMutableMap<Int, String> = StripedHashmap(::SinglyLinkedList)
|
||||
|
||||
override fun emptyCustomMutableMapStringInt(): ImperialMutableMap<String, Int> = StripedHashmap(::SinglyLinkedList)
|
||||
|
||||
override fun emptyCustomMutableMapCollidingStringInt(): ImperialMutableMap<CollidingString, Int> = StripedHashmap(::SinglyLinkedList)
|
||||
|
||||
// This test is present merely to ensure that at least one concrete test case exists.
|
||||
// The real tests are inherited from the abstract superclass.
|
||||
@Test
|
||||
fun `trivial test`() {
|
||||
assertFalse(emptyCustomMutableMapStringInt().iterator().hasNext())
|
||||
}
|
||||
}
|
||||
*/
|
||||
@@ -0,0 +1,238 @@
|
||||
package collections
|
||||
|
||||
import java.util.concurrent.locks.Lock
|
||||
import java.util.concurrent.locks.ReentrantLock
|
||||
import kotlin.concurrent.withLock
|
||||
import kotlin.random.Random
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertTrue
|
||||
import kotlin.test.fail
|
||||
|
||||
private class ExceptionMonitoringThread(
|
||||
private val exceptions: MutableList<Exception>,
|
||||
private val lock: Lock,
|
||||
private var body: () -> Unit,
|
||||
) : Runnable {
|
||||
override fun run() {
|
||||
try {
|
||||
body()
|
||||
} catch (exception: Exception) {
|
||||
lock.withLock() {
|
||||
exceptions.add(exception)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
abstract class ThreadSafeImperialMutableMapTestsParent : ImperialMutableMapTestsParent() {
|
||||
abstract fun emptyThreadSafeMapIntString(): ImperialMutableMap<Int, String>
|
||||
|
||||
@Suppress("SameParameterValue")
|
||||
private fun addElementsInRandomOrder(
|
||||
map: ImperialMutableMap<Int, String>,
|
||||
lowerBound: Int,
|
||||
numElements: Int,
|
||||
seed: Int,
|
||||
) {
|
||||
val randomGenerator = Random(seed)
|
||||
val remaining = mutableListOf<Int>()
|
||||
(lowerBound..<lowerBound + numElements).forEach {
|
||||
remaining.add(it)
|
||||
}
|
||||
while (remaining.isNotEmpty()) {
|
||||
val index = randomGenerator.nextInt(remaining.size)
|
||||
val toAdd = remaining.removeAt(index)
|
||||
map.put(toAdd, toAdd.toString())
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("SameParameterValue")
|
||||
private fun removeElementsInRandomOrder(
|
||||
map: ImperialMutableMap<Int, String>,
|
||||
lowerBound: Int,
|
||||
numElements: Int,
|
||||
seed: Int,
|
||||
) {
|
||||
val randomGenerator = Random(seed)
|
||||
val remaining = mutableListOf<Int>()
|
||||
(lowerBound..<lowerBound + numElements).forEach {
|
||||
remaining.add(it)
|
||||
}
|
||||
while (remaining.isNotEmpty()) {
|
||||
val index = randomGenerator.nextInt(remaining.size)
|
||||
val toRemove = remaining.removeAt(index)
|
||||
map.remove(toRemove)
|
||||
}
|
||||
}
|
||||
|
||||
private fun runConcurrencyTest(
|
||||
repeatRuns: Int,
|
||||
threadBodies: List<(ImperialMutableMap<Int, String>) -> Unit>,
|
||||
initialEntries: List<ImperialMutableMap.Entry<Int, String>>,
|
||||
expectedInFinalResult: Set<ImperialMutableMap.Entry<Int, String>>,
|
||||
notExpectedInFinalResult: Set<ImperialMutableMap.Entry<Int, String>>,
|
||||
expectedFinalSize: Int? = null,
|
||||
) {
|
||||
for (i in 1..repeatRuns) {
|
||||
println("Repeat run $i of $repeatRuns")
|
||||
val theMap = emptyThreadSafeMapIntString()
|
||||
for (entry in initialEntries) {
|
||||
theMap.put(entry.key, entry.value)
|
||||
}
|
||||
val exceptions = mutableListOf<Exception>()
|
||||
val lock = ReentrantLock()
|
||||
val threads = threadBodies.map {
|
||||
Thread(
|
||||
ExceptionMonitoringThread(
|
||||
exceptions,
|
||||
lock,
|
||||
) { it(theMap) },
|
||||
)
|
||||
}
|
||||
threads.forEach(Thread::start)
|
||||
threads.forEach(Thread::join)
|
||||
if (exceptions.isNotEmpty()) {
|
||||
System.err.println("Exceptions thrown by thread(s):")
|
||||
for (exception in exceptions) {
|
||||
System.err.println(exception)
|
||||
}
|
||||
fail()
|
||||
}
|
||||
val finalContentsAsList = theMap.toList()
|
||||
val finalContentsAsSet = finalContentsAsList.toSet()
|
||||
// There should be no difference in the size of final contents as a list vs. as a set
|
||||
assertEquals(finalContentsAsList.size, finalContentsAsSet.size)
|
||||
assertTrue(finalContentsAsSet.containsAll(expectedInFinalResult))
|
||||
assertTrue((finalContentsAsSet intersect notExpectedInFinalResult).isEmpty())
|
||||
expectedFinalSize?.let {
|
||||
assertEquals(it, finalContentsAsList.size)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `one thread adds, one thread removes`() {
|
||||
val chunkSize = 1 shl 12
|
||||
val adderBody: (ImperialMutableMap<Int, String>) -> Unit = { theMap ->
|
||||
Thread.sleep(1)
|
||||
addElementsInRandomOrder(
|
||||
map = theMap,
|
||||
lowerBound = 0,
|
||||
numElements = 2 * chunkSize,
|
||||
seed = 0,
|
||||
)
|
||||
}
|
||||
val removerBody: (ImperialMutableMap<Int, String>) -> Unit = { theMap ->
|
||||
Thread.sleep(1)
|
||||
removeElementsInRandomOrder(
|
||||
map = theMap,
|
||||
lowerBound = chunkSize,
|
||||
numElements = 3 * chunkSize,
|
||||
seed = 0,
|
||||
)
|
||||
}
|
||||
runConcurrencyTest(
|
||||
repeatRuns = 10,
|
||||
threadBodies = listOf(adderBody, removerBody),
|
||||
initialEntries = (chunkSize..<3 * chunkSize).map { ImperialMutableMap.Entry(it, it.toString()) },
|
||||
expectedInFinalResult = (0..<chunkSize).map { ImperialMutableMap.Entry(it, it.toString()) }.toSet(),
|
||||
notExpectedInFinalResult = (chunkSize * 2..<3 * chunkSize).map { ImperialMutableMap.Entry(it, it.toString()) }.toSet(),
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `eight threads add, eight threads remove`() {
|
||||
val chunkSize = 1 shl 12
|
||||
val adderBodies: List<(ImperialMutableMap<Int, String>) -> Unit> = (0..<8).map { seed ->
|
||||
{ theMap ->
|
||||
addElementsInRandomOrder(
|
||||
map = theMap,
|
||||
lowerBound = 0,
|
||||
numElements = 2 * chunkSize,
|
||||
seed = seed,
|
||||
)
|
||||
}
|
||||
}
|
||||
val removerBodies: List<(ImperialMutableMap<Int, String>) -> Unit> = (8..<16).map { seed ->
|
||||
{ theMap ->
|
||||
removeElementsInRandomOrder(
|
||||
map = theMap,
|
||||
lowerBound = chunkSize,
|
||||
numElements = 3 * chunkSize,
|
||||
seed = seed,
|
||||
)
|
||||
}
|
||||
}
|
||||
runConcurrencyTest(
|
||||
repeatRuns = 8,
|
||||
threadBodies = adderBodies + removerBodies,
|
||||
initialEntries = (chunkSize..<3 * chunkSize).map { ImperialMutableMap.Entry(it, it.toString()) },
|
||||
expectedInFinalResult = (0..<chunkSize).map { ImperialMutableMap.Entry(it, it.toString()) }.toSet(),
|
||||
notExpectedInFinalResult = (chunkSize * 2..<3 * chunkSize).map { ImperialMutableMap.Entry(it, it.toString()) }.toSet(),
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `size changes must not be observed during resizing`() {
|
||||
val worker: (ImperialMutableMap<Int, String>) -> Unit = {
|
||||
(10..1000).forEach { key ->
|
||||
it[key] = key.toString()
|
||||
}
|
||||
}
|
||||
val monitor: (ImperialMutableMap<Int, String>) -> Unit = {
|
||||
while (it.size <= 1000) {
|
||||
if (it.size < 10) {
|
||||
it.put(-1, "-1")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
runConcurrencyTest(
|
||||
repeatRuns = 10,
|
||||
threadBodies = listOf(worker, monitor),
|
||||
initialEntries = (0..<10).map {
|
||||
ImperialMutableMap.Entry(it, it.toString())
|
||||
},
|
||||
expectedInFinalResult = (0..1000).map {
|
||||
ImperialMutableMap.Entry(it, it.toString())
|
||||
}.toSet(),
|
||||
notExpectedInFinalResult = setOf(ImperialMutableMap.Entry(-1, "-1")),
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `eight threads add`() {
|
||||
val adderBodies: List<(ImperialMutableMap<Int, String>) -> Unit> = (0..<8).map { threadId ->
|
||||
{ theMap ->
|
||||
for (i in 0..<10000) {
|
||||
val number = threadId * 10000 + i
|
||||
theMap.put(number, number.toString())
|
||||
}
|
||||
}
|
||||
}
|
||||
runConcurrencyTest(
|
||||
repeatRuns = 8,
|
||||
threadBodies = adderBodies,
|
||||
initialEntries = emptyList(),
|
||||
expectedInFinalResult = (0..<80000).map { ImperialMutableMap.Entry(it, it.toString()) }.toSet(),
|
||||
notExpectedInFinalResult = emptySet(),
|
||||
expectedFinalSize = 80000,
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `no deadlock in concurrent resize`() {
|
||||
runConcurrencyTest(
|
||||
repeatRuns = 100,
|
||||
threadBodies = (0..<32).map {
|
||||
{ theMap ->
|
||||
theMap.put(it, it.toString())
|
||||
}
|
||||
},
|
||||
initialEntries = emptyList(),
|
||||
expectedInFinalResult = emptySet(),
|
||||
notExpectedInFinalResult = emptySet(),
|
||||
)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user