Detect concurrent modifications in ArrayDeque #KT-63355

Remove the ArrayDeque.subList().subList() test for comodification detection.
For types that extend AbstractList and to not override subList function,
the behavior varies depending on JDK version. With JKD8, the test fails for ArrayDeque.
While with JDK9+, it passes.
This commit is contained in:
Abduqodiri Qurbonzoda
2024-01-12 18:46:10 +05:00
committed by Space Team
parent 5f16fb2e4d
commit c9d8ecc599
3 changed files with 113 additions and 9 deletions
@@ -95,7 +95,12 @@ class ConcurrentModificationTest {
fun mutableList() {
if (TestPlatform.current == TestPlatform.Js) return
val operations = listOf<CollectionOperation<MutableList<String>>>(
/**
* Some operations should register a modification by contract, but java ArrayList,
* whose implementation we can't change, do not register.
* @param isJavaArrayListBehavior specifies whether to test java ArrayList behavior or the behavior by contract.
*/
fun operations(isJavaArrayListBehavior: Boolean) = listOf<CollectionOperation<MutableList<String>>>(
CollectionOperation("set()", throwsCME = false) { set(2, "e") },
CollectionOperation("add()") { add("e") },
@@ -106,9 +111,9 @@ class ConcurrentModificationTest {
CollectionOperation("removeAt()") { removeAt(2) },
CollectionOperation("addAll()") { addAll(listOf("e", "f")) },
CollectionOperation("addAll(emptyList())") { addAll(emptyList()) },
CollectionOperation("addAll(emptyList())", throwsCME = isJavaArrayListBehavior) { addAll(emptyList()) },
CollectionOperation("addAll(index)") { addAll(2, listOf("e", "f")) },
CollectionOperation("addAll(index, emptyList())") { addAll(2, emptyList()) },
CollectionOperation("addAll(index, emptyList())", throwsCME = isJavaArrayListBehavior) { addAll(2, emptyList()) },
CollectionOperation("removeAll(non-existing)", throwsCME = false) { removeAll(listOf("e", "f")) },
CollectionOperation("removeAll(some exist)") { removeAll(listOf("d", "e")) },
@@ -127,8 +132,8 @@ class ConcurrentModificationTest {
}
}
fun testThrowsCME(withMutableList: WithCollection<MutableList<String>>) {
testIteratorThrowsCME(withMutableList, operations)
fun testThrowsCME(isJavaArrayListBehavior: Boolean = true, withMutableList: WithCollection<MutableList<String>>) {
testIteratorThrowsCME(withMutableList, operations(isJavaArrayListBehavior))
}
// size == capacity
@@ -146,6 +151,16 @@ class ConcurrentModificationTest {
}
}
testThrowsCME(isJavaArrayListBehavior = false) { action ->
ArrayDeque<String>(4).apply {
addAll(listOf("a", "b", "c", "d"))
action(this)
}
}
testThrowsCME(isJavaArrayListBehavior = false) { action ->
ArrayDeque(listOf("a", "b", "c", "d")).also(action)
}
// size < capacity
testThrowsCME { action ->
ArrayList<String>(10).apply {
@@ -160,6 +175,13 @@ class ConcurrentModificationTest {
action(this)
}
}
testThrowsCME(isJavaArrayListBehavior = false) { action ->
ArrayDeque<String>(10).apply {
addAll(listOf("a", "b", "c", "d"))
action(this)
}
}
}
@Test
@@ -195,6 +217,45 @@ class ConcurrentModificationTest {
}
}
@Test
fun arrayDeque() {
if (TestPlatform.current == TestPlatform.Js) return
val operations = listOf<CollectionOperation<ArrayDeque<String>>>(
CollectionOperation("addFirst()") { addFirst("e") },
CollectionOperation("addLast()") { addLast("e") },
CollectionOperation("removeFirst()") { removeFirst() },
CollectionOperation("removeLast()") { removeLast() },
CollectionOperation("removeFirstOrNull()") { removeFirstOrNull() },
CollectionOperation("removeLastOrNull()") { removeLastOrNull() },
)
fun testThrowsCME(withArrayDeque: WithCollection<ArrayDeque<String>>) {
testIteratorThrowsCME(withArrayDeque, operations)
}
// size == capacity
testThrowsCME { action ->
ArrayDeque<String>(4).apply {
addAll(listOf("a", "b", "c", "d"))
action(this)
}
}
testThrowsCME { action ->
ArrayDeque(listOf("a", "b", "c", "d")).also(action)
}
// size < capacity
testThrowsCME { action ->
ArrayDeque<String>(10).apply {
addAll(listOf("a", "b", "c", "d"))
action(this)
}
}
}
@Test
fun subList() {
if (TestPlatform.current == TestPlatform.Js) return
@@ -230,8 +291,6 @@ class ConcurrentModificationTest {
CollectionOperation("clear()") { clear() },
CollectionOperation("iterator()") { iterator() },
CollectionOperation("listIterator()") { listIterator() },
CollectionOperation("subList()", throwsCME = false) { subList(0, 1) },
)
fun testThrowsCME(withMutableList: WithCollection<MutableList<String>>) {
@@ -244,6 +303,11 @@ class ConcurrentModificationTest {
arrayList.add("e")
action(subList)
}
assertFailsWith<ConcurrentModificationException> {
val arrayList = arrayListOf("a", "b", "c", "d")
for (e in arrayList.subList(1, 3)) arrayList.remove(e)
}
testThrowsCME { action ->
buildList {
addAll(listOf("a", "b", "c", "d"))
@@ -258,6 +322,17 @@ class ConcurrentModificationTest {
for (e in subList(1, 3)) remove(e)
}
}
testThrowsCME { action ->
val arrayDeque = ArrayDeque(listOf("a", "b", "c", "d"))
val subList = arrayDeque.subList(0, arrayDeque.size)
arrayDeque.add("e")
action(subList)
}
assertFailsWith<ConcurrentModificationException> {
val arrayDeque = ArrayDeque(listOf("a", "b", "c", "d"))
for (e in arrayDeque.subList(1, 3)) arrayDeque.remove(e)
}
}
@Test