lyng/lynglib/src/commonTest/kotlin/CoroutinesTest.kt
2025-08-13 23:22:04 +03:00

188 lines
5.5 KiB
Kotlin

/*
* Copyright 2025 Sergey S. Chernov real.sergeych@gmail.com
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
import kotlinx.coroutines.test.runTest
import net.sergeych.lyng.eval
import kotlin.test.Test
class TestCoroutines {
@Test
fun testLaunch() = runTest {
eval(
"""
var passed = false
val x = launch {
delay(10)
passed = true
"ok"
}
assert(!passed)
assertEquals( x.await(), "ok")
assert(passed)
assert(x.isCompleted)
""".trimIndent()
)
}
@Test
fun testCompletableDeferred() = runTest {
eval(
"""
val done = CompletableDeferred()
launch {
delay(30)
done.complete("ok")
}
assert(!done.isCompleted)
assert(done.isActive)
assertEquals( done.await(), "ok")
assert(done.isCompleted)
""".trimIndent()
)
}
@Test
fun testMutex() = runTest {
eval(
"""
var counter = 0
val mutex = Mutex()
(1..4).map {
launch {
// mutex.withLock {
val c = counter
delay(5)
counter = c + 1
// }
}
}.forEach { it.await() }
println(counter)
assert( counter < 10 )
""".trimIndent()
)
}
@Test
fun testFlows() = runTest {
eval("""
val f = flow {
println("Starting generator")
var n1 = 0
var n2 = 1
emit(n1)
emit(n2)
while(true) {
val n = n1 + n2
emit(n)
n1 = n2
n2 = n
}
}
val correctFibs = [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765]
assertEquals( correctFibs, f.take(correctFibs.size))
""".trimIndent())
}
@Test
fun testFlow2() = runTest {
eval("""
val f = flow {
emit("start")
emit("start2")
(1..4).forEach {
emit(it)
}
}
// let's collect flow:
val result = []
for( x in f ) result += x
println(result)
// let's collect it once again:
assertEquals( result, f.toList())
assertEquals( result, f.toList())
""".trimIndent())
}
@Test
fun testFlowClosures() = runTest {
eval("""
fun filter( a, b ) {
println("filter: %s, %s"(a,b))
flow {
emit(a)
emit(b)
}
}
assertEquals( [5, 1], filter(5,1).toList() )
assertEquals( [2, 3], filter(2,3).toList() )
""".trimIndent())
}
@Test
fun testFilterFlow() = runTest {
eval("""
fun filter( list, predicate ) {
val p = predicate
println("predicate "+predicate+" / "+p)
flow {
// here p is captured only once and does not change!
for( item in list ) {
print("filter "+p+" "+item+": ")
if( p(item) ) {
println("OK")
emit(item)
}
else println("NO")
}
}
}
// fun drop(i, n) {
// require( n >= 0, "drop amount must be non-negative")
// var count = 0
// println("drop %d"(n))
// filter(i) {
// count++ >= n
// }
// }
val src = (1..1).toList()
assertEquals( 1, filter(src) { true }.toList().size )
println("----------------------------------------------------------")
println("----------------------------------------------------------")
println("----------------------------------------------------------")
println("----------------------------------------------------------")
assertEquals( 0, filter(src) { false }.toList().size )
// assertEquals( 3, filter(src) { true }.size() )
// assertEquals( [7,8], drop((1..8).toList(),6).toList())
// assertEquals( [1,3,5,7], filter((1..8).toList()) {
// println("call2")
// it % 2 == 1
// }.toList())
""".trimIndent())
}
}