blob: 0380a282701a10601e9fc6e512ed208a3b0ee241 [file] [log] [blame]
Roman Elizarovf16fd272017-02-07 11:26:00 +03001/*
2 * Copyright 2016-2017 JetBrains s.r.o.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Roman Elizarova5676592017-01-19 10:31:13 +030017package kotlinx.coroutines.experimental.internal
Roman Elizarov3754f952017-01-18 20:47:54 +030018
19import org.junit.Assert.*
20import org.junit.Test
21
22class LockFreeLinkedListTest {
Roman Elizarovee7c0eb2017-02-16 15:29:28 +030023 data class IntNode(val i: Int) : LockFreeLinkedListNode()
Roman Elizarov3754f952017-01-18 20:47:54 +030024
25 @Test
26 fun testSimpleAddLast() {
27 val list = LockFreeLinkedListHead()
28 assertContents(list)
29 val n1 = IntNode(1).apply { list.addLast(this) }
30 assertContents(list, 1)
31 val n2 = IntNode(2).apply { list.addLast(this) }
32 assertContents(list, 1, 2)
33 val n3 = IntNode(3).apply { list.addLast(this) }
34 assertContents(list, 1, 2, 3)
35 val n4 = IntNode(4).apply { list.addLast(this) }
36 assertContents(list, 1, 2, 3, 4)
Roman Elizarov53a0a402017-01-19 20:21:57 +030037 assertTrue(n1.remove())
Roman Elizarov3754f952017-01-18 20:47:54 +030038 assertContents(list, 2, 3, 4)
Roman Elizarov53a0a402017-01-19 20:21:57 +030039 assertTrue(n3.remove())
Roman Elizarov3754f952017-01-18 20:47:54 +030040 assertContents(list, 2, 4)
Roman Elizarov53a0a402017-01-19 20:21:57 +030041 assertTrue(n4.remove())
Roman Elizarov3754f952017-01-18 20:47:54 +030042 assertContents(list, 2)
Roman Elizarov53a0a402017-01-19 20:21:57 +030043 assertTrue(n2.remove())
44 assertFalse(n2.remove())
Roman Elizarov3754f952017-01-18 20:47:54 +030045 assertContents(list)
46 }
47
48 @Test
49 fun testCondOps() {
50 val list = LockFreeLinkedListHead()
51 assertContents(list)
52 assertTrue(list.addLastIf(IntNode(1)) { true })
53 assertContents(list, 1)
54 assertFalse(list.addLastIf(IntNode(2)) { false })
55 assertContents(list, 1)
Roman Elizarovee7c0eb2017-02-16 15:29:28 +030056 assertTrue(list.addLastIf(IntNode(3)) { true })
57 assertContents(list, 1, 3)
58 assertFalse(list.addLastIf(IntNode(4)) { false })
59 assertContents(list, 1, 3)
60 }
61
62 @Test
63 fun testRemoveTwoAtomic() {
64 val list = LockFreeLinkedListHead()
65 val n1 = IntNode(1).apply { list.addLast(this) }
66 val n2 = IntNode(2).apply { list.addLast(this) }
67 assertContents(list, 1, 2)
68 assertFalse(n1.isRemoved)
69 assertFalse(n2.isRemoved)
70 val remove1Desc = n1.describeRemove()!!
71 val remove2Desc = n2.describeRemove()!!
Roman Elizarovd82b3a92017-06-23 21:52:08 +030072 val operation = object : AtomicOp<Any?>() {
73 override fun prepare(affected: Any?): Any? = remove1Desc.prepare(this) ?: remove2Desc.prepare(this)
Roman Elizarovee7c0eb2017-02-16 15:29:28 +030074 override fun complete(affected: Any?, failure: Any?) {
75 remove1Desc.complete(this, failure)
76 remove2Desc.complete(this, failure)
77 }
78 }
79 assertTrue(operation.perform(null) == null)
80 assertTrue(n1.isRemoved)
81 assertTrue(n2.isRemoved)
82 assertContents(list)
83 }
84
85 @Test
86 fun testAtomicOpsSingle() {
87 val list = LockFreeLinkedListHead()
88 assertContents(list)
Roman Elizarov1216e912017-02-22 09:57:06 +030089 val n1 = IntNode(1).also { single(list.describeAddLast(it)) }
Roman Elizarovee7c0eb2017-02-16 15:29:28 +030090 assertContents(list, 1)
Roman Elizarov1216e912017-02-22 09:57:06 +030091 val n2 = IntNode(2).also { single(list.describeAddLast(it)) }
Roman Elizarovee7c0eb2017-02-16 15:29:28 +030092 assertContents(list, 1, 2)
Roman Elizarov1216e912017-02-22 09:57:06 +030093 val n3 = IntNode(3).also { single(list.describeAddLast(it)) }
Roman Elizarovee7c0eb2017-02-16 15:29:28 +030094 assertContents(list, 1, 2, 3)
Roman Elizarov1216e912017-02-22 09:57:06 +030095 val n4 = IntNode(4).also { single(list.describeAddLast(it)) }
Roman Elizarovee7c0eb2017-02-16 15:29:28 +030096 assertContents(list, 1, 2, 3, 4)
97 single(n3.describeRemove()!!)
98 assertContents(list, 1, 2, 4)
99 assertTrue(n3.describeRemove() == null)
Roman Elizarov7adb8762017-03-17 17:54:13 +0300100 single(list.describeRemoveFirst())
Roman Elizarovee7c0eb2017-02-16 15:29:28 +0300101 assertContents(list, 2, 4)
102 assertTrue(n1.describeRemove() == null)
Roman Elizarov7adb8762017-03-17 17:54:13 +0300103 assertTrue(n2.remove())
104 assertContents(list, 4)
105 assertTrue(n4.remove())
106 assertContents(list)
Roman Elizarovee7c0eb2017-02-16 15:29:28 +0300107 }
108
109 private fun single(part: AtomicDesc) {
Roman Elizarovd82b3a92017-06-23 21:52:08 +0300110 val operation = object : AtomicOp<Any?>() {
111 override fun prepare(affected: Any?): Any? = part.prepare(this)
Roman Elizarovee7c0eb2017-02-16 15:29:28 +0300112 override fun complete(affected: Any?, failure: Any?) = part.complete(this, failure)
113 }
114 assertTrue(operation.perform(null) == null)
Roman Elizarov3754f952017-01-18 20:47:54 +0300115 }
116
117 private fun assertContents(list: LockFreeLinkedListHead, vararg expected: Int) {
118 list.validate()
119 val n = expected.size
120 val actual = IntArray(n)
121 var index = 0
122 list.forEach<IntNode> { actual[index++] = it.i }
123 assertEquals(n, index)
124 for (i in 0 until n) assertEquals("item i", expected[i], actual[i])
Roman Elizarov53a0a402017-01-19 20:21:57 +0300125 assertEquals(expected.isEmpty(), list.isEmpty)
Roman Elizarov3754f952017-01-18 20:47:54 +0300126 }
127}