Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 13 additions & 11 deletions kotlinx-coroutines-core/common/test/channels/BasicOperationsTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,31 +8,31 @@ class BasicOperationsTest : TestBase() {
@Test
fun testSimpleSendReceive() = runTest {
// Parametrized common test :(
TestChannelKind.values().forEach { kind -> testSendReceive(kind, 20) }
TestChannelKind.entries.forEach { kind -> testSendReceive(kind, 20) }
}

@Test
fun testTrySendToFullChannel() = runTest {
TestChannelKind.values().forEach { kind -> testTrySendToFullChannel(kind) }
TestChannelKind.entries.forEach { kind -> testTrySendToFullChannel(kind) }
}

@Test
fun testTrySendAfterClose() = runTest {
TestChannelKind.values().forEach { kind -> testTrySendAfterClose(kind) }
TestChannelKind.entries.forEach { kind -> testTrySendAfterClose(kind) }
}

@Test
fun testSendAfterClose() = runTest {
TestChannelKind.values().forEach { kind -> testSendAfterClose(kind) }
TestChannelKind.entries.forEach { kind -> testSendAfterClose(kind) }
}

@Test
fun testReceiveCatching() = runTest {
TestChannelKind.values().forEach { kind -> testReceiveCatching(kind) }
TestChannelKind.entries.forEach { kind -> testReceiveCatching(kind) }
}

@Test
fun testInvokeOnClose() = TestChannelKind.values().forEach { kind ->
fun testInvokeOnClose() = TestChannelKind.entries.forEach { kind ->
reset()
val channel = kind.create<Int>()
channel.invokeOnClose {
Expand All @@ -48,7 +48,7 @@ class BasicOperationsTest : TestBase() {
}

@Test
fun testInvokeOnClosed() = TestChannelKind.values().forEach { kind ->
fun testInvokeOnClosed() = TestChannelKind.entries.forEach { kind ->
reset()
expect(1)
val channel = kind.create<Int>()
Expand All @@ -59,7 +59,7 @@ class BasicOperationsTest : TestBase() {
}

@Test
fun testMultipleInvokeOnClose() = TestChannelKind.values().forEach { kind ->
fun testMultipleInvokeOnClose() = TestChannelKind.entries.forEach { kind ->
reset()
val channel = kind.create<Int>()
channel.invokeOnClose { expect(3) }
Expand All @@ -71,14 +71,16 @@ class BasicOperationsTest : TestBase() {
}

@Test
fun testIterator() = runTest {
TestChannelKind.values().forEach { kind ->
fun testIteratorHasNextMustPrecedeNext() = runTest {
TestChannelKind.entries.forEach { kind ->
val channel = kind.create<Int>()
val iterator = channel.iterator()
assertFailsWith<IllegalStateException> { iterator.next() }
channel.close()
assertFailsWith<IllegalStateException> { iterator.next() }
assertFalse(iterator.hasNext())
assertFailsWith<NoSuchElementException> { iterator.next() }
assertFailsWith<IllegalStateException> { iterator.next() }
}
}

Expand Down Expand Up @@ -109,7 +111,7 @@ class BasicOperationsTest : TestBase() {
try {
expect(2)
channel.close()
} catch (e: TestException) {
} catch (_: TestException) {
expect(4)
}
}
Expand Down
123 changes: 123 additions & 0 deletions kotlinx-coroutines-core/common/test/channels/ClosedChannelTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
package kotlinx.coroutines.channels

import kotlinx.coroutines.testing.*
import kotlin.test.*

class ClosedChannelTest : TestBase() {
/**
* Iterator.
*/

@Test
fun testIteratorClosedHasNextFalse() = runTest {
TestChannelKind.entries.forEach { kind ->
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Proposal:

    fun TestChannelKind.Companion.runTestForEach(
        testBody: suspend CoroutineScope.(TestChannelKind) -> Unit
    ): TestResult = runTest {
        TestChannelKind.entries.forEach { kind ->
            testBody(kind)
        }
    }

May be more convenient, with how often this pattern occurs.

val channel = kind.create<Int>()
val iterator = channel.iterator()
channel.close()
assertFalse(iterator.hasNext())
}
}

@Test
fun testIteratorClosedWithExceptionHasNextThrows() = runTest {
TestChannelKind.entries.forEach { kind ->
val channel = kind.create<Int>()
val iterator = channel.iterator()
channel.close(TestException())
assertFailsWith<TestException> { (iterator.hasNext()) }
}
}

@Test
fun testClosedToListOk() = runTest {
TestChannelKind.entries.forEach { kind ->
val channel = kind.create<Int>()
channel.close()
channel.toList()
}
}

/**
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This syntax means the comment is a KDoc and refers to the entity directly below it. To make this a normal multiline comment for separating groups of tests, use /*.

That said, I think the separation is easy to break accidentally. Why not introduce separate classes to make this more robust?

class ClosedChannelTest: TestBase() {
    /**
     * Properties.
     *
     * Properties stay the same regardless of whether the channel was closed with or without exception.
     */
    class PropertiesTests: TestBase() {
        
    }
}

* Properties.
*
* Properties stay the same regardless of whether the channel was closed with or without exception.
*/

@Test
fun testClosedIsClosedForReceive() = runTest {
TestChannelKind.entries.forEach { kind ->
val channel = kind.create<Int>()
assertFalse(channel.isClosedForReceive)
channel.close()
assertTrue(channel.isClosedForReceive)
}
}

@Test
fun testClosedWithExceptionIsClosedForReceive() = runTest {
TestChannelKind.entries.forEach { kind ->
val channel = kind.create<Int>()
assertFalse(channel.isClosedForReceive)
channel.close(TestException())
assertTrue(channel.isClosedForReceive)
}
}

@Test
fun testClosedIsEmptyFalse() = runTest {
TestChannelKind.entries.forEach { kind ->
val channel = kind.create<Int>()
assertTrue(channel.isEmpty)
assertFalse(channel.isClosedForReceive)
channel.close()
// NB! Not obvious.
assertFalse(channel.isEmpty)
assertTrue(channel.isClosedForReceive)
}
}

@Test
fun testClosedWithExceptionIsEmptyFalse() = runTest {
TestChannelKind.entries.forEach { kind ->
val channel = kind.create<Int>()
assertTrue(channel.isEmpty)
assertFalse(channel.isClosedForReceive)
channel.close(TestException())
assertFalse(channel.isEmpty)
assertTrue(channel.isClosedForReceive)
}
}

@Test
fun testSendClosedReceiveIsEmptyFalse() = runTest {
val channel = Channel<Int>(1)
assertTrue(channel.isEmpty)
assertFalse(channel.isClosedForReceive)
channel.send(1)
assertFalse(channel.isEmpty)
assertFalse(channel.isClosedForReceive)
channel.close()
assertFalse(channel.isEmpty)
assertFalse(channel.isClosedForReceive)
channel.receive()
assertFalse(channel.isEmpty)
assertTrue(channel.isClosedForReceive)
}

@Test
fun testSendClosedWithExceptionReceiveIsEmptyFalse() = runTest {
val channel = Channel<Int>(1)
assertTrue(channel.isEmpty)
assertFalse(channel.isClosedForReceive)
channel.send(1)
assertFalse(channel.isEmpty)
assertFalse(channel.isClosedForReceive)
channel.close(TestException())
assertFalse(channel.isEmpty)
assertFalse(channel.isClosedForReceive)
channel.receive()
assertFalse(channel.isEmpty)
assertTrue(channel.isClosedForReceive)
}

}