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.
This commit is contained in:
Edison Jwa
2026-06-07 23:36:31 +09:00
parent e048b6b6bd
commit 68a7892e19
2 changed files with 38 additions and 5 deletions
+12 -5
View File
@@ -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<void>(() async {
await Process.run('open', [
'x-apple.systempreferences:com.apple.preference.security?Privacy_LocalNetwork',
]);
}).catchError((_) {}),
);
},
),
),
@@ -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();
},
);
}