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<String> calls = [];
Future<Object?> 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<int>();
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'));
});
});
});
}