diff --git a/analysis_options.yaml b/analysis_options.yaml index 0e07b3324b81..85f5bde1b0de 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -68,7 +68,7 @@ linter: # - avoid_catching_errors # blocked on https://github.com/dart-lang/linter/issues/3023 - avoid_classes_with_only_static_members - avoid_double_and_int_checks - # - avoid_dynamic_calls # LOCAL CHANGE - Needs to be enabled and violations fixed. + - avoid_dynamic_calls - avoid_empty_else - avoid_equals_and_hash_code_on_mutable_classes - avoid_escaping_inner_quotes diff --git a/packages/camera/camera_android/CHANGELOG.md b/packages/camera/camera_android/CHANGELOG.md index 1b07c3005a4c..1a0b87e3c29d 100644 --- a/packages/camera/camera_android/CHANGELOG.md +++ b/packages/camera/camera_android/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.10.2+1 + +* Updates code for stricter lint checks. + ## 0.10.2 * Remove usage of deprecated quiver Optional type. diff --git a/packages/camera/camera_android/lib/src/android_camera.dart b/packages/camera/camera_android/lib/src/android_camera.dart index 4b342eee08d5..1a9c3d0e1bdd 100644 --- a/packages/camera/camera_android/lib/src/android_camera.dart +++ b/packages/camera/camera_android/lib/src/android_camera.dart @@ -549,9 +549,9 @@ class AndroidCamera extends CameraPlatform { Future _handleDeviceMethodCall(MethodCall call) async { switch (call.method) { case 'orientation_changed': + final Map arguments = _getArgumentDictionary(call); _deviceEventStreamController.add(DeviceOrientationChangedEvent( - deserializeDeviceOrientation( - call.arguments['orientation']! as String))); + deserializeDeviceOrientation(arguments['orientation']! as String))); break; default: throw MissingPluginException(); @@ -566,21 +566,23 @@ class AndroidCamera extends CameraPlatform { Future handleCameraMethodCall(MethodCall call, int cameraId) async { switch (call.method) { case 'initialized': + final Map arguments = _getArgumentDictionary(call); cameraEventStreamController.add(CameraInitializedEvent( cameraId, - call.arguments['previewWidth']! as double, - call.arguments['previewHeight']! as double, - deserializeExposureMode(call.arguments['exposureMode']! as String), - call.arguments['exposurePointSupported']! as bool, - deserializeFocusMode(call.arguments['focusMode']! as String), - call.arguments['focusPointSupported']! as bool, + arguments['previewWidth']! as double, + arguments['previewHeight']! as double, + deserializeExposureMode(arguments['exposureMode']! as String), + arguments['exposurePointSupported']! as bool, + deserializeFocusMode(arguments['focusMode']! as String), + arguments['focusPointSupported']! as bool, )); break; case 'resolution_changed': + final Map arguments = _getArgumentDictionary(call); cameraEventStreamController.add(CameraResolutionChangedEvent( cameraId, - call.arguments['captureWidth']! as double, - call.arguments['captureHeight']! as double, + arguments['captureWidth']! as double, + arguments['captureHeight']! as double, )); break; case 'camera_closing': @@ -589,23 +591,32 @@ class AndroidCamera extends CameraPlatform { )); break; case 'video_recorded': + final Map arguments = _getArgumentDictionary(call); cameraEventStreamController.add(VideoRecordedEvent( cameraId, - XFile(call.arguments['path']! as String), - call.arguments['maxVideoDuration'] != null - ? Duration( - milliseconds: call.arguments['maxVideoDuration']! as int) + XFile(arguments['path']! as String), + arguments['maxVideoDuration'] != null + ? Duration(milliseconds: arguments['maxVideoDuration']! as int) : null, )); break; case 'error': + final Map arguments = _getArgumentDictionary(call); cameraEventStreamController.add(CameraErrorEvent( cameraId, - call.arguments['description']! as String, + arguments['description']! as String, )); break; default: throw MissingPluginException(); } } + + /// Returns the arguments of [call] as typed string-keyed Map. + /// + /// This does not do any type validation, so is only safe to call if the + /// arguments are known to be a map. + Map _getArgumentDictionary(MethodCall call) { + return (call.arguments as Map).cast(); + } } diff --git a/packages/camera/camera_android/pubspec.yaml b/packages/camera/camera_android/pubspec.yaml index 6f25af7d61fb..9d86a00e0e50 100644 --- a/packages/camera/camera_android/pubspec.yaml +++ b/packages/camera/camera_android/pubspec.yaml @@ -2,7 +2,7 @@ name: camera_android description: Android implementation of the camera plugin. repository: https://github.com/flutter/plugins/tree/main/packages/camera/camera_android issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+camera%22 -version: 0.10.2 +version: 0.10.2+1 environment: sdk: ">=2.14.0 <3.0.0" diff --git a/packages/camera/camera_android/test/android_camera_test.dart b/packages/camera/camera_android/test/android_camera_test.dart index e35d0fd1beb4..bd55b0b722ba 100644 --- a/packages/camera/camera_android/test/android_camera_test.dart +++ b/packages/camera/camera_android/test/android_camera_test.dart @@ -504,11 +504,13 @@ void main() { ]); expect(cameras.length, returnData.length); for (int i = 0; i < returnData.length; i++) { + final Map typedData = + (returnData[i] as Map).cast(); final CameraDescription cameraDescription = CameraDescription( - name: returnData[i]['name']! as String, + name: typedData['name']! as String, lensDirection: - parseCameraLensDirection(returnData[i]['lensFacing']! as String), - sensorOrientation: returnData[i]['sensorOrientation']! as int, + parseCameraLensDirection(typedData['lensFacing']! as String), + sensorOrientation: typedData['sensorOrientation']! as int, ); expect(cameras[i], cameraDescription); } diff --git a/packages/camera/camera_android_camerax/lib/src/instance_manager.dart b/packages/camera/camera_android_camerax/lib/src/instance_manager.dart index dd48610c8b56..8c6081c855ba 100644 --- a/packages/camera/camera_android_camerax/lib/src/instance_manager.dart +++ b/packages/camera/camera_android_camerax/lib/src/instance_manager.dart @@ -124,22 +124,26 @@ class InstanceManager { /// This method also expects the host `InstanceManager` to have a strong /// reference to the instance the identifier is associated with. T? getInstanceWithWeakReference(int identifier) { - final Object? weakInstance = _weakInstances[identifier]?.target; + final T? weakInstance = _weakInstances[identifier]?.target as T?; if (weakInstance == null) { - final Object? strongInstance = _strongInstances[identifier]; + final T? strongInstance = _strongInstances[identifier] as T?; if (strongInstance != null) { - final Object copy = - _copyCallbacks[identifier]!(strongInstance)! as Object; + // This cast is safe since it matches the argument type for + // _addInstanceWithIdentifier, which is the only place _copyCallbacks + // is populated. + final T Function(T) copyCallback = + _copyCallbacks[identifier]! as T Function(T); + final T copy = copyCallback(strongInstance); _identifiers[copy] = identifier; - _weakInstances[identifier] = WeakReference(copy); + _weakInstances[identifier] = WeakReference(copy); _finalizer.attach(copy, identifier, detach: copy); - return copy as T; + return copy; } - return strongInstance as T?; + return strongInstance; } - return weakInstance as T; + return weakInstance; } /// Retrieves the identifier associated with instance. diff --git a/packages/camera/camera_avfoundation/CHANGELOG.md b/packages/camera/camera_avfoundation/CHANGELOG.md index 9217f2633322..d9fc8c37eb4f 100644 --- a/packages/camera/camera_avfoundation/CHANGELOG.md +++ b/packages/camera/camera_avfoundation/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.9.10+1 + +* Updates code for stricter lint checks. + ## 0.9.10 * Remove usage of deprecated quiver Optional type. diff --git a/packages/camera/camera_avfoundation/lib/src/avfoundation_camera.dart b/packages/camera/camera_avfoundation/lib/src/avfoundation_camera.dart index 011616d2d9f4..11bda5155819 100644 --- a/packages/camera/camera_avfoundation/lib/src/avfoundation_camera.dart +++ b/packages/camera/camera_avfoundation/lib/src/avfoundation_camera.dart @@ -555,9 +555,9 @@ class AVFoundationCamera extends CameraPlatform { Future _handleDeviceMethodCall(MethodCall call) async { switch (call.method) { case 'orientation_changed': + final Map arguments = _getArgumentDictionary(call); _deviceEventStreamController.add(DeviceOrientationChangedEvent( - deserializeDeviceOrientation( - call.arguments['orientation']! as String))); + deserializeDeviceOrientation(arguments['orientation']! as String))); break; default: throw MissingPluginException(); @@ -572,21 +572,23 @@ class AVFoundationCamera extends CameraPlatform { Future handleCameraMethodCall(MethodCall call, int cameraId) async { switch (call.method) { case 'initialized': + final Map arguments = _getArgumentDictionary(call); cameraEventStreamController.add(CameraInitializedEvent( cameraId, - call.arguments['previewWidth']! as double, - call.arguments['previewHeight']! as double, - deserializeExposureMode(call.arguments['exposureMode']! as String), - call.arguments['exposurePointSupported']! as bool, - deserializeFocusMode(call.arguments['focusMode']! as String), - call.arguments['focusPointSupported']! as bool, + arguments['previewWidth']! as double, + arguments['previewHeight']! as double, + deserializeExposureMode(arguments['exposureMode']! as String), + arguments['exposurePointSupported']! as bool, + deserializeFocusMode(arguments['focusMode']! as String), + arguments['focusPointSupported']! as bool, )); break; case 'resolution_changed': + final Map arguments = _getArgumentDictionary(call); cameraEventStreamController.add(CameraResolutionChangedEvent( cameraId, - call.arguments['captureWidth']! as double, - call.arguments['captureHeight']! as double, + arguments['captureWidth']! as double, + arguments['captureHeight']! as double, )); break; case 'camera_closing': @@ -595,23 +597,32 @@ class AVFoundationCamera extends CameraPlatform { )); break; case 'video_recorded': + final Map arguments = _getArgumentDictionary(call); cameraEventStreamController.add(VideoRecordedEvent( cameraId, - XFile(call.arguments['path']! as String), - call.arguments['maxVideoDuration'] != null - ? Duration( - milliseconds: call.arguments['maxVideoDuration']! as int) + XFile(arguments['path']! as String), + arguments['maxVideoDuration'] != null + ? Duration(milliseconds: arguments['maxVideoDuration']! as int) : null, )); break; case 'error': + final Map arguments = _getArgumentDictionary(call); cameraEventStreamController.add(CameraErrorEvent( cameraId, - call.arguments['description']! as String, + arguments['description']! as String, )); break; default: throw MissingPluginException(); } } + + /// Returns the arguments of [call] as typed string-keyed Map. + /// + /// This does not do any type validation, so is only safe to call if the + /// arguments are known to be a map. + Map _getArgumentDictionary(MethodCall call) { + return (call.arguments as Map).cast(); + } } diff --git a/packages/camera/camera_avfoundation/pubspec.yaml b/packages/camera/camera_avfoundation/pubspec.yaml index aa1c1106a774..975accff84b9 100644 --- a/packages/camera/camera_avfoundation/pubspec.yaml +++ b/packages/camera/camera_avfoundation/pubspec.yaml @@ -2,7 +2,7 @@ name: camera_avfoundation description: iOS implementation of the camera plugin. repository: https://github.com/flutter/plugins/tree/main/packages/camera/camera_avfoundation issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+camera%22 -version: 0.9.10 +version: 0.9.10+1 environment: sdk: ">=2.14.0 <3.0.0" diff --git a/packages/camera/camera_avfoundation/test/avfoundation_camera_test.dart b/packages/camera/camera_avfoundation/test/avfoundation_camera_test.dart index 8c5fad1fec8e..50d3e9875be1 100644 --- a/packages/camera/camera_avfoundation/test/avfoundation_camera_test.dart +++ b/packages/camera/camera_avfoundation/test/avfoundation_camera_test.dart @@ -478,6 +478,9 @@ void main() { test('Should fetch CameraDescription instances for available cameras', () async { // Arrange + // This deliberately uses 'dynamic' since that's what actual platform + // channel results will be, so using typed mock data could mask type + // handling bugs in the code under test. final List returnData = [ { 'name': 'Test 1', @@ -504,11 +507,13 @@ void main() { ]); expect(cameras.length, returnData.length); for (int i = 0; i < returnData.length; i++) { + final Map typedData = + (returnData[i] as Map).cast(); final CameraDescription cameraDescription = CameraDescription( - name: returnData[i]['name']! as String, + name: typedData['name']! as String, lensDirection: - parseCameraLensDirection(returnData[i]['lensFacing']! as String), - sensorOrientation: returnData[i]['sensorOrientation']! as int, + parseCameraLensDirection(typedData['lensFacing']! as String), + sensorOrientation: typedData['sensorOrientation']! as int, ); expect(cameras[i], cameraDescription); } diff --git a/packages/camera/camera_platform_interface/CHANGELOG.md b/packages/camera/camera_platform_interface/CHANGELOG.md index 5cde03c2e0db..55d93a3057bd 100644 --- a/packages/camera/camera_platform_interface/CHANGELOG.md +++ b/packages/camera/camera_platform_interface/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.3.3 + +* Updates code for stricter lint checks. + ## 2.3.2 * Updates MethodChannelCamera to have startVideoRecording call the newer startVideoCapturing. diff --git a/packages/camera/camera_platform_interface/lib/src/method_channel/method_channel_camera.dart b/packages/camera/camera_platform_interface/lib/src/method_channel/method_channel_camera.dart index 34c3fa2cca36..06c1ac69570f 100644 --- a/packages/camera/camera_platform_interface/lib/src/method_channel/method_channel_camera.dart +++ b/packages/camera/camera_platform_interface/lib/src/method_channel/method_channel_camera.dart @@ -551,9 +551,9 @@ class MethodChannelCamera extends CameraPlatform { Future handleDeviceMethodCall(MethodCall call) async { switch (call.method) { case 'orientation_changed': + final Map arguments = _getArgumentDictionary(call); deviceEventStreamController.add(DeviceOrientationChangedEvent( - deserializeDeviceOrientation( - call.arguments['orientation']! as String))); + deserializeDeviceOrientation(arguments['orientation']! as String))); break; default: throw MissingPluginException(); @@ -568,21 +568,23 @@ class MethodChannelCamera extends CameraPlatform { Future handleCameraMethodCall(MethodCall call, int cameraId) async { switch (call.method) { case 'initialized': + final Map arguments = _getArgumentDictionary(call); cameraEventStreamController.add(CameraInitializedEvent( cameraId, - call.arguments['previewWidth']! as double, - call.arguments['previewHeight']! as double, - deserializeExposureMode(call.arguments['exposureMode']! as String), - call.arguments['exposurePointSupported']! as bool, - deserializeFocusMode(call.arguments['focusMode']! as String), - call.arguments['focusPointSupported']! as bool, + arguments['previewWidth']! as double, + arguments['previewHeight']! as double, + deserializeExposureMode(arguments['exposureMode']! as String), + arguments['exposurePointSupported']! as bool, + deserializeFocusMode(arguments['focusMode']! as String), + arguments['focusPointSupported']! as bool, )); break; case 'resolution_changed': + final Map arguments = _getArgumentDictionary(call); cameraEventStreamController.add(CameraResolutionChangedEvent( cameraId, - call.arguments['captureWidth']! as double, - call.arguments['captureHeight']! as double, + arguments['captureWidth']! as double, + arguments['captureHeight']! as double, )); break; case 'camera_closing': @@ -591,23 +593,32 @@ class MethodChannelCamera extends CameraPlatform { )); break; case 'video_recorded': + final Map arguments = _getArgumentDictionary(call); cameraEventStreamController.add(VideoRecordedEvent( cameraId, - XFile(call.arguments['path']! as String), - call.arguments['maxVideoDuration'] != null - ? Duration( - milliseconds: call.arguments['maxVideoDuration']! as int) + XFile(arguments['path']! as String), + arguments['maxVideoDuration'] != null + ? Duration(milliseconds: arguments['maxVideoDuration']! as int) : null, )); break; case 'error': + final Map arguments = _getArgumentDictionary(call); cameraEventStreamController.add(CameraErrorEvent( cameraId, - call.arguments['description']! as String, + arguments['description']! as String, )); break; default: throw MissingPluginException(); } } + + /// Returns the arguments of [call] as typed string-keyed Map. + /// + /// This does not do any type validation, so is only safe to call if the + /// arguments are known to be a map. + Map _getArgumentDictionary(MethodCall call) { + return (call.arguments as Map).cast(); + } } diff --git a/packages/camera/camera_platform_interface/pubspec.yaml b/packages/camera/camera_platform_interface/pubspec.yaml index cb21a6c7e09c..54383cd853ee 100644 --- a/packages/camera/camera_platform_interface/pubspec.yaml +++ b/packages/camera/camera_platform_interface/pubspec.yaml @@ -4,7 +4,7 @@ repository: https://github.com/flutter/plugins/tree/main/packages/camera/camera_ issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+camera%22 # NOTE: We strongly prefer non-breaking changes, even at the expense of a # less-clean API. See https://flutter.dev/go/platform-interface-breaking-changes -version: 2.3.2 +version: 2.3.3 environment: sdk: '>=2.12.0 <3.0.0' diff --git a/packages/camera/camera_platform_interface/test/method_channel/method_channel_camera_test.dart b/packages/camera/camera_platform_interface/test/method_channel/method_channel_camera_test.dart index a58f7b4c5841..ed6151522f0c 100644 --- a/packages/camera/camera_platform_interface/test/method_channel/method_channel_camera_test.dart +++ b/packages/camera/camera_platform_interface/test/method_channel/method_channel_camera_test.dart @@ -484,11 +484,13 @@ void main() { ]); expect(cameras.length, returnData.length); for (int i = 0; i < returnData.length; i++) { + final Map typedData = + (returnData[i] as Map).cast(); final CameraDescription cameraDescription = CameraDescription( - name: returnData[i]['name']! as String, - lensDirection: parseCameraLensDirection( - returnData[i]['lensFacing']! as String), - sensorOrientation: returnData[i]['sensorOrientation']! as int, + name: typedData['name']! as String, + lensDirection: + parseCameraLensDirection(typedData['lensFacing']! as String), + sensorOrientation: typedData['sensorOrientation']! as int, ); expect(cameras[i], cameraDescription); } diff --git a/packages/camera/camera_web/example/integration_test/camera_test.dart b/packages/camera/camera_web/example/integration_test/camera_test.dart index 50451b9778af..705d7750e1a4 100644 --- a/packages/camera/camera_web/example/integration_test/camera_test.dart +++ b/packages/camera/camera_web/example/integration_test/camera_test.dart @@ -1286,11 +1286,10 @@ void main() { capturedVideoPartTwo, ]; - videoDataAvailableListener - ..call(FakeBlobEvent(capturedVideoPartOne)) - ..call(FakeBlobEvent(capturedVideoPartTwo)); + videoDataAvailableListener(FakeBlobEvent(capturedVideoPartOne)); + videoDataAvailableListener(FakeBlobEvent(capturedVideoPartTwo)); - videoRecordingStoppedListener.call(Event('stop')); + videoRecordingStoppedListener(Event('stop')); final XFile videoFile = await videoFileFuture; @@ -1378,7 +1377,7 @@ void main() { when(() => mediaRecorder.state).thenReturn('recording'); - videoDataAvailableListener.call(FakeBlobEvent(Blob([]))); + videoDataAvailableListener(FakeBlobEvent(Blob([]))); await Future.microtask(() {}); @@ -1412,7 +1411,7 @@ void main() { await camera.startVideoRecording(); - videoRecordingStoppedListener.call(Event('stop')); + videoRecordingStoppedListener(Event('stop')); await Future.microtask(() {}); @@ -1435,7 +1434,7 @@ void main() { await camera.startVideoRecording(); - videoRecordingStoppedListener.call(Event('stop')); + videoRecordingStoppedListener(Event('stop')); await Future.microtask(() {}); @@ -1464,7 +1463,7 @@ void main() { await camera.startVideoRecording(); - videoRecordingStoppedListener.call(Event('stop')); + videoRecordingStoppedListener(Event('stop')); await Future.microtask(() {}); @@ -1588,8 +1587,8 @@ void main() { return finalVideo!; }; - videoDataAvailableListener.call(FakeBlobEvent(Blob([]))); - videoRecordingStoppedListener.call(Event('stop')); + videoDataAvailableListener(FakeBlobEvent(Blob([]))); + videoRecordingStoppedListener(Event('stop')); expect( await streamQueue.next, diff --git a/packages/camera/camera_windows/CHANGELOG.md b/packages/camera/camera_windows/CHANGELOG.md index f46bb667735f..a6269b955983 100644 --- a/packages/camera/camera_windows/CHANGELOG.md +++ b/packages/camera/camera_windows/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.2.1+4 + +* Updates code for stricter lint checks. + ## 0.2.1+3 * Updates to latest camera platform interface but fails if user attempts to use streaming with recording (since streaming is currently unsupported on Windows). diff --git a/packages/camera/camera_windows/lib/camera_windows.dart b/packages/camera/camera_windows/lib/camera_windows.dart index 79dd305e2e14..4b0c1586f433 100644 --- a/packages/camera/camera_windows/lib/camera_windows.dart +++ b/packages/camera/camera_windows/lib/camera_windows.dart @@ -399,24 +399,25 @@ class CameraWindows extends CameraPlatform { ); break; case 'video_recorded': + final Map arguments = + (call.arguments as Map).cast(); + final int? maxDuration = arguments['maxVideoDuration'] as int?; // This is called if maxVideoDuration was given on record start. cameraEventStreamController.add( VideoRecordedEvent( cameraId, - XFile(call.arguments['path'] as String), - call.arguments['maxVideoDuration'] != null - ? Duration( - milliseconds: call.arguments['maxVideoDuration'] as int, - ) - : null, + XFile(arguments['path']! as String), + maxDuration != null ? Duration(milliseconds: maxDuration) : null, ), ); break; case 'error': + final Map arguments = + (call.arguments as Map).cast(); cameraEventStreamController.add( CameraErrorEvent( cameraId, - call.arguments['description'] as String, + arguments['description']! as String, ), ); break; diff --git a/packages/camera/camera_windows/pubspec.yaml b/packages/camera/camera_windows/pubspec.yaml index 523ee14d186e..d87491a6c0cf 100644 --- a/packages/camera/camera_windows/pubspec.yaml +++ b/packages/camera/camera_windows/pubspec.yaml @@ -2,7 +2,7 @@ name: camera_windows description: A Flutter plugin for getting information about and controlling the camera on Windows. repository: https://github.com/flutter/plugins/tree/main/packages/camera/camera_windows issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+camera%22 -version: 0.2.1+3 +version: 0.2.1+4 environment: sdk: ">=2.12.0 <3.0.0" diff --git a/packages/camera/camera_windows/test/camera_windows_test.dart b/packages/camera/camera_windows/test/camera_windows_test.dart index 615020e9f17d..8d7b5d3d7185 100644 --- a/packages/camera/camera_windows/test/camera_windows_test.dart +++ b/packages/camera/camera_windows/test/camera_windows_test.dart @@ -335,11 +335,13 @@ void main() { ]); expect(cameras.length, returnData.length); for (int i = 0; i < returnData.length; i++) { + final Map typedData = + (returnData[i] as Map).cast(); final CameraDescription cameraDescription = CameraDescription( - name: returnData[i]['name']! as String, - lensDirection: plugin.parseCameraLensDirection( - returnData[i]['lensFacing']! as String), - sensorOrientation: returnData[i]['sensorOrientation']! as int, + name: typedData['name']! as String, + lensDirection: plugin + .parseCameraLensDirection(typedData['lensFacing']! as String), + sensorOrientation: typedData['sensorOrientation']! as int, ); expect(cameras[i], cameraDescription); } diff --git a/packages/google_maps_flutter/google_maps_flutter/test/fake_maps_controllers.dart b/packages/google_maps_flutter/google_maps_flutter/test/fake_maps_controllers.dart index 9fe6923204ab..b2747c9cb5fe 100644 --- a/packages/google_maps_flutter/google_maps_flutter/test/fake_maps_controllers.dart +++ b/packages/google_maps_flutter/google_maps_flutter/test/fake_maps_controllers.dart @@ -93,7 +93,9 @@ class FakePlatformGoogleMap { Future onMethodCall(MethodCall call) { switch (call.method) { case 'map#update': - updateOptions(call.arguments['options'] as Map); + final Map arguments = + (call.arguments as Map).cast(); + updateOptions(arguments['options']! as Map); return Future.sync(() {}); case 'markers#update': updateMarkers(call.arguments as Map?); @@ -218,17 +220,18 @@ class FakePlatformGoogleMap { return result; } + // Converts a list of points expressed as two-element lists of doubles into + // a list of `LatLng`s. All list items are assumed to be non-null. List _deserializePoints(List points) { - return points.map((dynamic list) { - return LatLng(list[0] as double, list[1] as double); + return points.map((dynamic item) { + final List list = item as List; + return LatLng(list[0]! as double, list[1]! as double); }).toList(); } List> _deserializeHoles(List holes) { return holes.map>((dynamic hole) { - return hole.map((dynamic list) { - return LatLng(list[0] as double, list[1] as double); - }).toList() as List; + return _deserializePoints(hole as List); }).toList(); } diff --git a/packages/google_maps_flutter/google_maps_flutter_android/CHANGELOG.md b/packages/google_maps_flutter/google_maps_flutter_android/CHANGELOG.md index 7b697b4ccd13..66c5fcf85738 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/CHANGELOG.md +++ b/packages/google_maps_flutter/google_maps_flutter_android/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.4.2 + +* Updates code for stricter lint checks. + ## 2.4.1 * Update `androidx.test.espresso:espresso-core` to 3.5.1. diff --git a/packages/google_maps_flutter/google_maps_flutter_android/lib/src/google_maps_flutter_android.dart b/packages/google_maps_flutter/google_maps_flutter_android/lib/src/google_maps_flutter_android.dart index 11af3fe7f8df..0188bb18fb20 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/lib/src/google_maps_flutter_android.dart +++ b/packages/google_maps_flutter/google_maps_flutter_android/lib/src/google_maps_flutter_android.dart @@ -190,81 +190,93 @@ class GoogleMapsFlutterAndroid extends GoogleMapsFlutterPlatform { _mapEventStreamController.add(CameraMoveStartedEvent(mapId)); break; case 'camera#onMove': + final Map arguments = _getArgumentDictionary(call); _mapEventStreamController.add(CameraMoveEvent( mapId, - CameraPosition.fromMap(call.arguments['position'])!, + CameraPosition.fromMap(arguments['position'])!, )); break; case 'camera#onIdle': _mapEventStreamController.add(CameraIdleEvent(mapId)); break; case 'marker#onTap': + final Map arguments = _getArgumentDictionary(call); _mapEventStreamController.add(MarkerTapEvent( mapId, - MarkerId(call.arguments['markerId'] as String), + MarkerId(arguments['markerId']! as String), )); break; case 'marker#onDragStart': + final Map arguments = _getArgumentDictionary(call); _mapEventStreamController.add(MarkerDragStartEvent( mapId, - LatLng.fromJson(call.arguments['position'])!, - MarkerId(call.arguments['markerId'] as String), + LatLng.fromJson(arguments['position'])!, + MarkerId(arguments['markerId']! as String), )); break; case 'marker#onDrag': + final Map arguments = _getArgumentDictionary(call); _mapEventStreamController.add(MarkerDragEvent( mapId, - LatLng.fromJson(call.arguments['position'])!, - MarkerId(call.arguments['markerId'] as String), + LatLng.fromJson(arguments['position'])!, + MarkerId(arguments['markerId']! as String), )); break; case 'marker#onDragEnd': + final Map arguments = _getArgumentDictionary(call); _mapEventStreamController.add(MarkerDragEndEvent( mapId, - LatLng.fromJson(call.arguments['position'])!, - MarkerId(call.arguments['markerId'] as String), + LatLng.fromJson(arguments['position'])!, + MarkerId(arguments['markerId']! as String), )); break; case 'infoWindow#onTap': + final Map arguments = _getArgumentDictionary(call); _mapEventStreamController.add(InfoWindowTapEvent( mapId, - MarkerId(call.arguments['markerId'] as String), + MarkerId(arguments['markerId']! as String), )); break; case 'polyline#onTap': + final Map arguments = _getArgumentDictionary(call); _mapEventStreamController.add(PolylineTapEvent( mapId, - PolylineId(call.arguments['polylineId'] as String), + PolylineId(arguments['polylineId']! as String), )); break; case 'polygon#onTap': + final Map arguments = _getArgumentDictionary(call); _mapEventStreamController.add(PolygonTapEvent( mapId, - PolygonId(call.arguments['polygonId'] as String), + PolygonId(arguments['polygonId']! as String), )); break; case 'circle#onTap': + final Map arguments = _getArgumentDictionary(call); _mapEventStreamController.add(CircleTapEvent( mapId, - CircleId(call.arguments['circleId'] as String), + CircleId(arguments['circleId']! as String), )); break; case 'map#onTap': + final Map arguments = _getArgumentDictionary(call); _mapEventStreamController.add(MapTapEvent( mapId, - LatLng.fromJson(call.arguments['position'])!, + LatLng.fromJson(arguments['position'])!, )); break; case 'map#onLongPress': + final Map arguments = _getArgumentDictionary(call); _mapEventStreamController.add(MapLongPressEvent( mapId, - LatLng.fromJson(call.arguments['position'])!, + LatLng.fromJson(arguments['position'])!, )); break; case 'tileOverlay#getTile': + final Map arguments = _getArgumentDictionary(call); final Map? tileOverlaysForThisMap = _tileOverlays[mapId]; - final String tileOverlayId = call.arguments['tileOverlayId'] as String; + final String tileOverlayId = arguments['tileOverlayId']! as String; final TileOverlay? tileOverlay = tileOverlaysForThisMap?[TileOverlayId(tileOverlayId)]; final TileProvider? tileProvider = tileOverlay?.tileProvider; @@ -272,9 +284,9 @@ class GoogleMapsFlutterAndroid extends GoogleMapsFlutterPlatform { return TileProvider.noTile.toJson(); } final Tile tile = await tileProvider.getTile( - call.arguments['x'] as int, - call.arguments['y'] as int, - call.arguments['zoom'] as int?, + arguments['x']! as int, + arguments['y']! as int, + arguments['zoom'] as int?, ); return tile.toJson(); default: @@ -282,6 +294,14 @@ class GoogleMapsFlutterAndroid extends GoogleMapsFlutterPlatform { } } + /// Returns the arguments of [call] as typed string-keyed Map. + /// + /// This does not do any type validation, so is only safe to call if the + /// arguments are known to be a map. + Map _getArgumentDictionary(MethodCall call) { + return (call.arguments as Map).cast(); + } + @override Future updateMapOptions( Map optionsUpdate, { diff --git a/packages/google_maps_flutter/google_maps_flutter_android/pubspec.yaml b/packages/google_maps_flutter/google_maps_flutter_android/pubspec.yaml index ee7a61d919a9..492193e39f86 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/pubspec.yaml +++ b/packages/google_maps_flutter/google_maps_flutter_android/pubspec.yaml @@ -2,7 +2,7 @@ name: google_maps_flutter_android description: Android implementation of the google_maps_flutter plugin. repository: https://github.com/flutter/plugins/tree/main/packages/google_maps_flutter/google_maps_flutter_android issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+maps%22 -version: 2.4.1 +version: 2.4.2 environment: sdk: ">=2.14.0 <3.0.0" diff --git a/packages/google_maps_flutter/google_maps_flutter_ios/CHANGELOG.md b/packages/google_maps_flutter/google_maps_flutter_ios/CHANGELOG.md index e5f232d3ce16..fa135d8ff878 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios/CHANGELOG.md +++ b/packages/google_maps_flutter/google_maps_flutter_ios/CHANGELOG.md @@ -1,5 +1,6 @@ -## NEXT +## 2.1.13 +* Updates code for stricter lint checks. * Updates code for new analysis options. * Re-enable XCUITests: testUserInterface. * Remove unnecessary `RunnerUITests` target from Podfile of the example app. diff --git a/packages/google_maps_flutter/google_maps_flutter_ios/lib/src/google_maps_flutter_ios.dart b/packages/google_maps_flutter/google_maps_flutter_ios/lib/src/google_maps_flutter_ios.dart index 5298377763aa..a0b46f0a96d1 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios/lib/src/google_maps_flutter_ios.dart +++ b/packages/google_maps_flutter/google_maps_flutter_ios/lib/src/google_maps_flutter_ios.dart @@ -172,81 +172,93 @@ class GoogleMapsFlutterIOS extends GoogleMapsFlutterPlatform { _mapEventStreamController.add(CameraMoveStartedEvent(mapId)); break; case 'camera#onMove': + final Map arguments = _getArgumentDictionary(call); _mapEventStreamController.add(CameraMoveEvent( mapId, - CameraPosition.fromMap(call.arguments['position'])!, + CameraPosition.fromMap(arguments['position'])!, )); break; case 'camera#onIdle': _mapEventStreamController.add(CameraIdleEvent(mapId)); break; case 'marker#onTap': + final Map arguments = _getArgumentDictionary(call); _mapEventStreamController.add(MarkerTapEvent( mapId, - MarkerId(call.arguments['markerId'] as String), + MarkerId(arguments['markerId']! as String), )); break; case 'marker#onDragStart': + final Map arguments = _getArgumentDictionary(call); _mapEventStreamController.add(MarkerDragStartEvent( mapId, - LatLng.fromJson(call.arguments['position'])!, - MarkerId(call.arguments['markerId'] as String), + LatLng.fromJson(arguments['position'])!, + MarkerId(arguments['markerId']! as String), )); break; case 'marker#onDrag': + final Map arguments = _getArgumentDictionary(call); _mapEventStreamController.add(MarkerDragEvent( mapId, - LatLng.fromJson(call.arguments['position'])!, - MarkerId(call.arguments['markerId'] as String), + LatLng.fromJson(arguments['position'])!, + MarkerId(arguments['markerId']! as String), )); break; case 'marker#onDragEnd': + final Map arguments = _getArgumentDictionary(call); _mapEventStreamController.add(MarkerDragEndEvent( mapId, - LatLng.fromJson(call.arguments['position'])!, - MarkerId(call.arguments['markerId'] as String), + LatLng.fromJson(arguments['position'])!, + MarkerId(arguments['markerId']! as String), )); break; case 'infoWindow#onTap': + final Map arguments = _getArgumentDictionary(call); _mapEventStreamController.add(InfoWindowTapEvent( mapId, - MarkerId(call.arguments['markerId'] as String), + MarkerId(arguments['markerId']! as String), )); break; case 'polyline#onTap': + final Map arguments = _getArgumentDictionary(call); _mapEventStreamController.add(PolylineTapEvent( mapId, - PolylineId(call.arguments['polylineId'] as String), + PolylineId(arguments['polylineId']! as String), )); break; case 'polygon#onTap': + final Map arguments = _getArgumentDictionary(call); _mapEventStreamController.add(PolygonTapEvent( mapId, - PolygonId(call.arguments['polygonId'] as String), + PolygonId(arguments['polygonId']! as String), )); break; case 'circle#onTap': + final Map arguments = _getArgumentDictionary(call); _mapEventStreamController.add(CircleTapEvent( mapId, - CircleId(call.arguments['circleId'] as String), + CircleId(arguments['circleId']! as String), )); break; case 'map#onTap': + final Map arguments = _getArgumentDictionary(call); _mapEventStreamController.add(MapTapEvent( mapId, - LatLng.fromJson(call.arguments['position'])!, + LatLng.fromJson(arguments['position'])!, )); break; case 'map#onLongPress': + final Map arguments = _getArgumentDictionary(call); _mapEventStreamController.add(MapLongPressEvent( mapId, - LatLng.fromJson(call.arguments['position'])!, + LatLng.fromJson(arguments['position'])!, )); break; case 'tileOverlay#getTile': + final Map arguments = _getArgumentDictionary(call); final Map? tileOverlaysForThisMap = _tileOverlays[mapId]; - final String tileOverlayId = call.arguments['tileOverlayId'] as String; + final String tileOverlayId = arguments['tileOverlayId']! as String; final TileOverlay? tileOverlay = tileOverlaysForThisMap?[TileOverlayId(tileOverlayId)]; final TileProvider? tileProvider = tileOverlay?.tileProvider; @@ -254,9 +266,9 @@ class GoogleMapsFlutterIOS extends GoogleMapsFlutterPlatform { return TileProvider.noTile.toJson(); } final Tile tile = await tileProvider.getTile( - call.arguments['x'] as int, - call.arguments['y'] as int, - call.arguments['zoom'] as int?, + arguments['x']! as int, + arguments['y']! as int, + arguments['zoom'] as int?, ); return tile.toJson(); default: @@ -264,6 +276,14 @@ class GoogleMapsFlutterIOS extends GoogleMapsFlutterPlatform { } } + /// Returns the arguments of [call] as typed string-keyed Map. + /// + /// This does not do any type validation, so is only safe to call if the + /// arguments are known to be a map. + Map _getArgumentDictionary(MethodCall call) { + return (call.arguments as Map).cast(); + } + @override Future updateMapOptions( Map optionsUpdate, { diff --git a/packages/google_maps_flutter/google_maps_flutter_ios/pubspec.yaml b/packages/google_maps_flutter/google_maps_flutter_ios/pubspec.yaml index 7ca13a9273f2..579b24304cf4 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios/pubspec.yaml +++ b/packages/google_maps_flutter/google_maps_flutter_ios/pubspec.yaml @@ -2,7 +2,7 @@ name: google_maps_flutter_ios description: iOS implementation of the google_maps_flutter plugin. repository: https://github.com/flutter/plugins/tree/main/packages/google_maps_flutter/google_maps_flutter_ios issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+maps%22 -version: 2.1.12 +version: 2.1.13 environment: sdk: ">=2.14.0 <3.0.0" diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/CHANGELOG.md b/packages/google_maps_flutter/google_maps_flutter_platform_interface/CHANGELOG.md index a41d1fe487f3..307b70016009 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/CHANGELOG.md +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.2.5 + +* Updates code for stricter lint checks. + ## 2.2.4 * Updates code for `no_leading_underscores_for_local_identifiers` lint. diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/method_channel/method_channel_google_maps_flutter.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/method_channel/method_channel_google_maps_flutter.dart index e17510f90624..3fd860e126eb 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/method_channel/method_channel_google_maps_flutter.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/method_channel/method_channel_google_maps_flutter.dart @@ -175,81 +175,93 @@ class MethodChannelGoogleMapsFlutter extends GoogleMapsFlutterPlatform { _mapEventStreamController.add(CameraMoveStartedEvent(mapId)); break; case 'camera#onMove': + final Map arguments = _getArgumentDictionary(call); _mapEventStreamController.add(CameraMoveEvent( mapId, - CameraPosition.fromMap(call.arguments['position'])!, + CameraPosition.fromMap(arguments['position'])!, )); break; case 'camera#onIdle': _mapEventStreamController.add(CameraIdleEvent(mapId)); break; case 'marker#onTap': + final Map arguments = _getArgumentDictionary(call); _mapEventStreamController.add(MarkerTapEvent( mapId, - MarkerId(call.arguments['markerId'] as String), + MarkerId(arguments['markerId']! as String), )); break; case 'marker#onDragStart': + final Map arguments = _getArgumentDictionary(call); _mapEventStreamController.add(MarkerDragStartEvent( mapId, - LatLng.fromJson(call.arguments['position'])!, - MarkerId(call.arguments['markerId'] as String), + LatLng.fromJson(arguments['position'])!, + MarkerId(arguments['markerId']! as String), )); break; case 'marker#onDrag': + final Map arguments = _getArgumentDictionary(call); _mapEventStreamController.add(MarkerDragEvent( mapId, - LatLng.fromJson(call.arguments['position'])!, - MarkerId(call.arguments['markerId'] as String), + LatLng.fromJson(arguments['position'])!, + MarkerId(arguments['markerId']! as String), )); break; case 'marker#onDragEnd': + final Map arguments = _getArgumentDictionary(call); _mapEventStreamController.add(MarkerDragEndEvent( mapId, - LatLng.fromJson(call.arguments['position'])!, - MarkerId(call.arguments['markerId'] as String), + LatLng.fromJson(arguments['position'])!, + MarkerId(arguments['markerId']! as String), )); break; case 'infoWindow#onTap': + final Map arguments = _getArgumentDictionary(call); _mapEventStreamController.add(InfoWindowTapEvent( mapId, - MarkerId(call.arguments['markerId'] as String), + MarkerId(arguments['markerId']! as String), )); break; case 'polyline#onTap': + final Map arguments = _getArgumentDictionary(call); _mapEventStreamController.add(PolylineTapEvent( mapId, - PolylineId(call.arguments['polylineId'] as String), + PolylineId(arguments['polylineId']! as String), )); break; case 'polygon#onTap': + final Map arguments = _getArgumentDictionary(call); _mapEventStreamController.add(PolygonTapEvent( mapId, - PolygonId(call.arguments['polygonId'] as String), + PolygonId(arguments['polygonId']! as String), )); break; case 'circle#onTap': + final Map arguments = _getArgumentDictionary(call); _mapEventStreamController.add(CircleTapEvent( mapId, - CircleId(call.arguments['circleId'] as String), + CircleId(arguments['circleId']! as String), )); break; case 'map#onTap': + final Map arguments = _getArgumentDictionary(call); _mapEventStreamController.add(MapTapEvent( mapId, - LatLng.fromJson(call.arguments['position'])!, + LatLng.fromJson(arguments['position'])!, )); break; case 'map#onLongPress': + final Map arguments = _getArgumentDictionary(call); _mapEventStreamController.add(MapLongPressEvent( mapId, - LatLng.fromJson(call.arguments['position'])!, + LatLng.fromJson(arguments['position'])!, )); break; case 'tileOverlay#getTile': + final Map arguments = _getArgumentDictionary(call); final Map? tileOverlaysForThisMap = _tileOverlays[mapId]; - final String tileOverlayId = call.arguments['tileOverlayId'] as String; + final String tileOverlayId = arguments['tileOverlayId']! as String; final TileOverlay? tileOverlay = tileOverlaysForThisMap?[TileOverlayId(tileOverlayId)]; final TileProvider? tileProvider = tileOverlay?.tileProvider; @@ -257,9 +269,9 @@ class MethodChannelGoogleMapsFlutter extends GoogleMapsFlutterPlatform { return TileProvider.noTile.toJson(); } final Tile tile = await tileProvider.getTile( - call.arguments['x'] as int, - call.arguments['y'] as int, - call.arguments['zoom'] as int?, + arguments['x']! as int, + arguments['y']! as int, + arguments['zoom'] as int?, ); return tile.toJson(); default: @@ -267,6 +279,14 @@ class MethodChannelGoogleMapsFlutter extends GoogleMapsFlutterPlatform { } } + /// Returns the arguments of [call] as typed string-keyed Map. + /// + /// This does not do any type validation, so is only safe to call if the + /// arguments are known to be a map. + Map _getArgumentDictionary(MethodCall call) { + return (call.arguments as Map).cast(); + } + @override Future updateMapOptions( Map optionsUpdate, { diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/pubspec.yaml b/packages/google_maps_flutter/google_maps_flutter_platform_interface/pubspec.yaml index 5639ee8c6ad7..40b058ae6daf 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/pubspec.yaml +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/pubspec.yaml @@ -4,7 +4,7 @@ repository: https://github.com/flutter/plugins/tree/main/packages/google_maps_fl issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+maps%22 # NOTE: We strongly prefer non-breaking changes, even at the expense of a # less-clean API. See https://flutter.dev/go/platform-interface-breaking-changes -version: 2.2.4 +version: 2.2.5 environment: sdk: '>=2.12.0 <3.0.0' diff --git a/packages/google_maps_flutter/google_maps_flutter_web/CHANGELOG.md b/packages/google_maps_flutter/google_maps_flutter_web/CHANGELOG.md index 2333f7d16028..3bbc08ac7186 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/CHANGELOG.md +++ b/packages/google_maps_flutter/google_maps_flutter_web/CHANGELOG.md @@ -1,5 +1,6 @@ -## NEXT +## 0.4.0+4 +* Updates code for stricter lint checks. * Updates code for `no_leading_underscores_for_local_identifiers` lint. ## 0.4.0+3 diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/convert.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/convert.dart index 2b09950cc00d..d5f27ee05d0c 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/convert.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/convert.dart @@ -416,31 +416,46 @@ gmaps.PolylineOptions _polylineOptionsFromPolyline( // Translates a [CameraUpdate] into operations on a [gmaps.GMap]. void _applyCameraUpdate(gmaps.GMap map, CameraUpdate update) { + // Casts [value] to a JSON dictionary (string -> nullable object). [value] + // must be a non-null JSON dictionary. + Map asJsonObject(dynamic value) { + return (value as Map).cast(); + } + + // Casts [value] to a JSON list. [value] must be a non-null JSON list. + List asJsonList(dynamic value) { + return value as List; + } + final List json = update.toJson() as List; switch (json[0]) { case 'newCameraPosition': - map.heading = json[1]['bearing'] as num?; - map.zoom = json[1]['zoom'] as num?; + final Map position = asJsonObject(json[1]); + final List latLng = asJsonList(position['target']); + map.heading = position['bearing'] as num?; + map.zoom = position['zoom'] as num?; map.panTo( - gmaps.LatLng( - json[1]['target'][0] as num?, - json[1]['target'][1] as num?, - ), + gmaps.LatLng(latLng[0] as num?, latLng[1] as num?), ); - map.tilt = json[1]['tilt'] as num?; + map.tilt = position['tilt'] as num?; break; case 'newLatLng': - map.panTo(gmaps.LatLng(json[1][0] as num?, json[1][1] as num?)); + final List latLng = asJsonList(json[1]); + map.panTo(gmaps.LatLng(latLng[0] as num?, latLng[1] as num?)); break; case 'newLatLngZoom': + final List latLng = asJsonList(json[1]); map.zoom = json[2] as num?; - map.panTo(gmaps.LatLng(json[1][0] as num?, json[1][1] as num?)); + map.panTo(gmaps.LatLng(latLng[0] as num?, latLng[1] as num?)); break; case 'newLatLngBounds': + final List latLngPair = asJsonList(json[1]); + final List latLng1 = asJsonList(latLngPair[0]); + final List latLng2 = asJsonList(latLngPair[1]); map.fitBounds( gmaps.LatLngBounds( - gmaps.LatLng(json[1][0][0] as num?, json[1][0][1] as num?), - gmaps.LatLng(json[1][1][0] as num?, json[1][1][1] as num?), + gmaps.LatLng(latLng1[0] as num?, latLng1[1] as num?), + gmaps.LatLng(latLng2[0] as num?, latLng2[1] as num?), ), ); // padding = json[2]; @@ -456,10 +471,11 @@ void _applyCameraUpdate(gmaps.GMap map, CameraUpdate update) { final int newZoomDelta = zoomDelta < 0 ? zoomDelta.floor() : zoomDelta.ceil(); if (json.length == 3) { + final List latLng = asJsonList(json[2]); // With focus try { focusLatLng = - _pixelToLatLng(map, json[2][0] as int, json[2][1] as int); + _pixelToLatLng(map, latLng[0]! as int, latLng[1]! as int); } catch (e) { // https://github.com/a14n/dart-google-maps/issues/87 // print('Error computing new focus LatLng. JS Error: ' + e.toString()); diff --git a/packages/google_maps_flutter/google_maps_flutter_web/pubspec.yaml b/packages/google_maps_flutter/google_maps_flutter_web/pubspec.yaml index 572d9110be8e..6278ab01ba6c 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/pubspec.yaml +++ b/packages/google_maps_flutter/google_maps_flutter_web/pubspec.yaml @@ -2,7 +2,7 @@ name: google_maps_flutter_web description: Web platform implementation of google_maps_flutter repository: https://github.com/flutter/plugins/tree/main/packages/google_maps_flutter/google_maps_flutter_web issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+maps%22 -version: 0.4.0+3 +version: 0.4.0+4 environment: sdk: ">=2.12.0 <3.0.0" diff --git a/packages/google_sign_in/google_sign_in/CHANGELOG.md b/packages/google_sign_in/google_sign_in/CHANGELOG.md index 93497841fbd5..c7ddb6ba9345 100644 --- a/packages/google_sign_in/google_sign_in/CHANGELOG.md +++ b/packages/google_sign_in/google_sign_in/CHANGELOG.md @@ -1,3 +1,7 @@ +## 5.4.3 + +* Updates code for stricter lint checks. + ## 5.4.2 * Updates minimum Flutter version to 2.10. diff --git a/packages/google_sign_in/google_sign_in/example/lib/main.dart b/packages/google_sign_in/google_sign_in/example/lib/main.dart index 889993b448f1..271069e6e96b 100644 --- a/packages/google_sign_in/google_sign_in/example/lib/main.dart +++ b/packages/google_sign_in/google_sign_in/example/lib/main.dart @@ -86,12 +86,14 @@ class SignInDemoState extends State { String? _pickFirstNamedContact(Map data) { final List? connections = data['connections'] as List?; final Map? contact = connections?.firstWhere( - (dynamic contact) => contact['names'] != null, + (dynamic contact) => (contact as Map)['names'] != null, orElse: () => null, ) as Map?; if (contact != null) { - final Map? name = contact['names'].firstWhere( - (dynamic name) => name['displayName'] != null, + final List names = contact['names'] as List; + final Map? name = names.firstWhere( + (dynamic name) => + (name as Map)['displayName'] != null, orElse: () => null, ) as Map?; if (name != null) { diff --git a/packages/google_sign_in/google_sign_in/lib/google_sign_in.dart b/packages/google_sign_in/google_sign_in/lib/google_sign_in.dart index 3ae022306fe6..8e908dc479ed 100644 --- a/packages/google_sign_in/google_sign_in/lib/google_sign_in.dart +++ b/packages/google_sign_in/google_sign_in/lib/google_sign_in.dart @@ -267,7 +267,8 @@ class GoogleSignIn { // Future that completes when we've finished calling `init` on the native side Future? _initialization; - Future _callMethod(Function method) async { + Future _callMethod( + Future Function() method) async { await _ensureInitialized(); final dynamic response = await method(); @@ -324,7 +325,7 @@ class GoogleSignIn { /// method call may be skipped, if there's already [_currentUser] information. /// This is used from the [signIn] and [signInSilently] methods. Future _addMethodCall( - Function method, { + Future Function() method, { bool canSkipCall = false, }) async { Future response; diff --git a/packages/google_sign_in/google_sign_in/pubspec.yaml b/packages/google_sign_in/google_sign_in/pubspec.yaml index c32dee78468b..f6e1faf12089 100644 --- a/packages/google_sign_in/google_sign_in/pubspec.yaml +++ b/packages/google_sign_in/google_sign_in/pubspec.yaml @@ -3,7 +3,7 @@ description: Flutter plugin for Google Sign-In, a secure authentication system for signing in with a Google account on Android and iOS. repository: https://github.com/flutter/plugins/tree/main/packages/google_sign_in/google_sign_in issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+google_sign_in%22 -version: 5.4.2 +version: 5.4.3 environment: diff --git a/packages/google_sign_in/google_sign_in_android/test/google_sign_in_android_test.dart b/packages/google_sign_in/google_sign_in_android/test/google_sign_in_android_test.dart index c081418c7aeb..2565836f51aa 100644 --- a/packages/google_sign_in/google_sign_in_android/test/google_sign_in_android_test.dart +++ b/packages/google_sign_in/google_sign_in_android/test/google_sign_in_android_test.dart @@ -99,7 +99,7 @@ void main() { }); test('Other functions pass through arguments to the channel', () async { - final Map tests = { + final Map tests = { () { googleSignIn.init( hostedDomain: 'example.com', @@ -152,7 +152,7 @@ void main() { googleSignIn.isSignedIn: isMethodCall('isSignedIn', arguments: null), }; - for (final Function f in tests.keys) { + for (final void Function() f in tests.keys) { f(); } diff --git a/packages/google_sign_in/google_sign_in_ios/test/google_sign_in_ios_test.dart b/packages/google_sign_in/google_sign_in_ios/test/google_sign_in_ios_test.dart index 45842987c736..0fee1af66120 100644 --- a/packages/google_sign_in/google_sign_in_ios/test/google_sign_in_ios_test.dart +++ b/packages/google_sign_in/google_sign_in_ios/test/google_sign_in_ios_test.dart @@ -114,7 +114,7 @@ void main() { }); test('Other functions pass through arguments to the channel', () async { - final Map tests = { + final Map tests = { () { googleSignIn.init( hostedDomain: 'example.com', @@ -155,7 +155,7 @@ void main() { googleSignIn.isSignedIn: isMethodCall('isSignedIn', arguments: null), }; - for (final Function f in tests.keys) { + for (final void Function() f in tests.keys) { f(); } diff --git a/packages/google_sign_in/google_sign_in_platform_interface/test/method_channel_google_sign_in_test.dart b/packages/google_sign_in/google_sign_in_platform_interface/test/method_channel_google_sign_in_test.dart index 944ad3419b8e..0972d0be4855 100644 --- a/packages/google_sign_in/google_sign_in_platform_interface/test/method_channel_google_sign_in_test.dart +++ b/packages/google_sign_in/google_sign_in_platform_interface/test/method_channel_google_sign_in_test.dart @@ -95,7 +95,7 @@ void main() { }); test('Other functions pass through arguments to the channel', () async { - final Map tests = { + final Map tests = { () { googleSignIn.init( hostedDomain: 'example.com', @@ -132,7 +132,7 @@ void main() { googleSignIn.isSignedIn: isMethodCall('isSignedIn', arguments: null), }; - for (final Function f in tests.keys) { + for (final void Function() f in tests.keys) { f(); } diff --git a/packages/image_picker/image_picker_windows/test/image_picker_windows_test.dart b/packages/image_picker/image_picker_windows/test/image_picker_windows_test.dart index 3b27c08c5fe2..f8adde4051c7 100644 --- a/packages/image_picker/image_picker_windows/test/image_picker_windows_test.dart +++ b/packages/image_picker/image_picker_windows/test/image_picker_windows_test.dart @@ -15,6 +15,12 @@ import 'image_picker_windows_test.mocks.dart'; void main() { TestWidgetsFlutterBinding.ensureInitialized(); + // Returns the captured type groups from a mock call result, assuming that + // exactly one call was made and only the type groups were captured. + List capturedTypeGroups(VerificationResult result) { + return result.captured.single as List; + } + group('$ImagePickerWindows()', () { final ImagePickerWindows plugin = ImagePickerWindows(); late MockFileSelectorPlatform mockFileSelectorPlatform; @@ -42,12 +48,10 @@ void main() { test('pickImage passes the accepted type groups correctly', () async { await plugin.pickImage(source: ImageSource.gallery); - expect( - verify(mockFileSelectorPlatform.openFile( - acceptedTypeGroups: captureAnyNamed('acceptedTypeGroups'))) - .captured - .single[0] - .extensions, + final VerificationResult result = verify( + mockFileSelectorPlatform.openFile( + acceptedTypeGroups: captureAnyNamed('acceptedTypeGroups'))); + expect(capturedTypeGroups(result)[0].extensions, ImagePickerWindows.imageFormats); }); @@ -60,12 +64,10 @@ void main() { test('getImage passes the accepted type groups correctly', () async { await plugin.getImage(source: ImageSource.gallery); - expect( - verify(mockFileSelectorPlatform.openFile( - acceptedTypeGroups: captureAnyNamed('acceptedTypeGroups'))) - .captured - .single[0] - .extensions, + final VerificationResult result = verify( + mockFileSelectorPlatform.openFile( + acceptedTypeGroups: captureAnyNamed('acceptedTypeGroups'))); + expect(capturedTypeGroups(result)[0].extensions, ImagePickerWindows.imageFormats); }); @@ -78,12 +80,10 @@ void main() { test('getMultiImage passes the accepted type groups correctly', () async { await plugin.getMultiImage(); - expect( - verify(mockFileSelectorPlatform.openFiles( - acceptedTypeGroups: captureAnyNamed('acceptedTypeGroups'))) - .captured - .single[0] - .extensions, + final VerificationResult result = verify( + mockFileSelectorPlatform.openFiles( + acceptedTypeGroups: captureAnyNamed('acceptedTypeGroups'))); + expect(capturedTypeGroups(result)[0].extensions, ImagePickerWindows.imageFormats); }); }); @@ -91,12 +91,10 @@ void main() { test('pickVideo passes the accepted type groups correctly', () async { await plugin.pickVideo(source: ImageSource.gallery); - expect( - verify(mockFileSelectorPlatform.openFile( - acceptedTypeGroups: captureAnyNamed('acceptedTypeGroups'))) - .captured - .single[0] - .extensions, + final VerificationResult result = verify( + mockFileSelectorPlatform.openFile( + acceptedTypeGroups: captureAnyNamed('acceptedTypeGroups'))); + expect(capturedTypeGroups(result)[0].extensions, ImagePickerWindows.videoFormats); }); @@ -109,12 +107,10 @@ void main() { test('getVideo passes the accepted type groups correctly', () async { await plugin.getVideo(source: ImageSource.gallery); - expect( - verify(mockFileSelectorPlatform.openFile( - acceptedTypeGroups: captureAnyNamed('acceptedTypeGroups'))) - .captured - .single[0] - .extensions, + final VerificationResult result = verify( + mockFileSelectorPlatform.openFile( + acceptedTypeGroups: captureAnyNamed('acceptedTypeGroups'))); + expect(capturedTypeGroups(result)[0].extensions, ImagePickerWindows.videoFormats); }); diff --git a/packages/in_app_purchase/in_app_purchase_android/CHANGELOG.md b/packages/in_app_purchase/in_app_purchase_android/CHANGELOG.md index 4aa14a8b6b59..11192c3c8ace 100644 --- a/packages/in_app_purchase/in_app_purchase_android/CHANGELOG.md +++ b/packages/in_app_purchase/in_app_purchase_android/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.2.3+8 + +* Updates code for stricter lint checks. + ## 0.2.3+7 * Updates code for new analysis options. diff --git a/packages/in_app_purchase/in_app_purchase_android/lib/src/billing_client_wrappers/billing_client_wrapper.dart b/packages/in_app_purchase/in_app_purchase_android/lib/src/billing_client_wrappers/billing_client_wrapper.dart index b64eaab49a9d..2d4a3f96b50e 100644 --- a/packages/in_app_purchase/in_app_purchase_android/lib/src/billing_client_wrappers/billing_client_wrapper.dart +++ b/packages/in_app_purchase/in_app_purchase_android/lib/src/billing_client_wrappers/billing_client_wrapper.dart @@ -343,8 +343,12 @@ class BillingClient { (call.arguments as Map).cast())); break; case _kOnBillingServiceDisconnected: - final int handle = call.arguments['handle'] as int; - await _callbacks[_kOnBillingServiceDisconnected]![handle](); + final int handle = + (call.arguments as Map)['handle']! as int; + final List onDisconnected = + _callbacks[_kOnBillingServiceDisconnected]! + .cast(); + onDisconnected[handle](); break; } } diff --git a/packages/in_app_purchase/in_app_purchase_android/pubspec.yaml b/packages/in_app_purchase/in_app_purchase_android/pubspec.yaml index d70e5dfa0e1a..663f56f7e264 100644 --- a/packages/in_app_purchase/in_app_purchase_android/pubspec.yaml +++ b/packages/in_app_purchase/in_app_purchase_android/pubspec.yaml @@ -2,7 +2,7 @@ name: in_app_purchase_android description: An implementation for the Android platform of the Flutter `in_app_purchase` plugin. This uses the Android BillingClient APIs. repository: https://github.com/flutter/plugins/tree/main/packages/in_app_purchase/in_app_purchase_android issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+in_app_purchase%22 -version: 0.2.3+7 +version: 0.2.3+8 environment: sdk: ">=2.14.0 <3.0.0" diff --git a/packages/in_app_purchase/in_app_purchase_android/test/in_app_purchase_android_platform_test.dart b/packages/in_app_purchase/in_app_purchase_android/test/in_app_purchase_android_platform_test.dart index b6055cc9a8bb..70e519ce9f6e 100644 --- a/packages/in_app_purchase/in_app_purchase_android/test/in_app_purchase_android_platform_test.dart +++ b/packages/in_app_purchase/in_app_purchase_android/test/in_app_purchase_android_platform_test.dart @@ -426,7 +426,8 @@ void main() { name: consumeMethodName, value: buildBillingResultMap(expectedBillingResultForConsume), additionalStepBeforeReturn: (dynamic args) { - final String purchaseToken = args['purchaseToken'] as String; + final String purchaseToken = + (args as Map)['purchaseToken']! as String; consumeCompleter.complete(purchaseToken); }); @@ -540,7 +541,8 @@ void main() { name: consumeMethodName, value: buildBillingResultMap(expectedBillingResultForConsume), additionalStepBeforeReturn: (dynamic args) { - final String purchaseToken = args['purchaseToken'] as String; + final String purchaseToken = + (args as Map)['purchaseToken']! as String; consumeCompleter.complete(purchaseToken); }); @@ -617,7 +619,8 @@ void main() { name: consumeMethodName, value: buildBillingResultMap(expectedBillingResultForConsume), additionalStepBeforeReturn: (dynamic args) { - final String purchaseToken = args['purchaseToken'] as String; + final String purchaseToken = + (args as Map)['purchaseToken']! as String; consumeCompleter.complete(purchaseToken); }); @@ -682,7 +685,8 @@ void main() { name: consumeMethodName, value: buildBillingResultMap(expectedBillingResultForConsume), additionalStepBeforeReturn: (dynamic args) { - final String purchaseToken = args['purchaseToken'] as String; + final String purchaseToken = + (args as Map)['purchaseToken']! as String; consumeCompleter.complete(purchaseToken); }); diff --git a/packages/in_app_purchase/in_app_purchase_storekit/CHANGELOG.md b/packages/in_app_purchase/in_app_purchase_storekit/CHANGELOG.md index 3839419a32cf..434caf425d00 100644 --- a/packages/in_app_purchase/in_app_purchase_storekit/CHANGELOG.md +++ b/packages/in_app_purchase/in_app_purchase_storekit/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.3.4+1 + +* Updates code for stricter lint checks. + ## 0.3.4 * Adds macOS as a supported platform. diff --git a/packages/in_app_purchase/in_app_purchase_storekit/lib/src/store_kit_wrappers/sk_payment_queue_wrapper.dart b/packages/in_app_purchase/in_app_purchase_storekit/lib/src/store_kit_wrappers/sk_payment_queue_wrapper.dart index d360a2da3fe5..859946b557bf 100644 --- a/packages/in_app_purchase/in_app_purchase_storekit/lib/src/store_kit_wrappers/sk_payment_queue_wrapper.dart +++ b/packages/in_app_purchase/in_app_purchase_storekit/lib/src/store_kit_wrappers/sk_payment_queue_wrapper.dart @@ -245,11 +245,13 @@ class SKPaymentQueueWrapper { } case 'shouldAddStorePayment': { + final Map arguments = + call.arguments as Map; final SKPaymentWrapper payment = SKPaymentWrapper.fromJson( - (call.arguments['payment'] as Map) + (arguments['payment']! as Map) .cast()); final SKProductWrapper product = SKProductWrapper.fromJson( - (call.arguments['product'] as Map) + (arguments['product']! as Map) .cast()); return Future(() { if (observer.shouldAddStorePayment( @@ -290,12 +292,14 @@ class SKPaymentQueueWrapper { final SKPaymentQueueDelegateWrapper delegate = _paymentQueueDelegate!; switch (call.method) { case 'shouldContinueTransaction': + final Map arguments = + call.arguments as Map; final SKPaymentTransactionWrapper transaction = SKPaymentTransactionWrapper.fromJson( - (call.arguments['transaction'] as Map) + (arguments['transaction']! as Map) .cast()); final SKStorefrontWrapper storefront = SKStorefrontWrapper.fromJson( - (call.arguments['storefront'] as Map) + (arguments['storefront']! as Map) .cast()); return delegate.shouldContinueTransaction(transaction, storefront); case 'shouldShowPriceConsent': diff --git a/packages/in_app_purchase/in_app_purchase_storekit/pubspec.yaml b/packages/in_app_purchase/in_app_purchase_storekit/pubspec.yaml index f45b3acaad47..339d12320a18 100644 --- a/packages/in_app_purchase/in_app_purchase_storekit/pubspec.yaml +++ b/packages/in_app_purchase/in_app_purchase_storekit/pubspec.yaml @@ -2,7 +2,7 @@ name: in_app_purchase_storekit description: An implementation for the iOS and macOS platforms of the Flutter `in_app_purchase` plugin. This uses the StoreKit Framework. repository: https://github.com/flutter/plugins/tree/main/packages/in_app_purchase/in_app_purchase_storekit issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+in_app_purchase%22 -version: 0.3.4 +version: 0.3.4+1 environment: sdk: ">=2.14.0 <3.0.0" diff --git a/packages/in_app_purchase/in_app_purchase_storekit/test/fakes/fake_storekit_platform.dart b/packages/in_app_purchase/in_app_purchase_storekit/test/fakes/fake_storekit_platform.dart index e6b9696c8cb1..dfc715c86b4d 100644 --- a/packages/in_app_purchase/in_app_purchase_storekit/test/fakes/fake_storekit_platform.dart +++ b/packages/in_app_purchase/in_app_purchase_storekit/test/fakes/fake_storekit_platform.dart @@ -169,14 +169,15 @@ class FakeStoreKitPlatform { receiptData = 'refreshed receipt data'; return Future.sync(() {}); case '-[InAppPurchasePlugin addPayment:result:]': - final String id = call.arguments['productIdentifier'] as String; - final int quantity = call.arguments['quantity'] as int; + final Map arguments = _getArgumentDictionary(call); + final String id = arguments['productIdentifier']! as String; + final int quantity = arguments['quantity']! as int; // Keep the received paymentDiscount parameter when testing payment with discount. - if (call.arguments['applicationUsername'] == 'userWithDiscount') { - if (call.arguments['paymentDiscount'] != null) { - final Map discountArgument = - call.arguments['paymentDiscount'] as Map; + if (arguments['applicationUsername']! == 'userWithDiscount') { + final Map? discountArgument = + arguments['paymentDiscount'] as Map?; + if (discountArgument != null) { discountReceived = discountArgument.cast(); } else { discountReceived = {}; @@ -210,9 +211,10 @@ class FakeStoreKitPlatform { } break; case '-[InAppPurchasePlugin finishTransaction:result:]': + final Map arguments = _getArgumentDictionary(call); finishedTransactions.add(createPurchasedTransaction( - call.arguments['productIdentifier'] as String, - call.arguments['transactionIdentifier'] as String, + arguments['productIdentifier']! as String, + arguments['transactionIdentifier']! as String, quantity: transactions.first.payment.quantity)); break; case '-[SKPaymentQueue startObservingTransactionQueue]': @@ -224,4 +226,12 @@ class FakeStoreKitPlatform { } return Future.sync(() {}); } + + /// Returns the arguments of [call] as typed string-keyed Map. + /// + /// This does not do any type validation, so is only safe to call if the + /// arguments are known to be a map. + Map _getArgumentDictionary(MethodCall call) { + return (call.arguments as Map).cast(); + } } diff --git a/packages/shared_preferences/shared_preferences_android/test/shared_preferences_android_test.dart b/packages/shared_preferences/shared_preferences_android/test/shared_preferences_android_test.dart index d9c921378170..fb6764893651 100644 --- a/packages/shared_preferences/shared_preferences_android/test/shared_preferences_android_test.dart +++ b/packages/shared_preferences/shared_preferences_android/test/shared_preferences_android_test.dart @@ -33,13 +33,20 @@ void main() { setUp(() async { testData = InMemorySharedPreferencesStore.empty(); + Map getArgumentDictionary(MethodCall call) { + return (call.arguments as Map) + .cast(); + } + channel.setMockMethodCallHandler((MethodCall methodCall) async { log.add(methodCall); if (methodCall.method == 'getAll') { return testData.getAll(); } if (methodCall.method == 'remove') { - final String key = methodCall.arguments['key']! as String; + final Map arguments = + getArgumentDictionary(methodCall); + final String key = arguments['key']! as String; return testData.remove(key); } if (methodCall.method == 'clear') { @@ -49,8 +56,10 @@ void main() { final Match? match = setterRegExp.matchAsPrefix(methodCall.method); if (match?.groupCount == 1) { final String valueType = match!.group(1)!; - final String key = methodCall.arguments['key'] as String; - final Object value = methodCall.arguments['value'] as Object; + final Map arguments = + getArgumentDictionary(methodCall); + final String key = arguments['key']! as String; + final Object value = arguments['value']!; return testData.setValue(valueType, key, value); } fail('Unexpected method call: ${methodCall.method}'); diff --git a/packages/shared_preferences/shared_preferences_platform_interface/test/method_channel_shared_preferences_test.dart b/packages/shared_preferences/shared_preferences_platform_interface/test/method_channel_shared_preferences_test.dart index ed4ecc7f27e3..da333cf7f234 100644 --- a/packages/shared_preferences/shared_preferences_platform_interface/test/method_channel_shared_preferences_test.dart +++ b/packages/shared_preferences/shared_preferences_platform_interface/test/method_channel_shared_preferences_test.dart @@ -31,13 +31,20 @@ void main() { setUp(() async { testData = InMemorySharedPreferencesStore.empty(); + Map getArgumentDictionary(MethodCall call) { + return (call.arguments as Map) + .cast(); + } + channel.setMockMethodCallHandler((MethodCall methodCall) async { log.add(methodCall); if (methodCall.method == 'getAll') { return testData.getAll(); } if (methodCall.method == 'remove') { - final String key = (methodCall.arguments['key'] as String?)!; + final Map arguments = + getArgumentDictionary(methodCall); + final String key = arguments['key']! as String; return testData.remove(key); } if (methodCall.method == 'clear') { @@ -47,8 +54,10 @@ void main() { final Match? match = setterRegExp.matchAsPrefix(methodCall.method); if (match?.groupCount == 1) { final String valueType = match!.group(1)!; - final String key = (methodCall.arguments['key'] as String?)!; - final Object value = (methodCall.arguments['value'] as Object?)!; + final Map arguments = + getArgumentDictionary(methodCall); + final String key = arguments['key']! as String; + final Object value = arguments['value']!; return testData.setValue(valueType, key, value); } fail('Unexpected method call: ${methodCall.method}'); diff --git a/packages/url_launcher/url_launcher_android/test/url_launcher_android_test.dart b/packages/url_launcher/url_launcher_android/test/url_launcher_android_test.dart index eebd8cd4c059..b8ccc2cbbee7 100644 --- a/packages/url_launcher/url_launcher_android/test/url_launcher_android_test.dart +++ b/packages/url_launcher/url_launcher_android/test/url_launcher_android_test.dart @@ -61,7 +61,8 @@ void main() { const String genericUrl = 'http://flutter.dev'; channel.setMockMethodCallHandler((MethodCall methodCall) async { log.add(methodCall); - return methodCall.arguments['url'] != specificUrl; + return (methodCall.arguments as Map)['url'] != + specificUrl; }); final UrlLauncherAndroid launcher = UrlLauncherAndroid(); @@ -69,7 +70,7 @@ void main() { expect(canLaunch, true); expect(log.length, 2); - expect(log[1].arguments['url'], genericUrl); + expect((log[1].arguments as Map)['url'], genericUrl); }); test('checks a generic URL if an https URL returns false', () async { @@ -77,7 +78,8 @@ void main() { const String genericUrl = 'https://flutter.dev'; channel.setMockMethodCallHandler((MethodCall methodCall) async { log.add(methodCall); - return methodCall.arguments['url'] != specificUrl; + return (methodCall.arguments as Map)['url'] != + specificUrl; }); final UrlLauncherAndroid launcher = UrlLauncherAndroid(); @@ -85,7 +87,7 @@ void main() { expect(canLaunch, true); expect(log.length, 2); - expect(log[1].arguments['url'], genericUrl); + expect((log[1].arguments as Map)['url'], genericUrl); }); test('does not a generic URL if a non-web URL returns false', () async { diff --git a/packages/webview_flutter/webview_flutter_android/example/integration_test/legacy/webview_flutter_test.dart b/packages/webview_flutter/webview_flutter_android/example/integration_test/legacy/webview_flutter_test.dart index 57d33998a0d2..180175a22a0a 100644 --- a/packages/webview_flutter/webview_flutter_android/example/integration_test/legacy/webview_flutter_test.dart +++ b/packages/webview_flutter/webview_flutter_android/example/integration_test/legacy/webview_flutter_test.dart @@ -985,6 +985,11 @@ Future main() async { final Map viewportRectRelativeToViewport = jsonDecode(viewportRectJSON) as Map; + num getDomRectComponent( + Map rectAsJson, String component) { + return rectAsJson[component]! as num; + } + // Check that the input is originally outside of the viewport. final String initialInputClientRectJSON = @@ -994,8 +999,9 @@ Future main() async { jsonDecode(initialInputClientRectJSON) as Map; expect( - initialInputClientRectRelativeToViewport['bottom'] <= - viewportRectRelativeToViewport['bottom'], + getDomRectComponent( + initialInputClientRectRelativeToViewport, 'bottom') <= + getDomRectComponent(viewportRectRelativeToViewport, 'bottom'), isFalse); await controller.runJavascript('inputEl.focus()'); @@ -1009,21 +1015,22 @@ Future main() async { jsonDecode(lastInputClientRectJSON) as Map; expect( - lastInputClientRectRelativeToViewport['top'] >= - viewportRectRelativeToViewport['top'], + getDomRectComponent(lastInputClientRectRelativeToViewport, 'top') >= + getDomRectComponent(viewportRectRelativeToViewport, 'top'), isTrue); expect( - lastInputClientRectRelativeToViewport['bottom'] <= - viewportRectRelativeToViewport['bottom'], + getDomRectComponent( + lastInputClientRectRelativeToViewport, 'bottom') <= + getDomRectComponent(viewportRectRelativeToViewport, 'bottom'), isTrue); expect( - lastInputClientRectRelativeToViewport['left'] >= - viewportRectRelativeToViewport['left'], + getDomRectComponent(lastInputClientRectRelativeToViewport, 'left') >= + getDomRectComponent(viewportRectRelativeToViewport, 'left'), isTrue); expect( - lastInputClientRectRelativeToViewport['right'] <= - viewportRectRelativeToViewport['right'], + getDomRectComponent(lastInputClientRectRelativeToViewport, 'right') <= + getDomRectComponent(viewportRectRelativeToViewport, 'right'), isTrue); }); }); diff --git a/packages/webview_flutter/webview_flutter_android/test/legacy/surface_android_test.dart b/packages/webview_flutter/webview_flutter_android/test/legacy/surface_android_test.dart index 1657e1b0d525..196e7cc27093 100644 --- a/packages/webview_flutter/webview_flutter_android/test/legacy/surface_android_test.dart +++ b/packages/webview_flutter/webview_flutter_android/test/legacy/surface_android_test.dart @@ -21,9 +21,12 @@ void main() { (MethodCall call) async { log.add(call); if (call.method == 'resize') { + final Map arguments = + (call.arguments as Map) + .cast(); return { - 'width': call.arguments['width'], - 'height': call.arguments['height'], + 'width': arguments['width'], + 'height': arguments['height'], }; } }, diff --git a/packages/webview_flutter/webview_flutter_android/test/legacy/webview_android_widget_test.dart b/packages/webview_flutter/webview_flutter_android/test/legacy/webview_android_widget_test.dart index 909607ac8a71..22c161afa180 100644 --- a/packages/webview_flutter/webview_flutter_android/test/legacy/webview_android_widget_test.dart +++ b/packages/webview_flutter/webview_flutter_android/test/legacy/webview_android_widget_test.dart @@ -210,8 +210,10 @@ void main() { ), ); - final List javaScriptChannels = - verify(mockWebView.addJavaScriptChannel(captureAny)).captured; + final List javaScriptChannels = + verify(mockWebView.addJavaScriptChannel(captureAny)) + .captured + .cast(); expect(javaScriptChannels[0].channelName, 'a'); expect(javaScriptChannels[1].channelName, 'b'); }); @@ -656,8 +658,10 @@ void main() { await buildWidget(tester); await testController.addJavascriptChannels({'c', 'd'}); - final List javaScriptChannels = - verify(mockWebView.addJavaScriptChannel(captureAny)).captured; + final List javaScriptChannels = + verify(mockWebView.addJavaScriptChannel(captureAny)) + .captured + .cast(); expect(javaScriptChannels[0].channelName, 'c'); expect(javaScriptChannels[1].channelName, 'd'); }); @@ -667,8 +671,10 @@ void main() { await testController.addJavascriptChannels({'c', 'd'}); await testController.removeJavascriptChannels({'c', 'd'}); - final List javaScriptChannels = - verify(mockWebView.removeJavaScriptChannel(captureAny)).captured; + final List javaScriptChannels = + verify(mockWebView.removeJavaScriptChannel(captureAny)) + .captured + .cast(); expect(javaScriptChannels[0].channelName, 'c'); expect(javaScriptChannels[1].channelName, 'd'); }); diff --git a/packages/webview_flutter/webview_flutter_wkwebview/CHANGELOG.md b/packages/webview_flutter/webview_flutter_wkwebview/CHANGELOG.md index 7ae38d347711..b4ad2a16b425 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/CHANGELOG.md +++ b/packages/webview_flutter/webview_flutter_wkwebview/CHANGELOG.md @@ -1,3 +1,7 @@ +## 3.0.2 + +* Updates code for stricter lint checks. + ## 3.0.1 * Adds support for retrieving navigation type with internal class. diff --git a/packages/webview_flutter/webview_flutter_wkwebview/lib/src/legacy/web_kit_webview_widget.dart b/packages/webview_flutter/webview_flutter_wkwebview/lib/src/legacy/web_kit_webview_widget.dart index cc901a4a7efb..4d10db96a291 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/lib/src/legacy/web_kit_webview_widget.dart +++ b/packages/webview_flutter/webview_flutter_wkwebview/lib/src/legacy/web_kit_webview_widget.dart @@ -353,9 +353,9 @@ class WebKitWebViewPlatformController extends WebViewPlatformController { // unsupported. This also goes for `null` and `undefined` on iOS 14+. For // example, when running a void function. For ease of use, this specific // error is ignored when no return value is expected. - if (exception.details is! NSError || - exception.details.code != - WKErrorCode.javaScriptResultTypeIsUnsupported) { + final Object? details = exception.details; + if (details is! NSError || + details.code != WKErrorCode.javaScriptResultTypeIsUnsupported) { rethrow; } } diff --git a/packages/webview_flutter/webview_flutter_wkwebview/lib/src/webkit_webview_controller.dart b/packages/webview_flutter/webview_flutter_wkwebview/lib/src/webkit_webview_controller.dart index 48219416e44e..dc90906d78f4 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/lib/src/webkit_webview_controller.dart +++ b/packages/webview_flutter/webview_flutter_wkwebview/lib/src/webkit_webview_controller.dart @@ -269,9 +269,9 @@ class WebKitWebViewController extends PlatformWebViewController { // unsupported. This also goes for `null` and `undefined` on iOS 14+. For // example, when running a void function. For ease of use, this specific // error is ignored when no return value is expected. - if (exception.details is! NSError || - exception.details.code != - WKErrorCode.javaScriptResultTypeIsUnsupported) { + final Object? details = exception.details; + if (details is! NSError || + details.code != WKErrorCode.javaScriptResultTypeIsUnsupported) { rethrow; } } diff --git a/packages/webview_flutter/webview_flutter_wkwebview/pubspec.yaml b/packages/webview_flutter/webview_flutter_wkwebview/pubspec.yaml index 27a6a7863806..85440f6e3dfc 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/pubspec.yaml +++ b/packages/webview_flutter/webview_flutter_wkwebview/pubspec.yaml @@ -2,7 +2,7 @@ name: webview_flutter_wkwebview description: A Flutter plugin that provides a WebView widget based on Apple's WKWebView control. repository: https://github.com/flutter/plugins/tree/main/packages/webview_flutter/webview_flutter_wkwebview issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+webview%22 -version: 3.0.1 +version: 3.0.2 environment: sdk: ">=2.17.0 <3.0.0" diff --git a/packages/webview_flutter/webview_flutter_wkwebview/test/legacy/web_kit_webview_widget_test.dart b/packages/webview_flutter/webview_flutter_wkwebview/test/legacy/web_kit_webview_widget_test.dart index da7ce9b18aef..7982be1c0353 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/test/legacy/web_kit_webview_widget_test.dart +++ b/packages/webview_flutter/webview_flutter_wkwebview/test/legacy/web_kit_webview_widget_test.dart @@ -137,13 +137,13 @@ void main() { (WidgetTester tester) async { await buildWidget(tester); - final dynamic onCreateWebView = verify( - mockWebViewWidgetProxy.createUIDelgate( + final void Function(WKWebView, WKWebViewConfiguration, WKNavigationAction) + onCreateWebView = verify(mockWebViewWidgetProxy.createUIDelgate( onCreateWebView: captureAnyNamed('onCreateWebView'))) - .captured - .single - as void Function( - WKWebView, WKWebViewConfiguration, WKNavigationAction); + .captured + .single + as void Function( + WKWebView, WKWebViewConfiguration, WKNavigationAction); const NSUrlRequest request = NSUrlRequest(url: 'https://google.com'); onCreateWebView( @@ -989,7 +989,7 @@ void main() { testWidgets('onPageStarted', (WidgetTester tester) async { await buildWidget(tester); - final dynamic didStartProvisionalNavigation = + final void Function(WKWebView, String) didStartProvisionalNavigation = verify(mockWebViewWidgetProxy.createNavigationDelegate( didFinishNavigation: anyNamed('didFinishNavigation'), didStartProvisionalNavigation: @@ -1010,7 +1010,7 @@ void main() { testWidgets('onPageFinished', (WidgetTester tester) async { await buildWidget(tester); - final dynamic didFinishNavigation = + final void Function(WKWebView, String) didFinishNavigation = verify(mockWebViewWidgetProxy.createNavigationDelegate( didFinishNavigation: captureAnyNamed('didFinishNavigation'), didStartProvisionalNavigation: @@ -1032,7 +1032,7 @@ void main() { (WidgetTester tester) async { await buildWidget(tester); - final dynamic didFailNavigation = + final void Function(WKWebView, NSError) didFailNavigation = verify(mockWebViewWidgetProxy.createNavigationDelegate( didFinishNavigation: anyNamed('didFinishNavigation'), didStartProvisionalNavigation: @@ -1069,7 +1069,7 @@ void main() { (WidgetTester tester) async { await buildWidget(tester); - final dynamic didFailProvisionalNavigation = + final void Function(WKWebView, NSError) didFailProvisionalNavigation = verify(mockWebViewWidgetProxy.createNavigationDelegate( didFinishNavigation: anyNamed('didFinishNavigation'), didStartProvisionalNavigation: @@ -1110,7 +1110,7 @@ void main() { (WidgetTester tester) async { await buildWidget(tester); - final dynamic webViewWebContentProcessDidTerminate = + final void Function(WKWebView) webViewWebContentProcessDidTerminate = verify(mockWebViewWidgetProxy.createNavigationDelegate( didFinishNavigation: anyNamed('didFinishNavigation'), didStartProvisionalNavigation: @@ -1142,7 +1142,8 @@ void main() { (WidgetTester tester) async { await buildWidget(tester, hasNavigationDelegate: true); - final dynamic decidePolicyForNavigationAction = + final Future Function( + WKWebView, WKNavigationAction) decidePolicyForNavigationAction = verify(mockWebViewWidgetProxy.createNavigationDelegate( didFinishNavigation: anyNamed('didFinishNavigation'), didStartProvisionalNavigation: @@ -1191,15 +1192,13 @@ void main() { }, )); - final dynamic observeValue = verify( - mockWebViewWidgetProxy.createWebView(any, - observeValue: captureAnyNamed('observeValue'))) - .captured - .single as void Function( - String keyPath, - NSObject object, - Map change, - ); + final void Function(String, NSObject, Map) + observeValue = verify(mockWebViewWidgetProxy.createWebView(any, + observeValue: captureAnyNamed('observeValue'))) + .captured + .single + as void Function( + String, NSObject, Map); observeValue( 'estimatedProgress', @@ -1234,15 +1233,14 @@ void main() { await buildWidget(tester); await testController.addJavascriptChannels({'hello'}); - final dynamic didReceiveScriptMessage = verify( - mockWebViewWidgetProxy.createScriptMessageHandler( - didReceiveScriptMessage: - captureAnyNamed('didReceiveScriptMessage'))) - .captured - .single as void Function( - WKUserContentController userContentController, - WKScriptMessage message, - ); + final void Function(WKUserContentController, WKScriptMessage) + didReceiveScriptMessage = verify( + mockWebViewWidgetProxy.createScriptMessageHandler( + didReceiveScriptMessage: + captureAnyNamed('didReceiveScriptMessage'))) + .captured + .single + as void Function(WKUserContentController, WKScriptMessage); didReceiveScriptMessage( mockUserContentController, diff --git a/packages/webview_flutter/webview_flutter_wkwebview/test/src/web_kit/web_kit_test.dart b/packages/webview_flutter/webview_flutter_wkwebview/test/src/web_kit/web_kit_test.dart index a2b456ee5898..401aebfb8b25 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/test/src/web_kit/web_kit_test.dart +++ b/packages/webview_flutter/webview_flutter_wkwebview/test/src/web_kit/web_kit_test.dart @@ -116,13 +116,15 @@ void main() { completion(true), ); - final List typeData = + final List capturedArgs = verify(mockPlatformHostApi.removeDataOfTypes( instanceManager.getIdentifier(websiteDataStore), captureAny, 5.0, - )).captured.single.cast() - as List; + )).captured; + final List typeData = + (capturedArgs.single as List) + .cast(); expect(typeData.single.value, WKWebsiteDataTypeEnum.cookies); }); diff --git a/script/tool/lib/src/common/git_version_finder.dart b/script/tool/lib/src/common/git_version_finder.dart index b135424827a6..3965ae0ace47 100644 --- a/script/tool/lib/src/common/git_version_finder.dart +++ b/script/tool/lib/src/common/git_version_finder.dart @@ -88,7 +88,8 @@ class GitVersionFinder { if (fileContent.trim().isEmpty) { return null; } - final String? versionString = loadYaml(fileContent)['version'] as String?; + final YamlMap fileYaml = loadYaml(fileContent) as YamlMap; + final String? versionString = fileYaml['version'] as String?; return versionString == null ? null : Version.parse(versionString); } diff --git a/script/tool/lib/src/common/pub_version_finder.dart b/script/tool/lib/src/common/pub_version_finder.dart index 572cb913aa7d..c24ec429f8a3 100644 --- a/script/tool/lib/src/common/pub_version_finder.dart +++ b/script/tool/lib/src/common/pub_version_finder.dart @@ -44,11 +44,13 @@ class PubVersionFinder { result: PubVersionFinderResult.fail, httpResponse: response); } - final List versions = - (json.decode(response.body)['versions'] as List) - .map((final dynamic versionString) => - Version.parse(versionString as String)) - .toList(); + final Map responseBody = + json.decode(response.body) as Map; + final List versions = (responseBody['versions']! as List) + .cast() + .map( + (final String versionString) => Version.parse(versionString)) + .toList(); return PubVersionFinderResponse( versions: versions, diff --git a/script/tool/lib/src/create_all_packages_app_command.dart b/script/tool/lib/src/create_all_packages_app_command.dart index 4660413bc937..e7719e9f664c 100644 --- a/script/tool/lib/src/create_all_packages_app_command.dart +++ b/script/tool/lib/src/create_all_packages_app_command.dart @@ -244,24 +244,23 @@ dev_dependencies:${_pubspecMapString(pubspec.devDependencies)} ###'''; } - String _pubspecMapString(Map values) { + String _pubspecMapString(Map values) { final StringBuffer buffer = StringBuffer(); - for (final MapEntry entry in values.entries) { + for (final MapEntry entry in values.entries) { buffer.writeln(); - if (entry.value is VersionConstraint) { - String value = entry.value.toString(); + final Object? entryValue = entry.value; + if (entryValue is VersionConstraint) { + String value = entryValue.toString(); // Range constraints require quoting. if (value.startsWith('>') || value.startsWith('<')) { value = "'$value'"; } buffer.write(' ${entry.key}: $value'); - } else if (entry.value is SdkDependency) { - final SdkDependency dep = entry.value as SdkDependency; - buffer.write(' ${entry.key}: \n sdk: ${dep.sdk}'); - } else if (entry.value is PathDependency) { - final PathDependency dep = entry.value as PathDependency; - String depPath = dep.path; + } else if (entryValue is SdkDependency) { + buffer.write(' ${entry.key}: \n sdk: ${entryValue.sdk}'); + } else if (entryValue is PathDependency) { + String depPath = entryValue.path; if (path.style == p.Style.windows) { // Posix-style path separators are preferred in pubspec.yaml (and // using a consistent format makes unit testing simpler), so convert. @@ -278,7 +277,7 @@ dev_dependencies:${_pubspecMapString(pubspec.devDependencies)} buffer.write(' ${entry.key}: \n path: $depPath'); } else { throw UnimplementedError( - 'Not available for type: ${entry.value.runtimeType}', + 'Not available for type: ${entryValue.runtimeType}', ); } } diff --git a/script/tool/lib/src/dependabot_check_command.dart b/script/tool/lib/src/dependabot_check_command.dart index 5aa762e916e5..77b44e11b59e 100644 --- a/script/tool/lib/src/dependabot_check_command.dart +++ b/script/tool/lib/src/dependabot_check_command.dart @@ -58,8 +58,9 @@ class DependabotCheckCommand extends PackageLoopingCommand { const String typeKey = 'package-ecosystem'; const String dirKey = 'directory'; _gradleDirs = entries - .where((dynamic entry) => entry[typeKey] == 'gradle') - .map((dynamic entry) => (entry as YamlMap)[dirKey] as String) + .cast() + .where((YamlMap entry) => entry[typeKey] == 'gradle') + .map((YamlMap entry) => entry[dirKey] as String) .toSet(); } diff --git a/script/tool/lib/src/format_command.dart b/script/tool/lib/src/format_command.dart index 8198f6d36abd..43c450cbcf7c 100644 --- a/script/tool/lib/src/format_command.dart +++ b/script/tool/lib/src/format_command.dart @@ -298,13 +298,13 @@ class FormatCommand extends PackageCommand { Future> _whichAll(String command) async { try { final io.ProcessResult result = - await processRunner.run('which', ['-a', command]); + await processRunner.run('which', ['-a', command]); if (result.exitCode != 0) { return []; } - final String stdout = result.stdout.trim() as String; + final String stdout = (result.stdout as String).trim(); if (stdout.isEmpty) { return []; } diff --git a/script/tool/lib/src/pubspec_check_command.dart b/script/tool/lib/src/pubspec_check_command.dart index 79ef1e1d3e5e..5682ba057688 100644 --- a/script/tool/lib/src/pubspec_check_command.dart +++ b/script/tool/lib/src/pubspec_check_command.dart @@ -244,8 +244,8 @@ class PubspecCheckCommand extends PackageLoopingCommand { required RepositoryPackage package, }) { if (_isImplementationPackage(package)) { - final String? implements = - pubspec.flutter!['plugin']!['implements'] as String?; + final YamlMap pluginSection = pubspec.flutter!['plugin'] as YamlMap; + final String? implements = pluginSection['implements'] as String?; final String expectedImplements = package.directory.parent.basename; if (implements == null) { return 'Missing "implements: $expectedImplements" in "plugin" section.'; @@ -265,19 +265,20 @@ class PubspecCheckCommand extends PackageLoopingCommand { Pubspec pubspec, { required RepositoryPackage package, }) { - final dynamic platformsEntry = pubspec.flutter!['plugin']!['platforms']; - if (platformsEntry == null) { + final YamlMap pluginSection = pubspec.flutter!['plugin'] as YamlMap; + final YamlMap? platforms = pluginSection['platforms'] as YamlMap?; + if (platforms == null) { logWarning('Does not implement any platforms'); return null; } - final YamlMap platforms = platformsEntry as YamlMap; final String packageName = package.directory.basename; // Validate that the default_package entries look correct (e.g., no typos). final Set defaultPackages = {}; - for (final MapEntry platformEntry in platforms.entries) { + for (final MapEntry platformEntry in platforms.entries) { + final YamlMap platformDetails = platformEntry.value! as YamlMap; final String? defaultPackage = - platformEntry.value['default_package'] as String?; + platformDetails['default_package'] as String?; if (defaultPackage != null) { defaultPackages.add(defaultPackage); if (!defaultPackage.startsWith('${packageName}_')) { diff --git a/script/tool/lib/src/readme_check_command.dart b/script/tool/lib/src/readme_check_command.dart index e3fbc7bc454d..cbbb8b835a13 100644 --- a/script/tool/lib/src/readme_check_command.dart +++ b/script/tool/lib/src/readme_check_command.dart @@ -234,7 +234,8 @@ class ReadmeCheckCommand extends PackageLoopingCommand { } // Validate that the supported OS lists match. - final dynamic platformsEntry = pubspec.flutter!['plugin']!['platforms']; + final YamlMap pluginSection = pubspec.flutter!['plugin'] as YamlMap; + final dynamic platformsEntry = pluginSection['platforms']; if (platformsEntry == null) { logWarning('Plugin not support any platforms'); return null; diff --git a/script/tool/test/common/git_version_finder_test.dart b/script/tool/test/common/git_version_finder_test.dart index d5a5dd4fe876..538b72a90021 100644 --- a/script/tool/test/common/git_version_finder_test.dart +++ b/script/tool/test/common/git_version_finder_test.dart @@ -22,12 +22,14 @@ void main() { gitDir = MockGitDir(); when(gitDir.runCommand(any, throwOnError: anyNamed('throwOnError'))) .thenAnswer((Invocation invocation) { - gitDirCommands.add(invocation.positionalArguments[0] as List?); + final List arguments = + invocation.positionalArguments[0]! as List; + gitDirCommands.add(arguments); final MockProcessResult mockProcessResult = MockProcessResult(); - if (invocation.positionalArguments[0][0] == 'diff') { + if (arguments[0] == 'diff') { when(mockProcessResult.stdout as String?) .thenReturn(gitDiffResponse); - } else if (invocation.positionalArguments[0][0] == 'merge-base') { + } else if (arguments[0] == 'merge-base') { when(mockProcessResult.stdout as String?) .thenReturn(mergeBaseResponse); } diff --git a/script/tool/test/common/package_looping_command_test.dart b/script/tool/test/common/package_looping_command_test.dart index f90d58e12270..34f346c62fe7 100644 --- a/script/tool/test/common/package_looping_command_test.dart +++ b/script/tool/test/common/package_looping_command_test.dart @@ -110,8 +110,10 @@ void main() { final MockGitDir gitDir = MockGitDir(); when(gitDir.runCommand(any, throwOnError: anyNamed('throwOnError'))) .thenAnswer((Invocation invocation) { + final List arguments = + invocation.positionalArguments[0]! as List; final MockProcessResult mockProcessResult = MockProcessResult(); - if (invocation.positionalArguments[0][0] == 'diff') { + if (arguments[0] == 'diff') { when(mockProcessResult.stdout as String?) .thenReturn(gitDiffResponse); }