Skip to content

BridgeJS: Add more smoke tests for throwing functions #376

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 16, 2025
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
2 changes: 1 addition & 1 deletion Plugins/BridgeJS/Sources/BridgeJSTool/ExportSwift.swift
Original file line number Diff line number Diff line change
Expand Up @@ -523,7 +523,7 @@ class ExportSwift {
case .i64: return "return 0"
case .f32: return "return 0.0"
case .f64: return "return 0.0"
case .pointer: return "return UnsafeMutableRawPointer(bitPattern: -1)"
case .pointer: return "return UnsafeMutableRawPointer(bitPattern: -1).unsafelyUnwrapped"
case .none: return "return"
}
}
Expand Down
13 changes: 11 additions & 2 deletions Tests/BridgeJSRuntimeTests/ExportAPITests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,18 @@ struct TestError: Error {
let message: String
}

@JS func throwsSwiftError() throws(JSException) -> Void {
throw JSException(JSError(message: "TestError").jsValue)
@JS func throwsSwiftError(shouldThrow: Bool) throws(JSException) -> Void {
if shouldThrow {
throw JSException(JSError(message: "TestError").jsValue)
}
}
@JS func throwsWithIntResult() throws(JSException) -> Int { return 1 }
@JS func throwsWithStringResult() throws(JSException) -> String { return "Ok" }
@JS func throwsWithBoolResult() throws(JSException) -> Bool { return true }
@JS func throwsWithFloatResult() throws(JSException) -> Float { return 1.0 }
@JS func throwsWithDoubleResult() throws(JSException) -> Double { return 1.0 }
@JS func throwsWithSwiftHeapObjectResult() throws(JSException) -> Greeter { return Greeter(name: "Test") }
@JS func throwsWithJSObjectResult() throws(JSException) -> JSObject { return JSObject() }

@JS class Greeter {
var name: String
Expand Down
153 changes: 151 additions & 2 deletions Tests/BridgeJSRuntimeTests/Generated/ExportSwift.swift
Original file line number Diff line number Diff line change
Expand Up @@ -79,9 +79,9 @@ public func _bjs_roundTripJSObject(v: Int32) -> Int32 {

@_expose(wasm, "bjs_throwsSwiftError")
@_cdecl("bjs_throwsSwiftError")
public func _bjs_throwsSwiftError() -> Void {
public func _bjs_throwsSwiftError(shouldThrow: Int32) -> Void {
do {
try throwsSwiftError()
try throwsSwiftError(shouldThrow: shouldThrow == 1)
} catch let error {
if let error = error.thrownValue.object {
withExtendedLifetime(error) {
Expand All @@ -97,6 +97,155 @@ public func _bjs_throwsSwiftError() -> Void {
}
}

@_expose(wasm, "bjs_throwsWithIntResult")
@_cdecl("bjs_throwsWithIntResult")
public func _bjs_throwsWithIntResult() -> Int32 {
do {
let ret = try throwsWithIntResult()
return Int32(ret)
} catch let error {
if let error = error.thrownValue.object {
withExtendedLifetime(error) {
_swift_js_throw(Int32(bitPattern: $0.id))
}
} else {
let jsError = JSError(message: String(describing: error))
withExtendedLifetime(jsError.jsObject) {
_swift_js_throw(Int32(bitPattern: $0.id))
}
}
return 0
}
}

@_expose(wasm, "bjs_throwsWithStringResult")
@_cdecl("bjs_throwsWithStringResult")
public func _bjs_throwsWithStringResult() -> Void {
do {
var ret = try throwsWithStringResult()
return ret.withUTF8 { ptr in
_return_string(ptr.baseAddress, Int32(ptr.count))
}
} catch let error {
if let error = error.thrownValue.object {
withExtendedLifetime(error) {
_swift_js_throw(Int32(bitPattern: $0.id))
}
} else {
let jsError = JSError(message: String(describing: error))
withExtendedLifetime(jsError.jsObject) {
_swift_js_throw(Int32(bitPattern: $0.id))
}
}
return
}
}

@_expose(wasm, "bjs_throwsWithBoolResult")
@_cdecl("bjs_throwsWithBoolResult")
public func _bjs_throwsWithBoolResult() -> Int32 {
do {
let ret = try throwsWithBoolResult()
return Int32(ret ? 1 : 0)
} catch let error {
if let error = error.thrownValue.object {
withExtendedLifetime(error) {
_swift_js_throw(Int32(bitPattern: $0.id))
}
} else {
let jsError = JSError(message: String(describing: error))
withExtendedLifetime(jsError.jsObject) {
_swift_js_throw(Int32(bitPattern: $0.id))
}
}
return 0
}
}

@_expose(wasm, "bjs_throwsWithFloatResult")
@_cdecl("bjs_throwsWithFloatResult")
public func _bjs_throwsWithFloatResult() -> Float32 {
do {
let ret = try throwsWithFloatResult()
return Float32(ret)
} catch let error {
if let error = error.thrownValue.object {
withExtendedLifetime(error) {
_swift_js_throw(Int32(bitPattern: $0.id))
}
} else {
let jsError = JSError(message: String(describing: error))
withExtendedLifetime(jsError.jsObject) {
_swift_js_throw(Int32(bitPattern: $0.id))
}
}
return 0.0
}
}

@_expose(wasm, "bjs_throwsWithDoubleResult")
@_cdecl("bjs_throwsWithDoubleResult")
public func _bjs_throwsWithDoubleResult() -> Float64 {
do {
let ret = try throwsWithDoubleResult()
return Float64(ret)
} catch let error {
if let error = error.thrownValue.object {
withExtendedLifetime(error) {
_swift_js_throw(Int32(bitPattern: $0.id))
}
} else {
let jsError = JSError(message: String(describing: error))
withExtendedLifetime(jsError.jsObject) {
_swift_js_throw(Int32(bitPattern: $0.id))
}
}
return 0.0
}
}

@_expose(wasm, "bjs_throwsWithSwiftHeapObjectResult")
@_cdecl("bjs_throwsWithSwiftHeapObjectResult")
public func _bjs_throwsWithSwiftHeapObjectResult() -> UnsafeMutableRawPointer {
do {
let ret = try throwsWithSwiftHeapObjectResult()
return Unmanaged.passRetained(ret).toOpaque()
} catch let error {
if let error = error.thrownValue.object {
withExtendedLifetime(error) {
_swift_js_throw(Int32(bitPattern: $0.id))
}
} else {
let jsError = JSError(message: String(describing: error))
withExtendedLifetime(jsError.jsObject) {
_swift_js_throw(Int32(bitPattern: $0.id))
}
}
return UnsafeMutableRawPointer(bitPattern: -1).unsafelyUnwrapped
}
}

@_expose(wasm, "bjs_throwsWithJSObjectResult")
@_cdecl("bjs_throwsWithJSObjectResult")
public func _bjs_throwsWithJSObjectResult() -> Int32 {
do {
let ret = try throwsWithJSObjectResult()
return _swift_js_retain(Int32(bitPattern: ret.id))
} catch let error {
if let error = error.thrownValue.object {
withExtendedLifetime(error) {
_swift_js_throw(Int32(bitPattern: $0.id))
}
} else {
let jsError = JSError(message: String(describing: error))
withExtendedLifetime(jsError.jsObject) {
_swift_js_throw(Int32(bitPattern: $0.id))
}
}
return 0
}
}

@_expose(wasm, "bjs_takeGreeter")
@_cdecl("bjs_takeGreeter")
public func _bjs_takeGreeter(g: UnsafeMutableRawPointer, nameBytes: Int32, nameLen: Int32) -> Void {
Expand Down
120 changes: 120 additions & 0 deletions Tests/BridgeJSRuntimeTests/Generated/JavaScript/ExportSwift.json
Original file line number Diff line number Diff line change
Expand Up @@ -257,14 +257,134 @@
},
"name" : "throwsSwiftError",
"parameters" : [
{
"label" : "shouldThrow",
"name" : "shouldThrow",
"type" : {
"bool" : {

}
}
}
],
"returnType" : {
"void" : {

}
}
},
{
"abiName" : "bjs_throwsWithIntResult",
"effects" : {
"isAsync" : false,
"isThrows" : true
},
"name" : "throwsWithIntResult",
"parameters" : [

],
"returnType" : {
"int" : {

}
}
},
{
"abiName" : "bjs_throwsWithStringResult",
"effects" : {
"isAsync" : false,
"isThrows" : true
},
"name" : "throwsWithStringResult",
"parameters" : [

],
"returnType" : {
"string" : {

}
}
},
{
"abiName" : "bjs_throwsWithBoolResult",
"effects" : {
"isAsync" : false,
"isThrows" : true
},
"name" : "throwsWithBoolResult",
"parameters" : [

],
"returnType" : {
"bool" : {

}
}
},
{
"abiName" : "bjs_throwsWithFloatResult",
"effects" : {
"isAsync" : false,
"isThrows" : true
},
"name" : "throwsWithFloatResult",
"parameters" : [

],
"returnType" : {
"float" : {

}
}
},
{
"abiName" : "bjs_throwsWithDoubleResult",
"effects" : {
"isAsync" : false,
"isThrows" : true
},
"name" : "throwsWithDoubleResult",
"parameters" : [

],
"returnType" : {
"double" : {

}
}
},
{
"abiName" : "bjs_throwsWithSwiftHeapObjectResult",
"effects" : {
"isAsync" : false,
"isThrows" : true
},
"name" : "throwsWithSwiftHeapObjectResult",
"parameters" : [

],
"returnType" : {
"swiftHeapObject" : {
"_0" : "Greeter"
}
}
},
{
"abiName" : "bjs_throwsWithJSObjectResult",
"effects" : {
"isAsync" : false,
"isThrows" : true
},
"name" : "throwsWithJSObjectResult",
"parameters" : [

],
"returnType" : {
"jsObject" : {

}
}
},
{
"abiName" : "bjs_takeGreeter",
"effects" : {
Expand Down
8 changes: 7 additions & 1 deletion Tests/prelude.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -107,11 +107,17 @@ function BridgeJSRuntimeTests_runJsWorks(instance, exports) {
assert.equal(exports.roundTripJSObject(anyObject), anyObject);

try {
exports.throwsSwiftError();
exports.throwsSwiftError(true);
assert.fail("Expected error");
} catch (error) {
assert.equal(error.message, "TestError", error);
}

try {
exports.throwsSwiftError(false);
} catch (error) {
assert.fail("Expected no error");
}
}

function setupTestGlobals(global) {
Expand Down