161 lines
4.1 KiB
Kotlin
161 lines
4.1 KiB
Kotlin
/*
|
|
* Copyright 2026 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.async
|
|
import kotlinx.coroutines.launch
|
|
import kotlinx.coroutines.test.advanceTimeBy
|
|
import kotlinx.coroutines.test.runTest
|
|
import net.sergeych.lyng.EvalSession
|
|
import net.sergeych.lyng.Scope
|
|
import net.sergeych.lyng.obj.ObjBool
|
|
import net.sergeych.lyng.obj.ObjFlow
|
|
import net.sergeych.lyng.obj.ObjInt
|
|
import net.sergeych.lyng.obj.ObjList
|
|
import kotlin.test.*
|
|
|
|
class EvalSessionTest {
|
|
@Test
|
|
fun sessionCreatesAndReusesScope() = runTest {
|
|
val session = EvalSession()
|
|
|
|
assertEquals(null, session.scope)
|
|
assertEquals(10L, (session.eval("var x = 10; x") as ObjInt).value)
|
|
assertNotNull(session.scope)
|
|
assertEquals(session.scope, session.getScope())
|
|
assertEquals(15L, (session.eval("x += 5; x") as ObjInt).value)
|
|
}
|
|
|
|
@Test
|
|
fun sessionCancelStopsLaunchedCoroutines() = runTest {
|
|
val scope = Scope()
|
|
val session = EvalSession(scope)
|
|
|
|
session.eval(
|
|
"""
|
|
var touched = false
|
|
launch {
|
|
delay(100)
|
|
touched = true
|
|
}
|
|
"""
|
|
.trimIndent()
|
|
)
|
|
|
|
session.cancel()
|
|
session.join()
|
|
advanceTimeBy(150)
|
|
|
|
assertFalse((scope.eval("touched") as ObjBool).value)
|
|
}
|
|
|
|
@Test
|
|
fun joinObservesWorkStartedByLaterEval() = runTest {
|
|
val session = EvalSession(Scope())
|
|
|
|
session.eval("launch { delay(100) }")
|
|
|
|
var joined = false
|
|
val waiter = launch {
|
|
session.join()
|
|
joined = true
|
|
}
|
|
|
|
advanceTimeBy(50)
|
|
assertFalse(joined)
|
|
|
|
session.eval("launch { delay(100) }")
|
|
|
|
advanceTimeBy(60)
|
|
assertFalse(joined)
|
|
|
|
advanceTimeBy(50)
|
|
waiter.join()
|
|
assertTrue(joined)
|
|
}
|
|
|
|
@Test
|
|
fun concurrentEvalCallsAreSerialized() = runTest {
|
|
val session = EvalSession(Scope())
|
|
|
|
session.eval("var counter = 0")
|
|
|
|
val first = async {
|
|
session.eval(
|
|
"""
|
|
delay(100)
|
|
counter += 1
|
|
counter
|
|
"""
|
|
.trimIndent()
|
|
) as ObjInt
|
|
}
|
|
val second = async {
|
|
session.eval(
|
|
"""
|
|
counter += 10
|
|
counter
|
|
"""
|
|
.trimIndent()
|
|
) as ObjInt
|
|
}
|
|
|
|
advanceTimeBy(150)
|
|
|
|
assertEquals(1L, first.await().value)
|
|
assertEquals(11L, second.await().value)
|
|
assertEquals(11L, (session.eval("counter") as ObjInt).value)
|
|
}
|
|
|
|
@Test
|
|
fun joinWaitsForActiveFlowProducer() = runTest {
|
|
val scope = Scope()
|
|
val session = EvalSession(scope)
|
|
val flow = session.eval(
|
|
"""
|
|
flow {
|
|
delay(100)
|
|
emit(1)
|
|
delay(100)
|
|
emit(2)
|
|
}
|
|
"""
|
|
.trimIndent()
|
|
) as ObjFlow
|
|
|
|
var joined = false
|
|
var collected: ObjList? = null
|
|
|
|
val collector = launch {
|
|
collected = flow.callMethod(scope, "toList")
|
|
}
|
|
val waiter = launch {
|
|
session.join()
|
|
joined = true
|
|
}
|
|
|
|
advanceTimeBy(150)
|
|
assertFalse(joined)
|
|
|
|
advanceTimeBy(100)
|
|
collector.join()
|
|
waiter.join()
|
|
|
|
assertTrue(joined)
|
|
assertEquals(listOf(1L, 2L), collected!!.list.map { (it as ObjInt).value })
|
|
}
|
|
}
|