Improve script and REPL result handling:
- implement error result - refactor other result classes - implement handling in the script evaluation extension - also restores previous script error reporting functionality - add possibility to customize result fileds in script and REPL - refactor result calculation in the backend: cleanup, rename (since it is not only about REPL now)
This commit is contained in:
+47
-16
@@ -27,7 +27,7 @@ class ReplTest : TestCase() {
|
||||
@Test
|
||||
fun testCompileAndEval() {
|
||||
val out = captureOut {
|
||||
chechEvaluateInReplNoErrors(
|
||||
chechEvaluateInRepl(
|
||||
simpleScriptompilationConfiguration,
|
||||
simpleScriptEvaluationConfiguration,
|
||||
sequenceOf(
|
||||
@@ -41,6 +41,32 @@ class ReplTest : TestCase() {
|
||||
Assert.assertEquals("x = 3", out)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testEvalWithResult() {
|
||||
chechEvaluateInRepl(
|
||||
simpleScriptompilationConfiguration,
|
||||
simpleScriptEvaluationConfiguration,
|
||||
sequenceOf(
|
||||
"val x = 5",
|
||||
"x + 6",
|
||||
"res1 * 2"
|
||||
),
|
||||
sequenceOf(null, 11, 22)
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testEvalWithError() {
|
||||
chechEvaluateInRepl(
|
||||
simpleScriptompilationConfiguration,
|
||||
simpleScriptEvaluationConfiguration,
|
||||
sequenceOf(
|
||||
"throw RuntimeException(\"abc\")"
|
||||
),
|
||||
sequenceOf(RuntimeException("abc"))
|
||||
)
|
||||
}
|
||||
|
||||
fun evaluateInRepl(
|
||||
compilationConfiguration: ScriptCompilationConfiguration,
|
||||
evaluationConfiguration: ScriptEvaluationConfiguration,
|
||||
@@ -62,15 +88,12 @@ class ReplTest : TestCase() {
|
||||
}
|
||||
}
|
||||
.onSuccess {
|
||||
val snippetInstance = when (val retVal = it.returnValue) {
|
||||
is ResultValue.Value -> retVal.scriptInstance
|
||||
is ResultValue.UnitValue -> retVal.scriptInstance
|
||||
else -> throw IllegalStateException("Expecting value with script instance, got $it")
|
||||
}
|
||||
currentEvalConfig = ScriptEvaluationConfiguration(currentEvalConfig) {
|
||||
previousSnippets.append(snippetInstance)
|
||||
jvm {
|
||||
baseClassLoader(snippetInstance::class.java.classLoader)
|
||||
it.returnValue.scriptInstance?.let { snippetInstance ->
|
||||
currentEvalConfig = ScriptEvaluationConfiguration(currentEvalConfig) {
|
||||
previousSnippets.append(snippetInstance)
|
||||
jvm {
|
||||
baseClassLoader(snippetInstance::class.java.classLoader)
|
||||
}
|
||||
}
|
||||
}
|
||||
it.asSuccess()
|
||||
@@ -78,7 +101,7 @@ class ReplTest : TestCase() {
|
||||
}
|
||||
}
|
||||
|
||||
fun chechEvaluateInReplNoErrors(
|
||||
fun chechEvaluateInRepl(
|
||||
compilationConfiguration: ScriptCompilationConfiguration,
|
||||
evaluationConfiguration: ScriptEvaluationConfiguration,
|
||||
snippets: Sequence<String>,
|
||||
@@ -90,11 +113,19 @@ class ReplTest : TestCase() {
|
||||
is ResultWithDiagnostics.Failure -> Assert.fail("#$index: Expected result, got $res")
|
||||
is ResultWithDiagnostics.Success -> {
|
||||
val expectedVal = expectedIter.next()
|
||||
val resVal = res.value.returnValue
|
||||
if (resVal is ResultValue.Value && resVal.type.isNotBlank()) // TODO: the latter check is temporary while the result is used to return the instance too
|
||||
Assert.assertEquals("#$index: Expected $expectedVal, got $resVal", expectedVal, resVal.value)
|
||||
else
|
||||
Assert.assertTrue("#$index: Expected $expectedVal, got Unit", expectedVal == null)
|
||||
when (val resVal = res.value.returnValue) {
|
||||
is ResultValue.Value -> Assert.assertEquals(
|
||||
"#$index: Expected $expectedVal, got $resVal",
|
||||
expectedVal,
|
||||
resVal.value
|
||||
)
|
||||
is ResultValue.Unit -> Assert.assertTrue("#$index: Expected $expectedVal, got Unit", expectedVal == null)
|
||||
is ResultValue.Error -> Assert.assertTrue(
|
||||
"#$index: Expected $expectedVal, got Error: ${resVal.error}",
|
||||
expectedVal is Throwable && expectedVal.message == resVal.error.message
|
||||
)
|
||||
else -> Assert.assertTrue("#$index: Expected $expectedVal, got unknown result $resVal", expectedVal == null)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+45
-1
@@ -15,6 +15,7 @@ import org.jetbrains.org.objectweb.asm.Opcodes
|
||||
import org.junit.Assert
|
||||
import org.junit.Test
|
||||
import java.io.*
|
||||
import java.lang.RuntimeException
|
||||
import java.net.URLClassLoader
|
||||
import java.nio.file.Files
|
||||
import java.security.MessageDigest
|
||||
@@ -51,6 +52,41 @@ class ScriptingHostTest : TestCase() {
|
||||
Assert.assertEquals(greeting, output2)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testValueResult() {
|
||||
val resVal = evalScriptWithResult("42") as ResultValue.Value
|
||||
Assert.assertEquals(42, resVal.value)
|
||||
Assert.assertEquals("\$\$result", resVal.name)
|
||||
Assert.assertEquals("kotlin.Int", resVal.type)
|
||||
val resField = resVal.scriptInstance!!::class.java.getDeclaredField("\$\$result")
|
||||
Assert.assertEquals(42, resField.get(resVal.scriptInstance!!))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testUnitResult() {
|
||||
val resVal = evalScriptWithResult("val x = 42")
|
||||
Assert.assertTrue(resVal is ResultValue.Unit)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testErrorResult() {
|
||||
val resVal = evalScriptWithResult("throw RuntimeException(\"abc\")")
|
||||
Assert.assertTrue(resVal is ResultValue.Error)
|
||||
val resValError = (resVal as ResultValue.Error).error
|
||||
Assert.assertTrue(resValError is RuntimeException)
|
||||
Assert.assertEquals("abc", resValError.message)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testCustomResultField() {
|
||||
val resVal = evalScriptWithResult("42") {
|
||||
resultField("outcome")
|
||||
} as ResultValue.Value
|
||||
Assert.assertEquals("outcome", resVal.name)
|
||||
val resField = resVal.scriptInstance!!::class.java.getDeclaredField("outcome")
|
||||
Assert.assertEquals(42, resField.get(resVal.scriptInstance!!))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testSaveToClasses() {
|
||||
val greeting = "Hello from script classes!"
|
||||
@@ -366,7 +402,8 @@ class ScriptingHostTest : TestCase() {
|
||||
val evaluator = BasicJvmScriptEvaluator()
|
||||
val host = BasicJvmScriptingHost(compiler = compiler, evaluator = evaluator)
|
||||
|
||||
val scriptCompilationConfiguration = createJvmCompilationConfigurationFromTemplate<SimpleScriptTemplate>(body = configurationBuilder)
|
||||
val scriptCompilationConfiguration =
|
||||
createJvmCompilationConfigurationFromTemplate<SimpleScriptTemplate>(body = configurationBuilder)
|
||||
|
||||
Assert.assertEquals(0, cache.storedScripts)
|
||||
var compiledScript: CompiledScript<*>? = null
|
||||
@@ -453,6 +490,13 @@ fun <T> ResultWithDiagnostics<T>.throwOnFailure(): ResultWithDiagnostics<T> = ap
|
||||
private fun evalScript(script: String, host: BasicScriptingHost = BasicJvmScriptingHost()): ResultWithDiagnostics<*> =
|
||||
evalScriptWithConfiguration(script, host)
|
||||
|
||||
private fun evalScriptWithResult(
|
||||
script: String,
|
||||
host: BasicScriptingHost = BasicJvmScriptingHost(),
|
||||
body: ScriptCompilationConfiguration.Builder.() -> Unit = {}
|
||||
): ResultValue =
|
||||
evalScriptWithConfiguration(script, host, body).throwOnFailure().valueOrNull()!!.returnValue
|
||||
|
||||
private fun evalScriptWithConfiguration(
|
||||
script: String,
|
||||
host: BasicScriptingHost = BasicJvmScriptingHost(),
|
||||
|
||||
Reference in New Issue
Block a user