also looking at this
fix(ios): preserve busy errors through dispatch
#270
3 files
+33
-13
Review threads live on the whole diff, not on one commit, so none are shown here - a thread's line means something in the branch's final form, and painting it into an intermediate step would put it on code it is not about.
| @@ -190,6 +190,25 @@ pub fn errorMessage(err: BridgeError) []const u8 { | ||
| 190 | 190 | }; |
| 191 | 191 | } |
| 192 | 192 | |
| 193 | /// Narrow the wider error set inferred for a bridge handler to the failures | |
| 194 | /// the dispatcher exposes. Errors the protocol cannot name become the honest | |
| 195 | /// catch-all instead of leaving the page without a reply. | |
| 196 | pub fn fromHandlerError(err: anyerror) BridgeError { | |
| 197 | return switch (err) { | |
| 198 | error.AllocationFailed, error.OutOfMemory => BridgeError.AllocationFailed, | |
| 199 | error.UnknownAction => BridgeError.UnknownAction, | |
| 200 | error.MissingData => BridgeError.MissingData, | |
| 201 | error.InvalidJSON => BridgeError.InvalidJSON, | |
| 202 | error.InvalidParameter => BridgeError.InvalidParameter, | |
| 203 | error.Busy => BridgeError.Busy, | |
| 204 | error.PlatformNotSupported, error.UnsupportedPlatform => BridgeError.PlatformNotSupported, | |
| 205 | error.NotFound => BridgeError.NotFound, | |
| 206 | error.PermissionDenied => BridgeError.PermissionDenied, | |
| 207 | error.Timeout => BridgeError.Timeout, | |
| 208 | else => BridgeError.NativeCallFailed, | |
| 209 | }; | |
| 210 | } | |
| 211 | ||
| 193 | 212 | /// Send error to JavaScript via eval |
| 194 | 213 | pub fn sendErrorToJS(allocator: std.mem.Allocator, action: []const u8, err: BridgeError) void { |
| 195 | 214 | var ctx = ErrorContext.init(err, action, errorMessage(err)); |
| @@ -358,6 +377,14 @@ test "errorCodeString returns correct codes" { | ||
| 358 | 377 | try testing.expectEqualStrings("BUSY", errorCodeString(BridgeError.Busy)); |
| 359 | 378 | } |
| 360 | 379 | |
| 380 | test "handler error narrowing preserves protocol errors" { | |
| 381 | const testing = std.testing; | |
| 382 | try testing.expectEqual(BridgeError.Busy, fromHandlerError(error.Busy)); | |
| 383 | try testing.expectEqual(BridgeError.PlatformNotSupported, fromHandlerError(error.UnsupportedPlatform)); | |
| 384 | try testing.expectEqual(BridgeError.AllocationFailed, fromHandlerError(error.OutOfMemory)); | |
| 385 | try testing.expectEqual(BridgeError.NativeCallFailed, fromHandlerError(error.NotInTheProtocol)); | |
| 386 | } | |
| 387 | ||
| 361 | 388 | test "ErrorContext.toJSON produces valid JSON" { |
| 362 | 389 | const testing = std.testing; |
| 363 | 390 | const allocator = testing.allocator; |
| @@ -1434,7 +1434,7 @@ test "a delegate callback with no call recorded touches no slot" { | ||
| 1434 | 1434 | test "the pool refusal is an error the caller sees, not a dropped call" { |
| 1435 | 1435 | try testing.expectEqual( |
| 1436 | 1436 | bridge_error.BridgeError.Busy, |
| 1437 | poolFull(A.open_camera), | |
| 1437 | bridge_error.fromHandlerError(poolFull(A.open_camera)), | |
| 1438 | 1438 | ); |
| 1439 | 1439 | } |
| 1440 | 1440 | |
| @@ -418,18 +418,7 @@ fn hostServesItself(action: []const u8) bool { | ||
| 418 | 418 | /// settle. `NativeCallFailed` is the honest catch-all for "it broke in a way |
| 419 | 419 | /// the protocol has no word for". |
| 420 | 420 | fn asBridgeError(err: anyerror) bridge_error.BridgeError { |
| 421 | return switch (err) { | |
| 422 | error.AllocationFailed, error.OutOfMemory => bridge_error.BridgeError.AllocationFailed, | |
| 423 | error.InvalidJSON => bridge_error.BridgeError.InvalidJSON, | |
| 424 | error.InvalidParameter => bridge_error.BridgeError.InvalidParameter, | |
| 425 | error.MissingData => bridge_error.BridgeError.MissingData, | |
| 426 | error.NotFound => bridge_error.BridgeError.NotFound, | |
| 427 | error.PermissionDenied => bridge_error.BridgeError.PermissionDenied, | |
| 428 | error.PlatformNotSupported, error.UnsupportedPlatform => bridge_error.BridgeError.PlatformNotSupported, | |
| 429 | error.Timeout => bridge_error.BridgeError.Timeout, | |
| 430 | error.UnknownAction => bridge_error.BridgeError.UnknownAction, | |
| 431 | else => bridge_error.BridgeError.NativeCallFailed, | |
| 432 | }; | |
| 421 | return bridge_error.fromHandlerError(err); | |
| 433 | 422 | } |
| 434 | 423 | |
| 435 | 424 | /// Hand an action to the host shim. Returns false when there is no shim. |
| @@ -790,6 +779,10 @@ test "a handler error reaches the page as something the protocol can say" { | ||
| 790 | 779 | bridge_error.BridgeError.PlatformNotSupported, |
| 791 | 780 | asBridgeError(error.UnsupportedPlatform), |
| 792 | 781 | ); |
| 782 | try testing.expectEqual( | |
| 783 | bridge_error.BridgeError.Busy, | |
| 784 | asBridgeError(error.Busy), | |
| 785 | ); | |
| 793 | 786 | // The catch-all. An error the protocol has no word for still gets one. |
| 794 | 787 | try testing.expectEqual( |
| 795 | 788 | bridge_error.BridgeError.NativeCallFailed, |