This commit is contained in:
kunfei
2023-03-25 13:56:34 +08:00
parent c4f09e4578
commit b5b59826b7
5 changed files with 76 additions and 96 deletions
@@ -1,7 +1,5 @@
package io.legado.app package io.legado.app
import com.script.SimpleBindings
import io.legado.app.constant.SCRIPT_ENGINE
import org.junit.Assert.assertEquals import org.junit.Assert.assertEquals
import org.junit.Test import org.junit.Test
@@ -12,21 +10,10 @@ import org.junit.Test
* See [testing documentation](http://d.android.com/tools/testing). * See [testing documentation](http://d.android.com/tools/testing).
*/ */
class ExampleUnitTest { class ExampleUnitTest {
@Test @Test
fun addition_isCorrect() { fun addition_isCorrect() {
assertEquals(4, 2 + 2) assertEquals(4, 2 + 2)
} }
@Test
fun jsTest() {
val map = hashMapOf("id" to "3242532321")
map["id"] = "12314123"
val bindings = SimpleBindings()
bindings["result"] = map
val js = "$=result;id=$.id;id"
val result = SCRIPT_ENGINE.eval(js, bindings)?.toString()
assertEquals("12314123", result)
}
} }
+52
View File
@@ -0,0 +1,52 @@
package io.legado.app
import com.script.SimpleBindings
import io.legado.app.constant.SCRIPT_ENGINE
import org.intellij.lang.annotations.Language
import org.junit.Assert
import org.junit.Test
class JsTest {
@Test
fun testMap() {
val map = hashMapOf("id" to "3242532321")
map["id"] = "12314123"
val bindings = SimpleBindings()
bindings["result"] = map
@Language("js")
val jsMap = "$=result;id=$.id;id"
val result = SCRIPT_ENGINE.eval(jsMap, bindings)?.toString()
Assert.assertEquals("12314123", result)
}
@Test
fun testFor() {
@Language("js")
val jsFor = """
let result = 0
let a=[1,2,3]
let l=a.length
for (let i = 0;i<l;i++){
result = result + a[i]
}
for (let o of a){
result = result + o
}
for (let o in a){
result = result + o
}
result
""".trimIndent()
val result = SCRIPT_ENGINE.eval(jsFor).toString()
Assert.assertEquals("12012", result)
}
@Test
fun testReturnNull() {
val result = SCRIPT_ENGINE.eval("null")
Assert.assertEquals(null, result)
}
}
Binary file not shown.
@@ -48,12 +48,12 @@ open class InterfaceImplementor(private val engine: Invocable) {
if (!isImplemented(thiz, iface)) { if (!isImplemented(thiz, iface)) {
null null
} else { } else {
val accCtxt = AccessController.getContext() val accContext = AccessController.getContext()
iface.cast( iface.cast(
Proxy.newProxyInstance( Proxy.newProxyInstance(
iface.classLoader, iface.classLoader,
arrayOf<Class<*>>(iface), arrayOf<Class<*>>(iface),
InterfaceImplementorInvocationHandler(thiz, accCtxt) InterfaceImplementorInvocationHandler(thiz, accContext)
) )
) )
} }
@@ -67,7 +67,7 @@ open class InterfaceImplementor(private val engine: Invocable) {
} }
@Throws(ScriptException::class) @Throws(ScriptException::class)
protected open fun convertResult(method: Method?, res: Any): Any { protected open fun convertResult(method: Method?, res: Any): Any? {
return res return res
} }
@@ -78,10 +78,11 @@ open class InterfaceImplementor(private val engine: Invocable) {
private inner class InterfaceImplementorInvocationHandler( private inner class InterfaceImplementorInvocationHandler(
private val thiz: Any?, private val thiz: Any?,
private val accCtxt: AccessControlContext private val accContext: AccessControlContext
) : InvocationHandler { ) : InvocationHandler {
@Throws(Throwable::class) @Throws(Throwable::class)
override fun invoke(proxy: Any, method: Method, args: Array<Any>): Any { override fun invoke(proxy: Any, method: Method, args: Array<Any>): Any? {
val finalArgs = convertArguments(method, args) val finalArgs = convertArguments(method, args)
val result = AccessController.doPrivileged(PrivilegedExceptionAction { val result = AccessController.doPrivileged(PrivilegedExceptionAction {
if (thiz == null) engine.invokeFunction( if (thiz == null) engine.invokeFunction(
@@ -90,8 +91,9 @@ open class InterfaceImplementor(private val engine: Invocable) {
) else engine.invokeMethod( ) else engine.invokeMethod(
thiz, method.name, *finalArgs thiz, method.name, *finalArgs
) )
} as PrivilegedExceptionAction<Any>, accCtxt) } as PrivilegedExceptionAction<Any>, accContext)
return convertResult(method, result) return convertResult(method, result)
} }
} }
} }
@@ -156,48 +156,11 @@ class RhinoScriptEngine : AbstractScriptEngine(), Invocable, Compilable {
} }
} }
fun getRuntimeScope(ctxt: ScriptContext?): Scriptable { fun getRuntimeScope(context: ScriptContext): Scriptable {
return if (ctxt == null) { val newScope: Scriptable = ExternalScriptable(context, indexedProps)
throw NullPointerException("脚本context为空") newScope.prototype = topLevel
} else { newScope.put("context", newScope, context)
val newScope: Scriptable = ExternalScriptable(ctxt, indexedProps) return newScope
newScope.prototype = topLevel
newScope.put("context", newScope, ctxt)
/*
val cx = Context.enter()
try {
@Language("js")
val js = """
function print(str, newline) {
if (typeof(str) == 'undefined') {
str = 'undefined';
} else if (str == null) {
str = 'null';
}
var out = context.getWriter();
if (!(out instanceof java.io.PrintWriter))
out = new java.io.PrintWriter(out);
out.print(String(str));
if (newline) out.print('\\n');
out.flush();
}
function println(str) {
print(str, true);
}
""".trimIndent()
cx.evaluateString(
newScope,
js,
"print",
1,
null
)
} finally {
Context.exit()
}
*/
newScope
}
} }
@Throws(ScriptException::class) @Throws(ScriptException::class)
@@ -260,6 +223,7 @@ class RhinoScriptEngine : AbstractScriptEngine(), Invocable, Compilable {
} }
indexedProps = HashMap() indexedProps = HashMap()
implementor = object : InterfaceImplementor(this) { implementor = object : InterfaceImplementor(this) {
override fun isImplemented(thiz: Any?, iface: Class<*>): Boolean { override fun isImplemented(thiz: Any?, iface: Class<*>): Boolean {
var thiz1 = thiz var thiz1 = thiz
return try { return try {
@@ -289,12 +253,11 @@ class RhinoScriptEngine : AbstractScriptEngine(), Invocable, Compilable {
} }
} }
override fun convertResult(method: Method?, res: Any): Any { override fun convertResult(method: Method?, res: Any): Any? {
val desiredType = method!!.returnType method ?: return null
return (if (desiredType == Void.TYPE) null else Context.jsToJava( val desiredType = method.returnType
res, if (desiredType == Void.TYPE) return null
desiredType return Context.jsToJava(res, desiredType)
))!!
} }
} }
} }
@@ -302,30 +265,6 @@ class RhinoScriptEngine : AbstractScriptEngine(), Invocable, Compilable {
@Suppress("unused") @Suppress("unused")
companion object { companion object {
private const val DEBUG = false
/*
@Language("js")
private val printSource = """
function print(str, newline) {
if (typeof str == "undefined") {
str = "undefined";
} else if (str == null) {
str = "null";
}
var out = context.getWriter();
if (!(out instanceof java.io.PrintWriter))
out = new java.io.PrintWriter(out);
out.print(String(str));
if (newline) out.print("\\n");
out.flush();
}
function println(str) {
print(str, true);
}
""".trimIndent()
*/
init { init {
ContextFactory.initGlobal(object : ContextFactory() { ContextFactory.initGlobal(object : ContextFactory() {
@@ -352,16 +291,16 @@ class RhinoScriptEngine : AbstractScriptEngine(), Invocable, Compilable {
thisObj: Scriptable, thisObj: Scriptable,
args: Array<Any> args: Array<Any>
): Any? { ): Any? {
var accCtxt: AccessControlContext? = null var accContext: AccessControlContext? = null
val global = ScriptableObject.getTopLevelScope(scope) val global = ScriptableObject.getTopLevelScope(scope)
val globalProto = global.prototype val globalProto = global.prototype
if (globalProto is RhinoTopLevel) { if (globalProto is RhinoTopLevel) {
accCtxt = globalProto.accessContext accContext = globalProto.accessContext
} }
return if (accCtxt != null) AccessController.doPrivileged( return if (accContext != null) AccessController.doPrivileged(
PrivilegedAction { PrivilegedAction {
superDoTopCall(callable, cx, scope, thisObj, args) superDoTopCall(callable, cx, scope, thisObj, args)
} as PrivilegedAction<*>, accCtxt) else superDoTopCall( } as PrivilegedAction<*>, accContext) else superDoTopCall(
callable, callable,
cx, cx,
scope, scope,