import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:permission_handler/permission_handler.dart'; import 'package:smtias_capture/services/permission_service.dart'; /// permission_handler が使うプラットフォームチャネル名. const _channel = MethodChannel('flutter.baseflow.com/permissions/methods'); /// プラットフォームチャネルの応答を差し替えるテスト用のフェイク. /// /// `checkPermissionStatus` には [checkStatus] を, /// `requestPermissions` には [requestStatus] を返す. class _FakePermissionPlatform { PermissionStatus checkStatus = PermissionStatus.denied; PermissionStatus requestStatus = PermissionStatus.denied; final List calls = []; Future handle(MethodCall call) async { calls.add(call.method); switch (call.method) { case 'checkPermissionStatus': return checkStatus.index; case 'requestPermissions': final permissions = (call.arguments as List).cast(); return {for (final p in permissions) p: requestStatus.index}; case 'openAppSettings': return true; } return null; } } void main() { TestWidgetsFlutterBinding.ensureInitialized(); late _FakePermissionPlatform platform; setUp(() { platform = _FakePermissionPlatform(); TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger .setMockMethodCallHandler(_channel, platform.handle); }); tearDown(() { TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger .setMockMethodCallHandler(_channel, null); }); group('PermissionService', () { group('requestCamera()', () { test('許可された場合,true を返す', () async { platform.requestStatus = PermissionStatus.granted; final service = PermissionService(); expect(await service.requestCamera(), isTrue); expect(platform.calls, contains('requestPermissions')); }); test('拒否された場合,false を返す', () async { platform.requestStatus = PermissionStatus.denied; final service = PermissionService(); expect(await service.requestCamera(), isFalse); }); test('永久拒否された場合,false を返す', () async { platform.requestStatus = PermissionStatus.permanentlyDenied; final service = PermissionService(); expect(await service.requestCamera(), isFalse); }); }); group('requestStorage()', () { test('許可された場合,true を返す', () async { platform.requestStatus = PermissionStatus.granted; final service = PermissionService(); expect(await service.requestStorage(), isTrue); }); test('拒否された場合,false を返す', () async { platform.requestStatus = PermissionStatus.denied; final service = PermissionService(); expect(await service.requestStorage(), isFalse); }); }); group('isCameraPermanentlyDenied()(requestCamera 未実行)', () { test('status が permanentlyDenied の場合,true を返す', () async { platform.checkStatus = PermissionStatus.permanentlyDenied; final service = PermissionService(); expect(await service.isCameraPermanentlyDenied(), isTrue); expect(platform.calls, ['checkPermissionStatus']); }); test('status が denied の場合,false を返す', () async { platform.checkStatus = PermissionStatus.denied; final service = PermissionService(); expect(await service.isCameraPermanentlyDenied(), isFalse); }); test('status が granted の場合,false を返す', () async { platform.checkStatus = PermissionStatus.granted; final service = PermissionService(); expect(await service.isCameraPermanentlyDenied(), isFalse); }); }); group('isCameraPermanentlyDenied()(requestCamera 実行後)', () { test( 'request 結果が permanentlyDenied の場合,status が denied でも true を返す', () async { // permission_handler_android 14.1.0 以降の挙動を再現する: // status では永久拒否が分からず,request の結果でのみ分かる. platform.requestStatus = PermissionStatus.permanentlyDenied; platform.checkStatus = PermissionStatus.denied; final service = PermissionService(); await service.requestCamera(); expect(await service.isCameraPermanentlyDenied(), isTrue); }, ); test( 'request 結果が denied の場合,status が permanentlyDenied でも false を返す', () async { platform.requestStatus = PermissionStatus.denied; platform.checkStatus = PermissionStatus.permanentlyDenied; final service = PermissionService(); await service.requestCamera(); expect(await service.isCameraPermanentlyDenied(), isFalse); }, ); test('request 結果が granted の場合,false を返す', () async { platform.requestStatus = PermissionStatus.granted; platform.checkStatus = PermissionStatus.permanentlyDenied; final service = PermissionService(); await service.requestCamera(); expect(await service.isCameraPermanentlyDenied(), isFalse); }); test('request 後の判定ではプラットフォームの status を問い合わせない', () async { platform.requestStatus = PermissionStatus.permanentlyDenied; final service = PermissionService(); await service.requestCamera(); platform.calls.clear(); await service.isCameraPermanentlyDenied(); expect(platform.calls, isNot(contains('checkPermissionStatus'))); }); test('request を複数回実行した場合,直近の結果で判定する', () async { final service = PermissionService(); platform.requestStatus = PermissionStatus.permanentlyDenied; await service.requestCamera(); expect(await service.isCameraPermanentlyDenied(), isTrue); // 設定画面で許可して戻った後の再要求を想定する. platform.requestStatus = PermissionStatus.granted; await service.requestCamera(); expect(await service.isCameraPermanentlyDenied(), isFalse); }); test('requestStorage の結果はカメラの永久拒否判定に影響しない', () async { platform.checkStatus = PermissionStatus.denied; platform.requestStatus = PermissionStatus.permanentlyDenied; final service = PermissionService(); await service.requestStorage(); expect(await service.isCameraPermanentlyDenied(), isFalse); }); }); group('openSettings()', () { test('アプリの設定画面を開く要求をプラットフォームへ送る', () async { final service = PermissionService(); await service.openSettings(); expect(platform.calls, contains('openAppSettings')); }); }); }); }