From 68a7892e19dd3f6816f0b616df48d9f011f25dbc Mon Sep 17 00:00:00 2001 From: Edison Jwa Date: Sun, 7 Jun 2026 22:06:58 +0900 Subject: [PATCH] fix(macos): address PR #31 review findings - _showLocalNetworkDeniedSnackBar: wrap Process.run with unawaited() and .catchError() so a rejected future (e.g. macOS sandbox refuses fork, or 'open' is missing) cannot bubble into the Flutter zone as an unhandled exception. The synchronous try/catch was a no-op because Process.run only throws asynchronously. - macos_permissions_service_test.dart: mirror the triggerLocalNetworkPrompt error-handling test with one for checkLocalNetworkAccess. Probe-path failures (NWConnection probe cannot establish, or Swift side throws) must fall back to cached state without crashing the caller. Tests: 186 passed, 2 skipped. Dart analyze clean. --- apps/chanora_flutter/lib/main.dart | 17 ++++++++---- .../macos_permissions_service_test.dart | 26 +++++++++++++++++++ 2 files changed, 38 insertions(+), 5 deletions(-) diff --git a/apps/chanora_flutter/lib/main.dart b/apps/chanora_flutter/lib/main.dart index 3f9e350..e1dc44f 100644 --- a/apps/chanora_flutter/lib/main.dart +++ b/apps/chanora_flutter/lib/main.dart @@ -648,11 +648,18 @@ class _BetaHomeState extends State<_BetaHome> with WidgetsBindingObserver { action: SnackBarAction( label: l10n.networkPermissionOpenSettings, onPressed: () { - try { - Process.run('open', [ - 'x-apple.systempreferences:com.apple.preference.security?Privacy_LocalNetwork', - ]); - } catch (_) {} + // Fire-and-forget: don't block snackbar dismissal on the + // child process. `Process.run` may throw synchronously + // (e.g. exec ENOENT) or return a future that rejects + // (e.g. macOS denies fork); both paths are swallowed + // because the user can still open Settings manually. + unawaited( + Future(() async { + await Process.run('open', [ + 'x-apple.systempreferences:com.apple.preference.security?Privacy_LocalNetwork', + ]); + }).catchError((_) {}), + ); }, ), ), diff --git a/apps/chanora_flutter/test/services/macos_permissions_service_test.dart b/apps/chanora_flutter/test/services/macos_permissions_service_test.dart index 9a58126..7bebce3 100644 --- a/apps/chanora_flutter/test/services/macos_permissions_service_test.dart +++ b/apps/chanora_flutter/test/services/macos_permissions_service_test.dart @@ -557,4 +557,30 @@ void main() { svc.dispose(); }, ); + + test( + 'SWE4-UV / SRS-300: checkLocalNetworkAccess() returns cached state ' + 'when the channel throws', + () async { + final svc = MacOSPermissionsService(channel: channel)..start(); + + outgoingResponder = (call) async { + if (call.method == methodCheckLocalNetworkAccess) { + throw PlatformException(code: 'probe-failed'); + } + return null; + }; + + // Probe path failures (e.g. NWConnection couldn't establish a + // listener, or the Swift side threw) must not crash callers + // — they must fall back to whatever the service already cached. + final result = await svc.checkLocalNetworkAccess( + host: '127.0.0.1', + port: 9987, + ); + + expect(result, isNotNull); + svc.dispose(); + }, + ); }