diff --git a/packages/image_picker/image_picker/CHANGELOG.md b/packages/image_picker/image_picker/CHANGELOG.md index 156b9a3a6d23..36a47b1a3d42 100644 --- a/packages/image_picker/image_picker/CHANGELOG.md +++ b/packages/image_picker/image_picker/CHANGELOG.md @@ -1,3 +1,10 @@ +## 0.8.5+3 + +* Adds argument error assertions to the app-facing package, to ensure + consistency across platform implementations. +* Updates tests to use a mock platform instead of relying on default + method channel implementation internals. + ## 0.8.5+2 * Minor fixes for new analysis options. diff --git a/packages/image_picker/image_picker/lib/image_picker.dart b/packages/image_picker/image_picker/lib/image_picker.dart index 5bc99d7f0bb2..84c649028c96 100755 --- a/packages/image_picker/image_picker/lib/image_picker.dart +++ b/packages/image_picker/image_picker/lib/image_picker.dart @@ -207,6 +207,17 @@ class ImagePicker { int? imageQuality, CameraDevice preferredCameraDevice = CameraDevice.rear, }) { + if (imageQuality != null && (imageQuality < 0 || imageQuality > 100)) { + throw ArgumentError.value( + imageQuality, 'imageQuality', 'must be between 0 and 100'); + } + if (maxWidth != null && maxWidth < 0) { + throw ArgumentError.value(maxWidth, 'maxWidth', 'cannot be negative'); + } + if (maxHeight != null && maxHeight < 0) { + throw ArgumentError.value(maxHeight, 'maxHeight', 'cannot be negative'); + } + return platform.getImage( source: source, maxWidth: maxWidth, @@ -245,6 +256,17 @@ class ImagePicker { double? maxHeight, int? imageQuality, }) { + if (imageQuality != null && (imageQuality < 0 || imageQuality > 100)) { + throw ArgumentError.value( + imageQuality, 'imageQuality', 'must be between 0 and 100'); + } + if (maxWidth != null && maxWidth < 0) { + throw ArgumentError.value(maxWidth, 'maxWidth', 'cannot be negative'); + } + if (maxHeight != null && maxHeight < 0) { + throw ArgumentError.value(maxHeight, 'maxHeight', 'cannot be negative'); + } + return platform.getMultiImage( maxWidth: maxWidth, maxHeight: maxHeight, diff --git a/packages/image_picker/image_picker/pubspec.yaml b/packages/image_picker/image_picker/pubspec.yaml index cc34d8ab33f5..9d0cedeec484 100755 --- a/packages/image_picker/image_picker/pubspec.yaml +++ b/packages/image_picker/image_picker/pubspec.yaml @@ -3,7 +3,7 @@ description: Flutter plugin for selecting images from the Android and iOS image library, and taking new pictures with the camera. repository: https://github.com/flutter/plugins/tree/main/packages/image_picker/image_picker issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+image_picker%22 -version: 0.8.5+2 +version: 0.8.5+3 environment: sdk: ">=2.14.0 <3.0.0" @@ -28,6 +28,8 @@ dependencies: image_picker_platform_interface: ^2.3.0 dev_dependencies: + build_runner: ^2.1.10 + cross_file: ^0.3.1+1 # Mockito generates a direct include. flutter_test: sdk: flutter mockito: ^5.0.0 diff --git a/packages/image_picker/image_picker/test/image_picker_deprecated_test.dart b/packages/image_picker/image_picker/test/image_picker_deprecated_test.dart index 00049e14f808..b3db08020d7e 100644 --- a/packages/image_picker/image_picker/test/image_picker_deprecated_test.dart +++ b/packages/image_picker/image_picker/test/image_picker_deprecated_test.dart @@ -14,63 +14,46 @@ import 'package:image_picker_platform_interface/image_picker_platform_interface. import 'package:mockito/mockito.dart'; import 'package:plugin_platform_interface/plugin_platform_interface.dart'; -void main() { - TestWidgetsFlutterBinding.ensureInitialized(); - - group('$ImagePicker', () { - const MethodChannel channel = - MethodChannel('plugins.flutter.io/image_picker'); +import 'image_picker_test.mocks.dart' as base_mock; - final List log = []; +// Add the mixin to make the platform interface accept the mock. +class MockImagePickerPlatform extends base_mock.MockImagePickerPlatform + with MockPlatformInterfaceMixin {} - final ImagePicker picker = ImagePicker(); +void main() { + group('ImagePicker', () { + late MockImagePickerPlatform mockPlatform; - test('ImagePicker platform instance overrides the actual platform used', - () { - final ImagePickerPlatform savedPlatform = ImagePickerPlatform.instance; - final MockPlatform mockPlatform = MockPlatform(); + setUp(() { + mockPlatform = MockImagePickerPlatform(); ImagePickerPlatform.instance = mockPlatform; - expect(ImagePicker.platform, mockPlatform); - ImagePickerPlatform.instance = savedPlatform; }); group('#Single image/video', () { setUp(() { - channel.setMockMethodCallHandler((MethodCall methodCall) async { - log.add(methodCall); - return ''; - }); - - log.clear(); + when(mockPlatform.pickImage( + source: anyNamed('source'), + maxWidth: anyNamed('maxWidth'), + maxHeight: anyNamed('maxHeight'), + imageQuality: anyNamed('imageQuality'), + preferredCameraDevice: anyNamed('preferredCameraDevice'))) + .thenAnswer((Invocation _) async => null); }); group('#pickImage', () { test('passes the image source argument correctly', () async { + final ImagePicker picker = ImagePicker(); await picker.getImage(source: ImageSource.camera); await picker.getImage(source: ImageSource.gallery); - expect( - log, - [ - isMethodCall('pickImage', arguments: { - 'source': 0, - 'maxWidth': null, - 'maxHeight': null, - 'imageQuality': null, - 'cameraDevice': 0 - }), - isMethodCall('pickImage', arguments: { - 'source': 1, - 'maxWidth': null, - 'maxHeight': null, - 'imageQuality': null, - 'cameraDevice': 0 - }), - ], - ); + verifyInOrder([ + mockPlatform.pickImage(source: ImageSource.camera), + mockPlatform.pickImage(source: ImageSource.gallery), + ]); }); test('passes the width and height arguments correctly', () async { + final ImagePicker picker = ImagePicker(); await picker.getImage(source: ImageSource.camera); await picker.getImage( source: ImageSource.camera, @@ -95,277 +78,182 @@ void main() { maxHeight: 20.0, imageQuality: 70); - expect( - log, - [ - isMethodCall('pickImage', arguments: { - 'source': 0, - 'maxWidth': null, - 'maxHeight': null, - 'imageQuality': null, - 'cameraDevice': 0 - }), - isMethodCall('pickImage', arguments: { - 'source': 0, - 'maxWidth': 10.0, - 'maxHeight': null, - 'imageQuality': null, - 'cameraDevice': 0 - }), - isMethodCall('pickImage', arguments: { - 'source': 0, - 'maxWidth': null, - 'maxHeight': 10.0, - 'imageQuality': null, - 'cameraDevice': 0 - }), - isMethodCall('pickImage', arguments: { - 'source': 0, - 'maxWidth': 10.0, - 'maxHeight': 20.0, - 'imageQuality': null, - 'cameraDevice': 0 - }), - isMethodCall('pickImage', arguments: { - 'source': 0, - 'maxWidth': 10.0, - 'maxHeight': null, - 'imageQuality': 70, - 'cameraDevice': 0 - }), - isMethodCall('pickImage', arguments: { - 'source': 0, - 'maxWidth': null, - 'maxHeight': 10.0, - 'imageQuality': 70, - 'cameraDevice': 0 - }), - isMethodCall('pickImage', arguments: { - 'source': 0, - 'maxWidth': 10.0, - 'maxHeight': 20.0, - 'imageQuality': 70, - 'cameraDevice': 0 - }), - ], - ); - }); - - test('does not accept a negative width or height argument', () { - expect( - picker.getImage(source: ImageSource.camera, maxWidth: -1.0), - throwsArgumentError, - ); - - expect( - picker.getImage(source: ImageSource.camera, maxHeight: -1.0), - throwsArgumentError, - ); + verifyInOrder([ + mockPlatform.pickImage( + source: ImageSource.camera, + maxWidth: null, + maxHeight: null, + imageQuality: null), + mockPlatform.pickImage( + source: ImageSource.camera, + maxWidth: 10.0, + maxHeight: null, + imageQuality: null), + mockPlatform.pickImage( + source: ImageSource.camera, + maxWidth: null, + maxHeight: 10.0, + imageQuality: null), + mockPlatform.pickImage( + source: ImageSource.camera, + maxWidth: 10.0, + maxHeight: 20.0, + imageQuality: null), + mockPlatform.pickImage( + source: ImageSource.camera, + maxWidth: 10.0, + maxHeight: null, + imageQuality: 70), + mockPlatform.pickImage( + source: ImageSource.camera, + maxWidth: null, + maxHeight: 10.0, + imageQuality: 70), + mockPlatform.pickImage( + source: ImageSource.camera, + maxWidth: 10.0, + maxHeight: 20.0, + imageQuality: 70), + ]); }); - test('handles a null image path response gracefully', () async { - channel.setMockMethodCallHandler((MethodCall methodCall) => null); + test('handles a null image file response gracefully', () async { + final ImagePicker picker = ImagePicker(); expect(await picker.getImage(source: ImageSource.gallery), isNull); expect(await picker.getImage(source: ImageSource.camera), isNull); }); test('camera position defaults to back', () async { + final ImagePicker picker = ImagePicker(); await picker.getImage(source: ImageSource.camera); - expect( - log, - [ - isMethodCall('pickImage', arguments: { - 'source': 0, - 'maxWidth': null, - 'maxHeight': null, - 'imageQuality': null, - 'cameraDevice': 0, - }), - ], - ); + verify(mockPlatform.pickImage( + source: ImageSource.camera, + preferredCameraDevice: CameraDevice.rear)); }); test('camera position can set to front', () async { + final ImagePicker picker = ImagePicker(); await picker.getImage( source: ImageSource.camera, preferredCameraDevice: CameraDevice.front); - expect( - log, - [ - isMethodCall('pickImage', arguments: { - 'source': 0, - 'maxWidth': null, - 'maxHeight': null, - 'imageQuality': null, - 'cameraDevice': 1, - }), - ], - ); + verify(mockPlatform.pickImage( + source: ImageSource.camera, + preferredCameraDevice: CameraDevice.front)); }); }); group('#pickVideo', () { + setUp(() { + when(mockPlatform.pickVideo( + source: anyNamed('source'), + preferredCameraDevice: anyNamed('preferredCameraDevice'), + maxDuration: anyNamed('maxDuration'))) + .thenAnswer((Invocation _) async => null); + }); + test('passes the image source argument correctly', () async { + final ImagePicker picker = ImagePicker(); await picker.getVideo(source: ImageSource.camera); await picker.getVideo(source: ImageSource.gallery); - expect( - log, - [ - isMethodCall('pickVideo', arguments: { - 'source': 0, - 'cameraDevice': 0, - 'maxDuration': null, - }), - isMethodCall('pickVideo', arguments: { - 'source': 1, - 'cameraDevice': 0, - 'maxDuration': null, - }), - ], - ); + verifyInOrder([ + mockPlatform.pickVideo(source: ImageSource.camera), + mockPlatform.pickVideo(source: ImageSource.gallery), + ]); }); test('passes the duration argument correctly', () async { + final ImagePicker picker = ImagePicker(); await picker.getVideo(source: ImageSource.camera); await picker.getVideo( source: ImageSource.camera, maxDuration: const Duration(seconds: 10)); - await picker.getVideo( - source: ImageSource.camera, - maxDuration: const Duration(minutes: 1)); - await picker.getVideo( - source: ImageSource.camera, - maxDuration: const Duration(hours: 1)); - expect( - log, - [ - isMethodCall('pickVideo', arguments: { - 'source': 0, - 'maxDuration': null, - 'cameraDevice': 0, - }), - isMethodCall('pickVideo', arguments: { - 'source': 0, - 'maxDuration': 10, - 'cameraDevice': 0, - }), - isMethodCall('pickVideo', arguments: { - 'source': 0, - 'maxDuration': 60, - 'cameraDevice': 0, - }), - isMethodCall('pickVideo', arguments: { - 'source': 0, - 'maxDuration': 3600, - 'cameraDevice': 0, - }), - ], - ); + + verifyInOrder([ + mockPlatform.pickVideo( + source: ImageSource.camera, + preferredCameraDevice: CameraDevice.rear, + maxDuration: null), + mockPlatform.pickVideo( + source: ImageSource.camera, + preferredCameraDevice: CameraDevice.rear, + maxDuration: const Duration(seconds: 10)), + ]); }); - test('handles a null video path response gracefully', () async { - channel.setMockMethodCallHandler((MethodCall methodCall) => null); + test('handles a null video file response gracefully', () async { + final ImagePicker picker = ImagePicker(); expect(await picker.getVideo(source: ImageSource.gallery), isNull); expect(await picker.getVideo(source: ImageSource.camera), isNull); }); test('camera position defaults to back', () async { + final ImagePicker picker = ImagePicker(); await picker.getVideo(source: ImageSource.camera); - expect( - log, - [ - isMethodCall('pickVideo', arguments: { - 'source': 0, - 'cameraDevice': 0, - 'maxDuration': null, - }), - ], - ); + verify(mockPlatform.pickVideo( + source: ImageSource.camera, + preferredCameraDevice: CameraDevice.rear)); }); test('camera position can set to front', () async { + final ImagePicker picker = ImagePicker(); await picker.getVideo( source: ImageSource.camera, preferredCameraDevice: CameraDevice.front); - expect( - log, - [ - isMethodCall('pickVideo', arguments: { - 'source': 0, - 'maxDuration': null, - 'cameraDevice': 1, - }), - ], - ); + verify(mockPlatform.pickVideo( + source: ImageSource.camera, + preferredCameraDevice: CameraDevice.front)); }); }); group('#retrieveLostData', () { test('retrieveLostData get success response', () async { - channel.setMockMethodCallHandler((MethodCall methodCall) async { - return { - 'type': 'image', - 'path': '/example/path', - }; - }); + final ImagePicker picker = ImagePicker(); + when(mockPlatform.retrieveLostData()).thenAnswer( + (Invocation _) async => LostData( + file: PickedFile('/example/path'), type: RetrieveType.image)); + final LostData response = await picker.getLostData(); + expect(response.type, RetrieveType.image); expect(response.file!.path, '/example/path'); }); test('retrieveLostData get error response', () async { - channel.setMockMethodCallHandler((MethodCall methodCall) async { - return { - 'type': 'video', - 'errorCode': 'test_error_code', - 'errorMessage': 'test_error_message', - }; - }); + final ImagePicker picker = ImagePicker(); + when(mockPlatform.retrieveLostData()).thenAnswer( + (Invocation _) async => LostData( + exception: PlatformException( + code: 'test_error_code', message: 'test_error_message'), + type: RetrieveType.video)); + final LostData response = await picker.getLostData(); + expect(response.type, RetrieveType.video); expect(response.exception!.code, 'test_error_code'); expect(response.exception!.message, 'test_error_message'); }); - - test('retrieveLostData get null response', () async { - channel.setMockMethodCallHandler((MethodCall methodCall) async { - return null; - }); - expect((await picker.getLostData()).isEmpty, true); - }); - - test('retrieveLostData get both path and error should throw', () async { - channel.setMockMethodCallHandler((MethodCall methodCall) async { - return { - 'type': 'video', - 'errorCode': 'test_error_code', - 'errorMessage': 'test_error_message', - 'path': '/example/path', - }; - }); - expect(picker.getLostData(), throwsAssertionError); - }); }); }); group('Multi images', () { setUp(() { - channel.setMockMethodCallHandler((MethodCall methodCall) async { - log.add(methodCall); - return []; - }); - log.clear(); + when(mockPlatform.pickMultiImage( + maxWidth: anyNamed('maxWidth'), + maxHeight: anyNamed('maxHeight'), + imageQuality: anyNamed('imageQuality'))) + .thenAnswer((Invocation _) async => null); }); group('#pickMultiImage', () { test('passes the width and height arguments correctly', () async { + final ImagePicker picker = ImagePicker(); await picker.getMultiImage(); await picker.getMultiImage( maxWidth: 10.0, @@ -388,62 +276,26 @@ void main() { await picker.getMultiImage( maxWidth: 10.0, maxHeight: 20.0, imageQuality: 70); - expect( - log, - [ - isMethodCall('pickMultiImage', arguments: { - 'maxWidth': null, - 'maxHeight': null, - 'imageQuality': null, - }), - isMethodCall('pickMultiImage', arguments: { - 'maxWidth': 10.0, - 'maxHeight': null, - 'imageQuality': null, - }), - isMethodCall('pickMultiImage', arguments: { - 'maxWidth': null, - 'maxHeight': 10.0, - 'imageQuality': null, - }), - isMethodCall('pickMultiImage', arguments: { - 'maxWidth': 10.0, - 'maxHeight': 20.0, - 'imageQuality': null, - }), - isMethodCall('pickMultiImage', arguments: { - 'maxWidth': 10.0, - 'maxHeight': null, - 'imageQuality': 70, - }), - isMethodCall('pickMultiImage', arguments: { - 'maxWidth': null, - 'maxHeight': 10.0, - 'imageQuality': 70, - }), - isMethodCall('pickMultiImage', arguments: { - 'maxWidth': 10.0, - 'maxHeight': 20.0, - 'imageQuality': 70, - }), - ], - ); + verifyInOrder([ + mockPlatform.pickMultiImage( + maxWidth: null, maxHeight: null, imageQuality: null), + mockPlatform.pickMultiImage( + maxWidth: 10.0, maxHeight: null, imageQuality: null), + mockPlatform.pickMultiImage( + maxWidth: null, maxHeight: 10.0, imageQuality: null), + mockPlatform.pickMultiImage( + maxWidth: 10.0, maxHeight: 20.0, imageQuality: null), + mockPlatform.pickMultiImage( + maxWidth: 10.0, maxHeight: null, imageQuality: 70), + mockPlatform.pickMultiImage( + maxWidth: null, maxHeight: 10.0, imageQuality: 70), + mockPlatform.pickMultiImage( + maxWidth: 10.0, maxHeight: 20.0, imageQuality: 70), + ]); }); - test('does not accept a negative width or height argument', () { - expect( - picker.getMultiImage(maxWidth: -1.0), - throwsArgumentError, - ); - - expect( - picker.getMultiImage(maxHeight: -1.0), - throwsArgumentError, - ); - }); - - test('handles a null image path response gracefully', () async { - channel.setMockMethodCallHandler((MethodCall methodCall) => null); + test('handles a null image file response gracefully', () async { + final ImagePicker picker = ImagePicker(); expect(await picker.getMultiImage(), isNull); expect(await picker.getMultiImage(), isNull); @@ -452,7 +304,3 @@ void main() { }); }); } - -class MockPlatform extends Mock - with MockPlatformInterfaceMixin - implements ImagePickerPlatform {} diff --git a/packages/image_picker/image_picker/test/image_picker_test.dart b/packages/image_picker/image_picker/test/image_picker_test.dart index b41fbe3381df..f981195fe1b3 100644 --- a/packages/image_picker/image_picker/test/image_picker_test.dart +++ b/packages/image_picker/image_picker/test/image_picker_test.dart @@ -6,66 +6,51 @@ import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:image_picker/image_picker.dart'; import 'package:image_picker_platform_interface/image_picker_platform_interface.dart'; +import 'package:mockito/annotations.dart'; import 'package:mockito/mockito.dart'; import 'package:plugin_platform_interface/plugin_platform_interface.dart'; -void main() { - TestWidgetsFlutterBinding.ensureInitialized(); - - group('$ImagePicker', () { - const MethodChannel channel = - MethodChannel('plugins.flutter.io/image_picker'); +import 'image_picker_test.mocks.dart' as base_mock; - final List log = []; +// Add the mixin to make the platform interface accept the mock. +class MockImagePickerPlatform extends base_mock.MockImagePickerPlatform + with MockPlatformInterfaceMixin {} - final ImagePicker picker = ImagePicker(); +@GenerateMocks([ImagePickerPlatform]) +void main() { + group('ImagePicker', () { + late MockImagePickerPlatform mockPlatform; - test('ImagePicker platform instance overrides the actual platform used', - () { - final ImagePickerPlatform savedPlatform = ImagePickerPlatform.instance; - final MockPlatform mockPlatform = MockPlatform(); + setUp(() { + mockPlatform = MockImagePickerPlatform(); ImagePickerPlatform.instance = mockPlatform; - expect(ImagePicker.platform, mockPlatform); - ImagePickerPlatform.instance = savedPlatform; }); group('#Single image/video', () { - setUp(() { - channel.setMockMethodCallHandler((MethodCall methodCall) async { - log.add(methodCall); - return ''; + group('#pickImage', () { + setUp(() { + when(mockPlatform.getImage( + source: anyNamed('source'), + maxWidth: anyNamed('maxWidth'), + maxHeight: anyNamed('maxHeight'), + imageQuality: anyNamed('imageQuality'), + preferredCameraDevice: anyNamed('preferredCameraDevice'))) + .thenAnswer((Invocation _) async => null); }); - log.clear(); - }); - - group('#pickImage', () { test('passes the image source argument correctly', () async { + final ImagePicker picker = ImagePicker(); await picker.pickImage(source: ImageSource.camera); await picker.pickImage(source: ImageSource.gallery); - expect( - log, - [ - isMethodCall('pickImage', arguments: { - 'source': 0, - 'maxWidth': null, - 'maxHeight': null, - 'imageQuality': null, - 'cameraDevice': 0 - }), - isMethodCall('pickImage', arguments: { - 'source': 1, - 'maxWidth': null, - 'maxHeight': null, - 'imageQuality': null, - 'cameraDevice': 0 - }), - ], - ); + verifyInOrder([ + mockPlatform.getImage(source: ImageSource.camera), + mockPlatform.getImage(source: ImageSource.gallery), + ]); }); test('passes the width and height arguments correctly', () async { + final ImagePicker picker = ImagePicker(); await picker.pickImage(source: ImageSource.camera); await picker.pickImage( source: ImageSource.camera, @@ -90,242 +75,184 @@ void main() { maxHeight: 20.0, imageQuality: 70); - expect( - log, - [ - isMethodCall('pickImage', arguments: { - 'source': 0, - 'maxWidth': null, - 'maxHeight': null, - 'imageQuality': null, - 'cameraDevice': 0 - }), - isMethodCall('pickImage', arguments: { - 'source': 0, - 'maxWidth': 10.0, - 'maxHeight': null, - 'imageQuality': null, - 'cameraDevice': 0 - }), - isMethodCall('pickImage', arguments: { - 'source': 0, - 'maxWidth': null, - 'maxHeight': 10.0, - 'imageQuality': null, - 'cameraDevice': 0 - }), - isMethodCall('pickImage', arguments: { - 'source': 0, - 'maxWidth': 10.0, - 'maxHeight': 20.0, - 'imageQuality': null, - 'cameraDevice': 0 - }), - isMethodCall('pickImage', arguments: { - 'source': 0, - 'maxWidth': 10.0, - 'maxHeight': null, - 'imageQuality': 70, - 'cameraDevice': 0 - }), - isMethodCall('pickImage', arguments: { - 'source': 0, - 'maxWidth': null, - 'maxHeight': 10.0, - 'imageQuality': 70, - 'cameraDevice': 0 - }), - isMethodCall('pickImage', arguments: { - 'source': 0, - 'maxWidth': 10.0, - 'maxHeight': 20.0, - 'imageQuality': 70, - 'cameraDevice': 0 - }), - ], - ); + verifyInOrder([ + mockPlatform.getImage( + source: ImageSource.camera, + maxWidth: null, + maxHeight: null, + imageQuality: null), + mockPlatform.getImage( + source: ImageSource.camera, + maxWidth: 10.0, + maxHeight: null, + imageQuality: null), + mockPlatform.getImage( + source: ImageSource.camera, + maxWidth: null, + maxHeight: 10.0, + imageQuality: null), + mockPlatform.getImage( + source: ImageSource.camera, + maxWidth: 10.0, + maxHeight: 20.0, + imageQuality: null), + mockPlatform.getImage( + source: ImageSource.camera, + maxWidth: 10.0, + maxHeight: null, + imageQuality: 70), + mockPlatform.getImage( + source: ImageSource.camera, + maxWidth: null, + maxHeight: 10.0, + imageQuality: 70), + mockPlatform.getImage( + source: ImageSource.camera, + maxWidth: 10.0, + maxHeight: 20.0, + imageQuality: 70), + ]); }); test('does not accept a negative width or height argument', () { + final ImagePicker picker = ImagePicker(); expect( - picker.pickImage(source: ImageSource.camera, maxWidth: -1.0), + () => picker.pickImage(source: ImageSource.camera, maxWidth: -1.0), throwsArgumentError, ); expect( - picker.pickImage(source: ImageSource.camera, maxHeight: -1.0), + () => picker.pickImage(source: ImageSource.camera, maxHeight: -1.0), throwsArgumentError, ); }); - test('handles a null image path response gracefully', () async { - channel.setMockMethodCallHandler((MethodCall methodCall) => null); + test('handles a null image file response gracefully', () async { + final ImagePicker picker = ImagePicker(); expect(await picker.pickImage(source: ImageSource.gallery), isNull); expect(await picker.pickImage(source: ImageSource.camera), isNull); }); test('camera position defaults to back', () async { + final ImagePicker picker = ImagePicker(); await picker.pickImage(source: ImageSource.camera); - expect( - log, - [ - isMethodCall('pickImage', arguments: { - 'source': 0, - 'maxWidth': null, - 'maxHeight': null, - 'imageQuality': null, - 'cameraDevice': 0, - }), - ], - ); + verify(mockPlatform.getImage( + source: ImageSource.camera, + preferredCameraDevice: CameraDevice.rear)); }); test('camera position can set to front', () async { + final ImagePicker picker = ImagePicker(); await picker.pickImage( source: ImageSource.camera, preferredCameraDevice: CameraDevice.front); - expect( - log, - [ - isMethodCall('pickImage', arguments: { - 'source': 0, - 'maxWidth': null, - 'maxHeight': null, - 'imageQuality': null, - 'cameraDevice': 1, - }), - ], - ); + verify(mockPlatform.getImage( + source: ImageSource.camera, + preferredCameraDevice: CameraDevice.front)); }); }); group('#pickVideo', () { + setUp(() { + when(mockPlatform.getVideo( + source: anyNamed('source'), + preferredCameraDevice: anyNamed('preferredCameraDevice'), + maxDuration: anyNamed('maxDuration'))) + .thenAnswer((Invocation _) async => null); + }); + test('passes the image source argument correctly', () async { + final ImagePicker picker = ImagePicker(); await picker.pickVideo(source: ImageSource.camera); await picker.pickVideo(source: ImageSource.gallery); - expect( - log, - [ - isMethodCall('pickVideo', arguments: { - 'source': 0, - 'cameraDevice': 0, - 'maxDuration': null, - }), - isMethodCall('pickVideo', arguments: { - 'source': 1, - 'cameraDevice': 0, - 'maxDuration': null, - }), - ], - ); + verifyInOrder([ + mockPlatform.getVideo(source: ImageSource.camera), + mockPlatform.getVideo(source: ImageSource.gallery), + ]); }); test('passes the duration argument correctly', () async { + final ImagePicker picker = ImagePicker(); await picker.pickVideo(source: ImageSource.camera); await picker.pickVideo( source: ImageSource.camera, maxDuration: const Duration(seconds: 10)); - await picker.pickVideo( - source: ImageSource.camera, - maxDuration: const Duration(minutes: 1)); - await picker.pickVideo( - source: ImageSource.camera, - maxDuration: const Duration(hours: 1)); - expect( - log, - [ - isMethodCall('pickVideo', arguments: { - 'source': 0, - 'maxDuration': null, - 'cameraDevice': 0, - }), - isMethodCall('pickVideo', arguments: { - 'source': 0, - 'maxDuration': 10, - 'cameraDevice': 0, - }), - isMethodCall('pickVideo', arguments: { - 'source': 0, - 'maxDuration': 60, - 'cameraDevice': 0, - }), - isMethodCall('pickVideo', arguments: { - 'source': 0, - 'maxDuration': 3600, - 'cameraDevice': 0, - }), - ], - ); + + verifyInOrder([ + mockPlatform.getVideo( + source: ImageSource.camera, + preferredCameraDevice: CameraDevice.rear, + maxDuration: null), + mockPlatform.getVideo( + source: ImageSource.camera, + preferredCameraDevice: CameraDevice.rear, + maxDuration: const Duration(seconds: 10)), + ]); }); - test('handles a null video path response gracefully', () async { - channel.setMockMethodCallHandler((MethodCall methodCall) => null); + test('handles a null video file response gracefully', () async { + final ImagePicker picker = ImagePicker(); expect(await picker.pickVideo(source: ImageSource.gallery), isNull); expect(await picker.pickVideo(source: ImageSource.camera), isNull); }); test('camera position defaults to back', () async { + final ImagePicker picker = ImagePicker(); await picker.pickVideo(source: ImageSource.camera); - expect( - log, - [ - isMethodCall('pickVideo', arguments: { - 'source': 0, - 'cameraDevice': 0, - 'maxDuration': null, - }), - ], - ); + verify(mockPlatform.getVideo( + source: ImageSource.camera, + preferredCameraDevice: CameraDevice.rear)); }); test('camera position can set to front', () async { + final ImagePicker picker = ImagePicker(); await picker.pickVideo( source: ImageSource.camera, preferredCameraDevice: CameraDevice.front); - expect( - log, - [ - isMethodCall('pickVideo', arguments: { - 'source': 0, - 'maxDuration': null, - 'cameraDevice': 1, - }), - ], - ); + verify(mockPlatform.getVideo( + source: ImageSource.camera, + preferredCameraDevice: CameraDevice.front)); }); }); group('#retrieveLostData', () { test('retrieveLostData get success response', () async { - channel.setMockMethodCallHandler((MethodCall methodCall) async { - return { - 'type': 'image', - 'path': '/example/path', - }; - }); + final ImagePicker picker = ImagePicker(); + final XFile lostFile = XFile('/example/path'); + when(mockPlatform.getLostData()).thenAnswer((Invocation _) async => + LostDataResponse( + file: lostFile, + files: [lostFile], + type: RetrieveType.image)); + final LostDataResponse response = await picker.retrieveLostData(); + expect(response.type, RetrieveType.image); expect(response.file!.path, '/example/path'); }); test('retrieveLostData should successfully retrieve multiple files', () async { - channel.setMockMethodCallHandler((MethodCall methodCall) async { - return { - 'type': 'image', - 'path': '/example/path1', - 'pathList': ['/example/path0', '/example/path1'], - }; - }); + final ImagePicker picker = ImagePicker(); + final List lostFiles = [ + XFile('/example/path0'), + XFile('/example/path1'), + ]; + when(mockPlatform.getLostData()).thenAnswer((Invocation _) async => + LostDataResponse( + file: lostFiles.last, + files: lostFiles, + type: RetrieveType.image)); final LostDataResponse response = await picker.retrieveLostData(); + expect(response.type, RetrieveType.image); expect(response.file, isNotNull); expect(response.file!.path, '/example/path1'); @@ -334,51 +261,34 @@ void main() { }); test('retrieveLostData get error response', () async { - channel.setMockMethodCallHandler((MethodCall methodCall) async { - return { - 'type': 'video', - 'errorCode': 'test_error_code', - 'errorMessage': 'test_error_message', - }; - }); + final ImagePicker picker = ImagePicker(); + when(mockPlatform.getLostData()).thenAnswer((Invocation _) async => + LostDataResponse( + exception: PlatformException( + code: 'test_error_code', message: 'test_error_message'), + type: RetrieveType.video)); + final LostDataResponse response = await picker.retrieveLostData(); + expect(response.type, RetrieveType.video); expect(response.exception!.code, 'test_error_code'); expect(response.exception!.message, 'test_error_message'); }); - - test('retrieveLostData get null response', () async { - channel.setMockMethodCallHandler((MethodCall methodCall) async { - return null; - }); - expect((await picker.retrieveLostData()).isEmpty, true); - }); - - test('retrieveLostData get both path and error should throw', () async { - channel.setMockMethodCallHandler((MethodCall methodCall) async { - return { - 'type': 'video', - 'errorCode': 'test_error_code', - 'errorMessage': 'test_error_message', - 'path': '/example/path', - }; - }); - expect(picker.retrieveLostData(), throwsAssertionError); - }); }); }); group('#Multi images', () { setUp(() { - channel.setMockMethodCallHandler((MethodCall methodCall) async { - log.add(methodCall); - return []; - }); - log.clear(); + when(mockPlatform.getMultiImage( + maxWidth: anyNamed('maxWidth'), + maxHeight: anyNamed('maxHeight'), + imageQuality: anyNamed('imageQuality'))) + .thenAnswer((Invocation _) async => null); }); group('#pickMultiImage', () { test('passes the width and height arguments correctly', () async { + final ImagePicker picker = ImagePicker(); await picker.pickMultiImage(); await picker.pickMultiImage( maxWidth: 10.0, @@ -401,62 +311,39 @@ void main() { await picker.pickMultiImage( maxWidth: 10.0, maxHeight: 20.0, imageQuality: 70); - expect( - log, - [ - isMethodCall('pickMultiImage', arguments: { - 'maxWidth': null, - 'maxHeight': null, - 'imageQuality': null, - }), - isMethodCall('pickMultiImage', arguments: { - 'maxWidth': 10.0, - 'maxHeight': null, - 'imageQuality': null, - }), - isMethodCall('pickMultiImage', arguments: { - 'maxWidth': null, - 'maxHeight': 10.0, - 'imageQuality': null, - }), - isMethodCall('pickMultiImage', arguments: { - 'maxWidth': 10.0, - 'maxHeight': 20.0, - 'imageQuality': null, - }), - isMethodCall('pickMultiImage', arguments: { - 'maxWidth': 10.0, - 'maxHeight': null, - 'imageQuality': 70, - }), - isMethodCall('pickMultiImage', arguments: { - 'maxWidth': null, - 'maxHeight': 10.0, - 'imageQuality': 70, - }), - isMethodCall('pickMultiImage', arguments: { - 'maxWidth': 10.0, - 'maxHeight': 20.0, - 'imageQuality': 70, - }), - ], - ); + verifyInOrder([ + mockPlatform.getMultiImage( + maxWidth: null, maxHeight: null, imageQuality: null), + mockPlatform.getMultiImage( + maxWidth: 10.0, maxHeight: null, imageQuality: null), + mockPlatform.getMultiImage( + maxWidth: null, maxHeight: 10.0, imageQuality: null), + mockPlatform.getMultiImage( + maxWidth: 10.0, maxHeight: 20.0, imageQuality: null), + mockPlatform.getMultiImage( + maxWidth: 10.0, maxHeight: null, imageQuality: 70), + mockPlatform.getMultiImage( + maxWidth: null, maxHeight: 10.0, imageQuality: 70), + mockPlatform.getMultiImage( + maxWidth: 10.0, maxHeight: 20.0, imageQuality: 70), + ]); }); test('does not accept a negative width or height argument', () { + final ImagePicker picker = ImagePicker(); expect( - picker.pickMultiImage(maxWidth: -1.0), + () => picker.pickMultiImage(maxWidth: -1.0), throwsArgumentError, ); expect( - picker.pickMultiImage(maxHeight: -1.0), + () => picker.pickMultiImage(maxHeight: -1.0), throwsArgumentError, ); }); - test('handles a null image path response gracefully', () async { - channel.setMockMethodCallHandler((MethodCall methodCall) => null); + test('handles a null image file response gracefully', () async { + final ImagePicker picker = ImagePicker(); expect(await picker.pickMultiImage(), isNull); expect(await picker.pickMultiImage(), isNull); @@ -465,7 +352,3 @@ void main() { }); }); } - -class MockPlatform extends Mock - with MockPlatformInterfaceMixin - implements ImagePickerPlatform {} diff --git a/packages/image_picker/image_picker/test/image_picker_test.mocks.dart b/packages/image_picker/image_picker/test/image_picker_test.mocks.dart new file mode 100644 index 000000000000..641a104a33c5 --- /dev/null +++ b/packages/image_picker/image_picker/test/image_picker_test.mocks.dart @@ -0,0 +1,136 @@ +// Mocks generated by Mockito 5.1.0 from annotations +// in image_picker/test/image_picker_test.dart. +// Do not manually edit this file. + +import 'dart:async' as _i4; + +import 'package:cross_file/cross_file.dart' as _i5; +import 'package:image_picker_platform_interface/src/platform_interface/image_picker_platform.dart' + as _i3; +import 'package:image_picker_platform_interface/src/types/types.dart' as _i2; +import 'package:mockito/mockito.dart' as _i1; + +// ignore_for_file: type=lint +// ignore_for_file: avoid_redundant_argument_values +// ignore_for_file: avoid_setters_without_getters +// ignore_for_file: comment_references +// ignore_for_file: implementation_imports +// ignore_for_file: invalid_use_of_visible_for_testing_member +// ignore_for_file: prefer_const_constructors +// ignore_for_file: unnecessary_parenthesis +// ignore_for_file: camel_case_types + +class _FakeLostData_0 extends _i1.Fake implements _i2.LostData {} + +class _FakeLostDataResponse_1 extends _i1.Fake implements _i2.LostDataResponse { +} + +/// A class which mocks [ImagePickerPlatform]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockImagePickerPlatform extends _i1.Mock + implements _i3.ImagePickerPlatform { + MockImagePickerPlatform() { + _i1.throwOnMissingStub(this); + } + + @override + _i4.Future<_i2.PickedFile?> pickImage( + {_i2.ImageSource? source, + double? maxWidth, + double? maxHeight, + int? imageQuality, + _i2.CameraDevice? preferredCameraDevice = _i2.CameraDevice.rear}) => + (super.noSuchMethod( + Invocation.method(#pickImage, [], { + #source: source, + #maxWidth: maxWidth, + #maxHeight: maxHeight, + #imageQuality: imageQuality, + #preferredCameraDevice: preferredCameraDevice + }), + returnValue: Future<_i2.PickedFile?>.value()) + as _i4.Future<_i2.PickedFile?>); + @override + _i4.Future?> pickMultiImage( + {double? maxWidth, double? maxHeight, int? imageQuality}) => + (super.noSuchMethod( + Invocation.method(#pickMultiImage, [], { + #maxWidth: maxWidth, + #maxHeight: maxHeight, + #imageQuality: imageQuality + }), + returnValue: Future?>.value()) + as _i4.Future?>); + @override + _i4.Future<_i2.PickedFile?> pickVideo( + {_i2.ImageSource? source, + _i2.CameraDevice? preferredCameraDevice = _i2.CameraDevice.rear, + Duration? maxDuration}) => + (super.noSuchMethod( + Invocation.method(#pickVideo, [], { + #source: source, + #preferredCameraDevice: preferredCameraDevice, + #maxDuration: maxDuration + }), + returnValue: Future<_i2.PickedFile?>.value()) + as _i4.Future<_i2.PickedFile?>); + @override + _i4.Future<_i2.LostData> retrieveLostData() => + (super.noSuchMethod(Invocation.method(#retrieveLostData, []), + returnValue: Future<_i2.LostData>.value(_FakeLostData_0())) + as _i4.Future<_i2.LostData>); + @override + _i4.Future<_i5.XFile?> getImage( + {_i2.ImageSource? source, + double? maxWidth, + double? maxHeight, + int? imageQuality, + _i2.CameraDevice? preferredCameraDevice = _i2.CameraDevice.rear}) => + (super.noSuchMethod( + Invocation.method(#getImage, [], { + #source: source, + #maxWidth: maxWidth, + #maxHeight: maxHeight, + #imageQuality: imageQuality, + #preferredCameraDevice: preferredCameraDevice + }), + returnValue: Future<_i5.XFile?>.value()) as _i4.Future<_i5.XFile?>); + @override + _i4.Future?> getMultiImage( + {double? maxWidth, double? maxHeight, int? imageQuality}) => + (super.noSuchMethod( + Invocation.method(#getMultiImage, [], { + #maxWidth: maxWidth, + #maxHeight: maxHeight, + #imageQuality: imageQuality + }), + returnValue: Future?>.value()) + as _i4.Future?>); + @override + _i4.Future<_i5.XFile?> getVideo( + {_i2.ImageSource? source, + _i2.CameraDevice? preferredCameraDevice = _i2.CameraDevice.rear, + Duration? maxDuration}) => + (super.noSuchMethod( + Invocation.method(#getVideo, [], { + #source: source, + #preferredCameraDevice: preferredCameraDevice, + #maxDuration: maxDuration + }), + returnValue: Future<_i5.XFile?>.value()) as _i4.Future<_i5.XFile?>); + @override + _i4.Future<_i2.LostDataResponse> getLostData() => + (super.noSuchMethod(Invocation.method(#getLostData, []), + returnValue: + Future<_i2.LostDataResponse>.value(_FakeLostDataResponse_1())) + as _i4.Future<_i2.LostDataResponse>); + @override + _i4.Future<_i5.XFile?> getImageFromSource( + {_i2.ImageSource? source, + _i2.ImagePickerOptions? options = const _i2.ImagePickerOptions()}) => + (super.noSuchMethod( + Invocation.method( + #getImageFromSource, [], {#source: source, #options: options}), + returnValue: Future<_i5.XFile?>.value()) as _i4.Future<_i5.XFile?>); +}