This commit is contained in:
2026-03-13 12:11:24 +00:00
commit fb57e2e831
763 changed files with 12954 additions and 0 deletions

View File

@@ -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())
}
}

View File

@@ -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])
}
}

View File

@@ -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
}
}

View File

@@ -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())
}
}

View File

@@ -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
}
}
}

View File

@@ -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())
}
}

View File

@@ -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())
}
}

View File

@@ -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())
}
}
*/

View File

@@ -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(),
)
}
}