Skip to content
Merged
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
1 change: 0 additions & 1 deletion Sources/SkipScript/JSContext.swift
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,6 @@ extension JSInstance {
public class JSValue {
public let context: JSContext
public let value: JSValueRef
private var functionCallback: JSFunctionInfo? = nil

public init(jsValueRef: JSValueRef, in context: JSContext) {
self.context = context
Expand Down
6 changes: 2 additions & 4 deletions Sources/SkipScript/Skip/skip.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,10 @@ build:
- block: 'dependencies'
contents:
# JSC is now on Maven central (https://github.com/facebook/react-native/pull/47972): https://repo1.maven.org/maven2/io/github/react-native-community/jsc-android/2026004.0.1/
- 'implementation("io.github.react-native-community:jsc-android-intl:2026004.0.1")'
- 'implementation("io.github.react-native-community:jsc-android:2026004.0.1")' # 26.9 MB
#- 'implementation("io.github.react-native-community:jsc-android-intl:2026004.0.1")' # international version: 53.7 MB
- 'implementation("com.facebook.fbjni:fbjni:0.7.0")' # needed for libc++_shared.so, else no symbol "_ZNSt6__ndk122__libcpp_verbose_abortEPKcz"

# non-international version
#- 'implementation("io.github.react-native-community:jsc-android:2026004.0.1")'

#- 'implementation("org.webkit:android-jsc-cppruntime:r245459@aar")'
# the -intl variant is bigger (24M vs. 13M), but it is needed for locale support
#- 'implementation("org.webkit:android-jsc-intl:r245459@aar")'
Expand Down
54 changes: 4 additions & 50 deletions Tests/SkipScriptTests/JSContextTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,9 @@ class JSContextTests : XCTestCase {
}

func testIntl() throws {
// the Skip side uses jsc-android rather than jsc-android-intl for size savings
// TODO: provide a separate SkipScriptIntl target that depends on jsc-android-intl
#if !SKIP
let ctx = try XCTUnwrap(JSContext())

XCTAssertEqual("12,34 €", ctx.evaluateScript("new Intl.NumberFormat('de-DE', { style: 'currency', currency: 'EUR' }).format(12.34)")?.toString())
Expand All @@ -104,6 +107,7 @@ class JSContextTests : XCTestCase {

XCTAssertEqual("10/24/2022", ctx.evaluateScript("new Intl.DateTimeFormat('en-US', {timeZone: 'UTC'}).format(new Date('2022-10-24'))")?.toString())
XCTAssertEqual("24/10/2022", ctx.evaluateScript("new Intl.DateTimeFormat('fr-FR', {timeZone: 'UTC'}).format(new Date('2022-10-24'))")?.toString())
#endif
}

func testProxy() throws {
Expand Down Expand Up @@ -164,56 +168,6 @@ class JSContextTests : XCTestCase {
XCTAssertEqual(false, ctx.objectForKeyedSubscript("boolProp").toObject() as? Bool)
}

func testJSCCallbacks() throws {
let jsc = JavaScriptCore.JSGlobalContextCreate(nil)
defer { JavaScriptCore.JSGlobalContextRelease(jsc) }
let ctx = try XCTUnwrap(JSContext(jsGlobalContextRef: jsc))

func eval(_ script: String) throws -> JSValue {
let result = ctx.evaluateScript(script)
if let exception = ctx.exception {
throw JSEvalException(exception: exception)
}
if let result = result {
return result
} else {
throw JSEvalException()
}
}

XCTAssertEqual("test", try eval("'te' + 'st'").toString())

let callbackName = JavaScriptCore.JSStringCreateWithUTF8CString("skip_cb")
defer { JavaScriptCore.JSStringRelease(callbackName) }

#if !SKIP
func callbackPtr(ctx: JSContextRef?, function: JSObjectRef?, thisObject: JSObjectRef?, argumentCount: Int, arguments: UnsafePointer<JSValueRef?>?, exception: UnsafeMutablePointer<JSValueRef?>?) -> JSValueRef? {
JavaScriptCore.JSValueMakeNumber(ctx, callbackResult)
}
#else
let callbackPtr = JSCCallback()
#endif

let callbackFunction = JavaScriptCore.JSObjectMakeFunctionWithCallback(jsc, callbackName, callbackPtr)

// invoke the callback directly
let f = try XCTUnwrap(JavaScriptCore.JSObjectCallAsFunction(jsc, callbackFunction, nil, 0, nil, nil))
XCTAssertEqual(callbackResult, JavaScriptCore.JSValueToNumber(jsc, f, nil))

if !isAndroid { // crashes on Android, passes on Robolectric
JavaScriptCore.JSObjectSetProperty(jsc, jsc, callbackName, callbackFunction, JSPropertyAttributes(kJSPropertyAttributeNone), nil)
XCTAssertEqual(callbackResult.description, try eval("skip_cb()").toString())
}
}

#if SKIP
class JSCCallback : com.sun.jna.Callback {
func callback(ctx: JSContextRef?, function: JSObjectRef?, thisObject: JSObjectRef?, argumentCount: Int32, arguments: UnsafeMutableRawPointer?, exception: UnsafeMutableRawPointer?) -> JSValueRef {
JavaScriptCore.JSValueMakeNumber(ctx!, callbackResult)
}
}
#endif

func testJSCAPILow() throws {
let ctx = JavaScriptCore.JSGlobalContextCreate(nil)
defer { JavaScriptCore.JSGlobalContextRelease(ctx) }
Expand Down
19 changes: 13 additions & 6 deletions Tests/SkipScriptTests/SkipContextTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,9 @@ class SkipContextTests : XCTestCase {
}
for k in 1...100 {
let num = Double.random(in: 0.0...1000.0)
let result = ctx.evaluateScript("sum(\(j), \(k), \(num))")
XCTAssertEqual(Double(i) + Double(j) + Double(k) + num, result?.toDouble(), "\(i)-\(j)-\(k) failure")
let args = [JSValue(double: Double(j), in: ctx), JSValue(double: Double(k), in: ctx), JSValue(double: num, in: ctx)]
let result = try ctx.objectForKeyedSubscript("sum").call(withArguments: args)
XCTAssertEqual(Double(i) + Double(j) + Double(k) + num, result.toDouble(), "\(i)-\(j)-\(k) failure")
}
}
}
Expand All @@ -59,7 +60,6 @@ class SkipContextTests : XCTestCase {
ctx.setObject(stringify, forKeyedSubscript: "stringify")
XCTAssertEqual("", ctx.evaluateScript("stringify()")?.toString())

// call with args crashes on Android with SIGSEGV with Problematic frame: [jna9291175543343818311.tmp+0x7448] Java_com_sun_jna_Native__1getPointer+0x0
XCTAssertEqual("", ctx.evaluateScript("stringify('')")?.toString())
XCTAssertEqual("ABC", ctx.evaluateScript("stringify('A', 'BC')")?.toString())
XCTAssertEqual("true12X", ctx.evaluateScript("stringify(true, 1, 2, 'X')")?.toString())
Expand Down Expand Up @@ -103,9 +103,16 @@ class SkipContextTests : XCTestCase {
XCTAssertFalse(r0.isUndefined)
XCTAssertEqual(1.0, r0.toDouble())
}
}

XCTAssertTrue(sum.isFunction)
XCTAssertTrue(ctx.objectForKeyedSubscript("ob").objectForKeyedSubscript("sum").isFunction)
do {
// call with many args
XCTAssertTrue(sum.isFunction)
let sumf = ctx.objectForKeyedSubscript("ob").objectForKeyedSubscript("sum")
XCTAssertTrue(sumf.isFunction)
let args = (1..<1_000).map({ JSValue(double: Double($0), in: ctx) })
let result = try sumf.call(withArguments: args)
XCTAssertEqual(499_500.0, result.toDouble())
}
}
}
}