From 529fbc2f2accf5db8f78c3cf4649231768d303b8 Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Wed, 18 Mar 2026 12:08:32 -0400 Subject: [PATCH 01/10] Recreate from template --- .../camera_avfoundation/example/.gitignore | 45 ++ .../camera_avfoundation/example/.metadata | 30 + .../example/ios/.gitignore | 34 + .../ios/Flutter/AppFrameworkInfo.plist | 4 - .../ios/Runner.xcodeproj/project.pbxproj | 480 +++++-------- .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../xcshareddata/WorkspaceSettings.xcsettings | 8 + .../xcshareddata/xcschemes/Runner.xcscheme | 16 +- .../contents.xcworkspacedata | 3 - .../xcshareddata/WorkspaceSettings.xcsettings | 8 + .../example/ios/Runner/AppDelegate.h | 10 - .../example/ios/Runner/AppDelegate.m | 17 - .../example/ios/Runner/AppDelegate.swift | 16 + .../AppIcon.appiconset/Contents.json | 5 +- .../Icon-App-1024x1024@1x.png | Bin 0 -> 10932 bytes .../AppIcon.appiconset/Icon-App-20x20@1x.png | Bin 564 -> 295 bytes .../AppIcon.appiconset/Icon-App-20x20@2x.png | Bin 1283 -> 406 bytes .../AppIcon.appiconset/Icon-App-20x20@3x.png | Bin 1588 -> 450 bytes .../AppIcon.appiconset/Icon-App-29x29@1x.png | Bin 1025 -> 282 bytes .../AppIcon.appiconset/Icon-App-29x29@2x.png | Bin 1716 -> 462 bytes .../AppIcon.appiconset/Icon-App-29x29@3x.png | Bin 1920 -> 704 bytes .../AppIcon.appiconset/Icon-App-40x40@1x.png | Bin 1283 -> 406 bytes .../AppIcon.appiconset/Icon-App-40x40@2x.png | Bin 1895 -> 586 bytes .../AppIcon.appiconset/Icon-App-40x40@3x.png | Bin 2665 -> 862 bytes .../AppIcon.appiconset/Icon-App-60x60@2x.png | Bin 2665 -> 862 bytes .../AppIcon.appiconset/Icon-App-60x60@3x.png | Bin 3831 -> 1674 bytes .../AppIcon.appiconset/Icon-App-76x76@1x.png | Bin 1888 -> 762 bytes .../AppIcon.appiconset/Icon-App-76x76@2x.png | Bin 3294 -> 1226 bytes .../Icon-App-83.5x83.5@2x.png | Bin 3612 -> 1418 bytes .../example/ios/Runner/Info.plist | 46 +- .../ios/Runner/Runner-Bridging-Header.h | 1 + .../example/ios/Runner/SceneDelegate.swift | 6 + .../example/ios/Runner/main.m | 19 - .../RunnerTests/AvailableCamerasTests.swift | 138 ---- .../CameraInitRaceConditionsTests.swift | 92 --- .../CameraMethodChannelTests.swift | 80 --- .../RunnerTests/CameraOrientationTests.swift | 168 ----- .../RunnerTests/CameraPermissionTests.swift | 237 ------- .../CameraPluginCreateCameraTests.swift | 131 ---- .../CameraPluginDelegatingMethodTests.swift | 630 ------------------ .../CameraPluginInitializeCameraTests.swift | 105 --- .../RunnerTests/CameraPreviewPauseTests.swift | 26 - .../RunnerTests/CameraPropertiesTests.swift | 73 -- .../CameraSessionPresetsTests.swift | 97 --- .../ios/RunnerTests/CameraSettingsTests.swift | 355 ---------- .../ios/RunnerTests/CameraTestUtils.swift | 219 ------ .../ios/RunnerTests/ExceptionCatcher.h | 23 - .../ios/RunnerTests/ExceptionCatcher.m | 17 - .../ios/RunnerTests/FLTCamExposureTests.swift | 146 ---- .../ios/RunnerTests/FLTCamFocusTests.swift | 166 ----- .../FLTCamSetDeviceOrientationTests.swift | 108 --- .../RunnerTests/FLTCamSetFlashModeTests.swift | 168 ----- .../ios/RunnerTests/FLTCamZoomTests.swift | 111 --- .../example/ios/RunnerTests/Info.plist | 22 - .../RunnerTests/Mocks/MockAssetWriter.swift | 33 - .../Mocks/MockAssetWriterInput.swift | 25 - ...ckAssetWriterInputPixelBufferAdaptor.swift | 17 - .../ios/RunnerTests/Mocks/MockCamera.swift | 233 ------- .../Mocks/MockCameraDeviceDiscoverer.swift | 29 - .../Mocks/MockCaptureConnection.swift | 27 - .../RunnerTests/Mocks/MockCaptureDevice.swift | 127 ---- .../Mocks/MockCaptureDeviceFormat.swift | 43 -- .../Mocks/MockCaptureDeviceInputFactory.swift | 13 - .../RunnerTests/Mocks/MockCaptureInput.swift | 17 - .../Mocks/MockCapturePhotoOutput.swift | 32 - .../Mocks/MockCaptureSession.swift | 87 --- .../Mocks/MockCaptureVideoDataOutput.swift | 27 - .../Mocks/MockDeviceOrientationProvider.swift | 15 - .../MockFLTCameraPermissionManager.swift | 32 - .../Mocks/MockFlutterBinaryMessenger.swift | 26 - .../Mocks/MockFlutterTextureRegistry.swift | 16 - .../Mocks/MockFrameRateRange.swift | 17 - .../Mocks/MockGlobalEventApi.swift | 26 - .../RunnerTests/Mocks/MockWritableData.swift | 17 - .../ios/RunnerTests/PhotoCaptureTests.swift | 248 ------- .../ios/RunnerTests/QueueUtilsTests.swift | 35 - .../RunnerTests/RunnerTests-Bridging-Header.h | 5 - .../example/ios/RunnerTests/RunnerTests.swift | 12 + .../ios/RunnerTests/SampleBufferTests.swift | 542 --------------- .../RunnerTests/SavePhotoDelegateTests.swift | 99 --- .../ios/RunnerTests/StreamingTests.swift | 217 ------ 81 files changed, 370 insertions(+), 5515 deletions(-) create mode 100644 packages/camera/camera_avfoundation/example/.gitignore create mode 100644 packages/camera/camera_avfoundation/example/.metadata create mode 100644 packages/camera/camera_avfoundation/example/ios/.gitignore create mode 100644 packages/camera/camera_avfoundation/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 packages/camera/camera_avfoundation/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings create mode 100644 packages/camera/camera_avfoundation/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings delete mode 100644 packages/camera/camera_avfoundation/example/ios/Runner/AppDelegate.h delete mode 100644 packages/camera/camera_avfoundation/example/ios/Runner/AppDelegate.m create mode 100644 packages/camera/camera_avfoundation/example/ios/Runner/AppDelegate.swift create mode 100644 packages/camera/camera_avfoundation/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png create mode 100644 packages/camera/camera_avfoundation/example/ios/Runner/Runner-Bridging-Header.h create mode 100644 packages/camera/camera_avfoundation/example/ios/Runner/SceneDelegate.swift delete mode 100644 packages/camera/camera_avfoundation/example/ios/Runner/main.m delete mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/AvailableCamerasTests.swift delete mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraInitRaceConditionsTests.swift delete mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraMethodChannelTests.swift delete mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraOrientationTests.swift delete mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraPermissionTests.swift delete mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraPluginCreateCameraTests.swift delete mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraPluginDelegatingMethodTests.swift delete mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraPluginInitializeCameraTests.swift delete mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraPreviewPauseTests.swift delete mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraPropertiesTests.swift delete mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraSessionPresetsTests.swift delete mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraSettingsTests.swift delete mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraTestUtils.swift delete mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/ExceptionCatcher.h delete mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/ExceptionCatcher.m delete mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamExposureTests.swift delete mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamFocusTests.swift delete mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamSetDeviceOrientationTests.swift delete mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamSetFlashModeTests.swift delete mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamZoomTests.swift delete mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/Info.plist delete mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockAssetWriter.swift delete mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockAssetWriterInput.swift delete mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockAssetWriterInputPixelBufferAdaptor.swift delete mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCamera.swift delete mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCameraDeviceDiscoverer.swift delete mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureConnection.swift delete mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDevice.swift delete mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDeviceFormat.swift delete mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDeviceInputFactory.swift delete mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureInput.swift delete mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCapturePhotoOutput.swift delete mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureSession.swift delete mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureVideoDataOutput.swift delete mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockDeviceOrientationProvider.swift delete mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockFLTCameraPermissionManager.swift delete mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockFlutterBinaryMessenger.swift delete mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockFlutterTextureRegistry.swift delete mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockFrameRateRange.swift delete mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockGlobalEventApi.swift delete mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockWritableData.swift delete mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/PhotoCaptureTests.swift delete mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/QueueUtilsTests.swift delete mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/RunnerTests-Bridging-Header.h create mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/RunnerTests.swift delete mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/SampleBufferTests.swift delete mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/SavePhotoDelegateTests.swift delete mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/StreamingTests.swift diff --git a/packages/camera/camera_avfoundation/example/.gitignore b/packages/camera/camera_avfoundation/example/.gitignore new file mode 100644 index 000000000000..3820a95c65c3 --- /dev/null +++ b/packages/camera/camera_avfoundation/example/.gitignore @@ -0,0 +1,45 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.build/ +.buildlog/ +.history +.svn/ +.swiftpm/ +migrate_working_dir/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +**/doc/api/ +**/ios/Flutter/.last_build_id +.dart_tool/ +.flutter-plugins-dependencies +.pub-cache/ +.pub/ +/build/ +/coverage/ + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Android Studio will place build artifacts here +/android/app/debug +/android/app/profile +/android/app/release diff --git a/packages/camera/camera_avfoundation/example/.metadata b/packages/camera/camera_avfoundation/example/.metadata new file mode 100644 index 000000000000..3e79a8d8a334 --- /dev/null +++ b/packages/camera/camera_avfoundation/example/.metadata @@ -0,0 +1,30 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: "ff37bef603469fb030f2b72995ab929ccfc227f0" + channel: "stable" + +project_type: app + +# Tracks metadata for the flutter migrate command +migration: + platforms: + - platform: root + create_revision: ff37bef603469fb030f2b72995ab929ccfc227f0 + base_revision: ff37bef603469fb030f2b72995ab929ccfc227f0 + - platform: ios + create_revision: ff37bef603469fb030f2b72995ab929ccfc227f0 + base_revision: ff37bef603469fb030f2b72995ab929ccfc227f0 + + # User provided section + + # List of Local paths (relative to this file) that should be + # ignored by the migrate tool. + # + # Files that are not part of the templates will be ignored by default. + unmanaged_files: + - 'lib/main.dart' + - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/packages/camera/camera_avfoundation/example/ios/.gitignore b/packages/camera/camera_avfoundation/example/ios/.gitignore new file mode 100644 index 000000000000..7a7f9873ad7d --- /dev/null +++ b/packages/camera/camera_avfoundation/example/ios/.gitignore @@ -0,0 +1,34 @@ +**/dgph +*.mode1v3 +*.mode2v3 +*.moved-aside +*.pbxuser +*.perspectivev3 +**/*sync/ +.sconsign.dblite +.tags* +**/.vagrant/ +**/DerivedData/ +Icon? +**/Pods/ +**/.symlinks/ +profile +xcuserdata +**/.generated/ +Flutter/App.framework +Flutter/Flutter.framework +Flutter/Flutter.podspec +Flutter/Generated.xcconfig +Flutter/ephemeral/ +Flutter/app.flx +Flutter/app.zip +Flutter/flutter_assets/ +Flutter/flutter_export_environment.sh +ServiceDefinitions.json +Runner/GeneratedPluginRegistrant.* + +# Exceptions to above rules. +!default.mode1v3 +!default.mode2v3 +!default.pbxuser +!default.perspectivev3 diff --git a/packages/camera/camera_avfoundation/example/ios/Flutter/AppFrameworkInfo.plist b/packages/camera/camera_avfoundation/example/ios/Flutter/AppFrameworkInfo.plist index 6fe4034356ac..391a902b2beb 100644 --- a/packages/camera/camera_avfoundation/example/ios/Flutter/AppFrameworkInfo.plist +++ b/packages/camera/camera_avfoundation/example/ios/Flutter/AppFrameworkInfo.plist @@ -20,9 +20,5 @@ ???? CFBundleVersion 1.0 - UIRequiredDeviceCapabilities - - arm64 - diff --git a/packages/camera/camera_avfoundation/example/ios/Runner.xcodeproj/project.pbxproj b/packages/camera/camera_avfoundation/example/ios/Runner.xcodeproj/project.pbxproj index 2776179e27a0..420851afb872 100644 --- a/packages/camera/camera_avfoundation/example/ios/Runner.xcodeproj/project.pbxproj +++ b/packages/camera/camera_avfoundation/example/ios/Runner.xcodeproj/project.pbxproj @@ -8,61 +8,18 @@ /* Begin PBXBuildFile section */ 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; + 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; }; 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; + 7884E8682EC3CC0700C636F2 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7884E8672EC3CC0400C636F2 /* SceneDelegate.swift */; }; 78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */ = {isa = PBXBuildFile; productRef = 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */; }; - 970ADABE2D6740A900EFDCD9 /* MockWritableData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 970ADABD2D6740A900EFDCD9 /* MockWritableData.swift */; }; - 972CA92B2D5A1D8C004B846F /* CameraPropertiesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 972CA92A2D5A1D8C004B846F /* CameraPropertiesTests.swift */; }; - 972CA92D2D5A28C4004B846F /* QueueUtilsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 972CA92C2D5A28C4004B846F /* QueueUtilsTests.swift */; }; - 977A25202D5A439300931E34 /* AvailableCamerasTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 977A251F2D5A439300931E34 /* AvailableCamerasTests.swift */; }; - 977A25222D5A49EC00931E34 /* FLTCamFocusTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 977A25212D5A49EC00931E34 /* FLTCamFocusTests.swift */; }; - 977A25242D5A511600931E34 /* CameraPermissionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 977A25232D5A511600931E34 /* CameraPermissionTests.swift */; }; - 978296CF2D5F744B0009BDD3 /* PhotoCaptureTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 978296CE2D5F744B0009BDD3 /* PhotoCaptureTests.swift */; }; - 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */; }; - 978D90B42D5F630300CD817E /* StreamingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 978D90B32D5F630300CD817E /* StreamingTests.swift */; }; - 97922B0D2D6380C300A9B4CF /* SampleBufferTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 97922B0C2D6380C300A9B4CF /* SampleBufferTests.swift */; }; - 979B3DFB2D5B6BC7009BDE1A /* ExceptionCatcher.m in Sources */ = {isa = PBXBuildFile; fileRef = 979B3DFA2D5B6BC7009BDE1A /* ExceptionCatcher.m */; }; - 979B3DFE2D5B985B009BDE1A /* CameraInitRaceConditionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 979B3DFD2D5B985B009BDE1A /* CameraInitRaceConditionsTests.swift */; }; - 979B3E002D5B9E6C009BDE1A /* CameraMethodChannelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 979B3DFF2D5B9E6C009BDE1A /* CameraMethodChannelTests.swift */; }; - 979B3E022D5BA48F009BDE1A /* CameraOrientationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 979B3E012D5BA48F009BDE1A /* CameraOrientationTests.swift */; }; - 97BD4A0E2D5CC5AE00F857D5 /* CameraSettingsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 97BD4A0D2D5CC5AE00F857D5 /* CameraSettingsTests.swift */; }; - 97BD4A102D5CE13500F857D5 /* CameraSessionPresetsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 97BD4A0F2D5CE13500F857D5 /* CameraSessionPresetsTests.swift */; }; - 97C0FFAE2D5E023200A36284 /* SavePhotoDelegateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 97C0FFAD2D5E023200A36284 /* SavePhotoDelegateTests.swift */; }; - 97C146F31CF9000F007C117D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 97C146F21CF9000F007C117D /* main.m */; }; 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; - 97DB234D2D566D0700CEFE66 /* CameraPreviewPauseTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 97DB234C2D566D0700CEFE66 /* CameraPreviewPauseTests.swift */; }; - E11D6A8F2D81B81D0031E6C5 /* MockCaptureVideoDataOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E11D6A8E2D81B81D0031E6C5 /* MockCaptureVideoDataOutput.swift */; }; - E11D6A912D82C7740031E6C5 /* FLTCamExposureTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E11D6A902D82C7740031E6C5 /* FLTCamExposureTests.swift */; }; - E12C4FF62D68C69000515E70 /* CameraPluginDelegatingMethodTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E12C4FF52D68C69000515E70 /* CameraPluginDelegatingMethodTests.swift */; }; - E12C4FF82D68E85500515E70 /* MockFLTCameraPermissionManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = E12C4FF72D68E85500515E70 /* MockFLTCameraPermissionManager.swift */; }; - E142681D2D8483FD0046CBBC /* MockCaptureSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = E142681C2D8483FD0046CBBC /* MockCaptureSession.swift */; }; - E142681F2D8566230046CBBC /* CameraTestUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = E142681E2D8566230046CBBC /* CameraTestUtils.swift */; }; - E142F1362D8587F900824824 /* MockCameraDeviceDiscoverer.swift in Sources */ = {isa = PBXBuildFile; fileRef = E142F1352D8587F900824824 /* MockCameraDeviceDiscoverer.swift */; }; - E142F1382D85919700824824 /* MockDeviceOrientationProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = E142F1372D85919700824824 /* MockDeviceOrientationProvider.swift */; }; - E142F13A2D85940600824824 /* MockCapturePhotoOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E142F1392D85940600824824 /* MockCapturePhotoOutput.swift */; }; - E142F13C2D8596F100824824 /* MockCaptureDeviceFormat.swift in Sources */ = {isa = PBXBuildFile; fileRef = E142F13B2D8596F100824824 /* MockCaptureDeviceFormat.swift */; }; - E142F13E2D859ADC00824824 /* MockFrameRateRange.swift in Sources */ = {isa = PBXBuildFile; fileRef = E142F13D2D859ADC00824824 /* MockFrameRateRange.swift */; }; - E142F1402D85AD7900824824 /* MockCaptureConnection.swift in Sources */ = {isa = PBXBuildFile; fileRef = E142F13F2D85AD7900824824 /* MockCaptureConnection.swift */; }; - E142F1422D85AFA400824824 /* MockGlobalEventApi.swift in Sources */ = {isa = PBXBuildFile; fileRef = E142F1412D85AFA400824824 /* MockGlobalEventApi.swift */; }; - E15139182D80980900FEE47B /* FLTCamSetDeviceOrientationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E15139172D80980900FEE47B /* FLTCamSetDeviceOrientationTests.swift */; }; - E15BC7E42D86D08700F66474 /* MockFlutterTextureRegistry.swift in Sources */ = {isa = PBXBuildFile; fileRef = E15BC7E32D86D08700F66474 /* MockFlutterTextureRegistry.swift */; }; - E15BC7E62D86D17D00F66474 /* MockFlutterBinaryMessenger.swift in Sources */ = {isa = PBXBuildFile; fileRef = E15BC7E52D86D17D00F66474 /* MockFlutterBinaryMessenger.swift */; }; - E16602952D8471C0003CFE12 /* FLTCamZoomTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E16602942D8471C0003CFE12 /* FLTCamZoomTests.swift */; }; - E1A5F4E32D80259C0005BA64 /* FLTCamSetFlashModeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1A5F4E22D80259C0005BA64 /* FLTCamSetFlashModeTests.swift */; }; - E1ABED6C2D94392500AED9CC /* MockAssetWriter.swift in Sources */ = {isa = PBXBuildFile; fileRef = E15BC7E72D86D29F00F66474 /* MockAssetWriter.swift */; }; - E1ABED6D2D94392700AED9CC /* MockAssetWriterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E15BC7E92D86D41F00F66474 /* MockAssetWriterInput.swift */; }; - E1ABED6E2D94392900AED9CC /* MockAssetWriterInputPixelBufferAdaptor.swift in Sources */ = {isa = PBXBuildFile; fileRef = E15BC7EB2D86D50200F66474 /* MockAssetWriterInputPixelBufferAdaptor.swift */; }; - E1ABED6F2D943B2500AED9CC /* MockCaptureDevice.swift in Sources */ = {isa = PBXBuildFile; fileRef = E15BC7ED2D86D85500F66474 /* MockCaptureDevice.swift */; }; - E1ABED722D943DC700AED9CC /* MockCaptureDeviceInputFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1ABED702D943DC700AED9CC /* MockCaptureDeviceInputFactory.swift */; }; - E1ABED732D943DC700AED9CC /* MockCaptureInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1ABED712D943DC700AED9CC /* MockCaptureInput.swift */; }; - E1FFEAAD2D6C8DD700B14107 /* MockCamera.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1FFEAAC2D6C8DD700B14107 /* MockCamera.swift */; }; - E1FFEAAF2D6CDA8C00B14107 /* CameraPluginCreateCameraTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1FFEAAE2D6CDA8C00B14107 /* CameraPluginCreateCameraTests.swift */; }; - E1FFEAB12D6CDE5B00B14107 /* CameraPluginInitializeCameraTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1FFEAB02D6CDE5B00B14107 /* CameraPluginInitializeCameraTests.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ - 03BB766D2665316900CE5A93 /* PBXContainerItemProxy */ = { + 331C8085294A63A400263BE5 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 97C146E61CF9000F007C117D /* Project object */; proxyType = 1; @@ -85,81 +42,26 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ - 03BB76682665316900CE5A93 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; - 03BB766C2665316900CE5A93 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; + 331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; + 331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; - 784666492D4C4C64000A1A5F /* FlutterFramework */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = FlutterFramework; path = Flutter/ephemeral/Packages/.packages/FlutterFramework; sourceTree = ""; }; - 78DABEA22ED26510000E7860 /* camera_avfoundation */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = camera_avfoundation; path = ../../ios/camera_avfoundation; sourceTree = ""; }; + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 7884E8672EC3CC0400C636F2 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; 78E0A7A72DC9AD7400C4905E /* FlutterGeneratedPluginSwiftPackage */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = FlutterGeneratedPluginSwiftPackage; path = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; - 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; - 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; - 970ADABD2D6740A900EFDCD9 /* MockWritableData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockWritableData.swift; sourceTree = ""; }; - 972CA92A2D5A1D8C004B846F /* CameraPropertiesTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CameraPropertiesTests.swift; sourceTree = ""; }; - 972CA92C2D5A28C4004B846F /* QueueUtilsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QueueUtilsTests.swift; sourceTree = ""; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; - 977A251F2D5A439300931E34 /* AvailableCamerasTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AvailableCamerasTests.swift; sourceTree = ""; }; - 977A25212D5A49EC00931E34 /* FLTCamFocusTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FLTCamFocusTests.swift; sourceTree = ""; }; - 977A25232D5A511600931E34 /* CameraPermissionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CameraPermissionTests.swift; sourceTree = ""; }; - 978296CE2D5F744B0009BDD3 /* PhotoCaptureTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhotoCaptureTests.swift; sourceTree = ""; }; - 978D90B32D5F630300CD817E /* StreamingTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StreamingTests.swift; sourceTree = ""; }; - 97922B0C2D6380C300A9B4CF /* SampleBufferTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SampleBufferTests.swift; sourceTree = ""; }; - 979B3DF92D5B6BA2009BDE1A /* ExceptionCatcher.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ExceptionCatcher.h; sourceTree = ""; }; - 979B3DFA2D5B6BC7009BDE1A /* ExceptionCatcher.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ExceptionCatcher.m; sourceTree = ""; }; - 979B3DFC2D5B985B009BDE1A /* RunnerTests-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "RunnerTests-Bridging-Header.h"; sourceTree = ""; }; - 979B3DFD2D5B985B009BDE1A /* CameraInitRaceConditionsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CameraInitRaceConditionsTests.swift; sourceTree = ""; }; - 979B3DFF2D5B9E6C009BDE1A /* CameraMethodChannelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CameraMethodChannelTests.swift; sourceTree = ""; }; - 979B3E012D5BA48F009BDE1A /* CameraOrientationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CameraOrientationTests.swift; sourceTree = ""; }; - 97BD4A0D2D5CC5AE00F857D5 /* CameraSettingsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CameraSettingsTests.swift; sourceTree = ""; }; - 97BD4A0F2D5CE13500F857D5 /* CameraSessionPresetsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CameraSessionPresetsTests.swift; sourceTree = ""; }; - 97C0FFAD2D5E023200A36284 /* SavePhotoDelegateTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SavePhotoDelegateTests.swift; sourceTree = ""; }; 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 97C146F21CF9000F007C117D /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 97DB234C2D566D0700CEFE66 /* CameraPreviewPauseTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CameraPreviewPauseTests.swift; sourceTree = ""; }; - E11D6A8E2D81B81D0031E6C5 /* MockCaptureVideoDataOutput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockCaptureVideoDataOutput.swift; sourceTree = ""; }; - E11D6A902D82C7740031E6C5 /* FLTCamExposureTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FLTCamExposureTests.swift; sourceTree = ""; }; - E12C4FF52D68C69000515E70 /* CameraPluginDelegatingMethodTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CameraPluginDelegatingMethodTests.swift; sourceTree = ""; }; - E12C4FF72D68E85500515E70 /* MockFLTCameraPermissionManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockFLTCameraPermissionManager.swift; sourceTree = ""; }; - E142681C2D8483FD0046CBBC /* MockCaptureSession.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockCaptureSession.swift; sourceTree = ""; }; - E142681E2D8566230046CBBC /* CameraTestUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CameraTestUtils.swift; sourceTree = ""; }; - E142F1352D8587F900824824 /* MockCameraDeviceDiscoverer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockCameraDeviceDiscoverer.swift; sourceTree = ""; }; - E142F1372D85919700824824 /* MockDeviceOrientationProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockDeviceOrientationProvider.swift; sourceTree = ""; }; - E142F1392D85940600824824 /* MockCapturePhotoOutput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockCapturePhotoOutput.swift; sourceTree = ""; }; - E142F13B2D8596F100824824 /* MockCaptureDeviceFormat.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockCaptureDeviceFormat.swift; sourceTree = ""; }; - E142F13D2D859ADC00824824 /* MockFrameRateRange.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockFrameRateRange.swift; sourceTree = ""; }; - E142F13F2D85AD7900824824 /* MockCaptureConnection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockCaptureConnection.swift; sourceTree = ""; }; - E142F1412D85AFA400824824 /* MockGlobalEventApi.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockGlobalEventApi.swift; sourceTree = ""; }; - E15139172D80980900FEE47B /* FLTCamSetDeviceOrientationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FLTCamSetDeviceOrientationTests.swift; sourceTree = ""; }; - E15BC7E32D86D08700F66474 /* MockFlutterTextureRegistry.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockFlutterTextureRegistry.swift; sourceTree = ""; }; - E15BC7E52D86D17D00F66474 /* MockFlutterBinaryMessenger.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockFlutterBinaryMessenger.swift; sourceTree = ""; }; - E15BC7E72D86D29F00F66474 /* MockAssetWriter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockAssetWriter.swift; sourceTree = ""; }; - E15BC7E92D86D41F00F66474 /* MockAssetWriterInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockAssetWriterInput.swift; sourceTree = ""; }; - E15BC7EB2D86D50200F66474 /* MockAssetWriterInputPixelBufferAdaptor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockAssetWriterInputPixelBufferAdaptor.swift; sourceTree = ""; }; - E15BC7ED2D86D85500F66474 /* MockCaptureDevice.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockCaptureDevice.swift; sourceTree = ""; }; - E16602942D8471C0003CFE12 /* FLTCamZoomTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FLTCamZoomTests.swift; sourceTree = ""; }; - E1A5F4E22D80259C0005BA64 /* FLTCamSetFlashModeTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FLTCamSetFlashModeTests.swift; sourceTree = ""; }; - E1ABED702D943DC700AED9CC /* MockCaptureDeviceInputFactory.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MockCaptureDeviceInputFactory.swift; sourceTree = ""; }; - E1ABED712D943DC700AED9CC /* MockCaptureInput.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MockCaptureInput.swift; sourceTree = ""; }; - E1FFEAAC2D6C8DD700B14107 /* MockCamera.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockCamera.swift; sourceTree = ""; }; - E1FFEAAE2D6CDA8C00B14107 /* CameraPluginCreateCameraTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CameraPluginCreateCameraTests.swift; sourceTree = ""; }; - E1FFEAB02D6CDE5B00B14107 /* CameraPluginInitializeCameraTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CameraPluginInitializeCameraTests.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ - 03BB76652665316900CE5A93 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; 97C146EB1CF9000F007C117D /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -171,73 +73,17 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ - 03BB76692665316900CE5A93 /* RunnerTests */ = { + 331C8082294A63A400263BE5 /* RunnerTests */ = { isa = PBXGroup; children = ( - 7F29EB3F2D281C6D00740257 /* Mocks */, - 03BB766C2665316900CE5A93 /* Info.plist */, - E142681E2D8566230046CBBC /* CameraTestUtils.swift */, - 979B3DF92D5B6BA2009BDE1A /* ExceptionCatcher.h */, - 979B3DFA2D5B6BC7009BDE1A /* ExceptionCatcher.m */, - 979B3DFC2D5B985B009BDE1A /* RunnerTests-Bridging-Header.h */, - 979B3DFD2D5B985B009BDE1A /* CameraInitRaceConditionsTests.swift */, - 979B3DFF2D5B9E6C009BDE1A /* CameraMethodChannelTests.swift */, - 979B3E012D5BA48F009BDE1A /* CameraOrientationTests.swift */, - 97BD4A0D2D5CC5AE00F857D5 /* CameraSettingsTests.swift */, - 97BD4A0F2D5CE13500F857D5 /* CameraSessionPresetsTests.swift */, - 97DB234C2D566D0700CEFE66 /* CameraPreviewPauseTests.swift */, - 972CA92A2D5A1D8C004B846F /* CameraPropertiesTests.swift */, - 972CA92C2D5A28C4004B846F /* QueueUtilsTests.swift */, - 977A251F2D5A439300931E34 /* AvailableCamerasTests.swift */, - 977A25232D5A511600931E34 /* CameraPermissionTests.swift */, - 97C0FFAD2D5E023200A36284 /* SavePhotoDelegateTests.swift */, - 978D90B32D5F630300CD817E /* StreamingTests.swift */, - 97922B0C2D6380C300A9B4CF /* SampleBufferTests.swift */, - 978296CE2D5F744B0009BDD3 /* PhotoCaptureTests.swift */, - E12C4FF52D68C69000515E70 /* CameraPluginDelegatingMethodTests.swift */, - E1FFEAAE2D6CDA8C00B14107 /* CameraPluginCreateCameraTests.swift */, - E1FFEAB02D6CDE5B00B14107 /* CameraPluginInitializeCameraTests.swift */, - E11D6A902D82C7740031E6C5 /* FLTCamExposureTests.swift */, - 977A25212D5A49EC00931E34 /* FLTCamFocusTests.swift */, - E1A5F4E22D80259C0005BA64 /* FLTCamSetFlashModeTests.swift */, - E16602942D8471C0003CFE12 /* FLTCamZoomTests.swift */, - E15139172D80980900FEE47B /* FLTCamSetDeviceOrientationTests.swift */, + 331C807B294A618700263BE5 /* RunnerTests.swift */, ); path = RunnerTests; sourceTree = ""; }; - 7F29EB3F2D281C6D00740257 /* Mocks */ = { - isa = PBXGroup; - children = ( - E15BC7E72D86D29F00F66474 /* MockAssetWriter.swift */, - E15BC7E92D86D41F00F66474 /* MockAssetWriterInput.swift */, - E15BC7EB2D86D50200F66474 /* MockAssetWriterInputPixelBufferAdaptor.swift */, - E15BC7E52D86D17D00F66474 /* MockFlutterBinaryMessenger.swift */, - E15BC7E32D86D08700F66474 /* MockFlutterTextureRegistry.swift */, - E142F1412D85AFA400824824 /* MockGlobalEventApi.swift */, - E15BC7ED2D86D85500F66474 /* MockCaptureDevice.swift */, - E1ABED702D943DC700AED9CC /* MockCaptureDeviceInputFactory.swift */, - E1ABED712D943DC700AED9CC /* MockCaptureInput.swift */, - E142F13F2D85AD7900824824 /* MockCaptureConnection.swift */, - E142F13B2D8596F100824824 /* MockCaptureDeviceFormat.swift */, - E142F13D2D859ADC00824824 /* MockFrameRateRange.swift */, - E142F1392D85940600824824 /* MockCapturePhotoOutput.swift */, - E142F1372D85919700824824 /* MockDeviceOrientationProvider.swift */, - E142F1352D8587F900824824 /* MockCameraDeviceDiscoverer.swift */, - E1FFEAAC2D6C8DD700B14107 /* MockCamera.swift */, - E12C4FF72D68E85500515E70 /* MockFLTCameraPermissionManager.swift */, - 970ADABD2D6740A900EFDCD9 /* MockWritableData.swift */, - E11D6A8E2D81B81D0031E6C5 /* MockCaptureVideoDataOutput.swift */, - E142681C2D8483FD0046CBBC /* MockCaptureSession.swift */, - ); - path = Mocks; - sourceTree = ""; - }; 9740EEB11CF90186004384FC /* Flutter */ = { isa = PBXGroup; children = ( - 78DABEA22ED26510000E7860 /* camera_avfoundation */, - 784666492D4C4C64000A1A5F /* FlutterFramework */, 78E0A7A72DC9AD7400C4905E /* FlutterGeneratedPluginSwiftPackage */, 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, 9740EEB21CF90195004384FC /* Debug.xcconfig */, @@ -252,9 +98,8 @@ children = ( 9740EEB11CF90186004384FC /* Flutter */, 97C146F01CF9000F007C117D /* Runner */, - 03BB76692665316900CE5A93 /* RunnerTests */, 97C146EF1CF9000F007C117D /* Products */, - FD386F00E98D73419C929072 /* Pods */, + 331C8082294A63A400263BE5 /* RunnerTests */, ); sourceTree = ""; }; @@ -262,7 +107,7 @@ isa = PBXGroup; children = ( 97C146EE1CF9000F007C117D /* Runner.app */, - 03BB76682665316900CE5A93 /* RunnerTests.xctest */, + 331C8081294A63A400263BE5 /* RunnerTests.xctest */, ); name = Products; sourceTree = ""; @@ -270,53 +115,37 @@ 97C146F01CF9000F007C117D /* Runner */ = { isa = PBXGroup; children = ( - 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */, - 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */, 97C146FA1CF9000F007C117D /* Main.storyboard */, 97C146FD1CF9000F007C117D /* Assets.xcassets */, 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, 97C147021CF9000F007C117D /* Info.plist */, - 97C146F11CF9000F007C117D /* Supporting Files */, 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 7884E8672EC3CC0400C636F2 /* SceneDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, ); path = Runner; sourceTree = ""; }; - 97C146F11CF9000F007C117D /* Supporting Files */ = { - isa = PBXGroup; - children = ( - 97C146F21CF9000F007C117D /* main.m */, - ); - name = "Supporting Files"; - sourceTree = ""; - }; - FD386F00E98D73419C929072 /* Pods */ = { - isa = PBXGroup; - children = ( - ); - path = Pods; - sourceTree = ""; - }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ - 03BB76672665316900CE5A93 /* RunnerTests */ = { + 331C8080294A63A400263BE5 /* RunnerTests */ = { isa = PBXNativeTarget; - buildConfigurationList = 03BB76712665316900CE5A93 /* Build configuration list for PBXNativeTarget "RunnerTests" */; + buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; buildPhases = ( - 03BB76642665316900CE5A93 /* Sources */, - 03BB76652665316900CE5A93 /* Frameworks */, - 03BB76662665316900CE5A93 /* Resources */, + 331C807D294A63A400263BE5 /* Sources */, + 331C807F294A63A400263BE5 /* Resources */, ); buildRules = ( ); dependencies = ( - 03BB766E2665316900CE5A93 /* PBXTargetDependency */, + 331C8086294A63A400263BE5 /* PBXTargetDependency */, ); name = RunnerTests; - productName = camera_exampleTests; - productReference = 03BB76682665316900CE5A93 /* RunnerTests.xctest */; + productName = RunnerTests; + productReference = 331C8081294A63A400263BE5 /* RunnerTests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; 97C146ED1CF9000F007C117D /* Runner */ = { @@ -348,22 +177,22 @@ 97C146E61CF9000F007C117D /* Project object */ = { isa = PBXProject; attributes = { + BuildIndependentTargetsInParallel = YES; LastUpgradeCheck = 1510; - ORGANIZATIONNAME = "The Flutter Authors"; + ORGANIZATIONNAME = ""; TargetAttributes = { - 03BB76672665316900CE5A93 = { - CreatedOnToolsVersion = 12.5; - LastSwiftMigration = 1540; - ProvisioningStyle = Automatic; + 331C8080294A63A400263BE5 = { + CreatedOnToolsVersion = 14.0; TestTargetID = 97C146ED1CF9000F007C117D; }; 97C146ED1CF9000F007C117D = { CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; }; }; }; buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; - compatibilityVersion = "Xcode 3.2"; + compatibilityVersion = "Xcode 9.3"; developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( @@ -372,20 +201,20 @@ ); mainGroup = 97C146E51CF9000F007C117D; packageReferences = ( - 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "FlutterGeneratedPluginSwiftPackage" */, + 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage" */, ); productRefGroup = 97C146EF1CF9000F007C117D /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( 97C146ED1CF9000F007C117D /* Runner */, - 03BB76672665316900CE5A93 /* RunnerTests */, + 331C8080294A63A400263BE5 /* RunnerTests */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ - 03BB76662665316900CE5A93 /* Resources */ = { + 331C807F294A63A400263BE5 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( @@ -440,54 +269,11 @@ /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ - 03BB76642665316900CE5A93 /* Sources */ = { + 331C807D294A63A400263BE5 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - E11D6A912D82C7740031E6C5 /* FLTCamExposureTests.swift in Sources */, - 97BD4A0E2D5CC5AE00F857D5 /* CameraSettingsTests.swift in Sources */, - E142F1422D85AFA400824824 /* MockGlobalEventApi.swift in Sources */, - 972CA92D2D5A28C4004B846F /* QueueUtilsTests.swift in Sources */, - E1FFEAB12D6CDE5B00B14107 /* CameraPluginInitializeCameraTests.swift in Sources */, - E142F1362D8587F900824824 /* MockCameraDeviceDiscoverer.swift in Sources */, - 979B3DFB2D5B6BC7009BDE1A /* ExceptionCatcher.m in Sources */, - E1ABED6E2D94392900AED9CC /* MockAssetWriterInputPixelBufferAdaptor.swift in Sources */, - E1ABED6C2D94392500AED9CC /* MockAssetWriter.swift in Sources */, - E1A5F4E32D80259C0005BA64 /* FLTCamSetFlashModeTests.swift in Sources */, - E1ABED6D2D94392700AED9CC /* MockAssetWriterInput.swift in Sources */, - 977A25242D5A511600931E34 /* CameraPermissionTests.swift in Sources */, - 970ADABE2D6740A900EFDCD9 /* MockWritableData.swift in Sources */, - 979B3DFE2D5B985B009BDE1A /* CameraInitRaceConditionsTests.swift in Sources */, - E142F13A2D85940600824824 /* MockCapturePhotoOutput.swift in Sources */, - E12C4FF82D68E85500515E70 /* MockFLTCameraPermissionManager.swift in Sources */, - 97922B0D2D6380C300A9B4CF /* SampleBufferTests.swift in Sources */, - E142681D2D8483FD0046CBBC /* MockCaptureSession.swift in Sources */, - E15139182D80980900FEE47B /* FLTCamSetDeviceOrientationTests.swift in Sources */, - 972CA92B2D5A1D8C004B846F /* CameraPropertiesTests.swift in Sources */, - E15BC7E42D86D08700F66474 /* MockFlutterTextureRegistry.swift in Sources */, - 978296CF2D5F744B0009BDD3 /* PhotoCaptureTests.swift in Sources */, - 979B3E002D5B9E6C009BDE1A /* CameraMethodChannelTests.swift in Sources */, - E142F13C2D8596F100824824 /* MockCaptureDeviceFormat.swift in Sources */, - E1FFEAAF2D6CDA8C00B14107 /* CameraPluginCreateCameraTests.swift in Sources */, - E142F13E2D859ADC00824824 /* MockFrameRateRange.swift in Sources */, - 97DB234D2D566D0700CEFE66 /* CameraPreviewPauseTests.swift in Sources */, - E1ABED732D943DC700AED9CC /* MockCaptureInput.swift in Sources */, - E1ABED6F2D943B2500AED9CC /* MockCaptureDevice.swift in Sources */, - E1ABED722D943DC700AED9CC /* MockCaptureDeviceInputFactory.swift in Sources */, - 977A25202D5A439300931E34 /* AvailableCamerasTests.swift in Sources */, - E142681F2D8566230046CBBC /* CameraTestUtils.swift in Sources */, - E1FFEAAD2D6C8DD700B14107 /* MockCamera.swift in Sources */, - E16602952D8471C0003CFE12 /* FLTCamZoomTests.swift in Sources */, - 97BD4A102D5CE13500F857D5 /* CameraSessionPresetsTests.swift in Sources */, - 979B3E022D5BA48F009BDE1A /* CameraOrientationTests.swift in Sources */, - E12C4FF62D68C69000515E70 /* CameraPluginDelegatingMethodTests.swift in Sources */, - 977A25222D5A49EC00931E34 /* FLTCamFocusTests.swift in Sources */, - 978D90B42D5F630300CD817E /* StreamingTests.swift in Sources */, - E142F1382D85919700824824 /* MockDeviceOrientationProvider.swift in Sources */, - E11D6A8F2D81B81D0031E6C5 /* MockCaptureVideoDataOutput.swift in Sources */, - E142F1402D85AD7900824824 /* MockCaptureConnection.swift in Sources */, - E15BC7E62D86D17D00F66474 /* MockFlutterBinaryMessenger.swift in Sources */, - 97C0FFAE2D5E023200A36284 /* SavePhotoDelegateTests.swift in Sources */, + 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -495,19 +281,19 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */, - 97C146F31CF9000F007C117D /* main.m in Sources */, + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + 7884E8682EC3CC0700C636F2 /* SceneDelegate.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ - 03BB766E2665316900CE5A93 /* PBXTargetDependency */ = { + 331C8086294A63A400263BE5 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 97C146ED1CF9000F007C117D /* Runner */; - targetProxy = 03BB766D2665316900CE5A93 /* PBXContainerItemProxy */; + targetProxy = 331C8085294A63A400263BE5 /* PBXContainerItemProxy */; }; /* End PBXTargetDependency section */ @@ -531,73 +317,132 @@ /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ - 03BB766F2665316900CE5A93 /* Debug */ = { + 249021D3217E4FDB00AE95B9 /* Profile */ = { isa = XCBuildConfiguration; buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_WEAK = YES; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CODE_SIGN_STYLE = Automatic; - GCC_C_LANGUAGE_STANDARD = gnu11; - INFOPLIST_FILE = RunnerTests/Info.plist; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 13.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Profile; + }; + 249021D4217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = EQHXZ8M8AV; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", - "@loader_path/Frameworks", ); - MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; - MTL_FAST_MATH = YES; - PRODUCT_BUNDLE_IDENTIFIER = "dev.flutter.plugins.cameraExample.camera-exampleTests"; + PRODUCT_BUNDLE_IDENTIFIER = dev.flutter.cameraExample; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_OBJC_BRIDGING_HEADER = "RunnerTests/RunnerTests-Bridging-Header.h"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 331C8088294A63A400263BE5 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = dev.flutter.cameraExample.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/Runner"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; }; name = Debug; }; - 03BB76702665316900CE5A93 /* Release */ = { + 331C8089294A63A400263BE5 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_WEAK = YES; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CODE_SIGN_STYLE = Automatic; - GCC_C_LANGUAGE_STANDARD = gnu11; - INFOPLIST_FILE = RunnerTests/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 13.0; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - MTL_FAST_MATH = YES; - PRODUCT_BUNDLE_IDENTIFIER = "dev.flutter.plugins.cameraExample.camera-exampleTests"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = dev.flutter.cameraExample.RunnerTests; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_OBJC_BRIDGING_HEADER = "RunnerTests/RunnerTests-Bridging-Header.h"; SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/Runner"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; }; name = Release; }; + 331C808A294A63A400263BE5 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = dev.flutter.cameraExample.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Profile; + }; 97C147031CF9000F007C117D /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; @@ -627,6 +472,7 @@ DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; @@ -653,7 +499,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; @@ -683,6 +529,7 @@ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; @@ -694,6 +541,9 @@ IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; }; @@ -704,22 +554,21 @@ baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = EQHXZ8M8AV; ENABLE_BITCODE = NO; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); INFOPLIST_FILE = Runner/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); - LIBRARY_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); - PRODUCT_BUNDLE_IDENTIFIER = dev.flutter.plugins.cameraExample; + PRODUCT_BUNDLE_IDENTIFIER = dev.flutter.cameraExample; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; }; name = Debug; }; @@ -728,33 +577,32 @@ baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = EQHXZ8M8AV; ENABLE_BITCODE = NO; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); INFOPLIST_FILE = Runner/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); - LIBRARY_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); - PRODUCT_BUNDLE_IDENTIFIER = dev.flutter.plugins.cameraExample; + PRODUCT_BUNDLE_IDENTIFIER = dev.flutter.cameraExample; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ - 03BB76712665316900CE5A93 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { + 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { isa = XCConfigurationList; buildConfigurations = ( - 03BB766F2665316900CE5A93 /* Debug */, - 03BB76702665316900CE5A93 /* Release */, + 331C8088294A63A400263BE5 /* Debug */, + 331C8089294A63A400263BE5 /* Release */, + 331C808A294A63A400263BE5 /* Profile */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; @@ -764,6 +612,7 @@ buildConfigurations = ( 97C147031CF9000F007C117D /* Debug */, 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; @@ -773,6 +622,7 @@ buildConfigurations = ( 97C147061CF9000F007C117D /* Debug */, 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; @@ -780,7 +630,7 @@ /* End XCConfigurationList section */ /* Begin XCLocalSwiftPackageReference section */ - 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "FlutterGeneratedPluginSwiftPackage" */ = { + 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage" */ = { isa = XCLocalSwiftPackageReference; relativePath = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage; }; diff --git a/packages/camera/camera_avfoundation/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/packages/camera/camera_avfoundation/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000000..18d981003d68 --- /dev/null +++ b/packages/camera/camera_avfoundation/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/packages/camera/camera_avfoundation/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/packages/camera/camera_avfoundation/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 000000000000..f9b0d7c5ea15 --- /dev/null +++ b/packages/camera/camera_avfoundation/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/packages/camera/camera_avfoundation/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/packages/camera/camera_avfoundation/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index ba0c5508103c..c3fedb29c990 100644 --- a/packages/camera/camera_avfoundation/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/packages/camera/camera_avfoundation/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -44,6 +44,7 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" + customLLDBInitFile = "$(SRCROOT)/Flutter/ephemeral/flutter_lldbinit" shouldUseLaunchSchemeArgsEnv = "YES"> + skipped = "NO" + parallelizable = "YES"> @@ -71,6 +73,7 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" + customLLDBInitFile = "$(SRCROOT)/Flutter/ephemeral/flutter_lldbinit" launchStyle = "0" useCustomWorkingDirectory = "NO" ignoresPersistentStateOnLaunch = "NO" @@ -88,16 +91,9 @@ ReferencedContainer = "container:Runner.xcodeproj"> - - - - - - diff --git a/packages/camera/camera_avfoundation/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/packages/camera/camera_avfoundation/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 000000000000..f9b0d7c5ea15 --- /dev/null +++ b/packages/camera/camera_avfoundation/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/packages/camera/camera_avfoundation/example/ios/Runner/AppDelegate.h b/packages/camera/camera_avfoundation/example/ios/Runner/AppDelegate.h deleted file mode 100644 index 721cca1e11bb..000000000000 --- a/packages/camera/camera_avfoundation/example/ios/Runner/AppDelegate.h +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright 2013 The Flutter Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#import -#import - -@interface AppDelegate : FlutterAppDelegate - -@end diff --git a/packages/camera/camera_avfoundation/example/ios/Runner/AppDelegate.m b/packages/camera/camera_avfoundation/example/ios/Runner/AppDelegate.m deleted file mode 100644 index fff9545d5055..000000000000 --- a/packages/camera/camera_avfoundation/example/ios/Runner/AppDelegate.m +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2013 The Flutter Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "AppDelegate.h" -#include "GeneratedPluginRegistrant.h" - -@implementation AppDelegate - -- (BOOL)application:(UIApplication *)application - didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { - [GeneratedPluginRegistrant registerWithRegistry:self]; - // Override point for customization after application launch. - return [super application:application didFinishLaunchingWithOptions:launchOptions]; -} - -@end diff --git a/packages/camera/camera_avfoundation/example/ios/Runner/AppDelegate.swift b/packages/camera/camera_avfoundation/example/ios/Runner/AppDelegate.swift new file mode 100644 index 000000000000..c30b367ec0a9 --- /dev/null +++ b/packages/camera/camera_avfoundation/example/ios/Runner/AppDelegate.swift @@ -0,0 +1,16 @@ +import Flutter +import UIKit + +@main +@objc class AppDelegate: FlutterAppDelegate, FlutterImplicitEngineDelegate { + override func application( + _ application: UIApplication, + didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? + ) -> Bool { + return super.application(application, didFinishLaunchingWithOptions: launchOptions) + } + + func didInitializeImplicitFlutterEngine(_ engineBridge: FlutterImplicitEngineBridge) { + GeneratedPluginRegistrant.register(with: engineBridge.pluginRegistry) + } +} diff --git a/packages/camera/camera_avfoundation/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/packages/camera/camera_avfoundation/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json index d225b3c2cfe2..d36b1fab2d9d 100644 --- a/packages/camera/camera_avfoundation/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json +++ b/packages/camera/camera_avfoundation/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -109,8 +109,9 @@ "scale" : "2x" }, { - "idiom" : "ios-marketing", "size" : "1024x1024", + "idiom" : "ios-marketing", + "filename" : "Icon-App-1024x1024@1x.png", "scale" : "1x" } ], @@ -118,4 +119,4 @@ "version" : 1, "author" : "xcode" } -} \ No newline at end of file +} diff --git a/packages/camera/camera_avfoundation/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/packages/camera/camera_avfoundation/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..dc9ada4725e9b0ddb1deab583e5b5102493aa332 GIT binary patch literal 10932 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 delta 550 zcmV+>0@?ki0<;8>8Gi-<0051N9Sr~g00DDSM?wIu&K&6g00HhvL_t(I5v`QFOB_)Y z#?QI;j_a;jjf#Z$YJ7mH(xecJU?W)A`9CN~KrBV85C}GDQ=|;GDFPNjtWty!L{u=? zh>8yo%^GE+J9o~_IZFoiamQVQXP7%LzTbT3F@uf+9x&7cvVV%GdjTaC;zf>@mq<=3 z!c<%*UT)@yJ|0BK6~d4Jx-*KV`ZQ(@VyUPupum=XhInNG#Z_k-X|hK{B}~9IfiWx} zLD5QY6Vm)p0NrWymdkrHPN5Vgwd>5>4HI1=@PA+e^rq~CEj|n2X`??)0mUI*D{KBn zjv{V=y5X9|X@3grkpcXC6oou4ML~ezCc2EtnsQTB4tWNg?4bkf;hG7IMfhgNI(FV5 zGs4|*GyMTIY0$B=_*mso9+>eB z?J{?+FLkYu+4_Uk`r_>LHF~flZm0oBf#vr8%vJ>#p~!KNvqGG3)|f1T_)ydeh8$vDceZ>oNbH^|*hJ*t?Yc*1`WB&W>VYVEzu) zq#7;;VjO)t*nbgf(!`OXJBr45rP>>AQr$6c7slJWvbpNW@KTwna6d?PP>hvXCcp=4 zF;=GR@R4E7{4VU^0p4F>v^#A|>07*qoM6N<$f<+$JJpcdz delta 1274 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 diff --git a/packages/camera/camera_avfoundation/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/packages/camera/camera_avfoundation/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png index 4cde12118dda48d71e01fcb589a74d069c5d7cb5..4cd7b0099ca80c806f8fe495613e8d6c69460d76 100644 GIT binary patch delta 266 zcmV+l0rmcY2$}+r8Gi!+003c4mpuRg09{Z_R7L;)|5U~JDYo_jSDX9(|7FYh`2GLd z^Zv2r{H^2sT*&w!Y^SB+`<>qVZqE6)=lqo0`vF#&*75!I`TIh@_d&k*HoEtQyV-iD z%Xz2D9EQRbeYh5Nr~y=#0ZD;^+vz0$004MNL_t(2&&|%+4u6C&2tZM$Wf&dzefR%A z(^3-?6X>hnCz2Ba@RH&`m!pgy?n@#@AuLYB&}Q)FGY`?vcft0!vht0Z@M&ZeNCWXh75gzRTXR8EE3oN&6 Q00000NkvXXt^-0~g5kS`djJ3c delta 1014 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 Zxpx7IC@PekH?;r&002ovPDHLkV1i)CYaajr delta 1916 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 delta 1274 zcmV@pi1MCNO0zH7s z{8#}P0)7Ba8DqYf&QgSne>X__O83t$NZM4&R0{XJq|x}oAU?tcfC@|eNz$04T}34& z8DJf78R&>*Zz`k$q{`#gfGHnx7nlH^G{y`jfER)1<_fNi<9aM%_zrm1C`yPkKma(+ ztQ;y*CR2bbBYz>zG*SVsfpkGU(q>uHZf3iogk_%#9E|5SWeHrmAo>P;ejX7mwq#*} zW25m^ZI+{(Z8fI?4jM_fffY0nok=+88^|*_DwcW>mR#e+X$F_KMdb6sRz!~7K zkyN0G(3XQ+;z3X%PZ4gh;n-%62U<*VUKNv(D&IDi_4_D!s#MVXp|-XhH;H z#&@_;oApJVd}}5O@b=X_gJboD^-fM@6|#V@sA%X)Rlkd}3MLH0dGXGG&-HX|aD~|M zC)W#H7=H?AbtdaV#dGpubj_O^J-SlWpVNv-5(;wR%mvE9`Qaqo>03b&##eNNf=m#B z9@^lsd8tJ;BvI86kNV zc~0CY(7V{s+h%cWG|y=gt|q`z$l<(@qU=i?9q#uz`G?PgDMK!VMGidHZt*N+1L0ZI zFkH=mFtywc6rJ}C_?)=m)18V!ZQ`*-j(D`gCFK|nt#{bk*%%zuQ7o7kvJgA^=(^7b zzkm5GZ;jxRn{Wup8IOUx8D4uh&(=Ox-7$a;U><*5L^!% zxRlw)vAbh;sdlR||&e}8_8%)c2Fwy=F& zH|LM+p{pZB5DKTx>Y?F1N%BlZkXf!}Jb#viX>Oi;kBKp1x_fc0#UIbIeSJ^EkWFox zijdim{ojmn@#7EC*aY;fC0W*WN+DmQtE06pNK3SfZ^#@2K`6RgEuU_KwJTQ>E?Yar zc_9e#I$F8%>kuy-JI6ocSsYvQGbsxUCx04(w1z-pMRz9`kH5smmF@WHEG?dcYkv){ zV?kn3XB$_3zr*h1Uow)(<5)w5;3Wh1jHI)`ZlXp&!yEV{Y_~@;?CLwq;4eeaGOe6( zEsSSbwSGD0-`dUUl014$1_O8Gi!+006nq0-pc?0H{z*R7L;)|5U~JDYo_jSDXF*|5nEMy6F5^ z$M}8I`uzU?*Yf=uXr;5|{0m;6_Wb|A>ik^D_|)+I$?g3CSDK^3+eX0mD!2CP`2NN0 z{dLg!a?km&%iyTt`yiax0acdp`~T(l{$a`ZF1YpsRg(cvjDG_-U$Er-fz#Bw>2W$eUI#iU z)Wdgs8Y3U+A$Gd&{+j)d)BmGKx+43U_!tik_YlN)>$7G!hkE!s;%oku3;IwG3U^2k zw?z+HM)jB{@zFhK8P#KMSytSthr+4!c(5c%+^UBn_j%}l|2+O?a>_7qq7W zmx(qtA2nV^tZlLpy_#$U%ZNx5;$`0L&dZ!@e7rFXPGAOup%q`|03hpdtXsPP0000< KMNUMnLSTZ1N;Pr- delta 1891 zcmV-p2b}oI1m_Nr8Gi-<0052=@~r>>2QEoOK~#9!?VW3E6jc<*XLh$yKNt;)Mial3 z7z%<>zxaV5DhMs*(b6YIW1=KP6Jj(m21QYbiJ}su&;o5EN=$%gptMj6p|(7#AOTUJ zlt8fsX(iGq?ZQ50=XmbU+~w|cmz~|6$KBbz$-g^IcV>Hk`+q<8%-p?uMi3G-0B~!5 ze-yPCwFPw?HGmpMc~K)7BCq;C528+>zC*o^8h^XKC)IFgkv#xzm!ewK7j|kRa9dFo zC>MoDSR@P2#cWSU{i1oH5K2-Xb3jRz>|h7VOh0K` zhq^--L3H}A0r)nr z;Tr|-kPjB1s=ItpnS`oT%|U=a4oK-ZFIE^YBLH{u2#~@%%D^K)$`9*Tg(~9M-B+Zj z;~H?4LVsEt0eFtN4&>H(DZ@KpI6RhBKLL21CxC`J&m4Gc^9wwMZU#7SR1+KtuhSZM z+yLY}Vekzw6T_ApfEkuB_yU;e&a)L@rX~z70A_N+upOXN!qygmPDmKG0d%7CECcAI zgkd>ArzH$a0XjKsO$X@IgkcH5Y;m3`0G*yNOn(KK4GF_EfL4aB5i1j9o&Z{vFk~k> z&?@K2jQcJO%W!cddG(_DyfSoO55bUMHtbDF8DPkwF^~Ql#Eq4w15k{h%ML5Ar&pzi zl-D7v8kQXQ!&RRgKCW#5DZB$$6?mjWm50rRw*ukK>P-GkA|k69h{NARc>e}uLx+U4 z0DqE>7pa}9Fez+Vc-3jb`%i^uulglFoMzAVR|2%rf= zf#;74FXF^Ku_4+G&-4$KVy%YP>%2rxu2VG_cdm?XRjEhF&wPXJ># z_Q2+jGs=l~Fyx#MmGn+PZ0`@kBfGp|fO;Vov<$;z`(+sSZ7;Y=zXaF(8rb@CuQDV^ zq3i(2LfqO%AS!Ss>V%j7%>{6mtbYQrtQK5V4InPq0NZSaXv+f2U=&2}Z6OvkBfNHi z{LSaVJ!d5dC2K*ft_L^DRk;boQhOoVw!~Kt#0b2vd%!(&DF|~u1F@nG#LA5zR&7Fv z4GKgXooMSKb1g)6Obo-rgpuEP20T;W0Aa>55KC4gtQrKkAq-Hgs@FigV1GG8+rQ=z z6Jm=Bui-SfpDYLA=|vzGE(dYm=OC8XM&MDo7ux4UF1~0J1+i%aCUpRet3L_uNyQ*c zE(38Uy03H%I*)*Bh=Lb^Xj3?I^Hnbeq72(EOK^Y93CNp*uAA{5Lc=kyx=~RKa4{iT zm{_>_vSCm?$Ej=i6@=m%@PE9t1zZaoM}@2|h!#1K02~31S_I<0ZV=|K0}n!RRX6Ac zXmMf*5P-dLW}WPVsCKq)-x(0*txpZ2xrv3cxJ%l=7lpoNCyG< zK92ySAcmb-3m&}s@VwXv9(0#p<>B-5$bMxT;rk;OmENa6eM4D&LVo~01soUL39?R{ zyFLt3m|v?rCK7#KNu9E9Q4KV-pEUv^{rrClE&X&9I4-e7%pu_31#zGTOfC=ab%w20R*zBP+uT#l2{a~~~0wuG%6 zco*tVxK&e>%SJj*K!2tq*_h&ES5S9@TKb8WzpK;`&b9dNdxh4S)z%Q)o`aYWUh}9L z(`p!#WO5IxI|nf?yz{90R93Ed6@2qim*}Zjj$H&Esd`?JsFJUnDfiAgF_eYiWR3GC z>M9SHDylEWrA(%mfm~;u7OU9!Wz^!7Z%jZF zi@JR;>Mhi7S>V7wQ176|FdW2m?&`qa(ScO^CFPR80HucLHOTy%5s*HR0^8)i0WYBP d*#0Ks^FNSabJA*5${_#%002ovPDHLkV1gB0Vle;! diff --git a/packages/camera/camera_avfoundation/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/packages/camera/camera_avfoundation/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png index a6d6b8609df07bf62e5100a53a01510388bd2b22..0ec303439225b78712f49115768196d8d76f6790 100644 GIT binary patch delta 850 zcmV-Y1Fih&6y64q8Gi!+000iU#^3+|0OwFlR7L;)|5U~J09TtSw)Xt~|5(QO`~Ck( z!T0|D|3<*~RmJ%E{r+;#`2ba!klFf7!uJMSo%Q?vP{jByxcAZE>;OrUCbaZYjJo^$ z{nGILmD~Da$@upC{`C6(Ey4dPw)Pyc^>5DkHoEo!QcuK-Jwl-l}t(fQKv z{dds$V#@dygS`PvhX6is7Z+@*x-d;$ zb=6f@U3Jw}_s+W3%*+b9H_vS)-R#9?zrXogeLVI2We2RFTTAL}&3C8PS~<5D&v@UI z+`s*$wqQ=yd$laNUY-|ovcS9~n_90tFUdl#qq0tEUXle|k{Op|DHpSrbxEeZ5~$>o%>OSe z^=41qvh3LlC2xXzu+-2eQoqs1^L>7ylB$bCP);(%(xYZL1 cY5!B-0ft0f?Lgb>C;$Ke07*qoM6N<$f@rA97ytkO literal 2665 zcmV-v3YPVWP)oFh3q0MFesq&64WThn3$;G69TfjsAv=f2G9}p zgSx99+!YV6qME!>9MD13x)k(+XE7W?_O4LoLb5ND8 zaV{9+P@>42xDfRiYBMSgD$0!vssptcb;&?u9u(LLBKmkZ>RMD=kvD3h`sk6!QYtBa ztlZI#nu$8lJ^q2Z79UTgZe>BU73(Aospiq+?SdMt8lDZ;*?@tyWVZVS_Q7S&*tJaiRlJ z+aSMOmbg3@h5}v;A*c8SbqM3icg-`Cnwl;7Ts%A1RkNIp+Txl-Ckkvg4oxrqGA5ewEgYqwtECD<_3Egu)xGllKt&J8g&+=ac@Jq4-?w6M3b*>w5 z69N3O%=I^6&UL5gZ!}trC7bUj*12xLdkNs~Bz4QdJJ*UDZox2UGR}SNg@lmOvhCc~ z*f_UeXv(=#I#*7>VZx2ObEN~UoGUTl=-@)E;YtCRZ>SVp$p9yG5hEFZ!`wI!spd)n zSk+vK0Vin7FL{7f&6OB%f;SH22dtbcF<|9fi2Fp%q4kxL!b1#l^)8dUwJ zwEf{(wJj@8iYDVnKB`eSU+;ml-t2`@%_)0jDM`+a46xhDbBj2+&Ih>1A>6aky#(-SYyE{R3f#y57wfLs z6w1p~$bp;6!9DX$M+J~S@D6vJAaElETnsX4h9a5tvPhC3L@qB~bOzkL@^z0k_hS{T4PF*TDrgdXp+dzsE? z>V|VR035Pl9n5&-RePFdS{7KAr2vPOqR9=M$vXA1Yy5>w;EsF`;OK{2pkn-kpp9Pw z)r;5JfJKKaT$4qCb{TaXHjb$QA{y0EYy*+b1XI;6Ah- zw13P)xT`>~eFoJC!>{2XL(a_#upp3gaR1#5+L(Jmzp4TBnx{~WHedpJ1ch8JFk~Sw z>F+gN+i+VD?gMXwcIhn8rz`>e>J^TI3E-MW>f}6R-pL}>WMOa0k#jN+`RyUVUC;#D zg|~oS^$6%wpF{^Qr+}X>0PKcr3Fc&>Z>uv@C);pwDs@2bZWhYP!rvGx?_|q{d`t<*XEb#=aOb=N+L@CVBGqImZf&+a zCQEa3$~@#kC);pasdG=f6tuIi0PO-y&tvX%>Mv=oY3U$nD zJ#gMegnQ46pq+3r=;zmgcG+zRc9D~c>z+jo9&D+`E6$LmyFqlmCYw;-Zooma{sR@~ z)_^|YL1&&@|GXo*pivH7k!msl+$Sew3%XJnxajt0K%3M6Bd&YFNy9}tWG^aovK2eX z1aL1%7;KRDrA@eG-Wr6w+;*H_VD~qLiVI`{_;>o)k`{8xa3EJT1O_>#iy_?va0eR? zDV=N%;Zjb%Z2s$@O>w@iqt!I}tLjGk!=p`D23I}N4Be@$(|iSA zf3Ih7b<{zqpDB4WF_5X1(peKe+rASze%u8eKLn#KKXt;UZ+Adf$_TO+vTqshLLJ5c z52HucO=lrNVae5XWOLm!V@n-ObU11!b+DN<$RuU+YsrBq*lYT;?AwJpmNKniF0Q1< zJCo>Q$=v$@&y=sj6{r!Y&y&`0$-I}S!H_~pI&2H8Z1C|BX4VgZ^-! zje3-;x0PBD!M`v*J_)rL^+$<1VJhH*2Fi~aA7s&@_rUHYJ9zD=M%4AFQ`}k8OC$9s XsPq=LnkwKG00000NkvXXu0mjfhAk5^ diff --git a/packages/camera/camera_avfoundation/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/packages/camera/camera_avfoundation/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png index a6d6b8609df07bf62e5100a53a01510388bd2b22..0ec303439225b78712f49115768196d8d76f6790 100644 GIT binary patch delta 850 zcmV-Y1Fih&6y64q8Gi!+000iU#^3+|0OwFlR7L;)|5U~J09TtSw)Xt~|5(QO`~Ck( z!T0|D|3<*~RmJ%E{r+;#`2ba!klFf7!uJMSo%Q?vP{jByxcAZE>;OrUCbaZYjJo^$ z{nGILmD~Da$@upC{`C6(Ey4dPw)Pyc^>5DkHoEo!QcuK-Jwl-l}t(fQKv z{dds$V#@dygS`PvhX6is7Z+@*x-d;$ zb=6f@U3Jw}_s+W3%*+b9H_vS)-R#9?zrXogeLVI2We2RFTTAL}&3C8PS~<5D&v@UI z+`s*$wqQ=yd$laNUY-|ovcS9~n_90tFUdl#qq0tEUXle|k{Op|DHpSrbxEeZ5~$>o%>OSe z^=41qvh3LlC2xXzu+-2eQoqs1^L>7ylB$bCP);(%(xYZL1 cY5!B-0ft0f?Lgb>C;$Ke07*qoM6N<$f@rA97ytkO literal 2665 zcmV-v3YPVWP)oFh3q0MFesq&64WThn3$;G69TfjsAv=f2G9}p zgSx99+!YV6qME!>9MD13x)k(+XE7W?_O4LoLb5ND8 zaV{9+P@>42xDfRiYBMSgD$0!vssptcb;&?u9u(LLBKmkZ>RMD=kvD3h`sk6!QYtBa ztlZI#nu$8lJ^q2Z79UTgZe>BU73(Aospiq+?SdMt8lDZ;*?@tyWVZVS_Q7S&*tJaiRlJ z+aSMOmbg3@h5}v;A*c8SbqM3icg-`Cnwl;7Ts%A1RkNIp+Txl-Ckkvg4oxrqGA5ewEgYqwtECD<_3Egu)xGllKt&J8g&+=ac@Jq4-?w6M3b*>w5 z69N3O%=I^6&UL5gZ!}trC7bUj*12xLdkNs~Bz4QdJJ*UDZox2UGR}SNg@lmOvhCc~ z*f_UeXv(=#I#*7>VZx2ObEN~UoGUTl=-@)E;YtCRZ>SVp$p9yG5hEFZ!`wI!spd)n zSk+vK0Vin7FL{7f&6OB%f;SH22dtbcF<|9fi2Fp%q4kxL!b1#l^)8dUwJ zwEf{(wJj@8iYDVnKB`eSU+;ml-t2`@%_)0jDM`+a46xhDbBj2+&Ih>1A>6aky#(-SYyE{R3f#y57wfLs z6w1p~$bp;6!9DX$M+J~S@D6vJAaElETnsX4h9a5tvPhC3L@qB~bOzkL@^z0k_hS{T4PF*TDrgdXp+dzsE? z>V|VR035Pl9n5&-RePFdS{7KAr2vPOqR9=M$vXA1Yy5>w;EsF`;OK{2pkn-kpp9Pw z)r;5JfJKKaT$4qCb{TaXHjb$QA{y0EYy*+b1XI;6Ah- zw13P)xT`>~eFoJC!>{2XL(a_#upp3gaR1#5+L(Jmzp4TBnx{~WHedpJ1ch8JFk~Sw z>F+gN+i+VD?gMXwcIhn8rz`>e>J^TI3E-MW>f}6R-pL}>WMOa0k#jN+`RyUVUC;#D zg|~oS^$6%wpF{^Qr+}X>0PKcr3Fc&>Z>uv@C);pwDs@2bZWhYP!rvGx?_|q{d`t<*XEb#=aOb=N+L@CVBGqImZf&+a zCQEa3$~@#kC);pasdG=f6tuIi0PO-y&tvX%>Mv=oY3U$nD zJ#gMegnQ46pq+3r=;zmgcG+zRc9D~c>z+jo9&D+`E6$LmyFqlmCYw;-Zooma{sR@~ z)_^|YL1&&@|GXo*pivH7k!msl+$Sew3%XJnxajt0K%3M6Bd&YFNy9}tWG^aovK2eX z1aL1%7;KRDrA@eG-Wr6w+;*H_VD~qLiVI`{_;>o)k`{8xa3EJT1O_>#iy_?va0eR? zDV=N%;Zjb%Z2s$@O>w@iqt!I}tLjGk!=p`D23I}N4Be@$(|iSA zf3Ih7b<{zqpDB4WF_5X1(peKe+rASze%u8eKLn#KKXt;UZ+Adf$_TO+vTqshLLJ5c z52HucO=lrNVae5XWOLm!V@n-ObU11!b+DN<$RuU+YsrBq*lYT;?AwJpmNKniF0Q1< zJCo>Q$=v$@&y=sj6{r!Y&y&`0$-I}S!H_~pI&2H8Z1C|BX4VgZ^-! zje3-;x0PBD!M`v*J_)rL^+$<1VJhH*2Fi~aA7s&@_rUHYJ9zD=M%4AFQ`}k8OC$9s XsPq=LnkwKG00000NkvXXu0mjfhAk5^ diff --git a/packages/camera/camera_avfoundation/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/packages/camera/camera_avfoundation/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png index 75b2d164a5a98e212cca15ea7bf2ab5de5108680..e9f5fea27c705180eb716271f41b582e76dcbd90 100644 GIT binary patch delta 1668 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 diff --git a/packages/camera/camera_avfoundation/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/packages/camera/camera_avfoundation/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png index c4df70d39da7941ef3f6dcb7f06a192d8dcb308d..84ac32ae7d989f82d5e46a60405adcc8279e8001 100644 GIT binary patch delta 749 zcmVg;Ps8|O$@u8^{Z_{KM!@$5TAfS6_e#O{MZfpz`2O`0$7~@NRr(1{THzH08y3x{{PYM{eL;T_A9^tcF_4Sxb`8l z_9V3RD6;a(-0A^Pjsi!1?)d#Ap4Tk3^CP0(07;VpJ7@tgQ}z4)*zx@&yZwC9`DV-b z0ZobH_5IB4{KxD3;p_6%|f=bdFhu+F!zMZ2UFj;GUKX7tI;hv3{q~!*pMj75WP_c}> z6)IWvg5_yyg<9Op()eD1hWC19M@?_9_MHec{Z8n3FMs~w_u?Av_yNBmRxVYrpi(M% zFMP21g+hmocQp3ay*Su=qM6He)*HaaTg$E^sym`(t%s3A)x!M+vfjXUBEpK6X9%iU zU!u9jj3(-$dM~sJ%Liy#?|+!6IY#MTau#O6vVj`yh_7%Ni!?!VS+MPTO(_fG+1<#p zqu;A#i+_(N%CmVnYvb>#nA{>Q%3E`Ds7<~jZMywn@h2t>G-LrYy7?Dj{aZqhQd6tzX%(Trn+ z)HNF}%-F{rr=m*0{=a;s#YDL00000NkvXXu0mjfaGjYE delta 1884 zcmV-i2c!7<1>g>l8Gi-<0076AQ7Zrd2Pa8HK~#9!?VNjT6h$1z_m0EFf5bmb1dTDK zp;kdKV1h(V(8Sc1M<37!RE>znAk{x4#zX@eOeE1j3~!+nB5IL z<xS}u?#DBMB>w^b($1Z)`9G?eP95EKi& z$eOy@K%h;ryrR3la%;>|o*>CgB(s>dDcNOXg}CK9SPmD?Uu$P4(=PGA0ShFasNfcIHTL?9WjB9#(2xSLC z`0%$#9DW9F;B4mbU{BlaYx!SjF!QSeF~(msQRxwboh5B_O$BWOQja)GboJz$&!?mgB&3$ytsA zvns&b3Cl5Hx#%p%faR*Q906u&fbXy$maV`n?S>A)vJIH!F-vxCrY+rq5_JA(GcOgu7(Ky4X3ATR9z8*%k&<5qYeV&4Y`~}XYmK(j{)!g8d2UgHXIINM!Rvn zKtEq~Foe0s!U{kux~F6Y7Sp+2f|*Cc${S{@oh8D0=XhB8Ec-w9CflfL+te4ium2cU zoPTCj_m<3d#gjK=<*8R`HP^C$lOPM5d~UhKhRRmvv{LI za^|oavk1$QiEApSrP@~Jjbg`<*dW4TO@DPEEX$Tg$xh?Y>Qd}y@kaH~IT8!lLpS^J zR7(&wZSI6+>Eb)tX>9Z?GX#q$u z4I>7e#b7ojyJ1grOh!^}s8S#ubi^Jkd1?UK)3mp6rI^_zxRY zrx6_QmhoWoDR`fp4R7gu6@OBFGu7IDVR6~nJsB{^f5jHn<{WJ&&f^X?3f8TIk3#U& zu1*Q-e@;snJxNx8-PBnpI|uFTKN!+Lp;fPfZ+eqqU^Y1|#DJY~126?zOx-+d>%4*? z&o`TbrXSNXZW^!P0t2>@$6&aiBtUDh2wLXLD9&a(1J=k_FK|iGbAQ@x4Qmx}Ms+*; zze&q6bH(=wYuXHfz0H6<05!LkE4rl~v^!bj=^9d+vI5fN<;GP>*Pas=q2l9RxDkk` zPRk&EQI+t_0$Y%nKE)Ma)W?jaA@4Z{h zTk*7;;#lG?hvTN_On=Jaxp%bdE;mDq(q#dgdYF|-?wrMeI4h`$idZ6^VyXZVlaCd0 z;i)OYR3npf@9>00Gqn##Zb4HRurgaWFCzL9u6@J@sse>Z1XznxWvSy%Td32I3!#YN zXt9v0)RQtDDZRd?#WY?~KF7A0UcR{jt9 W+;fr}hV%pg0000&=UXv0SHh`R7L;)|5U~JDYo_jSDRDC`1<|-SjPDL z{{Q{{{{H{}09Kk-#rR9Y_viNgVafPO!S|ls`uzR=MZfp^{QU=8od8La1X`Tr_Wmff z_5e$ivgQ1@=KMy$_g9a+`TPAle6cOJ_Fc#L7qIpvwDkd1mw$fK`6IOUD75rX!}mad zv(fMTE4=(Nx%L54lL1hVF1YpqNrC`FddBPg#_Ietx%Lrkq5wX00X1L{S%Cm9QY*av z#_Rh5PKy9KYTWbvz3BX9%J>0Hi1+#X{rLA{m%$Kamk?i!03AC38#Yrxs)5QTeTVRiEmz~MKK1WAjCw(c-JK6eox;2O)?`?TG`AHia671e^vgmp!llK zp|=5sVHk#C7=~epA~VAf-~%aPC=%Qw01h8mnSZ|p?tc*y?iZ$PR7_ceEIapF3KB14K0Pog?7wtd+^xgUCa_GVmlD z<^nU>AU_Yn-JU?NFdu|wf^bTCNf-wSBYVZltDdvGBln-YrbeGvJ!|s{#`gjN@yAMb zM6cjFz0eFECCsc|_8hTa3*9-JQGehksdoVP^K4m?&wpA~+|b%{EP5D-+7h)6CE; z*{>BP=GRR3Ea}xyV*bqry{l^J=0#DaC4ej;1qs8_by?H6Tr@7hl>UKNZt)^B&yl;)&oqzLg zcfZxpE?3k%_iTOVywh%`XVN-E#COl+($9{v(pqSQcrz=)>G!!3HeNxbXGM@})1|9g zG4*@(OBaMvY0P0_TfMFPh fVHk#CZX3S=^^2mI>Ux-D00000NkvXXu0mjfzK(<8 literal 3294 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 cX)(b1KSk$MOV07*qoM6N<$f&{Qds= z{r_0T`1}6fwc-8!#-TGX}_?g)CZq4{k!uZ_g@DrQdoW0kI zu+W69&uN^)W`CK&06mMNcYMVF00dG=L_t(|+U?wHQxh>12H+Dm+1+fh+IF>G0SjJM zkQQre1x4|G*Z==(Ot&kCnUrL4I(rf(ucITwmuHf^hXiJTkdTm&kdTm&kdTm&kdP`e zsgWG0BcWCVkVZ&2dUwN`cgM8QJb`Z7Z~e<&Yj2(}>VI$fQI%^ugM`#6By?GeadWcu z0gy9!D`m!H>Bd!JW(@avE8`|5XX(0PN}!8K>`dkavs;rHL+wy96QGNT=S@#7%xtlm zIW!++@*2zm-Py#Zr`DzqsLm!b{iskFNULSqE9A>SqHem>o31A%XL>S_5?=;V_i_y+ z(xxXhnt#r-l1Y8_*h`r?8Tr|)(RAiO)4jQR`13X0mx07C&p@KBP_2s``KEhv^|*8c z$$_T(v6^1Ig=#R}sE{vjA?ErGDZGUsyoJuWdJMc7Nb1^KF)-u<7q zPy$=;)0>vuWuK2hQhswLf!9yg`88u&eBbR8uhod?Nw09AXH}-#qOLLxeT2%C;R)QQ$Za#qp~cM&YVmS4i-*Fpd!cC zBXc?(4wcg>sHmXGd^VdE<5QX{Kyz$;$sCPl(_*-P2Iw?p^C6J2ZC!+UppiK6&y3Kmbv&O!oYF34$0Z;QO!J zOY#!`qyGH<3Pd}Pt@q*A0V=3SVtWKRR8d8Z&@)3qLPA19LPA19LPEUCUoZo%k(yku QW&i*H07*qoM6N<$g47z!?*IS* literal 3612 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 iW8CADisableMinimumFrameDurationOnPhone CFBundleDevelopmentRegion - en + $(DEVELOPMENT_LANGUAGE) + CFBundleDisplayName + Camera Example CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier @@ -17,31 +19,43 @@ CFBundlePackageType APPL CFBundleShortVersionString - 1.0 + $(FLUTTER_BUILD_NAME) CFBundleSignature ???? CFBundleVersion - 1 - LSApplicationCategoryType - + $(FLUTTER_BUILD_NUMBER) LSRequiresIPhoneOS - NSCameraUsageDescription - Can I use the camera please? Only for demo purpose of the app - NSMicrophoneUsageDescription - Only for demo purpose of the app + UIApplicationSceneManifest + + UIApplicationSupportsMultipleScenes + + UISceneConfigurations + + UIWindowSceneSessionRoleApplication + + + UISceneClassName + UIWindowScene + UISceneConfigurationName + flutter + UISceneDelegateClassName + $(PRODUCT_MODULE_NAME).SceneDelegate + UISceneStoryboardFile + Main + + + + + UIApplicationSupportsIndirectInputEvents + UILaunchStoryboardName LaunchScreen UIMainStoryboardFile Main - UIRequiredDeviceCapabilities - - arm64 - UISupportedInterfaceOrientations UIInterfaceOrientationPortrait - UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight @@ -52,9 +66,5 @@ UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight - CADisableMinimumFrameDurationOnPhone - - UIApplicationSupportsIndirectInputEvents - diff --git a/packages/camera/camera_avfoundation/example/ios/Runner/Runner-Bridging-Header.h b/packages/camera/camera_avfoundation/example/ios/Runner/Runner-Bridging-Header.h new file mode 100644 index 000000000000..308a2a560b42 --- /dev/null +++ b/packages/camera/camera_avfoundation/example/ios/Runner/Runner-Bridging-Header.h @@ -0,0 +1 @@ +#import "GeneratedPluginRegistrant.h" diff --git a/packages/camera/camera_avfoundation/example/ios/Runner/SceneDelegate.swift b/packages/camera/camera_avfoundation/example/ios/Runner/SceneDelegate.swift new file mode 100644 index 000000000000..b9ce8ea2b2ad --- /dev/null +++ b/packages/camera/camera_avfoundation/example/ios/Runner/SceneDelegate.swift @@ -0,0 +1,6 @@ +import Flutter +import UIKit + +class SceneDelegate: FlutterSceneDelegate { + +} diff --git a/packages/camera/camera_avfoundation/example/ios/Runner/main.m b/packages/camera/camera_avfoundation/example/ios/Runner/main.m deleted file mode 100644 index 3ec494eae7e8..000000000000 --- a/packages/camera/camera_avfoundation/example/ios/Runner/main.m +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2013 The Flutter Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#import -#import -#import "AppDelegate.h" - -int main(int argc, char *argv[]) { - @autoreleasepool { - // The setup logic in `AppDelegate::didFinishLaunchingWithOptions:` eventually sends camera - // operations on the background queue, which would run concurrently with the test cases during - // unit tests, making the debugging process confusing. This setup is actually not necessary for - // the unit tests, so it is better to skip the AppDelegate when running unit tests. - BOOL isTesting = NSClassFromString(@"XCTestCase") != nil; - return UIApplicationMain(argc, argv, nil, - isTesting ? nil : NSStringFromClass([AppDelegate class])); - } -} diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/AvailableCamerasTests.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/AvailableCamerasTests.swift deleted file mode 100644 index 4fbece5523d5..000000000000 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/AvailableCamerasTests.swift +++ /dev/null @@ -1,138 +0,0 @@ -// Copyright 2013 The Flutter Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import AVFoundation -import XCTest - -@testable import camera_avfoundation - -final class AvailableCamerasTest: XCTestCase { - private func createCameraPlugin(with deviceDiscoverer: MockCameraDeviceDiscoverer) -> CameraPlugin - { - return CameraPlugin( - registry: MockFlutterTextureRegistry(), - messenger: MockFlutterBinaryMessenger(), - globalAPI: MockGlobalEventApi(), - deviceDiscoverer: deviceDiscoverer, - permissionManager: MockCameraPermissionManager(), - deviceFactory: { _ in MockCaptureDevice() }, - captureSessionFactory: { MockCaptureSession() }, - captureDeviceInputFactory: MockCaptureDeviceInputFactory(), - captureSessionQueue: DispatchQueue(label: "io.flutter.camera.captureSessionQueue") - ) - } - - func testAvailableCamerasShouldReturnAllCamerasOnMultiCameraIPhone() { - let mockDeviceDiscoverer = MockCameraDeviceDiscoverer() - let cameraPlugin = createCameraPlugin(with: mockDeviceDiscoverer) - let expectation = self.expectation(description: "Result finished") - - mockDeviceDiscoverer.discoverySessionStub = { deviceTypes, mediaType, position in - // iPhone 13 Cameras: - let wideAngleCamera = MockCaptureDevice() - wideAngleCamera.uniqueID = "0" - wideAngleCamera.position = .back - - let frontFacingCamera = MockCaptureDevice() - frontFacingCamera.uniqueID = "1" - frontFacingCamera.position = .front - - let ultraWideCamera = MockCaptureDevice() - ultraWideCamera.uniqueID = "2" - ultraWideCamera.position = .back - - let telephotoCamera = MockCaptureDevice() - telephotoCamera.uniqueID = "3" - telephotoCamera.position = .back - - var requiredTypes: [AVCaptureDevice.DeviceType] = [ - .builtInWideAngleCamera, .builtInTelephotoCamera, .builtInUltraWideCamera, - ] - var cameras = [wideAngleCamera, frontFacingCamera, telephotoCamera, ultraWideCamera] - - XCTAssertEqual(deviceTypes, requiredTypes) - XCTAssertEqual(mediaType, .video) - XCTAssertEqual(position, .unspecified) - return cameras - } - - var resultValue: [PlatformCameraDescription]? - cameraPlugin.getAvailableCameras { result in - resultValue = self.assertSuccess(result) - expectation.fulfill() - } - waitForExpectations(timeout: 30, handler: nil) - - // Verify the result. - XCTAssertEqual(resultValue?.count, 4) - } - - func testAvailableCamerasShouldReturnTwoCamerasOnDualCameraIPhone() { - let mockDeviceDiscoverer = MockCameraDeviceDiscoverer() - let cameraPlugin = createCameraPlugin(with: mockDeviceDiscoverer) - let expectation = self.expectation(description: "Result finished") - - mockDeviceDiscoverer.discoverySessionStub = { deviceTypes, mediaType, position in - // iPhone 8 Cameras: - let wideAngleCamera = MockCaptureDevice() - wideAngleCamera.uniqueID = "0" - wideAngleCamera.position = .back - - let frontFacingCamera = MockCaptureDevice() - frontFacingCamera.uniqueID = "1" - frontFacingCamera.position = .front - - var requiredTypes: [AVCaptureDevice.DeviceType] = [ - .builtInWideAngleCamera, .builtInTelephotoCamera, .builtInUltraWideCamera, - ] - let cameras = [wideAngleCamera, frontFacingCamera] - - XCTAssertEqual(deviceTypes, requiredTypes) - XCTAssertEqual(mediaType, .video) - XCTAssertEqual(position, .unspecified) - return cameras - } - - var resultValue: [PlatformCameraDescription]? - cameraPlugin.getAvailableCameras { result in - resultValue = self.assertSuccess(result) - expectation.fulfill() - } - waitForExpectations(timeout: 30, handler: nil) - - // Verify the result. - XCTAssertEqual(resultValue?.count, 2) - } - - func testAvailableCamerasShouldReturnExternalLensDirectionForUnspecifiedCameraPosition() { - let mockDeviceDiscoverer = MockCameraDeviceDiscoverer() - let cameraPlugin = createCameraPlugin(with: mockDeviceDiscoverer) - let expectation = self.expectation(description: "Result finished") - - mockDeviceDiscoverer.discoverySessionStub = { deviceTypes, mediaType, position in - let unspecifiedCamera = MockCaptureDevice() - unspecifiedCamera.uniqueID = "0" - unspecifiedCamera.position = .unspecified - - var requiredTypes: [AVCaptureDevice.DeviceType] = [ - .builtInWideAngleCamera, .builtInTelephotoCamera, .builtInUltraWideCamera, - ] - let cameras = [unspecifiedCamera] - - XCTAssertEqual(deviceTypes, requiredTypes) - XCTAssertEqual(mediaType, .video) - XCTAssertEqual(position, .unspecified) - return cameras - } - - var resultValue: [PlatformCameraDescription]? - cameraPlugin.getAvailableCameras { result in - resultValue = self.assertSuccess(result) - expectation.fulfill() - } - waitForExpectations(timeout: 30, handler: nil) - - XCTAssertEqual(resultValue?.first?.lensDirection, .external) - } -} diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraInitRaceConditionsTests.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraInitRaceConditionsTests.swift deleted file mode 100644 index 03f5fa3e9fab..000000000000 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraInitRaceConditionsTests.swift +++ /dev/null @@ -1,92 +0,0 @@ -// Copyright 2013 The Flutter Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import XCTest - -@testable import camera_avfoundation - -final class CameraInitRaceConditionsTests: XCTestCase { - private func createCameraPlugin() -> (CameraPlugin, DispatchQueue) { - let captureSessionQueue = DispatchQueue(label: "io.flutter.camera.captureSessionQueue") - - let cameraPlugin = CameraPlugin( - registry: MockFlutterTextureRegistry(), - messenger: MockFlutterBinaryMessenger(), - globalAPI: MockGlobalEventApi(), - deviceDiscoverer: MockCameraDeviceDiscoverer(), - permissionManager: MockCameraPermissionManager(), - deviceFactory: { _ in MockCaptureDevice() }, - captureSessionFactory: { MockCaptureSession() }, - captureDeviceInputFactory: MockCaptureDeviceInputFactory(), - captureSessionQueue: captureSessionQueue - ) - - return (cameraPlugin, captureSessionQueue) - } - - func testFixForCaptureSessionQueueNullPointerCrashDueToRaceCondition() { - let (cameraPlugin, captureSessionQueue) = createCameraPlugin() - let disposeExpectation = expectation(description: "dispose's result block must be called") - let createExpectation = expectation(description: "create's result block must be called") - - // Mimic a dispose call followed by a create call, which can be triggered by slightly dragging the - // home bar, causing the app to be inactive, and immediately regain active. - cameraPlugin.dispose(cameraId: 0) { error in - disposeExpectation.fulfill() - } - - cameraPlugin.createCameraOnSessionQueue( - withName: "acamera", - settings: PlatformMediaSettings( - resolutionPreset: .medium, - framesPerSecond: nil, - videoBitrate: nil, - audioBitrate: nil, - enableAudio: true - ) - ) { result in - createExpectation.fulfill() - } - - waitForExpectations(timeout: 30, handler: nil) - - // `captureSessionQueue` must not be nil after `create` call. Otherwise a nil - // `captureSessionQueue` passed into `AVCaptureVideoDataOutput::setSampleBufferDelegate:queue:` - // API will cause a crash. - XCTAssertNotNil( - captureSessionQueue, "captureSessionQueue must not be nil after create method.") - } - - func testFlutterChannelInitializedWhenStartingImageStream() { - let (cameraPlugin, _captureSessionQueue) = createCameraPlugin() - let createExpectation = expectation(description: "create's result block must be called") - - cameraPlugin.createCameraOnSessionQueue( - withName: "acamera", - settings: PlatformMediaSettings( - resolutionPreset: .medium, - framesPerSecond: nil, - videoBitrate: nil, - audioBitrate: nil, - enableAudio: true - ) - ) { result in - createExpectation.fulfill() - } - - waitForExpectations(timeout: 30, handler: nil) - - // Start stream and wait for its completion. - let startStreamExpectation = expectation( - description: "startImageStream's result block must be called") - cameraPlugin.startImageStream(completion: { - _ in - startStreamExpectation.fulfill() - }) - - waitForExpectations(timeout: 30, handler: nil) - XCTAssertEqual(cameraPlugin.camera?.isStreamingImages, true) - } - -} diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraMethodChannelTests.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraMethodChannelTests.swift deleted file mode 100644 index 80231393b5d4..000000000000 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraMethodChannelTests.swift +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright 2013 The Flutter Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import AVFoundation -import XCTest - -@testable import camera_avfoundation - -final class CameraMethodChannelTests: XCTestCase { - private func createCameraPlugin(with session: MockCaptureSession) -> CameraPlugin { - return CameraPlugin( - registry: MockFlutterTextureRegistry(), - messenger: MockFlutterBinaryMessenger(), - globalAPI: MockGlobalEventApi(), - deviceDiscoverer: MockCameraDeviceDiscoverer(), - permissionManager: MockCameraPermissionManager(), - deviceFactory: { _ in MockCaptureDevice() }, - captureSessionFactory: { session }, - captureDeviceInputFactory: MockCaptureDeviceInputFactory(), - captureSessionQueue: DispatchQueue(label: "io.flutter.camera.captureSessionQueue") - ) - } - - func testCreate_ShouldCallResultOnMainThread() { - let avCaptureSessionMock = MockCaptureSession() - avCaptureSessionMock.canSetSessionPresetStub = { _ in true } - let camera = createCameraPlugin(with: avCaptureSessionMock) - let expectation = self.expectation(description: "Result finished") - - var resultValue: Int64? - camera.createCameraOnSessionQueue( - withName: "acamera", - settings: PlatformMediaSettings( - resolutionPreset: .medium, - framesPerSecond: nil, - videoBitrate: nil, - audioBitrate: nil, - enableAudio: true - ) - ) { result in - resultValue = self.assertSuccess(result) - expectation.fulfill() - } - - waitForExpectations(timeout: 30, handler: nil) - XCTAssertNotNil(resultValue) - } - - func testDisposeShouldDeallocCamera() { - let avCaptureSessionMock = MockCaptureSession() - avCaptureSessionMock.canSetSessionPresetStub = { _ in true } - let camera = createCameraPlugin(with: avCaptureSessionMock) - let createExpectation = self.expectation(description: "create's result block must be called") - - camera.createCameraOnSessionQueue( - withName: "acamera", - settings: PlatformMediaSettings( - resolutionPreset: .medium, - framesPerSecond: nil, - videoBitrate: nil, - audioBitrate: nil, - enableAudio: true - ) - ) { result in - createExpectation.fulfill() - } - - waitForExpectations(timeout: 30, handler: nil) - XCTAssertNotNil(camera.camera) - - let disposeExpectation = self.expectation(description: "dispose's result block must be called") - camera.dispose(cameraId: 0) { error in - disposeExpectation.fulfill() - } - - waitForExpectations(timeout: 30, handler: nil) - XCTAssertNil(camera.camera, "camera should be deallocated after dispose") - } -} diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraOrientationTests.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraOrientationTests.swift deleted file mode 100644 index 4878cbe51d6f..000000000000 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraOrientationTests.swift +++ /dev/null @@ -1,168 +0,0 @@ -// Copyright 2013 The Flutter Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import AVFoundation -import Flutter -import XCTest - -@testable import camera_avfoundation - -private final class MockUIDevice: UIDevice { - var mockOrientation: UIDeviceOrientation = .unknown - - override var orientation: UIDeviceOrientation { - return mockOrientation - } -} - -final class CameraOrientationTests: XCTestCase { - private func createCameraPlugin() -> ( - cameraPlugin: CameraPlugin, - mockCamera: MockCamera, - mockEventAPI: MockGlobalEventApi, - mockDevice: MockCaptureDevice, - mockDeviceDiscoverer: MockCameraDeviceDiscoverer, - captureSessionQueue: DispatchQueue - ) { - let mockDevice = MockCaptureDevice() - let mockCamera = MockCamera() - let mockEventAPI = MockGlobalEventApi() - let mockDeviceDiscoverer = MockCameraDeviceDiscoverer() - let captureSessionQueue = DispatchQueue(label: "io.flutter.camera.captureSessionQueue") - - let cameraPlugin = CameraPlugin( - registry: MockFlutterTextureRegistry(), - messenger: MockFlutterBinaryMessenger(), - globalAPI: mockEventAPI, - deviceDiscoverer: mockDeviceDiscoverer, - permissionManager: MockCameraPermissionManager(), - deviceFactory: { _ in mockDevice }, - captureSessionFactory: { MockCaptureSession() }, - captureDeviceInputFactory: MockCaptureDeviceInputFactory(), - captureSessionQueue: captureSessionQueue - ) - cameraPlugin.camera = mockCamera - - return ( - cameraPlugin, - mockCamera, - mockEventAPI, - mockDevice, - mockDeviceDiscoverer, - captureSessionQueue - ) - } - - private func sendOrientation( - _ orientation: UIDeviceOrientation, - to cameraPlugin: CameraPlugin, - captureSessionQueue: DispatchQueue - ) { - cameraPlugin.orientationChanged(createMockNotification(for: orientation)) - waitForQueueRoundTrip(with: captureSessionQueue) - } - - private func createMockNotification(for deviceOrientation: UIDeviceOrientation) -> Notification { - let mockDevice = MockUIDevice() - mockDevice.mockOrientation = deviceOrientation - return Notification(name: Notification.Name("orientation_test"), object: mockDevice) - } - - func testOrientationNotifications() { - let (cameraPlugin, _, mockEventAPI, _, _, captureSessionQueue) = createCameraPlugin() - - sendOrientation(.portraitUpsideDown, to: cameraPlugin, captureSessionQueue: captureSessionQueue) - XCTAssertEqual(mockEventAPI.lastOrientation, .portraitDown) - sendOrientation(.portrait, to: cameraPlugin, captureSessionQueue: captureSessionQueue) - XCTAssertEqual(mockEventAPI.lastOrientation, .portraitUp) - sendOrientation(.landscapeLeft, to: cameraPlugin, captureSessionQueue: captureSessionQueue) - XCTAssertEqual(mockEventAPI.lastOrientation, .landscapeLeft) - sendOrientation(.landscapeRight, to: cameraPlugin, captureSessionQueue: captureSessionQueue) - XCTAssertEqual(mockEventAPI.lastOrientation, .landscapeRight) - } - - func testOrientationNotificationsNotCalledForFaceUp() { - let (cameraPlugin, _, mockEventAPI, _, _, captureSessionQueue) = createCameraPlugin() - sendOrientation(.faceUp, to: cameraPlugin, captureSessionQueue: captureSessionQueue) - XCTAssertFalse(mockEventAPI.deviceOrientationChangedCalled) - } - - func testOrientationNotificationsNotCalledForFaceDown() { - let (cameraPlugin, _, mockEventAPI, _, _, captureSessionQueue) = createCameraPlugin() - sendOrientation(.faceDown, to: cameraPlugin, captureSessionQueue: captureSessionQueue) - XCTAssertFalse(mockEventAPI.deviceOrientationChangedCalled) - } - - func testOrientationUpdateMustBeOnCaptureSessionQueue() { - let queueExpectation = expectation( - description: "Orientation update must happen on the capture session queue") - let (cameraPlugin, mockCamera, _, _, _, captureSessionQueue) = createCameraPlugin() - let captureSessionQueueSpecific = DispatchSpecificKey() - captureSessionQueue.setSpecific( - key: captureSessionQueueSpecific, - value: ()) - - mockCamera.setDeviceOrientationStub = { orientation in - if DispatchQueue.getSpecific(key: captureSessionQueueSpecific) != nil { - queueExpectation.fulfill() - } - } - - cameraPlugin.orientationChanged(createMockNotification(for: .landscapeLeft)) - waitForExpectations(timeout: 30, handler: nil) - } - - func testOrientationChangedNoRetainCycle() { - let (_, mockCamera, mockEventAPI, mockDevice, mockDeviceDiscoverer, _) = createCameraPlugin() - let captureSessionQueue = DispatchQueue(label: "capture_session_queue") - weak var weakPlugin: CameraPlugin? - weak var weakDevice = mockDevice - - autoreleasepool { - let cameraPlugin = CameraPlugin( - registry: MockFlutterTextureRegistry(), - messenger: MockFlutterBinaryMessenger(), - globalAPI: mockEventAPI, - deviceDiscoverer: mockDeviceDiscoverer, - permissionManager: MockCameraPermissionManager(), - deviceFactory: { _ in weakDevice! }, - captureSessionFactory: { MockCaptureSession() }, - captureDeviceInputFactory: MockCaptureDeviceInputFactory(), - captureSessionQueue: captureSessionQueue - ) - weakPlugin = cameraPlugin - cameraPlugin.camera = mockCamera - - cameraPlugin.orientationChanged(createMockNotification(for: .landscapeLeft)) - } - - // Sanity check. - let cameraDeallocatedExpectation = self.expectation( - description: "Camera must have been deallocated.") - captureSessionQueue.async { - XCTAssertNil(weakPlugin) - cameraDeallocatedExpectation.fulfill() - } - // Awaiting expectation is needed. The test is flaky when checking for nil right away. - waitForExpectations(timeout: 1, handler: nil) - - var setDeviceOrientationCalled = false - mockCamera.setDeviceOrientationStub = { orientation in - if orientation == .landscapeLeft { - setDeviceOrientationCalled = true - } - } - - weak var weakEventAPI = mockEventAPI - // Must check in captureSessionQueue since orientationChanged dispatches to this queue. - let expectation = self.expectation(description: "Dispatched to capture session queue") - captureSessionQueue.async { - XCTAssertFalse(setDeviceOrientationCalled) - XCTAssertFalse(weakEventAPI?.deviceOrientationChangedCalled ?? false) - expectation.fulfill() - } - - waitForExpectations(timeout: 30, handler: nil) - } -} diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraPermissionTests.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraPermissionTests.swift deleted file mode 100644 index d8ca79f65eca..000000000000 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraPermissionTests.swift +++ /dev/null @@ -1,237 +0,0 @@ -// Copyright 2013 The Flutter Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import AVFoundation -import Flutter -import XCTest - -@testable import camera_avfoundation - -private final class MockPermissionService: NSObject, PermissionServicing { - var authorizationStatusStub: ((AVMediaType) -> AVAuthorizationStatus)? - var requestAccessStub: ((AVMediaType, @escaping @Sendable (Bool) -> Void) -> Void)? - - func authorizationStatus(for mediaType: AVMediaType) -> AVAuthorizationStatus { - return authorizationStatusStub?(mediaType) ?? .notDetermined - } - - func requestAccess(for mediaType: AVMediaType, completion: @escaping @Sendable (Bool) -> Void) { - requestAccessStub?(mediaType, completion) - } -} - -final class CameraPermissionManagerTests: XCTestCase { - private func createSutAndMocks() -> (CameraPermissionManager, MockPermissionService) { - let mockPermissionService = MockPermissionService() - let permissionManager = CameraPermissionManager(permissionService: mockPermissionService) - - return (permissionManager, mockPermissionService) - } - - // MARK: - Camera permissions - - func testRequestCameraPermission_completeWithoutErrorIfPreviouslyAuthorized() { - let (permissionManager, mockPermissionService) = createSutAndMocks() - let expectation = self.expectation( - description: "Must complete without error if camera access was previously authorized.") - - mockPermissionService.authorizationStatusStub = { mediaType in - XCTAssertEqual(mediaType, .video) - return .authorized - } - permissionManager.requestCameraPermission { error in - XCTAssertNil(error) - expectation.fulfill() - } - - waitForExpectations(timeout: 30, handler: nil) - } - - func testRequestCameraPermission_completeWithErrorIfPreviouslyDenied() { - let (permissionManager, mockPermissionService) = createSutAndMocks() - let expectation = self.expectation( - description: "Must complete with error if camera access was previously denied.") - - mockPermissionService.authorizationStatusStub = { mediaType in - XCTAssertEqual(mediaType, .video) - return .denied - } - permissionManager.requestCameraPermission { error in - XCTAssertEqual(error?.code, "CameraAccessDeniedWithoutPrompt") - XCTAssertEqual( - error?.message, - "User has previously denied the camera access request. Go to Settings to enable camera access." - ) - expectation.fulfill() - } - - waitForExpectations(timeout: 30, handler: nil) - } - - func testRequestCameraPermission_completeWithErrorIfRestricted() { - let (permissionManager, mockPermissionService) = createSutAndMocks() - let expectation = self.expectation( - description: "Must complete with error if camera access is restricted.") - - mockPermissionService.authorizationStatusStub = { mediaType in - XCTAssertEqual(mediaType, .video) - return .restricted - } - permissionManager.requestCameraPermission { error in - XCTAssertEqual(error?.code, "CameraAccessRestricted") - XCTAssertEqual(error?.message, "Camera access is restricted.") - expectation.fulfill() - } - - waitForExpectations(timeout: 30, handler: nil) - } - - func testRequestCameraPermission_completeWithoutErrorIfUserGrantAccess() { - let (permissionManager, mockPermissionService) = createSutAndMocks() - let expectation = self.expectation( - description: "Must complete without error if user granted access.") - - mockPermissionService.authorizationStatusStub = { mediaType in - XCTAssertEqual(mediaType, .video) - return .notDetermined - } - mockPermissionService.requestAccessStub = { mediaType, handler in - XCTAssertEqual(mediaType, .video) - // Grant access. - handler(true) - } - permissionManager.requestCameraPermission { error in - XCTAssertNil(error) - expectation.fulfill() - } - - waitForExpectations(timeout: 30, handler: nil) - } - - func testRequestCameraPermission_completeWithErrorIfUserDenyAccess() { - let (permissionManager, mockPermissionService) = createSutAndMocks() - let expectation = self.expectation( - description: "Must complete with error if user denied access.") - - mockPermissionService.authorizationStatusStub = { mediaType in - XCTAssertEqual(mediaType, .video) - return .notDetermined - } - mockPermissionService.requestAccessStub = { mediaType, handler in - XCTAssertEqual(mediaType, .video) - // Deny access. - handler(false) - } - permissionManager.requestCameraPermission { error in - XCTAssertEqual(error?.code, "CameraAccessDenied") - XCTAssertEqual(error?.message, "User denied the camera access request.") - expectation.fulfill() - } - - waitForExpectations(timeout: 30, handler: nil) - } - - // MARK: - Audio permissions - - func testRequestAudioPermission_completeWithoutErrorIfPreviouslyAuthorized() { - let (permissionManager, mockPermissionService) = createSutAndMocks() - let expectation = self.expectation( - description: "Must complete without error if audio access was previously authorized.") - - mockPermissionService.authorizationStatusStub = { mediaType in - XCTAssertEqual(mediaType, .audio) - return .authorized - } - permissionManager.requestAudioPermission { error in - XCTAssertNil(error) - expectation.fulfill() - } - - waitForExpectations(timeout: 30, handler: nil) - } - - func testRequestAudioPermission_completeWithErrorIfPreviouslyDenied() { - let (permissionManager, mockPermissionService) = createSutAndMocks() - let expectation = self.expectation( - description: "Must complete with error if audio access was previously denied.") - - mockPermissionService.authorizationStatusStub = { mediaType in - XCTAssertEqual(mediaType, .audio) - return .denied - } - permissionManager.requestAudioPermission { error in - XCTAssertEqual(error?.code, "AudioAccessDeniedWithoutPrompt") - XCTAssertEqual( - error?.message, - "User has previously denied the audio access request. Go to Settings to enable audio access." - ) - expectation.fulfill() - } - - waitForExpectations(timeout: 30, handler: nil) - } - - func testRequestAudioPermission_completeWithErrorIfRestricted() { - let (permissionManager, mockPermissionService) = createSutAndMocks() - let expectation = self.expectation( - description: "Must complete with error if audio access is restricted.") - - mockPermissionService.authorizationStatusStub = { mediaType in - XCTAssertEqual(mediaType, .audio) - return .restricted - } - permissionManager.requestAudioPermission { error in - XCTAssertEqual(error?.code, "AudioAccessRestricted") - XCTAssertEqual(error?.message, "Audio access is restricted.") - expectation.fulfill() - } - - waitForExpectations(timeout: 30, handler: nil) - } - - func testRequestAudioPermission_completeWithoutErrorIfUserGrantAccess() { - let (permissionManager, mockPermissionService) = createSutAndMocks() - let expectation = self.expectation( - description: "Must complete without error if user granted access.") - - mockPermissionService.authorizationStatusStub = { mediaType in - XCTAssertEqual(mediaType, .audio) - return .notDetermined - } - mockPermissionService.requestAccessStub = { mediaType, handler in - XCTAssertEqual(mediaType, .audio) - // Grant access. - handler(true) - } - permissionManager.requestAudioPermission { error in - XCTAssertNil(error) - expectation.fulfill() - } - - waitForExpectations(timeout: 30, handler: nil) - } - - func testRequestAudioPermission_completeWithErrorIfUserDenyAccess() { - let (permissionManager, mockPermissionService) = createSutAndMocks() - let expectation = self.expectation( - description: "Must complete with error if user denied access") - - mockPermissionService.authorizationStatusStub = { mediaType in - XCTAssertEqual(mediaType, .audio) - return .notDetermined - } - mockPermissionService.requestAccessStub = { mediaType, handler in - XCTAssertEqual(mediaType, .audio) - // Deny access. - handler(false) - } - permissionManager.requestAudioPermission { error in - XCTAssertEqual(error?.code, "AudioAccessDenied") - XCTAssertEqual(error?.message, "User denied the audio access request.") - expectation.fulfill() - } - - waitForExpectations(timeout: 30, handler: nil) - } -} diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraPluginCreateCameraTests.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraPluginCreateCameraTests.swift deleted file mode 100644 index 5eb2b61e8ea2..000000000000 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraPluginCreateCameraTests.swift +++ /dev/null @@ -1,131 +0,0 @@ -// Copyright 2013 The Flutter Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import XCTest - -@testable import camera_avfoundation - -final class CameraPluginCreateCameraTests: XCTestCase { - private func createCameraPlugin() -> ( - CameraPlugin, MockCameraPermissionManager, MockCaptureSession - ) { - let mockPermissionManager = MockCameraPermissionManager() - let mockCaptureSession = MockCaptureSession() - - let cameraPlugin = CameraPlugin( - registry: MockFlutterTextureRegistry(), - messenger: MockFlutterBinaryMessenger(), - globalAPI: MockGlobalEventApi(), - deviceDiscoverer: MockCameraDeviceDiscoverer(), - permissionManager: mockPermissionManager, - deviceFactory: { _ in MockCaptureDevice() }, - captureSessionFactory: { mockCaptureSession }, - captureDeviceInputFactory: MockCaptureDeviceInputFactory(), - captureSessionQueue: DispatchQueue(label: "io.flutter.camera.captureSessionQueue") - ) - - return (cameraPlugin, mockPermissionManager, mockCaptureSession) - } - - func testCreateCamera_requestsOnlyCameraPermissionWithAudioDisabled() { - let (cameraPlugin, mockPermissionManager, _) = createCameraPlugin() - let expectation = expectation(description: "Initialization completed") - - var requestCameraPermissionCalled = false - mockPermissionManager.requestCameraPermissionStub = { completion in - requestCameraPermissionCalled = true - // Permission is granted - completion(nil) - } - var requestAudioPermissionCalled = false - mockPermissionManager.requestAudioPermissionStub = { completion in - requestAudioPermissionCalled = true - // Permission is granted - completion(nil) - } - - cameraPlugin.create( - cameraName: "camera_name", - settings: PlatformMediaSettings( - resolutionPreset: .medium, - framesPerSecond: nil, - videoBitrate: nil, - audioBitrate: nil, - enableAudio: false) - ) { result in - expectation.fulfill() - } - - waitForExpectations(timeout: 30, handler: nil) - - XCTAssertTrue(requestCameraPermissionCalled) - XCTAssertFalse(requestAudioPermissionCalled) - } - - func testCreateCamera_requestsCameraAndAudioPermissionWithAudioEnabled() { - let (cameraPlugin, mockPermissionManager, _) = createCameraPlugin() - let expectation = expectation(description: "Initialization completed") - - var requestCameraPermissionCalled = false - mockPermissionManager.requestCameraPermissionStub = { completion in - requestCameraPermissionCalled = true - // Permission is granted - completion(nil) - } - var requestAudioPermissionCalled = false - mockPermissionManager.requestAudioPermissionStub = { completion in - requestAudioPermissionCalled = true - // Permission is granted - completion(nil) - } - - cameraPlugin.create( - cameraName: "camera_name", - settings: PlatformMediaSettings( - resolutionPreset: .medium, - framesPerSecond: nil, - videoBitrate: nil, - audioBitrate: nil, - enableAudio: true) - ) { result in - expectation.fulfill() - } - - waitForExpectations(timeout: 30, handler: nil) - - XCTAssertTrue(requestCameraPermissionCalled) - XCTAssertTrue(requestAudioPermissionCalled) - } - - func testCreateCamera_createsFLTCamSuccessfully() { - let (cameraPlugin, mockPermissionManager, mockCaptureSession) = createCameraPlugin() - let expectation = expectation(description: "Initialization completed") - - mockPermissionManager.requestCameraPermissionStub = { completion in - // Permission is granted - completion(nil) - } - mockPermissionManager.requestAudioPermissionStub = { completion in - // Permission is granted - completion(nil) - } - mockCaptureSession.canSetSessionPresetStub = { _ in true } - - cameraPlugin.create( - cameraName: "camera_name", - settings: PlatformMediaSettings( - resolutionPreset: .medium, - framesPerSecond: nil, - videoBitrate: nil, - audioBitrate: nil, - enableAudio: true) - ) { result in - expectation.fulfill() - } - - waitForExpectations(timeout: 30, handler: nil) - - XCTAssertNotNil(cameraPlugin.camera) - } -} diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraPluginDelegatingMethodTests.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraPluginDelegatingMethodTests.swift deleted file mode 100644 index 4e3c5a377f06..000000000000 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraPluginDelegatingMethodTests.swift +++ /dev/null @@ -1,630 +0,0 @@ -// Copyright 2013 The Flutter Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import XCTest - -@testable import camera_avfoundation - -/// Tests of `CameraPlugin` methods delegating to `FLTCam` instance -final class CameraPluginDelegatingMethodTests: XCTestCase { - private func createCameraPlugin() -> (CameraPlugin, MockCamera) { - let mockCamera = MockCamera() - - let cameraPlugin = CameraPlugin( - registry: MockFlutterTextureRegistry(), - messenger: MockFlutterBinaryMessenger(), - globalAPI: MockGlobalEventApi(), - deviceDiscoverer: MockCameraDeviceDiscoverer(), - permissionManager: MockCameraPermissionManager(), - deviceFactory: { _ in MockCaptureDevice() }, - captureSessionFactory: { MockCaptureSession() }, - captureDeviceInputFactory: MockCaptureDeviceInputFactory(), - captureSessionQueue: DispatchQueue(label: "io.flutter.camera.captureSessionQueue") - ) - cameraPlugin.camera = mockCamera - - return (cameraPlugin, mockCamera) - } - - func testLockCapture_callsCameraLockCapture() { - let (cameraPlugin, mockCamera) = createCameraPlugin() - let expectation = expectation(description: "Call completed") - - let targetOrientation = PlatformDeviceOrientation.landscapeLeft - - var lockCaptureCalled = false - mockCamera.lockCaptureOrientationStub = { orientation in - XCTAssertEqual(orientation, targetOrientation) - lockCaptureCalled = true - } - - cameraPlugin.lockCaptureOrientation(orientation: targetOrientation) { result in - let _ = self.assertSuccess(result) - expectation.fulfill() - } - - waitForExpectations(timeout: 30, handler: nil) - - XCTAssertTrue(lockCaptureCalled) - } - - func testPausePreview_callsCameraPausePreview() { - let (cameraPlugin, mockCamera) = createCameraPlugin() - let expectation = expectation(description: "Call completed") - - var pausePreviewCalled = false - mockCamera.pausePreviewStub = { - pausePreviewCalled = true - } - - cameraPlugin.pausePreview { result in - let _ = self.assertSuccess(result) - expectation.fulfill() - } - - waitForExpectations(timeout: 30, handler: nil) - - XCTAssertTrue(pausePreviewCalled) - } - - func testPauseVideoRecording_callsCameraPauseVideoRecording() { - let (cameraPlugin, mockCamera) = createCameraPlugin() - let expectation = expectation(description: "Call completed") - - var pauseVideoRecordingCalled = false - mockCamera.pauseVideoRecordingStub = { - pauseVideoRecordingCalled = true - } - - cameraPlugin.pauseVideoRecording { result in - let _ = self.assertSuccess(result) - expectation.fulfill() - } - - waitForExpectations(timeout: 30, handler: nil) - - XCTAssertTrue(pauseVideoRecordingCalled) - } - - func testPrepareForVideoRecording_callsCameraSetUpCaptureSessionForAudioIfNeeded() { - let (cameraPlugin, mockCamera) = createCameraPlugin() - let expectation = expectation(description: "Call completed") - - var setUpCaptureSessionForAudioIfNeededCalled = false - mockCamera.setUpCaptureSessionForAudioIfNeededStub = { - setUpCaptureSessionForAudioIfNeededCalled = true - } - - cameraPlugin.prepareForVideoRecording { result in - let _ = self.assertSuccess(result) - expectation.fulfill() - } - - waitForExpectations(timeout: 30, handler: nil) - - XCTAssertTrue(setUpCaptureSessionForAudioIfNeededCalled) - } - - func testReceivedImageStreamData_callsCameraReceivedImageStreamData() { - let (cameraPlugin, mockCamera) = createCameraPlugin() - let expectation = expectation(description: "Call completed") - - var receivedImageStreamDataCalled = false - mockCamera.receivedImageStreamDataStub = { - receivedImageStreamDataCalled = true - } - - cameraPlugin.receivedImageStreamData { result in - let _ = self.assertSuccess(result) - expectation.fulfill() - } - - waitForExpectations(timeout: 30, handler: nil) - - XCTAssertTrue(receivedImageStreamDataCalled) - } - - func testResumeVideoRecording_callsCameraResumeVideoRecording() { - let (cameraPlugin, mockCamera) = createCameraPlugin() - let expectation = expectation(description: "Call completed") - - var resumeVideoRecordingCalled = false - mockCamera.resumeVideoRecordingStub = { - resumeVideoRecordingCalled = true - } - - cameraPlugin.resumeVideoRecording { result in - let _ = self.assertSuccess(result) - expectation.fulfill() - } - - waitForExpectations(timeout: 30, handler: nil) - - XCTAssertTrue(resumeVideoRecordingCalled) - } - - func testResumePreview_callsCameraResumePreview() { - let (cameraPlugin, mockCamera) = createCameraPlugin() - let expectation = expectation(description: "Call completed") - - var resumePreviewCalled = false - mockCamera.resumePreviewStub = { - resumePreviewCalled = true - } - - cameraPlugin.resumePreview { result in - let _ = self.assertSuccess(result) - expectation.fulfill() - } - - waitForExpectations(timeout: 30, handler: nil) - - XCTAssertTrue(resumePreviewCalled) - } - - func testSetExposureMode_callsCameraExposureMode() { - let (cameraPlugin, mockCamera) = createCameraPlugin() - let expectation = expectation(description: "Call completed") - - let targetExposureMode = PlatformExposureMode.locked - - var setExposureModeCalled = false - mockCamera.setExposureModeStub = { mode in - XCTAssertEqual(mode, targetExposureMode) - setExposureModeCalled = true - } - - cameraPlugin.setExposureMode(mode: targetExposureMode) { result in - let _ = self.assertSuccess(result) - expectation.fulfill() - } - - waitForExpectations(timeout: 30, handler: nil) - - XCTAssertTrue(setExposureModeCalled) - } - - func testSetExposureOffset_callsCameraSetExposureOffset() { - let (cameraPlugin, mockCamera) = createCameraPlugin() - let expectation = expectation(description: "Call completed") - - let targetExposureOffset = 1.0 - - var setExposureOffsetCalled = false - mockCamera.setExposureOffsetStub = { offset in - XCTAssertEqual(offset, targetExposureOffset) - setExposureOffsetCalled = true - } - - cameraPlugin.setExposureOffset(offset: targetExposureOffset) { result in - let _ = self.assertSuccess(result) - expectation.fulfill() - } - - waitForExpectations(timeout: 30, handler: nil) - - XCTAssertTrue(setExposureOffsetCalled) - } - - func testSetFocusMode_callsCameraSetFocusMode() { - let (cameraPlugin, mockCamera) = createCameraPlugin() - let expectation = expectation(description: "Call completed") - - let targetFocusMode = PlatformFocusMode.locked - - var setFocusModeCalled = false - mockCamera.setFocusModeStub = { mode in - XCTAssertEqual(mode, targetFocusMode) - setFocusModeCalled = true - } - - cameraPlugin.setFocusMode(mode: targetFocusMode) { result in - let _ = self.assertSuccess(result) - expectation.fulfill() - } - - waitForExpectations(timeout: 30, handler: nil) - - XCTAssertTrue(setFocusModeCalled) - } - - func testSetImageFileFormat_callsCameraSetImageFileFormat() { - let (cameraPlugin, mockCamera) = createCameraPlugin() - let expectation = expectation(description: "Call completed") - - let targetFileFormat = PlatformImageFileFormat.heif - - var setImageFileFormatCalled = false - mockCamera.setImageFileFormatStub = { fileFormat in - XCTAssertEqual(fileFormat, targetFileFormat) - setImageFileFormatCalled = true - } - - cameraPlugin.setImageFileFormat(format: targetFileFormat) { result in - let _ = self.assertSuccess(result) - expectation.fulfill() - } - - waitForExpectations(timeout: 30, handler: nil) - - XCTAssertTrue(setImageFileFormatCalled) - } - - func testStartImageStream_callsCameraStartImageStream() { - let (cameraPlugin, mockCamera) = createCameraPlugin() - let expectation = expectation(description: "Call completed") - - var startImageStreamCalled = false - mockCamera.startImageStreamStub = { messenger, completion in - startImageStreamCalled = true - completion(.success(())) - } - - cameraPlugin.startImageStream { result in - let _ = self.assertSuccess(result) - expectation.fulfill() - } - - waitForExpectations(timeout: 30, handler: nil) - - XCTAssertTrue(startImageStreamCalled) - } - - func testStopImageStream_callsCameraStopImageStream() { - let (cameraPlugin, mockCamera) = createCameraPlugin() - let expectation = expectation(description: "Call completed") - - var stopImageStreamCalled = false - mockCamera.stopImageStreamStub = { - stopImageStreamCalled = true - } - - cameraPlugin.stopImageStream { result in - let _ = self.assertSuccess(result) - expectation.fulfill() - } - - waitForExpectations(timeout: 30, handler: nil) - - XCTAssertTrue(stopImageStreamCalled) - } - - func testStartVideoRecording_withStreamingTrue_callsCameraStartVideoRecordingWithMessenger() { - let (cameraPlugin, mockCamera) = createCameraPlugin() - let expectation = expectation(description: "Call completed") - - var startVideoRecordingCalled = false - mockCamera.startVideoRecordingStub = { completion, messenger in - XCTAssertNotNil(messenger) - completion(.success(())) - startVideoRecordingCalled = true - } - - cameraPlugin.startVideoRecording(enableStream: true) { result in - let _ = self.assertSuccess(result) - expectation.fulfill() - } - - waitForExpectations(timeout: 30, handler: nil) - - XCTAssertTrue(startVideoRecordingCalled) - } - - func testStartVideoRecording_withStreamingFalse_callsCameraStartVideoRecordingWithoutMessenger() { - let (cameraPlugin, mockCamera) = createCameraPlugin() - let expectation = expectation(description: "Call completed") - - var startVideoRecordingCalled = false - mockCamera.startVideoRecordingStub = { completion, messenger in - XCTAssertNil(messenger) - completion(.success(())) - startVideoRecordingCalled = true - } - - cameraPlugin.startVideoRecording(enableStream: false) { result in - let _ = self.assertSuccess(result) - expectation.fulfill() - } - - waitForExpectations(timeout: 30, handler: nil) - - XCTAssertTrue(startVideoRecordingCalled) - } - - func testStopVideoRecording_callsCameraStopVideoRecording() { - let (cameraPlugin, mockCamera) = createCameraPlugin() - let expectation = expectation(description: "Call completed") - - let targetPath = "path" - - var stopVideoRecordingCalled = false - mockCamera.stopVideoRecordingStub = { completion in - completion(.success(targetPath)) - stopVideoRecordingCalled = true - } - - cameraPlugin.stopVideoRecording { result in - switch result { - case .success(let path): - XCTAssertEqual(path, targetPath) - case .failure: - XCTFail("Unexpected error") - } - expectation.fulfill() - } - - waitForExpectations(timeout: 30, handler: nil) - - XCTAssertTrue(stopVideoRecordingCalled) - } - - func testUnlockCaptureOrientation_callsCameraUnlockCaptureOrientation() { - let (cameraPlugin, mockCamera) = createCameraPlugin() - let expectation = expectation(description: "Call completed") - - var unlockCaptureOrientationCalled = false - mockCamera.unlockCaptureOrientationStub = { - unlockCaptureOrientationCalled = true - } - - cameraPlugin.unlockCaptureOrientation { result in - let _ = self.assertSuccess(result) - expectation.fulfill() - } - - waitForExpectations(timeout: 30, handler: nil) - - XCTAssertTrue(unlockCaptureOrientationCalled) - } - - func testSetExposurePoint_callsCameraSetExposurePoint() { - let (cameraPlugin, mockCamera) = createCameraPlugin() - let expectation = expectation(description: "Call completed") - - let targetExposurePoint = PlatformPoint(x: 1.0, y: 1.0) - - var setExposurePointCalled = false - mockCamera.setExposurePointStub = { point, completion in - XCTAssertEqual(point, targetExposurePoint) - completion(.success(())) - setExposurePointCalled = true - } - - cameraPlugin.setExposurePoint(point: targetExposurePoint) { result in - let _ = self.assertSuccess(result) - expectation.fulfill() - } - - waitForExpectations(timeout: 30, handler: nil) - - XCTAssertTrue(setExposurePointCalled) - } - - func testSetFlashMode_callsCameraSetFlashMode() { - let (cameraPlugin, mockCamera) = createCameraPlugin() - let expectation = expectation(description: "Call completed") - - let targetFlashMode = PlatformFlashMode.auto - - var setFlashModeCalled = false - mockCamera.setFlashModeStub = { mode, completion in - XCTAssertEqual(mode, targetFlashMode) - completion(.success(())) - setFlashModeCalled = true - } - - cameraPlugin.setFlashMode(mode: targetFlashMode) { result in - let _ = self.assertSuccess(result) - expectation.fulfill() - } - - waitForExpectations(timeout: 30, handler: nil) - - XCTAssertTrue(setFlashModeCalled) - } - - func testSetFocusPoint_callsCameraSetFocusPoint() { - let (cameraPlugin, mockCamera) = createCameraPlugin() - let expectation = expectation(description: "Call completed") - - let targetFocusPoint = PlatformPoint(x: 1.0, y: 1.0) - - var setFocusPointCalled = false - mockCamera.setFocusPointStub = { point, completion in - XCTAssertEqual(point, targetFocusPoint) - completion(.success(())) - setFocusPointCalled = true - } - - cameraPlugin.setFocusPoint(point: targetFocusPoint) { result in - let _ = self.assertSuccess(result) - expectation.fulfill() - } - - waitForExpectations(timeout: 30, handler: nil) - - XCTAssertTrue(setFocusPointCalled) - } - - func testSetZoomLevel_callsCameraSetZoomLevel() { - let (cameraPlugin, mockCamera) = createCameraPlugin() - let expectation = expectation(description: "Call completed") - - let targetZoomLevel = 1.0 - - var setZoomLevelCalled = false - mockCamera.setZoomLevelStub = { zoom, completion in - XCTAssertEqual(zoom, targetZoomLevel) - completion(.success(())) - setZoomLevelCalled = true - } - - cameraPlugin.setZoomLevel(zoom: targetZoomLevel) { result in - let _ = self.assertSuccess(result) - expectation.fulfill() - } - - waitForExpectations(timeout: 30, handler: nil) - - XCTAssertTrue(setZoomLevelCalled) - } - - func testTakePicture_callsCameraCaptureToFile() { - let (cameraPlugin, mockCamera) = createCameraPlugin() - let expectation = expectation(description: "Call completed") - - let targetPath = "path" - - var captureToFileCalled = false - mockCamera.captureToFileStub = { completion in - completion(.success(targetPath)) - captureToFileCalled = true - } - - cameraPlugin.takePicture { result in - switch result { - case .success(let path): - XCTAssertEqual(path, targetPath) - case .failure: - XCTFail("Unexpected error") - } - expectation.fulfill() - } - - waitForExpectations(timeout: 30, handler: nil) - - XCTAssertTrue(captureToFileCalled) - } - - func testUpdateDescriptionWhileRecording_callsCameraSetDescriptionWhileRecording() { - let (cameraPlugin, mockCamera) = createCameraPlugin() - let expectation = expectation(description: "Call completed") - - let targetCameraName = "camera_name" - - var setDescriptionWhileRecordingCalled = false - mockCamera.setDescriptionWhileRecordingStub = { cameraName, completion in - XCTAssertEqual(cameraName, targetCameraName) - completion(.success(())) - setDescriptionWhileRecordingCalled = true - } - - cameraPlugin.updateDescriptionWhileRecording(cameraName: targetCameraName) { result in - let _ = self.assertSuccess(result) - expectation.fulfill() - } - - waitForExpectations(timeout: 30, handler: nil) - - XCTAssertTrue(setDescriptionWhileRecordingCalled) - } - - func testGetMaxZoomLevel_returnsValueFromCameraGetMaximumAvailableZoomFactor() { - let (cameraPlugin, mockCamera) = createCameraPlugin() - let expectation = expectation(description: "Call completed") - - let targetMaximumZoomLevel = CGFloat(1.0) - - var getMaximumAvailableZoomFactorCalled = false - mockCamera.getMaximumAvailableZoomFactorStub = { - getMaximumAvailableZoomFactorCalled = true - return targetMaximumZoomLevel - } - - cameraPlugin.getMaxZoomLevel { result in - switch result { - case .success(let zoom): - XCTAssertEqual(zoom, targetMaximumZoomLevel) - case .failure: - XCTFail("Unexpected error") - } - expectation.fulfill() - } - - waitForExpectations(timeout: 30, handler: nil) - - XCTAssertTrue(getMaximumAvailableZoomFactorCalled) - } - - func testGetMinZoomLevel_returnsValueFromCameraGetMinimumAvailableZoomFactor() { - let (cameraPlugin, mockCamera) = createCameraPlugin() - let expectation = expectation(description: "Call completed") - - let targetMinimumZoomLevel = CGFloat(1.0) - - var getMinimumAvailableZoomFactorCalled = false - mockCamera.getMinimumAvailableZoomFactorStub = { - getMinimumAvailableZoomFactorCalled = true - return targetMinimumZoomLevel - } - - cameraPlugin.getMinZoomLevel { result in - switch result { - case .success(let zoom): - XCTAssertEqual(zoom, targetMinimumZoomLevel) - case .failure: - XCTFail("Unexpected error") - } - expectation.fulfill() - } - - waitForExpectations(timeout: 30, handler: nil) - - XCTAssertTrue(getMinimumAvailableZoomFactorCalled) - } - - func testGetMaxExposureOffset_returnsValueFromCameraGetMaximumExposureOffset() { - let (cameraPlugin, mockCamera) = createCameraPlugin() - let expectation = expectation(description: "Call completed") - - let targetMaximumExposureOffset = CGFloat(1.0) - - var getMaximumExposureOffsetCalled = false - mockCamera.getMaximumExposureOffsetStub = { - getMaximumExposureOffsetCalled = true - return targetMaximumExposureOffset - } - - cameraPlugin.getMaxExposureOffset { result in - switch result { - case .success(let offset): - XCTAssertEqual(offset, targetMaximumExposureOffset) - case .failure: - XCTFail("Unexpected error") - } - expectation.fulfill() - } - - waitForExpectations(timeout: 30, handler: nil) - - XCTAssertTrue(getMaximumExposureOffsetCalled) - } - - func testGetMinExposureOffset_returnsValueFromCameraGetMinimumExposureOffset() { - let (cameraPlugin, mockCamera) = createCameraPlugin() - let expectation = expectation(description: "Call completed") - - let targetMinimumExposureOffset = CGFloat(1.0) - - var getMinimumExposureOffsetCalled = false - mockCamera.getMinimumExposureOffsetStub = { - getMinimumExposureOffsetCalled = true - return targetMinimumExposureOffset - } - - cameraPlugin.getMinExposureOffset { result in - switch result { - case .success(let offset): - XCTAssertEqual(offset, targetMinimumExposureOffset) - case .failure: - XCTFail("Unexpected error") - } - expectation.fulfill() - } - - waitForExpectations(timeout: 30, handler: nil) - - XCTAssertTrue(getMinimumExposureOffsetCalled) - } -} diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraPluginInitializeCameraTests.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraPluginInitializeCameraTests.swift deleted file mode 100644 index 979ff895cfed..000000000000 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraPluginInitializeCameraTests.swift +++ /dev/null @@ -1,105 +0,0 @@ -// Copyright 2013 The Flutter Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import XCTest - -@testable import camera_avfoundation - -final class CameraPluginInitializeCameraTests: XCTestCase { - private func createCameraPlugin() -> ( - CameraPlugin, MockCamera, MockGlobalEventApi, DispatchQueue - ) { - let mockCamera = MockCamera() - let mockGlobalEventApi = MockGlobalEventApi() - let captureSessionQueue = DispatchQueue(label: "io.flutter.camera.captureSessionQueue") - - let cameraPlugin = CameraPlugin( - registry: MockFlutterTextureRegistry(), - messenger: MockFlutterBinaryMessenger(), - globalAPI: mockGlobalEventApi, - deviceDiscoverer: MockCameraDeviceDiscoverer(), - permissionManager: MockCameraPermissionManager(), - deviceFactory: { _ in MockCaptureDevice() }, - captureSessionFactory: { MockCaptureSession() }, - captureDeviceInputFactory: MockCaptureDeviceInputFactory(), - captureSessionQueue: captureSessionQueue - ) - cameraPlugin.camera = mockCamera - - return (cameraPlugin, mockCamera, mockGlobalEventApi, captureSessionQueue) - } - - func testInitializeCamera_setsCameraOnFrameAvailableCallback() { - let (cameraPlugin, mockCamera, _, _) = createCameraPlugin() - let expectation = expectation(description: "Initialization completed") - - var onFrameAvailableSet = false - mockCamera.setOnFrameAvailableStub = { callback in - onFrameAvailableSet = true - } - - cameraPlugin.initialize(cameraId: 0, imageFormat: PlatformImageFormatGroup.bgra8888) { - result in - let _ = self.assertSuccess(result) - expectation.fulfill() - } - - waitForExpectations(timeout: 30, handler: nil) - - XCTAssertTrue(onFrameAvailableSet) - } - - func testInitializeCamera_setsCameraDartAPI() { - let (cameraPlugin, mockCamera, _, _) = createCameraPlugin() - let expectation = expectation(description: "Initialization completed") - - var dartAPISet = false - mockCamera.setDartApiStub = { api in - dartAPISet = true - } - - cameraPlugin.initialize(cameraId: 0, imageFormat: PlatformImageFormatGroup.bgra8888) { - result in - let _ = self.assertSuccess(result) - expectation.fulfill() - } - - waitForExpectations(timeout: 30, handler: nil) - - XCTAssertTrue(dartAPISet) - } - - func testInitializeCamera_sendsDeviceOrientation() { - let (cameraPlugin, _, mockGlobalEventApi, captureSessionQueue) = createCameraPlugin() - - cameraPlugin.initialize(cameraId: 0, imageFormat: PlatformImageFormatGroup.bgra8888) { - result in - let _ = self.assertSuccess(result) - } - - waitForQueueRoundTrip(with: captureSessionQueue) - - XCTAssertTrue(mockGlobalEventApi.deviceOrientationChangedCalled) - } - - func testInitializeCamera_startsCamera() { - let (cameraPlugin, mockCamera, _, _) = createCameraPlugin() - let expectation = expectation(description: "Initialization completed") - - var startCalled = false - mockCamera.startStub = { - startCalled = true - } - - cameraPlugin.initialize(cameraId: 0, imageFormat: PlatformImageFormatGroup.bgra8888) { - result in - let _ = self.assertSuccess(result) - expectation.fulfill() - } - - waitForExpectations(timeout: 30, handler: nil) - - XCTAssertTrue(startCalled) - } -} diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraPreviewPauseTests.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraPreviewPauseTests.swift deleted file mode 100644 index 7803ec38ec0a..000000000000 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraPreviewPauseTests.swift +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright 2013 The Flutter Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import AVFoundation -import XCTest - -@testable import camera_avfoundation - -final class CameraPreviewPauseTests: XCTestCase { - func testPausePreviewWithResult_shouldPausePreview() { - let camera = CameraTestUtils.createTestCamera() - - camera.pausePreview() - - XCTAssertTrue(camera.isPreviewPaused) - } - - func testResumePreviewWithResult_shouldResumePreview() { - let camera = CameraTestUtils.createTestCamera() - - camera.resumePreview() - - XCTAssertFalse(camera.isPreviewPaused) - } -} diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraPropertiesTests.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraPropertiesTests.swift deleted file mode 100644 index bac0ce6ed19e..000000000000 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraPropertiesTests.swift +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright 2013 The Flutter Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import AVFoundation -import Foundation -import XCTest - -@testable import camera_avfoundation - -final class CameraPropertiesTests: XCTestCase { - // MARK: - Flash Mode Tests - - func testGetAVCaptureFlashModeForPigeonFlashMode() { - XCTAssertEqual( - AVCaptureDevice.FlashMode.off, - getAVCaptureFlashMode(for: .off)) - XCTAssertEqual( - AVCaptureDevice.FlashMode.auto, - getAVCaptureFlashMode(for: .auto)) - XCTAssertEqual( - AVCaptureDevice.FlashMode.on, - getAVCaptureFlashMode(for: .always)) - } - - // MARK: - Video Format Tests - - func testGetPixelFormatForPigeonFormat() { - XCTAssertEqual( - kCVPixelFormatType_32BGRA, - getPixelFormat(for: .bgra8888)) - XCTAssertEqual( - kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange, - getPixelFormat(for: .yuv420)) - } - - // MARK: - Device Orientation Tests - - func testGetUIDeviceOrientationForPigeonDeviceOrientation() { - XCTAssertEqual( - UIDeviceOrientation.portraitUpsideDown, - getUIDeviceOrientation(for: .portraitDown) - ) - XCTAssertEqual( - UIDeviceOrientation.landscapeLeft, - getUIDeviceOrientation(for: .landscapeLeft)) - XCTAssertEqual( - UIDeviceOrientation.landscapeRight, - getUIDeviceOrientation(for: .landscapeRight)) - XCTAssertEqual( - UIDeviceOrientation.portrait, - getUIDeviceOrientation(for: .portraitUp)) - } - - func testGetPigeonDeviceOrientationForUIDeviceOrientation() { - XCTAssertEqual( - PlatformDeviceOrientation.portraitDown, - getPigeonDeviceOrientation(for: .portraitUpsideDown)) - XCTAssertEqual( - PlatformDeviceOrientation.landscapeLeft, - getPigeonDeviceOrientation(for: .landscapeLeft)) - XCTAssertEqual( - PlatformDeviceOrientation.landscapeRight, - getPigeonDeviceOrientation(for: .landscapeRight)) - XCTAssertEqual( - PlatformDeviceOrientation.portraitUp, - getPigeonDeviceOrientation(for: .portrait)) - // Test default case. - XCTAssertEqual( - PlatformDeviceOrientation.portraitUp, - getPigeonDeviceOrientation(for: .unknown)) - } -} diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraSessionPresetsTests.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraSessionPresetsTests.swift deleted file mode 100644 index b7b6a00734be..000000000000 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraSessionPresetsTests.swift +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright 2013 The Flutter Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import AVFoundation -import XCTest - -@testable import camera_avfoundation - -/// Includes test cases related to resolution presets setting operations for FLTCam class. -final class CameraSessionPresetsTests: XCTestCase { - func testResolutionPresetWithBestFormat_mustUpdateCaptureSessionPreset() { - let expectedPreset = AVCaptureSession.Preset.inputPriority - let presetExpectation = expectation(description: "Expected preset set") - let lockForConfigurationExpectation = expectation( - description: "Expected lockForConfiguration called") - - let videoSessionMock = MockCaptureSession() - videoSessionMock.canSetSessionPresetStub = { _ in true } - videoSessionMock.setSessionPresetStub = { preset in - if preset == expectedPreset { - presetExpectation.fulfill() - } - } - let captureFormatMock = MockCaptureDeviceFormat() - let captureDeviceMock = MockCaptureDevice() - captureDeviceMock.flutterFormats = [captureFormatMock] - var currentFormat: CaptureDeviceFormat = captureFormatMock - captureDeviceMock.activeFormatStub = { - return currentFormat - } - captureDeviceMock.lockForConfigurationStub = { - lockForConfigurationExpectation.fulfill() - } - - let configuration = CameraTestUtils.createTestCameraConfiguration() - configuration.videoCaptureDeviceFactory = { _ in captureDeviceMock } - configuration.videoDimensionsConverter = { _ in - return CMVideoDimensions(width: 4, height: 3) - } - configuration.videoCaptureSession = videoSessionMock - configuration.mediaSettings = CameraTestUtils.createDefaultMediaSettings( - resolutionPreset: PlatformResolutionPreset.max) - - let _ = CameraTestUtils.createTestCamera(configuration) - - waitForExpectations(timeout: 30, handler: nil) - } - - func testResolutionPresetWithCanSetSessionPresetMax_mustUpdateCaptureSessionPreset() { - let expectedPreset = AVCaptureSession.Preset.hd4K3840x2160 - let expectation = self.expectation(description: "Expected preset set") - - let videoSessionMock = MockCaptureSession() - // Make sure that setting resolution preset for session always succeeds. - videoSessionMock.canSetSessionPresetStub = { _ in true } - videoSessionMock.setSessionPresetStub = { preset in - if preset == expectedPreset { - expectation.fulfill() - } - } - - let configuration = CameraTestUtils.createTestCameraConfiguration() - configuration.videoCaptureSession = videoSessionMock - configuration.mediaSettings = CameraTestUtils.createDefaultMediaSettings( - resolutionPreset: PlatformResolutionPreset.max) - configuration.videoCaptureDeviceFactory = { _ in MockCaptureDevice() } - - let _ = CameraTestUtils.createTestCamera(configuration) - - waitForExpectations(timeout: 30, handler: nil) - } - - func testResolutionPresetWithCanSetSessionPresetUltraHigh_mustUpdateCaptureSessionPreset() { - let expectedPreset = AVCaptureSession.Preset.hd4K3840x2160 - let expectation = self.expectation(description: "Expected preset set") - - let videoSessionMock = MockCaptureSession() - // Make sure that setting resolution preset for session always succeeds. - videoSessionMock.canSetSessionPresetStub = { _ in true } - // Expect that setting "ultraHigh" resolutionPreset correctly updates videoCaptureSession. - videoSessionMock.setSessionPresetStub = { preset in - if preset == expectedPreset { - expectation.fulfill() - } - } - - let configuration = CameraTestUtils.createTestCameraConfiguration() - configuration.videoCaptureSession = videoSessionMock - configuration.mediaSettings = CameraTestUtils.createDefaultMediaSettings( - resolutionPreset: PlatformResolutionPreset.ultraHigh) - - let _ = CameraTestUtils.createTestCamera(configuration) - - waitForExpectations(timeout: 30, handler: nil) - } -} diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraSettingsTests.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraSettingsTests.swift deleted file mode 100644 index 984549b06516..000000000000 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraSettingsTests.swift +++ /dev/null @@ -1,355 +0,0 @@ -// Copyright 2013 The Flutter Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import AVFoundation -import XCTest - -@testable import camera_avfoundation - -private let testResolutionPreset = PlatformResolutionPreset.medium -private let testFramesPerSecond: Int64 = 15 -private let testVideoBitrate: Int64 = 200000 -private let testAudioBitrate: Int64 = 32000 - -private final class TestMediaSettingsAVWrapper: FLTCamMediaSettingsAVWrapper { - let lockExpectation: XCTestExpectation - let unlockExpectation: XCTestExpectation - let minFrameDurationExpectation: XCTestExpectation - let maxFrameDurationExpectation: XCTestExpectation - let beginConfigurationExpectation: XCTestExpectation - let commitConfigurationExpectation: XCTestExpectation - let audioSettingsExpectation: XCTestExpectation - let videoSettingsExpectation: XCTestExpectation - - init(test: XCTestCase, expectAudio: Bool) { - lockExpectation = test.expectation(description: "lockExpectation") - unlockExpectation = test.expectation(description: "unlockExpectation") - minFrameDurationExpectation = test.expectation(description: "minFrameDurationExpectation") - maxFrameDurationExpectation = test.expectation(description: "maxFrameDurationExpectation") - beginConfigurationExpectation = test.expectation(description: "beginConfigurationExpectation") - commitConfigurationExpectation = test.expectation(description: "commitConfigurationExpectation") - audioSettingsExpectation = test.expectation(description: "audioSettingsExpectation") - audioSettingsExpectation.isInverted = !expectAudio - videoSettingsExpectation = test.expectation(description: "videoSettingsExpectation") - } - - override func lockDevice(_ captureDevice: CaptureDevice) throws { - lockExpectation.fulfill() - } - - override func unlockDevice(_ captureDevice: CaptureDevice) { - unlockExpectation.fulfill() - } - - override func beginConfiguration(for videoCaptureSession: CaptureSession) { - beginConfigurationExpectation.fulfill() - } - - override func commitConfiguration(for videoCaptureSession: CaptureSession) { - commitConfigurationExpectation.fulfill() - } - - override func setMinFrameDuration(_ duration: CMTime, on captureDevice: CaptureDevice) { - // FLTCam allows to set frame rate with 1/10 precision. - let expectedDuration = CMTimeMake(value: 10, timescale: Int32(testFramesPerSecond * 10)) - if duration == expectedDuration { - minFrameDurationExpectation.fulfill() - } - } - - override func setMaxFrameDuration(_ duration: CMTime, on captureDevice: CaptureDevice) { - // FLTCam allows to set frame rate with 1/10 precision. - let expectedDuration = CMTimeMake(value: 10, timescale: Int32(testFramesPerSecond * 10)) - if duration == expectedDuration { - maxFrameDurationExpectation.fulfill() - } - } - - override func assetWriterAudioInput(withOutputSettings outputSettings: [String: Any]?) - -> AssetWriterInput - { - if let bitrate = outputSettings?[AVEncoderBitRateKey] as? Int, bitrate == Int(testAudioBitrate) - { - audioSettingsExpectation.fulfill() - } - return MockAssetWriterInput() - } - - override func assetWriterVideoInput(withOutputSettings outputSettings: [String: Any]?) - -> AssetWriterInput - { - if let compressionProperties = outputSettings?[AVVideoCompressionPropertiesKey] - as? [String: Any], - let bitrate = compressionProperties[AVVideoAverageBitRateKey] as? Int, - let frameRate = compressionProperties[AVVideoExpectedSourceFrameRateKey] as? Double, - bitrate == testVideoBitrate, frameRate == Double(testFramesPerSecond) - { - videoSettingsExpectation.fulfill() - } - - // AVAssetWriterInput needs these three keys, otherwise it throws. - var outputSettingsWithRequiredKeys = outputSettings ?? [:] - outputSettingsWithRequiredKeys[AVVideoCodecKey] = AVVideoCodecType.h264 - outputSettingsWithRequiredKeys[AVVideoWidthKey] = 1280 - outputSettingsWithRequiredKeys[AVVideoHeightKey] = 720 - - return MockAssetWriterInput() - } - - override func addInput(_ writerInput: AssetWriterInput, to writer: AssetWriter) { - // No-op. - } - - override func recommendedVideoSettingsForAssetWriter( - withFileType fileType: AVFileType, for output: CaptureVideoDataOutput - ) -> [String: Any]? { - return [:] - } -} - -final class CameraSettingsTests: XCTestCase { - func testSettings_shouldPassConfigurationToCameraDeviceAndWriter() { - let enableAudio: Bool = true - let settings = PlatformMediaSettings( - resolutionPreset: testResolutionPreset, - framesPerSecond: testFramesPerSecond, - videoBitrate: testVideoBitrate, - audioBitrate: testAudioBitrate, - enableAudio: enableAudio - ) - let injectedWrapper = TestMediaSettingsAVWrapper(test: self, expectAudio: enableAudio) - - let configuration = CameraTestUtils.createTestCameraConfiguration() - configuration.mediaSettingsWrapper = injectedWrapper - configuration.mediaSettings = settings - let camera = CameraTestUtils.createTestCamera(configuration) - - // Expect FPS configuration is passed to camera device. - wait( - for: [ - injectedWrapper.lockExpectation, - injectedWrapper.beginConfigurationExpectation, - injectedWrapper.minFrameDurationExpectation, - injectedWrapper.maxFrameDurationExpectation, - injectedWrapper.commitConfigurationExpectation, - injectedWrapper.unlockExpectation, - ], timeout: 1, enforceOrder: true) - - camera.startVideoRecording( - completion: { error in - // No-op. - }, messengerForStreaming: nil) - - wait( - for: [ - injectedWrapper.audioSettingsExpectation, - injectedWrapper.videoSettingsExpectation, - ], timeout: 1) - } - - func testSettings_ShouldBeSupportedByMethodCall() { - let mockDevice = MockCaptureDevice() - let mockSession = MockCaptureSession() - mockSession.canSetSessionPresetStub = { _ in true } - let camera = CameraPlugin( - registry: MockFlutterTextureRegistry(), - messenger: MockFlutterBinaryMessenger(), - globalAPI: MockGlobalEventApi(), - deviceDiscoverer: MockCameraDeviceDiscoverer(), - permissionManager: MockCameraPermissionManager(), - deviceFactory: { _ in mockDevice }, - captureSessionFactory: { mockSession }, - captureDeviceInputFactory: MockCaptureDeviceInputFactory(), - captureSessionQueue: DispatchQueue(label: "io.flutter.camera.captureSessionQueue") - ) - - let expectation = self.expectation(description: "Result finished") - let mediaSettings = PlatformMediaSettings( - resolutionPreset: testResolutionPreset, - framesPerSecond: testFramesPerSecond, - videoBitrate: testVideoBitrate, - audioBitrate: testAudioBitrate, - enableAudio: false - ) - var resultValue: Int64? - camera.createCameraOnSessionQueue( - withName: "acamera", - settings: mediaSettings - ) { result in - resultValue = self.assertSuccess(result) - expectation.fulfill() - } - - waitForExpectations(timeout: 30, handler: nil) - XCTAssertNotNil(resultValue) - } - - func testSettings_ShouldSelectFormatWhichSupports60FPS() { - let settings = PlatformMediaSettings( - resolutionPreset: testResolutionPreset, - framesPerSecond: 60, - videoBitrate: testVideoBitrate, - audioBitrate: testAudioBitrate, - enableAudio: false - ) - - let configuration = CameraTestUtils.createTestCameraConfiguration() - configuration.mediaSettings = settings - let camera = CameraTestUtils.createTestCamera(configuration) - - let range = camera.captureDevice.flutterActiveFormat.flutterVideoSupportedFrameRateRanges[0] - XCTAssertLessThanOrEqual(range.minFrameRate, 60) - XCTAssertGreaterThanOrEqual(range.maxFrameRate, 60) - } - - func test_setUpCaptureSessionForAudioIfNeeded_skipsAudioSession_whenAudioDisabled() { - let settings = PlatformMediaSettings( - resolutionPreset: testResolutionPreset, - framesPerSecond: testFramesPerSecond, - videoBitrate: testVideoBitrate, - audioBitrate: testAudioBitrate, - enableAudio: false - ) - - let wrapper = TestMediaSettingsAVWrapper(test: self, expectAudio: false) - let mockAudioSession = MockCaptureSession() - - let configuration = CameraTestUtils.createTestCameraConfiguration() - configuration.mediaSettingsWrapper = wrapper - configuration.mediaSettings = settings - configuration.audioCaptureSession = mockAudioSession - let camera = CameraTestUtils.createTestCamera(configuration) - - wait( - for: [ - wrapper.lockExpectation, - wrapper.beginConfigurationExpectation, - wrapper.minFrameDurationExpectation, - wrapper.maxFrameDurationExpectation, - wrapper.commitConfigurationExpectation, - wrapper.unlockExpectation, - ], - timeout: 1, - enforceOrder: true - ) - - camera.startVideoRecording(completion: { _ in }, messengerForStreaming: nil) - - wait( - for: [ - wrapper.audioSettingsExpectation, - wrapper.videoSettingsExpectation, - ], - timeout: 1 - ) - - XCTAssertEqual( - mockAudioSession.addedAudioOutputCount, 0, - "Audio session should not receive AVCaptureAudioDataOutput when enableAudio is false" - ) - } - - func test_setUpCaptureSessionForAudioIfNeeded_addsAudioSession_whenAudioEnabled() { - let settings = PlatformMediaSettings( - resolutionPreset: testResolutionPreset, - framesPerSecond: testFramesPerSecond, - videoBitrate: testVideoBitrate, - audioBitrate: testAudioBitrate, - enableAudio: true - ) - - let wrapper = TestMediaSettingsAVWrapper(test: self, expectAudio: true) - let mockAudioSession = MockCaptureSession() - - let configuration = CameraTestUtils.createTestCameraConfiguration() - configuration.mediaSettingsWrapper = wrapper - configuration.mediaSettings = settings - configuration.audioCaptureSession = mockAudioSession - let camera = CameraTestUtils.createTestCamera(configuration) - - wait( - for: [ - wrapper.lockExpectation, - wrapper.beginConfigurationExpectation, - wrapper.minFrameDurationExpectation, - wrapper.maxFrameDurationExpectation, - wrapper.commitConfigurationExpectation, - wrapper.unlockExpectation, - ], - timeout: 1, - enforceOrder: true - ) - - camera.startVideoRecording(completion: { _ in }, messengerForStreaming: nil) - - wait( - for: [ - wrapper.audioSettingsExpectation, - wrapper.videoSettingsExpectation, - ], - timeout: 1 - ) - - XCTAssertGreaterThan( - mockAudioSession.addedAudioOutputCount, 0, - "Audio session should receive AVCaptureAudioDataOutput when enableAudio is true" - ) - } - - func testResolutionPresetWithMax_mustIgnoreLossyFormatsAndSquares() { - let videoSessionMock = MockCaptureSession() - videoSessionMock.canSetSessionPresetStub = { _ in true } - - let lossyFormat = MockCaptureDeviceFormat( - codecType: 1_651_798_066, // 'btp2' - width: 4224, - height: 3024 - ) - let squareFormat = MockCaptureDeviceFormat( - codecType: kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange, - width: 4032, - height: 4032 - ) - let safe4KFormat = MockCaptureDeviceFormat( - codecType: kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange, - width: 3840, - height: 2160 - ) - - let captureDeviceMock = MockCaptureDevice() - captureDeviceMock.flutterFormats = [lossyFormat, squareFormat, safe4KFormat] - - var currentFormat: CaptureDeviceFormat = safe4KFormat - captureDeviceMock.activeFormatStub = { currentFormat } - captureDeviceMock.setActiveFormatStub = { newFormat in currentFormat = newFormat } - - let configuration = CameraTestUtils.createTestCameraConfiguration() - configuration.videoCaptureDeviceFactory = { _ in captureDeviceMock } - configuration.videoCaptureSession = videoSessionMock - - configuration.videoDimensionsConverter = { format in - return CMVideoFormatDescriptionGetDimensions(format.formatDescription) - } - - configuration.mediaSettings = CameraTestUtils.createDefaultMediaSettings( - resolutionPreset: PlatformResolutionPreset.max - ) - - let _ = CameraTestUtils.createTestCamera(configuration) - - let selectedFormat = captureDeviceMock.flutterActiveFormat - let selectedDimensions = CMVideoFormatDescriptionGetDimensions(selectedFormat.formatDescription) - - XCTAssertEqual( - selectedDimensions.width, - 3840, - "Camera should have ignored the lossy and square formats, safely falling back to 4K." - ) - XCTAssertEqual( - selectedDimensions.height, - 2160, - "Camera should have ignored the lossy and square formats, safely falling back to 4K." - ) - } -} diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraTestUtils.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraTestUtils.swift deleted file mode 100644 index a46d23cfe7b1..000000000000 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraTestUtils.swift +++ /dev/null @@ -1,219 +0,0 @@ -// Copyright 2013 The Flutter Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import AVFoundation -import XCTest - -@testable import camera_avfoundation - -/// Utils for creating default class instances used in tests -enum CameraTestUtils { - /// This method provides a convenient way to create media settings with minimal configuration. - /// Audio is enabled by default, while other parameters use platform-specific defaults. - static func createDefaultMediaSettings(resolutionPreset: PlatformResolutionPreset) - -> PlatformMediaSettings - { - return PlatformMediaSettings( - resolutionPreset: resolutionPreset, - framesPerSecond: nil, - videoBitrate: nil, - audioBitrate: nil, - enableAudio: true) - } - - /// Creates a test `CameraConfiguration` with a default mock setup. - static func createTestCameraConfiguration() -> CameraConfiguration { - let captureSessionQueue = DispatchQueue(label: "capture_session_queue") - - let videoSessionMock = MockCaptureSession() - videoSessionMock.canSetSessionPresetStub = { _ in true } - - let audioSessionMock = MockCaptureSession() - audioSessionMock.canSetSessionPresetStub = { _ in true } - - let frameRateRangeMock1 = MockFrameRateRange.init(minFrameRate: 3, maxFrameRate: 30) - - let captureDeviceFormatMock1 = MockCaptureDeviceFormat() - captureDeviceFormatMock1.flutterVideoSupportedFrameRateRanges = [frameRateRangeMock1] - - let frameRateRangeMock2 = MockFrameRateRange.init(minFrameRate: 3, maxFrameRate: 60) - - let captureDeviceFormatMock2 = MockCaptureDeviceFormat() - captureDeviceFormatMock2.flutterVideoSupportedFrameRateRanges = [frameRateRangeMock2] - - let captureDeviceMock = MockCaptureDevice() - captureDeviceMock.flutterFormats = [captureDeviceFormatMock1, captureDeviceFormatMock2] - - var currentFormat: CaptureDeviceFormat = captureDeviceFormatMock1 - - captureDeviceMock.activeFormatStub = { currentFormat } - captureDeviceMock.setActiveFormatStub = { format in - currentFormat = format - } - - let configuration = CameraConfiguration( - mediaSettings: createDefaultMediaSettings( - resolutionPreset: PlatformResolutionPreset.medium), - mediaSettingsWrapper: FLTCamMediaSettingsAVWrapper(), - captureDeviceFactory: { _ in captureDeviceMock }, - audioCaptureDeviceFactory: { MockCaptureDevice() }, - captureSessionFactory: { videoSessionMock }, - captureSessionQueue: captureSessionQueue, - captureDeviceInputFactory: MockCaptureDeviceInputFactory(), - initialCameraName: "camera_name" - ) - - configuration.videoCaptureSession = videoSessionMock - configuration.audioCaptureSession = audioSessionMock - configuration.orientation = .portrait - - configuration.assetWriterFactory = { _, _ in MockAssetWriter() } - - configuration.inputPixelBufferAdaptorFactory = { _, _ in - MockAssetWriterInputPixelBufferAdaptor() - } - - return configuration - } - - static func createTestCamera(_ configuration: CameraConfiguration) -> DefaultCamera { - return (try? DefaultCamera(configuration: configuration))! - } - - static func createTestCamera() -> DefaultCamera { - return createTestCamera(createTestCameraConfiguration()) - } - - static func createCameraWithCaptureSessionQueue(_ captureSessionQueue: DispatchQueue) - -> DefaultCamera - { - let configuration = createTestCameraConfiguration() - configuration.captureSessionQueue = captureSessionQueue - return createTestCamera(configuration) - } - - /// Creates a test sample buffer. - /// @return a test sample buffer. - static func createTestSampleBuffer( - timestamp: CMTime = .zero, - duration: CMTime = CMTimeMake(value: 1, timescale: 44100) - ) -> CMSampleBuffer { - var pixelBuffer: CVPixelBuffer? - CVPixelBufferCreate(kCFAllocatorDefault, 100, 100, kCVPixelFormatType_32BGRA, nil, &pixelBuffer) - - var formatDescription: CMFormatDescription? - CMVideoFormatDescriptionCreateForImageBuffer( - allocator: kCFAllocatorDefault, - imageBuffer: pixelBuffer!, - formatDescriptionOut: &formatDescription) - - var timingInfo = CMSampleTimingInfo( - duration: duration, - presentationTimeStamp: timestamp, - decodeTimeStamp: .invalid) - - var sampleBuffer: CMSampleBuffer? - CMSampleBufferCreateReadyWithImageBuffer( - allocator: kCFAllocatorDefault, - imageBuffer: pixelBuffer!, - formatDescription: formatDescription!, - sampleTiming: &timingInfo, - sampleBufferOut: &sampleBuffer) - - return sampleBuffer! - } - - /// Creates a test audio sample buffer. - /// @return a test audio sample buffer. - static func createTestAudioSampleBuffer( - timestamp: CMTime = .zero, - duration: CMTime = CMTimeMake(value: 1, timescale: 44100) - ) -> CMSampleBuffer { - var blockBuffer: CMBlockBuffer? - CMBlockBufferCreateWithMemoryBlock( - allocator: kCFAllocatorDefault, - memoryBlock: nil, - blockLength: Int(duration.value), - blockAllocator: kCFAllocatorDefault, - customBlockSource: nil, - offsetToData: 0, - dataLength: Int(duration.value), - flags: kCMBlockBufferAssureMemoryNowFlag, - blockBufferOut: &blockBuffer) - - var formatDescription: CMFormatDescription? - var basicDescription = AudioStreamBasicDescription( - mSampleRate: Float64(duration.timescale), - mFormatID: kAudioFormatLinearPCM, - mFormatFlags: 0, - mBytesPerPacket: 1, - mFramesPerPacket: 1, - mBytesPerFrame: 1, - mChannelsPerFrame: 1, - mBitsPerChannel: 8, - mReserved: 0) - - CMAudioFormatDescriptionCreate( - allocator: kCFAllocatorDefault, - asbd: &basicDescription, - layoutSize: 0, - layout: nil, - magicCookieSize: 0, - magicCookie: nil, - extensions: nil, - formatDescriptionOut: &formatDescription) - - var sampleBuffer: CMSampleBuffer? - CMAudioSampleBufferCreateReadyWithPacketDescriptions( - allocator: kCFAllocatorDefault, - dataBuffer: blockBuffer!, - formatDescription: formatDescription!, - sampleCount: CMItemCount(duration.value), - presentationTimeStamp: timestamp, - packetDescriptions: nil, - sampleBufferOut: &sampleBuffer) - - return sampleBuffer! - } - - static func createTestAudioOutput() -> AVCaptureOutput { - return AVCaptureAudioDataOutput() - } - - static func createTestConnection(_ output: AVCaptureOutput) -> AVCaptureConnection { - return AVCaptureConnection(inputPorts: [], output: output) - } -} - -extension XCTestCase { - /// Wait until a round trip of a given `DispatchQueue` is complete. This allows for testing - /// side-effects of async functions that do not provide any notification of completion. - func waitForQueueRoundTrip(with queue: DispatchQueue) { - let expectation = expectation(description: "Queue flush") - - queue.async { - if queue == DispatchQueue.main { - expectation.fulfill() - } else { - DispatchQueue.main.async { - expectation.fulfill() - } - } - } - - wait(for: [expectation], timeout: 1) - } - - func assertSuccess( - _ result: Result, file: StaticString = #file, line: UInt = #line - ) -> T? { - switch result { - case .success(let value): - return value - case .failure(let error): - XCTFail("Expected success, but got failure: \(error)", file: file, line: line) - return nil - } - } -} diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/ExceptionCatcher.h b/packages/camera/camera_avfoundation/example/ios/RunnerTests/ExceptionCatcher.h deleted file mode 100644 index 4c7ae95dac32..000000000000 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/ExceptionCatcher.h +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2013 The Flutter Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// TODO(FirentisTFW): Remove this file when the plugin code that uses it is migrated to Swift. -// After the migration, the code should throw Swift errors instead of Objective-C exceptions, thus -// this file will not be needed. - -#import - -NS_ASSUME_NONNULL_BEGIN - -/// A utility class for catching Objective-C exceptions. -/// -/// It allows to execute a block of code and catch any exceptions that are thrown during its -/// execution. This is useful for bridging between Objective-C and Swift code, as Swift does not -/// support catching Objective-C exceptions directly. -@interface ExceptionCatcher : NSObject -/// Executes a block of code and catches any exceptions that are thrown. -+ (nullable NSException *)catchException:(void (^)(void))tryBlock; -@end - -NS_ASSUME_NONNULL_END diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/ExceptionCatcher.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/ExceptionCatcher.m deleted file mode 100644 index febd9ac4f79d..000000000000 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/ExceptionCatcher.m +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2013 The Flutter Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#import "ExceptionCatcher.h" - -@implementation ExceptionCatcher -+ (nullable NSException *)catchException:(void (^)(void))tryBlock { - @try { - tryBlock(); - // No exception occurred. - return nil; - } @catch (NSException *exception) { - return exception; - } -} -@end diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamExposureTests.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamExposureTests.swift deleted file mode 100644 index 33ee0325b8e0..000000000000 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamExposureTests.swift +++ /dev/null @@ -1,146 +0,0 @@ -// Copyright 2013 The Flutter Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import XCTest - -@testable import camera_avfoundation - -final class FLTCamExposureTests: XCTestCase { - private func createCamera() -> (Camera, MockCaptureDevice, MockDeviceOrientationProvider) { - let mockDevice = MockCaptureDevice() - let mockDeviceOrientationProvider = MockDeviceOrientationProvider() - - let configuration = CameraTestUtils.createTestCameraConfiguration() - configuration.videoCaptureDeviceFactory = { _ in mockDevice } - configuration.deviceOrientationProvider = mockDeviceOrientationProvider - let camera = CameraTestUtils.createTestCamera(configuration) - - return (camera, mockDevice, mockDeviceOrientationProvider) - } - - func testSetExposureModeLocked_setsAuthExposeMode() { - let (camera, mockDevice, _) = createCamera() - - mockDevice.setExposureModeStub = { mode in - // AVCaptureExposureModeAutoExpose automatically adjusts the exposure one time, and then - // locks exposure for the device - XCTAssertEqual(mode, .autoExpose) - } - - camera.setExposureMode(.locked) - } - - func testSetExposureModeAuto_setsContinousAutoExposureMode_ifSupported() { - let (camera, mockDevice, _) = createCamera() - - // All exposure modes are supported - mockDevice.isExposureModeSupportedStub = { _ in true } - - mockDevice.setExposureModeStub = { mode in - XCTAssertEqual(mode, .continuousAutoExposure) - } - - camera.setExposureMode(.auto) - } - - func testSetExposureModeAuto_setsAutoExposeMode_ifContinousAutoIsNotSupported() { - let (camera, mockDevice, _) = createCamera() - - // Continous auto exposure is not supported - mockDevice.isExposureModeSupportedStub = { mode in - mode != .continuousAutoExposure - } - - mockDevice.setExposureModeStub = { mode in - XCTAssertEqual(mode, .autoExpose) - } - - camera.setExposureMode(.auto) - } - - func testSetExposurePoint_setsExposurePointOfInterest() { - let (camera, mockDevice, mockDeviceOrientationProvider) = createCamera() - // UI is currently in landscape left orientation. - mockDeviceOrientationProvider.orientationStub = { .landscapeLeft } - // Exposure point of interest is supported. - mockDevice.isExposurePointOfInterestSupported = true - - // Verify the focus point of interest has been set. - var setPoint = CGPoint.zero - mockDevice.setExposurePointOfInterestStub = { point in - if point == CGPoint(x: 1, y: 1) { - setPoint = point - } - } - - let expectation = expectation(description: "Completion called") - camera.setExposurePoint(PlatformPoint(x: 1, y: 1)) { - result in - let _ = self.assertSuccess(result) - expectation.fulfill() - } - - waitForExpectations(timeout: 30, handler: nil) - XCTAssertEqual(setPoint, CGPoint(x: 1.0, y: 1.0)) - } - - func testSetExposurePoint_returnsError_ifNotSupported() { - let (camera, mockDevice, mockDeviceOrientationProvider) = createCamera() - // UI is currently in landscape left orientation. - mockDeviceOrientationProvider.orientationStub = { .landscapeLeft } - // Exposure point of interest is not supported. - mockDevice.isExposurePointOfInterestSupported = false - - let expectation = expectation(description: "Completion with error") - - camera.setExposurePoint(PlatformPoint(x: 1, y: 1)) { result in - switch result { - case .failure(let error as PigeonError): - XCTAssertEqual(error.code, "setExposurePointFailed") - XCTAssertEqual(error.message, "Device does not have exposure point capabilities") - default: - XCTFail("Expected failure") - } - expectation.fulfill() - } - - waitForExpectations(timeout: 30, handler: nil) - } - - func testSetExposureOffset_setsExposureTargetBias() { - let (camera, mockDevice, _) = createCamera() - - let targetOffset = CGFloat(1.0) - - var setExposureTargetBiasCalled = false - mockDevice.setExposureTargetBiasStub = { bias, handler in - XCTAssertEqual(bias, Float(targetOffset)) - setExposureTargetBiasCalled = true - } - - camera.setExposureOffset(targetOffset) - - XCTAssertTrue(setExposureTargetBiasCalled) - } - - func testMaximumExposureOffset_returnsDeviceMaxExposureTargetBias() { - let (camera, mockDevice, _) = createCamera() - - let targetOffset = CGFloat(1.0) - - mockDevice.maxExposureTargetBias = Float(targetOffset) - - XCTAssertEqual(camera.maximumExposureOffset, targetOffset) - } - - func testMinimumExposureOffset_returnsDeviceMinExposureTargetBias() { - let (camera, mockDevice, _) = createCamera() - - let targetOffset = CGFloat(1.0) - - mockDevice.minExposureTargetBias = Float(targetOffset) - - XCTAssertEqual(camera.minimumExposureOffset, targetOffset) - } -} diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamFocusTests.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamFocusTests.swift deleted file mode 100644 index 00eaddf71faf..000000000000 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamFocusTests.swift +++ /dev/null @@ -1,166 +0,0 @@ -// Copyright 2013 The Flutter Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import AVFoundation -import XCTest - -@testable import camera_avfoundation - -final class FLTCamSetFocusModeTests: XCTestCase { - private func createCamera() -> (Camera, MockCaptureDevice, MockDeviceOrientationProvider) { - let mockDevice = MockCaptureDevice() - let mockDeviceOrientationProvider = MockDeviceOrientationProvider() - - let configuration = CameraTestUtils.createTestCameraConfiguration() - configuration.videoCaptureDeviceFactory = { _ in mockDevice } - configuration.deviceOrientationProvider = mockDeviceOrientationProvider - let camera = CameraTestUtils.createTestCamera(configuration) - - return (camera, mockDevice, mockDeviceOrientationProvider) - } - - func testAutoFocusWithContinuousModeSupported_ShouldSetContinuousAutoFocus() { - let (camera, mockDevice, _) = createCamera() - // AVCaptureFocusModeContinuousAutoFocus and AVCaptureFocusModeAutoFocus are supported. - mockDevice.isFocusModeSupportedStub = { mode in - mode == .continuousAutoFocus || mode == .autoFocus - } - - var setFocusModeContinuousAutoFocusCalled = false - - mockDevice.setFocusModeStub = { mode in - // Don't expect setFocusMode:AVCaptureFocusModeAutoFocus. - if mode == .autoFocus { - XCTFail("Unexpected call to setFocusMode") - } else if mode == .continuousAutoFocus { - setFocusModeContinuousAutoFocusCalled = true - } - } - - camera.setFocusMode(.auto) - - XCTAssertTrue(setFocusModeContinuousAutoFocusCalled) - } - - func testAutoFocusWithContinuousModeNotSupported_ShouldSetAutoFocus() { - let (camera, mockDevice, _) = createCamera() - // AVCaptureFocusModeContinuousAutoFocus is not supported. - // AVCaptureFocusModeAutoFocus is supported. - mockDevice.isFocusModeSupportedStub = { mode in - mode == .autoFocus - } - - var setFocusModeAutoFocusCalled = false - - // Don't expect setFocusMode:AVCaptureFocusModeContinuousAutoFocus. - mockDevice.setFocusModeStub = { mode in - if mode == .continuousAutoFocus { - XCTFail("Unexpected call to setFocusMode") - } else if mode == .autoFocus { - setFocusModeAutoFocusCalled = true - } - } - - camera.setFocusMode(.auto) - - XCTAssertTrue(setFocusModeAutoFocusCalled) - } - - func testAutoFocusWithNoModeSupported_ShouldSetNothing() { - let (camera, mockDevice, _) = createCamera() - // No modes are supported. - mockDevice.isFocusModeSupportedStub = { _ in - false - } - - // Don't expect any setFocus. - mockDevice.setFocusModeStub = { - _ in XCTFail("Unexpected call to setFocusMode") - } - - camera.setFocusMode(.auto) - } - - func testLockedFocusWithModeSupported_ShouldSetModeAutoFocus() { - let (camera, mockDevice, _) = createCamera() - // AVCaptureFocusModeContinuousAutoFocus and AVCaptureFocusModeAutoFocus are supported. - mockDevice.isFocusModeSupportedStub = { mode in - mode == .continuousAutoFocus || mode == .autoFocus - } - - var setFocusModeAutoFocusCalled = false - - // AVCaptureFocusModeAutoFocus automatically adjusts the focus one time, and then locks focus - mockDevice.setFocusModeStub = { mode in - if mode == .continuousAutoFocus { - XCTFail("Unexpected call to setFocusMode") - } else if mode == .autoFocus { - setFocusModeAutoFocusCalled = true - } - } - - camera.setFocusMode(.locked) - - XCTAssertTrue(setFocusModeAutoFocusCalled) - } - - func testLockedFocusWithModeNotSupported_ShouldSetNothing() { - let (camera, mockDevice, _) = createCamera() - mockDevice.isFocusModeSupportedStub = { mode in - mode == .continuousAutoFocus - } - - // Don't expect any setFocus. - mockDevice.setFocusModeStub = { _ in - XCTFail("Unexpected call to setFocusMode") - } - - camera.setFocusMode(.locked) - } - - func testSetFocusPointWithResult_SetsFocusPointOfInterest() { - let (camera, mockDevice, mockDeviceOrientationProvider) = createCamera() - // UI is currently in landscape left orientation. - mockDeviceOrientationProvider.orientationStub = { .landscapeLeft } - // Focus point of interest is supported. - mockDevice.isFocusPointOfInterestSupported = true - - var setFocusPointOfInterestCalled = false - mockDevice.setFocusPointOfInterestStub = { point in - if point == CGPoint(x: 1.0, y: 1.0) { - setFocusPointOfInterestCalled = true - } - } - - camera.setFocusPoint(PlatformPoint(x: 1, y: 1)) { - result in - let _ = self.assertSuccess(result) - } - - XCTAssertTrue(setFocusPointOfInterestCalled) - } - - func testSetFocusPoint_WhenNotSupported_ReturnsError() { - let (camera, mockDevice, mockDeviceOrientationProvider) = createCamera() - // UI is currently in landscape left orientation. - mockDeviceOrientationProvider.orientationStub = { .landscapeLeft } - // Focus point of interest is not supported. - mockDevice.isFocusPointOfInterestSupported = false - - let expectation = self.expectation(description: "Completion with error") - - camera.setFocusPoint(PlatformPoint(x: 1, y: 1)) { result in - switch result { - case .failure(let error as PigeonError): - XCTAssertEqual(error.code, "setFocusPointFailed") - XCTAssertEqual(error.message, "Device does not have focus point capabilities") - default: - XCTFail("Expected failure") - } - expectation.fulfill() - } - - waitForExpectations(timeout: 30, handler: nil) - } -} diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamSetDeviceOrientationTests.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamSetDeviceOrientationTests.swift deleted file mode 100644 index ab688c9f5933..000000000000 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamSetDeviceOrientationTests.swift +++ /dev/null @@ -1,108 +0,0 @@ -// Copyright 2013 The Flutter Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import AVFoundation -import XCTest - -@testable import camera_avfoundation - -final class FLTCamSetDeviceOrientationTests: XCTestCase { - private func createCamera() -> (Camera, MockCaptureConnection, MockCaptureConnection) { - let camera = CameraTestUtils.createTestCamera() - - let mockCapturePhotoOutput = MockCapturePhotoOutput() - let mockPhotoCaptureConnection = MockCaptureConnection() - mockPhotoCaptureConnection.isVideoOrientationSupported = true - - mockCapturePhotoOutput.connectionWithMediaTypeStub = { _ in mockPhotoCaptureConnection } - camera.capturePhotoOutput = mockCapturePhotoOutput - - let mockCaptureVideoDataOutput = MockCaptureVideoDataOutput() - let mockVideoCaptureConnection = MockCaptureConnection() - mockVideoCaptureConnection.isVideoOrientationSupported = true - - mockCaptureVideoDataOutput.connectionWithMediaTypeStub = { _ in mockVideoCaptureConnection } - camera.captureVideoOutput = mockCaptureVideoDataOutput - - return (camera, mockPhotoCaptureConnection, mockVideoCaptureConnection) - } - - func testSetDeviceOrientation_setsOrientationsOfCaptureConnections() { - let (camera, mockPhotoCaptureConnection, mockVideoCaptureConnection) = createCamera() - var photoSetVideoOrientationCalled = false - mockPhotoCaptureConnection.setVideoOrientationStub = { orientation in - // Device orientation is flipped compared to video orientation. When UIDeviceOrientation - // is landscape left the video orientation should be landscape right. - XCTAssertEqual(orientation, .landscapeRight) - photoSetVideoOrientationCalled = true - } - - var videoSetVideoOrientationCalled = false - mockVideoCaptureConnection.setVideoOrientationStub = { orientation in - // Device orientation is flipped compared to video orientation. When UIDeviceOrientation - // is landscape left the video orientation should be landscape right. - XCTAssertEqual(orientation, .landscapeRight) - videoSetVideoOrientationCalled = true - } - - camera.deviceOrientation = .landscapeLeft - - XCTAssertTrue(photoSetVideoOrientationCalled) - XCTAssertTrue(videoSetVideoOrientationCalled) - } - - func - testSetDeviceOrientation_setsLockedOrientationsOfCaptureConnection_ifCaptureOrientationIsLocked() - { - let (camera, mockPhotoCaptureConnection, mockVideoCaptureConnection) = createCamera() - var photoSetVideoOrientationCalled = false - mockPhotoCaptureConnection.setVideoOrientationStub = { orientation in - XCTAssertEqual(orientation, .portraitUpsideDown) - photoSetVideoOrientationCalled = true - } - - var videoSetVideoOrientationCalled = false - mockVideoCaptureConnection.setVideoOrientationStub = { orientation in - XCTAssertEqual(orientation, .portraitUpsideDown) - videoSetVideoOrientationCalled = true - } - - camera.lockCaptureOrientation(PlatformDeviceOrientation.portraitDown) - - camera.deviceOrientation = .landscapeLeft - - XCTAssertTrue(photoSetVideoOrientationCalled) - XCTAssertTrue(videoSetVideoOrientationCalled) - } - - func testSetDeviceOrientation_doesNotSetOrientations_ifRecordingIsInProgress() { - let (camera, mockPhotoCaptureConnection, mockVideoCaptureConnection) = createCamera() - - camera.startVideoRecording(completion: { _ in }, messengerForStreaming: nil) - - mockPhotoCaptureConnection.setVideoOrientationStub = { _ in XCTFail() } - mockVideoCaptureConnection.setVideoOrientationStub = { _ in XCTFail() } - - camera.deviceOrientation = .landscapeLeft - } - - func testSetDeviceOrientation_doesNotSetOrientations_forDuplicateUpdates() { - let (camera, mockPhotoCaptureConnection, mockVideoCaptureConnection) = createCamera() - var photoSetVideoOrientationCallCount = 0 - mockPhotoCaptureConnection.setVideoOrientationStub = { _ in - photoSetVideoOrientationCallCount += 1 - } - - var videoSetVideoOrientationCallCount = 0 - mockVideoCaptureConnection.setVideoOrientationStub = { _ in - videoSetVideoOrientationCallCount += 1 - } - - camera.deviceOrientation = .landscapeRight - camera.deviceOrientation = .landscapeRight - - XCTAssertEqual(photoSetVideoOrientationCallCount, 1) - XCTAssertEqual(videoSetVideoOrientationCallCount, 1) - } -} diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamSetFlashModeTests.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamSetFlashModeTests.swift deleted file mode 100644 index 0941a06d96e4..000000000000 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamSetFlashModeTests.swift +++ /dev/null @@ -1,168 +0,0 @@ -// Copyright 2013 The Flutter Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import AVFoundation -import XCTest - -@testable import camera_avfoundation - -final class FLTCamSetFlashModeTests: XCTestCase { - private func createCamera() -> (Camera, MockCaptureDevice, MockCapturePhotoOutput) { - let mockDevice = MockCaptureDevice() - let mockCapturePhotoOutput = MockCapturePhotoOutput() - - let configuration = CameraTestUtils.createTestCameraConfiguration() - configuration.videoCaptureDeviceFactory = { _ in mockDevice } - let camera = CameraTestUtils.createTestCamera(configuration) - camera.capturePhotoOutput = mockCapturePhotoOutput - - return (camera, mockDevice, mockCapturePhotoOutput) - } - - func testSetFlashModeWithTorchMode_setsTrochModeOn() { - let (camera, mockDevice, _) = createCamera() - - mockDevice.hasTorch = true - mockDevice.isTorchAvailable = true - - var setTorchModeCalled = false - mockDevice.setTorchModeStub = { torchMode in - XCTAssertEqual(torchMode, .on) - setTorchModeCalled = true - } - - let expectation = expectation(description: "Call completed") - - camera.setFlashMode(.torch) { - result in - let _ = self.assertSuccess(result) - expectation.fulfill() - } - - waitForExpectations(timeout: 30) - - XCTAssertTrue(setTorchModeCalled) - } - - func testSetFlashModeWithTorchMode_returnError_ifHasNoTorch() { - let (camera, mockDevice, _) = createCamera() - - mockDevice.hasTorch = false - - let expectation = expectation(description: "Call completed") - - camera.setFlashMode(.torch) { result in - switch result { - case .failure(let error as PigeonError): - XCTAssertEqual(error.code, "setFlashModeFailed") - XCTAssertEqual(error.message, "Device does not support torch mode") - default: - XCTFail("Expected failure") - } - expectation.fulfill() - } - - waitForExpectations(timeout: 30) - } - - func testSetFlashModeWithTorchMode_returnError_ifTorchIsNotAvailable() { - let (camera, mockDevice, _) = createCamera() - - mockDevice.hasTorch = true - mockDevice.isTorchAvailable = false - - let expectation = expectation(description: "Call completed") - - camera.setFlashMode(.torch) { result in - switch result { - case .failure(let error as PigeonError): - XCTAssertEqual(error.code, "setFlashModeFailed") - XCTAssertEqual(error.message, "Torch mode is currently not available") - default: - XCTFail("Expected failure") - } - expectation.fulfill() - } - - waitForExpectations(timeout: 30) - } - - func testSetFlashModeWithNonTorchMode_setsTrochModeOff_ifTorchModeIsEnabled() { - let (camera, mockDevice, mockCapturePhotoOutput) = createCamera() - - mockCapturePhotoOutput.supportedFlashModes = [.auto] - - mockDevice.hasFlash = true - // Torch mode is enabled - mockDevice.getTorchModeStub = { .on } - - var setTorchModeCalled = false - mockDevice.setTorchModeStub = { torchMode in - XCTAssertEqual(torchMode, .off) - setTorchModeCalled = true - } - - let expectation = expectation(description: "Call completed") - - camera.setFlashMode(.auto) { - result in - switch result { - case .success: - break - case .failure: - XCTFail("Unexpected failure") - } - expectation.fulfill() - } - - waitForExpectations(timeout: 30) - - XCTAssertTrue(setTorchModeCalled) - } - - func testSetFlashModeWithNonTorchMode_returnError_ifHasNoFlash() { - let (camera, mockDevice, _) = createCamera() - - mockDevice.hasFlash = false - - let expectation = expectation(description: "Call completed") - - camera.setFlashMode(.auto) { result in - switch result { - case .failure(let error as PigeonError): - XCTAssertEqual(error.code, "setFlashModeFailed") - XCTAssertEqual(error.message, "Device does not have flash capabilities") - default: - XCTFail("Expected failure") - } - expectation.fulfill() - } - - waitForExpectations(timeout: 30) - } - - func testSetFlashModeWithNonTorchMode_returnError_ifModeIsNotSupported() { - let (camera, mockDevice, mockCapturePhotoOutput) = createCamera() - - // No flash modes are supported - mockCapturePhotoOutput.supportedFlashModes = [] - - mockDevice.hasFlash = true - - let expectation = expectation(description: "Call completed") - - camera.setFlashMode(.auto) { result in - switch result { - case .failure(let error as PigeonError): - XCTAssertEqual(error.code, "setFlashModeFailed") - XCTAssertEqual(error.message, "Device does not support this specific flash mode") - default: - XCTFail("Expected failure") - } - expectation.fulfill() - } - - waitForExpectations(timeout: 30) - } -} diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamZoomTests.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamZoomTests.swift deleted file mode 100644 index 46f302058b06..000000000000 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamZoomTests.swift +++ /dev/null @@ -1,111 +0,0 @@ -// Copyright 2013 The Flutter Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import AVFoundation -import XCTest - -@testable import camera_avfoundation - -final class FLTCamZoomTests: XCTestCase { - private func createCamera() -> (Camera, MockCaptureDevice) { - let mockDevice = MockCaptureDevice() - - let configuration = CameraTestUtils.createTestCameraConfiguration() - configuration.videoCaptureDeviceFactory = { _ in mockDevice } - let camera = CameraTestUtils.createTestCamera(configuration) - - return (camera, mockDevice) - } - - func testSetZoomLevel_setVideoZoomFactor() { - let (camera, mockDevice) = createCamera() - - mockDevice.maxAvailableVideoZoomFactor = 2.0 - mockDevice.minAvailableVideoZoomFactor = 0.0 - - let targetZoom = CGFloat(1.0) - - var setVideoZoomFactorCalled = false - mockDevice.setVideoZoomFactorStub = { zoom in - XCTAssertEqual(zoom, targetZoom) - setVideoZoomFactorCalled = true - } - - let expectation = expectation(description: "Call completed") - - camera.setZoomLevel(targetZoom) { - result in - let _ = self.assertSuccess(result) - expectation.fulfill() - } - - waitForExpectations(timeout: 30) - - XCTAssertTrue(setVideoZoomFactorCalled) - } - - func testSetZoomLevel_returnsError_forZoomLevelBlowMinimum() { - let (camera, mockDevice) = createCamera() - - // Allowed zoom range between 2.0 and 3.0 - mockDevice.maxAvailableVideoZoomFactor = 2.0 - mockDevice.minAvailableVideoZoomFactor = 3.0 - - let expectation = expectation(description: "Call completed") - - camera.setZoomLevel(CGFloat(1.0)) { result in - switch result { - case .failure(let error as PigeonError): - XCTAssertEqual(error.code, "ZOOM_ERROR") - default: - XCTFail("Expected failure") - } - expectation.fulfill() - } - - waitForExpectations(timeout: 30) - } - - func testSetZoomLevel_returnsError_forZoomLevelAboveMaximum() { - let (camera, mockDevice) = createCamera() - - // Allowed zoom range between 0.0 and 1.0 - mockDevice.maxAvailableVideoZoomFactor = 0.0 - mockDevice.minAvailableVideoZoomFactor = 1.0 - - let expectation = expectation(description: "Call completed") - - camera.setZoomLevel(CGFloat(2.0)) { result in - switch result { - case .failure(let error as PigeonError): - XCTAssertEqual(error.code, "ZOOM_ERROR") - default: - XCTFail("Expected failure") - } - expectation.fulfill() - } - - waitForExpectations(timeout: 30) - } - - func testMaximumAvailableZoomFactor_returnsDeviceMaxAvailableVideoZoomFactor() { - let (camera, mockDevice) = createCamera() - - let targetZoom = CGFloat(1.0) - - mockDevice.maxAvailableVideoZoomFactor = CGFloat(targetZoom) - - XCTAssertEqual(camera.maximumAvailableZoomFactor, targetZoom) - } - - func testMinimumAvailableZoomFactor_returnsDeviceMinAvailableVideoZoomFactor() { - let (camera, mockDevice) = createCamera() - - let targetZoom = CGFloat(1.0) - - mockDevice.minAvailableVideoZoomFactor = CGFloat(targetZoom) - - XCTAssertEqual(camera.minimumAvailableZoomFactor, targetZoom) - } -} diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Info.plist b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Info.plist deleted file mode 100644 index 64d65ca49577..000000000000 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Info.plist +++ /dev/null @@ -1,22 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - $(PRODUCT_BUNDLE_PACKAGE_TYPE) - CFBundleShortVersionString - 1.0 - CFBundleVersion - 1 - - diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockAssetWriter.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockAssetWriter.swift deleted file mode 100644 index 2b345c00b3ab..000000000000 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockAssetWriter.swift +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2013 The Flutter Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import AVFoundation - -@testable import camera_avfoundation - -/// Mock implementation of `AssetWriter` protocol which allows injecting a custom -/// implementation. -final class MockAssetWriter: NSObject, AssetWriter { - var statusStub: (() -> AVAssetWriter.Status)? - var startWritingStub: (() -> Bool)? - var finishWritingStub: ((() -> Void) -> Void)? - - var status: AVAssetWriter.Status { - return statusStub?() ?? .unknown - } - - var error: Error? = nil - - func startWriting() -> Bool { - return startWritingStub?() ?? true - } - - func finishWriting(completionHandler handler: @escaping () -> Void) { - finishWritingStub?(handler) - } - - func startSession(atSourceTime startTime: CMTime) {} - - func add(_ input: AVAssetWriterInput) {} -} diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockAssetWriterInput.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockAssetWriterInput.swift deleted file mode 100644 index 9e70646e2fb1..000000000000 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockAssetWriterInput.swift +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2013 The Flutter Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import AVFoundation - -@testable import camera_avfoundation - -/// Mock implementation of `AssetWriterInput` protocol which allows injecting a custom -/// implementation. -final class MockAssetWriterInput: NSObject, AssetWriterInput { - var appendStub: ((CMSampleBuffer) -> Bool)? - - var avInput: AVAssetWriterInput { - preconditionFailure("Attempted to access unimplemented property: avInput") - } - - var expectsMediaDataInRealTime = false - - var isReadyForMoreMediaData = false - - func append(_ sampleBuffer: CMSampleBuffer) -> Bool { - return appendStub?(sampleBuffer) ?? false - } -} diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockAssetWriterInputPixelBufferAdaptor.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockAssetWriterInputPixelBufferAdaptor.swift deleted file mode 100644 index a27106e3a0a7..000000000000 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockAssetWriterInputPixelBufferAdaptor.swift +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2013 The Flutter Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import AVFoundation - -@testable import camera_avfoundation - -/// Mock implementation of `AssetWriterInputPixelBufferAdaptor` protocol which allows injecting a custom -/// implementation. -final class MockAssetWriterInputPixelBufferAdaptor: NSObject, AssetWriterInputPixelBufferAdaptor { - var appendStub: ((CVPixelBuffer, CMTime) -> Bool)? - - func append(_ pixelBuffer: CVPixelBuffer, withPresentationTime presentationTime: CMTime) -> Bool { - appendStub?(pixelBuffer, presentationTime) ?? true - } -} diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCamera.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCamera.swift deleted file mode 100644 index ec6e6fd88f9c..000000000000 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCamera.swift +++ /dev/null @@ -1,233 +0,0 @@ -// Copyright 2013 The Flutter Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import AVFoundation -import Flutter - -@testable import camera_avfoundation - -final class MockCamera: NSObject, Camera { - var setDartApiStub: ((CameraEventApi?) -> Void)? - var setOnFrameAvailableStub: (((() -> Void)?) -> Void)? - var getMinimumExposureOffsetStub: (() -> CGFloat)? - var getMaximumExposureOffsetStub: (() -> CGFloat)? - var getMinimumAvailableZoomFactorStub: (() -> CGFloat)? - var getMaximumAvailableZoomFactorStub: (() -> CGFloat)? - var setUpCaptureSessionForAudioIfNeededStub: (() -> Void)? - var receivedImageStreamDataStub: (() -> Void)? - var startStub: (() -> Void)? - var startVideoRecordingStub: - ((@escaping (Result) -> Void, FlutterBinaryMessenger?) -> Void)? - var pauseVideoRecordingStub: (() -> Void)? - var resumeVideoRecordingStub: (() -> Void)? - var stopVideoRecordingStub: ((@escaping (Result) -> Void) -> Void)? - var captureToFileStub: ((@escaping (Result) -> Void) -> Void)? - var setDeviceOrientationStub: ((UIDeviceOrientation) -> Void)? - var lockCaptureOrientationStub: ((PlatformDeviceOrientation) -> Void)? - var unlockCaptureOrientationStub: (() -> Void)? - var setImageFileFormatStub: ((PlatformImageFileFormat) -> Void)? - var setExposureModeStub: ((PlatformExposureMode) -> Void)? - var setExposureOffsetStub: ((Double) -> Void)? - var setExposurePointStub: ((PlatformPoint?, @escaping (Result) -> Void) -> Void)? - var setFocusModeStub: ((PlatformFocusMode) -> Void)? - var setFocusPointStub: ((PlatformPoint?, @escaping (Result) -> Void) -> Void)? - var setZoomLevelStub: ((CGFloat, @escaping (Result) -> Void) -> Void)? - var setFlashModeStub: ((PlatformFlashMode, @escaping (Result) -> Void) -> Void)? - var pausePreviewStub: (() -> Void)? - var resumePreviewStub: (() -> Void)? - var setDescriptionWhileRecordingStub: - ((String, @escaping (Result) -> Void) -> Void)? - var startImageStreamStub: - ((FlutterBinaryMessenger, @escaping (Result) -> Void) -> Void)? - var stopImageStreamStub: (() -> Void)? - var setVideoStabilizationModeStub: - ((PlatformVideoStabilizationMode, @escaping (Result) -> Void) -> Void)? - var getIsVideoStabilizationModeSupportedStub: ((PlatformVideoStabilizationMode) -> Bool)? - - var dartAPI: CameraEventApi? { - get { - preconditionFailure("Attempted to access unimplemented property: dartAPI") - } - set { - setDartApiStub?(newValue) - } - } - - var onFrameAvailable: (() -> Void)? { - get { - preconditionFailure("Attempted to access unimplemented property: onFrameAvailable") - } - set { - setOnFrameAvailableStub?(newValue) - } - } - - var videoFormat: FourCharCode = kCVPixelFormatType_32BGRA - - var isPreviewPaused: Bool = false - var isStreamingImages: Bool = false - - var deviceOrientation: UIDeviceOrientation { - get { - preconditionFailure("Attempted to access unimplemented property: deviceOrientation") - } - set { - setDeviceOrientationStub?(newValue) - } - } - - var minimumExposureOffset: CGFloat { - return getMinimumExposureOffsetStub?() ?? 0 - } - - var maximumExposureOffset: CGFloat { - return getMaximumExposureOffsetStub?() ?? 0 - } - - var minimumAvailableZoomFactor: CGFloat { - return getMinimumAvailableZoomFactorStub?() ?? 0 - } - - var maximumAvailableZoomFactor: CGFloat { - return getMaximumAvailableZoomFactorStub?() ?? 0 - } - - func setUpCaptureSessionForAudioIfNeeded() { - setUpCaptureSessionForAudioIfNeededStub?() - } - - func reportInitializationState() {} - - func receivedImageStreamData() { - receivedImageStreamDataStub?() - } - - func start() { - startStub?() - } - - func stop() {} - - func startVideoRecording( - completion: @escaping (Result) -> Void, - messengerForStreaming messenger: FlutterBinaryMessenger? - ) { - startVideoRecordingStub?(completion, messenger) - } - - func pauseVideoRecording() { - pauseVideoRecordingStub?() - } - - func resumeVideoRecording() { - resumeVideoRecordingStub?() - } - - func stopVideoRecording(completion: @escaping (Result) -> Void) { - stopVideoRecordingStub?(completion) - } - - func captureToFile(completion: @escaping (Result) -> Void) { - captureToFileStub?(completion) - } - - func lockCaptureOrientation(_ orientation: PlatformDeviceOrientation) { - lockCaptureOrientationStub?(orientation) - } - - func unlockCaptureOrientation() { - unlockCaptureOrientationStub?() - } - - func setImageFileFormat(_ fileFormat: PlatformImageFileFormat) { - setImageFileFormatStub?(fileFormat) - } - - func setExposureMode(_ mode: PlatformExposureMode) { - setExposureModeStub?(mode) - } - - func setExposureOffset(_ offset: Double) { - setExposureOffsetStub?(offset) - } - - func setExposurePoint( - _ point: PlatformPoint?, withCompletion: @escaping (Result) -> Void - ) { - setExposurePointStub?(point, withCompletion) - } - - func setFocusMode(_ mode: PlatformFocusMode) { - setFocusModeStub?(mode) - } - - func setFocusPoint( - _ point: PlatformPoint?, completion: @escaping (Result) -> Void - ) { - setFocusPointStub?(point, completion) - } - - func setZoomLevel( - _ zoom: CGFloat, - withCompletion completion: @escaping (Result) -> Void - ) { - setZoomLevelStub?(zoom, completion) - } - - func setFlashMode( - _ mode: PlatformFlashMode, - withCompletion completion: @escaping (Result) -> Void - ) { - setFlashModeStub?(mode, completion) - } - - func pausePreview() { - pausePreviewStub?() - } - - func resumePreview() { - resumePreviewStub?() - } - - func setVideoStabilizationMode( - _ mode: PlatformVideoStabilizationMode, - withCompletion completion: @escaping (Result) -> Void - ) { - setVideoStabilizationModeStub?(mode, completion) - } - - func isVideoStabilizationModeSupported(_ mode: PlatformVideoStabilizationMode) -> Bool { - return getIsVideoStabilizationModeSupportedStub?(mode) ?? false - } - - func setDescriptionWhileRecording( - _ cameraName: String, - withCompletion completion: @escaping (Result) -> Void - ) { - setDescriptionWhileRecordingStub?(cameraName, completion) - } - - func startImageStream( - with messenger: FlutterBinaryMessenger, - completion: @escaping (Result) -> Void - ) { - startImageStreamStub?(messenger, completion) - } - - func stopImageStream() { - stopImageStreamStub?() - } - - func captureOutput( - _ output: AVCaptureOutput, - didOutput sampleBuffer: CMSampleBuffer, - from connection: AVCaptureConnection - ) {} - - func close() {} - - func copyPixelBuffer() -> Unmanaged? { - return nil - } -} diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCameraDeviceDiscoverer.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCameraDeviceDiscoverer.swift deleted file mode 100644 index 972f34ab8d5e..000000000000 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCameraDeviceDiscoverer.swift +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2013 The Flutter Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import AVFoundation - -@testable import camera_avfoundation - -/// Mock implementation of `FLTCameraDeviceDiscoverer` protocol which allows injecting a custom -/// implementation for session discovery. -final class MockCameraDeviceDiscoverer: NSObject, CameraDeviceDiscoverer { - var discoverySessionStub: - ( - ( - _ deviceTypes: [AVCaptureDevice.DeviceType], - _ mediaType: AVMediaType, - _ position: AVCaptureDevice.Position - ) -> [NSObject & CaptureDevice]? - )? - - /// A stub that replaces the default implementation of - /// `discoverySessionWithDeviceTypes:mediaType:position`. - func discoverySession( - withDeviceTypes deviceTypes: [AVCaptureDevice.DeviceType], mediaType: AVMediaType, - position: AVCaptureDevice.Position - ) -> [CaptureDevice] { - return discoverySessionStub?(deviceTypes, mediaType, position) ?? [] - } -} diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureConnection.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureConnection.swift deleted file mode 100644 index d6ea85f20e29..000000000000 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureConnection.swift +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright 2013 The Flutter Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import AVFoundation - -@testable import camera_avfoundation - -/// A mock implementation of `CaptureConnection` that allows injecting a custom implementation. -final class MockCaptureConnection: NSObject, CaptureConnection { - var setVideoOrientationStub: ((AVCaptureVideoOrientation) -> Void)? - - var connection: AVCaptureConnection { - preconditionFailure("Attempted to access unimplemented property: connection") - } - var isVideoMirrored = false - var videoOrientation: AVCaptureVideoOrientation { - get { AVCaptureVideoOrientation.portrait } - set { - setVideoOrientationStub?(newValue) - } - } - var inputPorts: [AVCaptureInput.Port] = [] - var isVideoMirroringSupported = false - var isVideoOrientationSupported = false - var preferredVideoStabilizationMode = AVCaptureVideoStabilizationMode.off -} diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDevice.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDevice.swift deleted file mode 100644 index be6fc7dca28a..000000000000 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDevice.swift +++ /dev/null @@ -1,127 +0,0 @@ -// Copyright 2013 The Flutter Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import AVFoundation - -@testable import camera_avfoundation - -/// A mock implementation of `FLTCaptureDevice` that allows mocking the class -/// properties. -class MockCaptureDevice: NSObject, CaptureDevice { - var activeFormatStub: (() -> CaptureDeviceFormat)? - var setActiveFormatStub: ((CaptureDeviceFormat) -> Void)? - var getTorchModeStub: (() -> AVCaptureDevice.TorchMode)? - var setTorchModeStub: ((AVCaptureDevice.TorchMode) -> Void)? - var isFocusModeSupportedStub: ((AVCaptureDevice.FocusMode) -> Bool)? - var setFocusModeStub: ((AVCaptureDevice.FocusMode) -> Void)? - var setFocusPointOfInterestStub: ((CGPoint) -> Void)? - var setExposureModeStub: ((AVCaptureDevice.ExposureMode) -> Void)? - var setExposurePointOfInterestStub: ((CGPoint) -> Void)? - var setExposureTargetBiasStub: ((Float, ((CMTime) -> Void)?) -> Void)? - var isExposureModeSupportedStub: ((AVCaptureDevice.ExposureMode) -> Bool)? - var setVideoZoomFactorStub: ((CGFloat) -> Void)? - var lockForConfigurationStub: (() throws -> Void)? - - var avDevice: AVCaptureDevice { - preconditionFailure("Attempted to access unimplemented property: device") - } - - var uniqueID = "" - var position = AVCaptureDevice.Position.unspecified - var deviceType = AVCaptureDevice.DeviceType.builtInWideAngleCamera - - var flutterActiveFormat: CaptureDeviceFormat { - get { - activeFormatStub?() ?? MockCaptureDeviceFormat() - } - set { - setActiveFormatStub?(newValue) - } - } - - var flutterFormats: [CaptureDeviceFormat] = [] - var hasFlash = false - var hasTorch = false - var isTorchAvailable = false - var torchMode: AVCaptureDevice.TorchMode { - get { - getTorchModeStub?() ?? .off - } - set { - setTorchModeStub?(newValue) - } - } - var isFocusPointOfInterestSupported = false - var maxAvailableVideoZoomFactor = CGFloat(0) - var minAvailableVideoZoomFactor = CGFloat(0) - var videoZoomFactor: CGFloat { - get { 0 } - set { - setVideoZoomFactorStub?(newValue) - } - } - var isExposurePointOfInterestSupported = false - var minExposureTargetBias = Float(0) - var maxExposureTargetBias = Float(0) - var activeVideoMinFrameDuration = CMTime(value: 1, timescale: 1) - var activeVideoMaxFrameDuration = CMTime(value: 1, timescale: 1) - - func isFlashModeSupported(_ mode: AVCaptureDevice.FlashMode) -> Bool { - return false - } - - func isFocusModeSupported(_ mode: AVCaptureDevice.FocusMode) -> Bool { - return isFocusModeSupportedStub?(mode) ?? false - } - - var focusMode: AVCaptureDevice.FocusMode { - get { .autoFocus } - set { setFocusModeStub?(newValue) } - } - - func setFocusMode(_ focusMode: AVCaptureDevice.FocusMode) { - setFocusModeStub?(focusMode) - } - - var focusPointOfInterest: CGPoint { - get { CGPoint.zero } - set { setFocusPointOfInterestStub?(newValue) } - } - - var exposureMode: AVCaptureDevice.ExposureMode { - get { .autoExpose } - set { setExposureModeStub?(newValue) } - } - - var exposurePointOfInterest: CGPoint { - get { CGPoint.zero } - set { setExposurePointOfInterestStub?(newValue) } - } - - func setExposureTargetBias(_ bias: Float, completionHandler handler: ((CMTime) -> Void)? = nil) { - setExposureTargetBiasStub?(bias, handler) - } - - func isExposureModeSupported(_ mode: AVCaptureDevice.ExposureMode) -> Bool { - return isExposureModeSupportedStub?(mode) ?? false - } - - var lensAperture: Float { 1.8 } - - var exposureDuration: CMTime { CMTime(value: 1, timescale: 1) } - - var iso: Float { 100 } - - func isVideoStabilizationModeSupported(_ videoStabilizationMode: AVCaptureVideoStabilizationMode) - -> Bool - { - return false - } - - func lockForConfiguration() throws { - try lockForConfigurationStub?() - } - - func unlockForConfiguration() {} -} diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDeviceFormat.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDeviceFormat.swift deleted file mode 100644 index 557ff4ba7ca2..000000000000 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDeviceFormat.swift +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2013 The Flutter Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import AVFoundation - -@testable import camera_avfoundation - -/// A mock implementation of `CaptureDeviceFormat` that allows mocking the class -/// properties. -final class MockCaptureDeviceFormat: NSObject, CaptureDeviceFormat { - - /// The format associated with the capture device. - var avFormat: AVCaptureDevice.Format { - preconditionFailure("Attempted to access unimplemented property: avFormat") - } - - var _formatDescription: CMVideoFormatDescription? - - /// The format description for the capture device. - var formatDescription: CMFormatDescription { - _formatDescription! - } - - /// The array of frame rate ranges supported by the video format. - var flutterVideoSupportedFrameRateRanges: [FrameRateRange] = [] - - override init() { - super.init() - - CMVideoFormatDescriptionCreate( - allocator: kCFAllocatorDefault, codecType: kCVPixelFormatType_32BGRA, width: 1920, - height: 1080, extensions: nil, formatDescriptionOut: &_formatDescription) - } - - init(codecType: OSType, width: Int32, height: Int32) { - super.init() - - CMVideoFormatDescriptionCreate( - allocator: kCFAllocatorDefault, codecType: codecType, width: width, - height: height, extensions: nil, formatDescriptionOut: &_formatDescription) - } -} diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDeviceInputFactory.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDeviceInputFactory.swift deleted file mode 100644 index 9292b6256d7c..000000000000 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDeviceInputFactory.swift +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2013 The Flutter Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -@testable import camera_avfoundation - -///// A mocked implementation of FLTCaptureDeviceInputFactory which allows injecting a custom -///// implementation. -final class MockCaptureDeviceInputFactory: NSObject, CaptureDeviceInputFactory { - func deviceInput(with device: CaptureDevice) throws -> CaptureInput { - return MockCaptureInput() - } -} diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureInput.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureInput.swift deleted file mode 100644 index 74d8742bd161..000000000000 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureInput.swift +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2013 The Flutter Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import AVFoundation - -@testable import camera_avfoundation - -/// A mocked implementation of FLTCaptureInput which allows injecting a custom -/// implementation. -final class MockCaptureInput: NSObject, CaptureInput { - var avInput: AVCaptureInput { - preconditionFailure("Attempted to access unimplemented property: input") - } - - var ports: [AVCaptureInput.Port] = [] -} diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCapturePhotoOutput.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCapturePhotoOutput.swift deleted file mode 100644 index a0b2faee8c00..000000000000 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCapturePhotoOutput.swift +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright 2013 The Flutter Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import AVFoundation - -@testable import camera_avfoundation - -/// Mock implementation of `FLTCapturePhotoOutput` protocol which allows injecting a custom -/// implementation. -final class MockCapturePhotoOutput: NSObject, CapturePhotoOutput { - var avOutput = AVCapturePhotoOutput() - var availablePhotoCodecTypes: [AVVideoCodecType] = [] - var isHighResolutionCaptureEnabled = false - var supportedFlashModes: [AVCaptureDevice.FlashMode] = [] - - // Stub that is called when the corresponding public method is called. - var capturePhotoWithSettingsStub: - ((_ settings: AVCapturePhotoSettings, _ delegate: AVCapturePhotoCaptureDelegate) -> Void)? - - // Stub that is called when the corresponding public method is called. - var connectionWithMediaTypeStub: ((_ mediaType: AVMediaType) -> CaptureConnection?)? - - func capturePhoto(with settings: AVCapturePhotoSettings, delegate: AVCapturePhotoCaptureDelegate) - { - capturePhotoWithSettingsStub?(settings, delegate) - } - - func connection(with mediaType: AVMediaType) -> CaptureConnection? { - return connectionWithMediaTypeStub?(mediaType) - } -} diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureSession.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureSession.swift deleted file mode 100644 index 08d2427b4438..000000000000 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureSession.swift +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright 2013 The Flutter Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import AVFoundation - -@testable import camera_avfoundation - -/// Mock implementation of `FLTCaptureSession` protocol which allows injecting a custom -/// implementation. -final class MockCaptureSession: NSObject, CaptureSession { - var setSessionPresetStub: ((AVCaptureSession.Preset) -> Void)? - var beginConfigurationStub: (() -> Void)? - var commitConfigurationStub: (() -> Void)? - var startRunningStub: (() -> Void)? - var stopRunningStub: (() -> Void)? - var canSetSessionPresetStub: ((AVCaptureSession.Preset) -> Bool)? - - var _sessionPreset = AVCaptureSession.Preset.high - var inputs = [AVCaptureInput]() - var outputs = [AVCaptureOutput]() - - private(set) var addedAudioOutputCount: Int = 0 - - var automaticallyConfiguresApplicationAudioSession = false - var isRunning = true - - var sessionPreset: AVCaptureSession.Preset { - get { - return _sessionPreset - } - set { - setSessionPresetStub?(newValue) - } - } - - func beginConfiguration() { - beginConfigurationStub?() - } - - func commitConfiguration() { - commitConfigurationStub?() - } - - func startRunning() { - startRunningStub?() - } - - func stopRunning() { - stopRunningStub?() - } - - func canSetSessionPreset(_ preset: AVCaptureSession.Preset) -> Bool { - return canSetSessionPresetStub?(preset) ?? true - } - - func addInputWithNoConnections(_ input: CaptureInput) {} - - func addOutputWithNoConnections(_ output: AVCaptureOutput) {} - - func addConnection(_: AVCaptureConnection) {} - - func addInput(_: CaptureInput) {} - - func addOutput(_ output: AVCaptureOutput) { - - if output is AVCaptureAudioDataOutput { - addedAudioOutputCount += 1 - } - } - - func removeInput(_: CaptureInput) {} - - func removeOutput(_: AVCaptureOutput) {} - - func canAddInput(_: CaptureInput) -> Bool { - return true - } - - func canAddOutput(_: AVCaptureOutput) -> Bool { - return true - } - - func canAddConnection(_: AVCaptureConnection) -> Bool { - return true - } -} diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureVideoDataOutput.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureVideoDataOutput.swift deleted file mode 100644 index c36397321201..000000000000 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureVideoDataOutput.swift +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright 2013 The Flutter Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import AVFoundation - -@testable import camera_avfoundation - -/// Mock implementation of `FLTCaptureVideoDataOutput` protocol which allows injecting a custom -/// implementation. -class MockCaptureVideoDataOutput: NSObject, CaptureVideoDataOutput { - var avOutput = AVCaptureVideoDataOutput() - var alwaysDiscardsLateVideoFrames = false - var videoSettings: [String: Any]! = [:] - var availableVideoPixelFormatTypes: [FourCharCode] = [] - - var connectionWithMediaTypeStub: ((AVMediaType) -> CaptureConnection?)? - - func connection(with mediaType: AVMediaType) -> CaptureConnection? { - return connectionWithMediaTypeStub?(mediaType) - } - - func setSampleBufferDelegate( - _ sampleBufferDelegate: AVCaptureVideoDataOutputSampleBufferDelegate?, - queue sampleBufferCallbackQueue: DispatchQueue? - ) {} -} diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockDeviceOrientationProvider.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockDeviceOrientationProvider.swift deleted file mode 100644 index 034eafc4d184..000000000000 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockDeviceOrientationProvider.swift +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2013 The Flutter Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import UIKit - -@testable import camera_avfoundation - -final class MockDeviceOrientationProvider: NSObject, DeviceOrientationProvider { - var orientationStub: (() -> UIDeviceOrientation)? - - var orientation: UIDeviceOrientation { - return orientationStub?() ?? .unknown - } -} diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockFLTCameraPermissionManager.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockFLTCameraPermissionManager.swift deleted file mode 100644 index 73f991f43a38..000000000000 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockFLTCameraPermissionManager.swift +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright 2013 The Flutter Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import Flutter - -@testable import camera_avfoundation - -final class MockCameraPermissionManager: CameraPermissionManager { - var requestCameraPermissionStub: ((@escaping CameraPermissionRequestCompletionHandler) -> Void)? - var requestAudioPermissionStub: ((@escaping CameraPermissionRequestCompletionHandler) -> Void)? - - init() { - super.init(permissionService: DefaultPermissionService()) - } - - override func requestCameraPermission(completionHandler: @escaping (PigeonError?) -> Void) { - if let stub = requestCameraPermissionStub { - stub(completionHandler) - } else { - super.requestCameraPermission(completionHandler: completionHandler) - } - } - - override func requestAudioPermission(completionHandler: @escaping (PigeonError?) -> Void) { - if let stub = requestAudioPermissionStub { - stub(completionHandler) - } else { - super.requestAudioPermission(completionHandler: completionHandler) - } - } -} diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockFlutterBinaryMessenger.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockFlutterBinaryMessenger.swift deleted file mode 100644 index 7aad9804a1ba..000000000000 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockFlutterBinaryMessenger.swift +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright 2013 The Flutter Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import Flutter - -/// Mocked implementation of `FlutterBinaryMessenger` protocol that exists to allow constructing -/// a `CameraPlugin` instance for testing. It contains an empty implementation for all protocol -/// methods. -final class MockFlutterBinaryMessenger: NSObject, FlutterBinaryMessenger { - func send(onChannel channel: String, message: Data?) {} - - func send( - onChannel channel: - String, - message: - Data?, binaryReply callback: FlutterBinaryReply? = nil - ) {} - - func setMessageHandlerOnChannel( - _ channel: String, - binaryMessageHandler handler: FlutterBinaryMessageHandler? = nil - ) -> FlutterBinaryMessengerConnection { 0 } - - func cleanUpConnection(_ connection: FlutterBinaryMessengerConnection) {} -} diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockFlutterTextureRegistry.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockFlutterTextureRegistry.swift deleted file mode 100644 index a798e55cced6..000000000000 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockFlutterTextureRegistry.swift +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2013 The Flutter Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import Flutter - -/// Mocked implementation of `FlutterTextureRegistry` protocol that exists to allow constructing -/// a `CameraPlugin` instance for testing. It contains an empty implementation for all protocol -/// methods. -final class MockFlutterTextureRegistry: NSObject, FlutterTextureRegistry { - func register(_ texture: FlutterTexture) -> Int64 { 0 } - - func textureFrameAvailable(_ textureId: Int64) {} - - func unregisterTexture(_ textureId: Int64) {} -} diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockFrameRateRange.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockFrameRateRange.swift deleted file mode 100644 index 1130a35937e7..000000000000 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockFrameRateRange.swift +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2013 The Flutter Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -@testable import camera_avfoundation - -/// A mock implementation of `FrameRateRange` that allows mocking the class properties. -final class MockFrameRateRange: NSObject, FrameRateRange { - var minFrameRate: Float64 - var maxFrameRate: Float64 - - /// Initializes a `MockFrameRateRange` with the given frame rate range. - init(minFrameRate: Float64, maxFrameRate: Float64) { - self.minFrameRate = minFrameRate - self.maxFrameRate = maxFrameRate - } -} diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockGlobalEventApi.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockGlobalEventApi.swift deleted file mode 100644 index 1a95e4278216..000000000000 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockGlobalEventApi.swift +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright 2013 The Flutter Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import Flutter - -@testable import camera_avfoundation - -/// A mock implementation of `CameraGlobalEventApi` that captures received -/// `deviceOrientationChanged` events and exposes whether they were received to the testing code. -final class MockGlobalEventApi: CameraGlobalEventApiProtocol { - /// Whether the `deviceOrientationChanged` callback was called. - var deviceOrientationChangedCalled = false - - /// The last orientation received by the `deviceOrientationChanged` callback. - var lastOrientation = PlatformDeviceOrientation.portraitUp - - func deviceOrientationChanged( - orientation orientationArg: PlatformDeviceOrientation, - completion: @escaping (Result) -> Void - ) { - deviceOrientationChangedCalled = true - lastOrientation = orientationArg - completion(.success(())) - } -} diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockWritableData.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockWritableData.swift deleted file mode 100644 index 9feb13e3f997..000000000000 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockWritableData.swift +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2013 The Flutter Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -@testable import camera_avfoundation - -/// A mock implementation of `WritableData` that allows injecting a custom implementation -/// for writing to a file. -final class MockWritableData: WritableData { - var writeToFileStub: ((String, Data.WritingOptions) throws -> Void)? - - func writeToPath(_ path: String, options: Data.WritingOptions) throws { - if let stub = self.writeToFileStub { - try stub(path, options) - } - } -} diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/PhotoCaptureTests.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/PhotoCaptureTests.swift deleted file mode 100644 index e20a15dba9d3..000000000000 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/PhotoCaptureTests.swift +++ /dev/null @@ -1,248 +0,0 @@ -// Copyright 2013 The Flutter Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import AVFoundation -import XCTest - -@testable import camera_avfoundation - -/// Includes test cases related to photo capture operations for FLTCam class. -final class PhotoCaptureTests: XCTestCase { - private func createCam(with captureSessionQueue: DispatchQueue) -> DefaultCamera { - let configuration = CameraTestUtils.createTestCameraConfiguration() - configuration.captureSessionQueue = captureSessionQueue - return CameraTestUtils.createTestCamera(configuration) - } - - func testCaptureToFile_mustReportErrorToResultIfSavePhotoDelegateCompletionsWithError() { - let errorExpectation = expectation( - description: "Must send error to result if save photo delegate completes with error.") - let captureSessionQueue = DispatchQueue(label: "capture_session_queue") - captureSessionQueue.setSpecific( - key: captureSessionQueueSpecificKey, value: captureSessionQueueSpecificValue) - let cam = createCam(with: captureSessionQueue) - let error = NSError(domain: "test", code: 0, userInfo: nil) - - let mockOutput = MockCapturePhotoOutput() - mockOutput.capturePhotoWithSettingsStub = { settings, photoDelegate in - let delegate = - cam.inProgressSavePhotoDelegates[settings.uniqueID] - // Completion runs on IO queue. - let ioQueue = DispatchQueue(label: "io_queue") - ioQueue.async { - delegate?.completionHandler(nil, error) - } - } - cam.capturePhotoOutput = mockOutput - - // `FLTCam::captureToFile` runs on capture session queue. - captureSessionQueue.async { - cam.captureToFile { result in - switch result { - case .success(_): - XCTFail("Expected failure") - case .failure(_): - break - } - errorExpectation.fulfill() - } - } - - waitForExpectations(timeout: 30, handler: nil) - } - - func testCaptureToFile_mustReportPathToResultIfSavePhotoDelegateCompletionsWithPath() { - let pathExpectation = expectation( - description: "Must send file path to result if save photo delegate completes with file path.") - let captureSessionQueue = DispatchQueue(label: "capture_session_queue") - captureSessionQueue.setSpecific( - key: captureSessionQueueSpecificKey, value: captureSessionQueueSpecificValue) - let cam = createCam(with: captureSessionQueue) - let filePath = "test" - - let mockOutput = MockCapturePhotoOutput() - mockOutput.capturePhotoWithSettingsStub = { settings, photoDelegate in - let delegate = - cam.inProgressSavePhotoDelegates[settings.uniqueID] - // Completion runs on IO queue. - let ioQueue = DispatchQueue(label: "io_queue") - ioQueue.async { - delegate?.completionHandler(filePath, nil) - } - } - cam.capturePhotoOutput = mockOutput - - // `FLTCam::captureToFile` runs on capture session queue. - captureSessionQueue.async { - cam.captureToFile { result in - switch result { - case .success(let result): - XCTAssertEqual(result, filePath) - case .failure(_): - XCTFail("Unexpected failure") - } - pathExpectation.fulfill() - } - } - - waitForExpectations(timeout: 30, handler: nil) - } - - func testCaptureToFile_mustReportFileExtensionWithHeifWhenHEVCIsAvailableAndFileFormatIsHEIF() { - let expectation = self.expectation( - description: "Test must set extension to heif if availablePhotoCodecTypes contains HEVC.") - - let captureSessionQueue = DispatchQueue(label: "capture_session_queue") - captureSessionQueue.setSpecific( - key: captureSessionQueueSpecificKey, value: captureSessionQueueSpecificValue) - let cam = createCam(with: captureSessionQueue) - cam.setImageFileFormat(PlatformImageFileFormat.heif) - - let mockOutput = MockCapturePhotoOutput() - mockOutput.availablePhotoCodecTypes = [AVVideoCodecType.hevc] - mockOutput.capturePhotoWithSettingsStub = { settings, photoDelegate in - let delegate = - cam.inProgressSavePhotoDelegates[settings.uniqueID] - // Completion runs on IO queue. - let ioQueue = DispatchQueue(label: "io_queue") - ioQueue.async { - delegate?.completionHandler(delegate?.filePath, nil) - } - } - cam.capturePhotoOutput = mockOutput - - // `FLTCam::captureToFile` runs on capture session queue. - captureSessionQueue.async { - cam.captureToFile { result in - if let filePath = self.assertSuccess(result) { - XCTAssertEqual((filePath as NSString).pathExtension, "heif") - } - expectation.fulfill() - } - } - - waitForExpectations(timeout: 30, handler: nil) - } - - func testCaptureToFile_mustReportFileExtensionWithJpgWhenHEVCNotAvailableAndFileFormatIsHEIF() { - let expectation = self.expectation( - description: - "Test must set extension to jpg if availablePhotoCodecTypes does not contain HEVC.") - - let captureSessionQueue = DispatchQueue(label: "capture_session_queue") - captureSessionQueue.setSpecific( - key: captureSessionQueueSpecificKey, value: captureSessionQueueSpecificValue) - let cam = createCam(with: captureSessionQueue) - cam.setImageFileFormat(PlatformImageFileFormat.heif) - - let mockOutput = MockCapturePhotoOutput() - mockOutput.capturePhotoWithSettingsStub = { settings, photoDelegate in - let delegate = - cam.inProgressSavePhotoDelegates[settings.uniqueID] - // Completion runs on IO queue. - let ioQueue = DispatchQueue(label: "io_queue") - ioQueue.async { - delegate?.completionHandler(delegate?.filePath, nil) - } - } - cam.capturePhotoOutput = mockOutput - - // `FLTCam::captureToFile` runs on capture session queue. - captureSessionQueue.async { - cam.captureToFile { result in - if let filePath = self.assertSuccess(result) { - XCTAssertEqual((filePath as NSString).pathExtension, "jpg") - } - expectation.fulfill() - } - } - - waitForExpectations(timeout: 30, handler: nil) - } - - func testCaptureToFile_handlesTorchMode() { - let pathExpectation = expectation( - description: "Must send file path to result if save photo delegate completes with file path.") - let setTorchExpectation = expectation( - description: "Should set torch mode to AVCaptureTorchModeOn.") - - let captureDeviceMock = MockCaptureDevice() - captureDeviceMock.hasTorch = true - captureDeviceMock.isTorchAvailable = true - captureDeviceMock.getTorchModeStub = { .auto } - captureDeviceMock.setTorchModeStub = { mode in - if mode == .on { - setTorchExpectation.fulfill() - } - } - - let captureSessionQueue = DispatchQueue(label: "capture_session_queue") - captureSessionQueue.setSpecific( - key: captureSessionQueueSpecificKey, value: captureSessionQueueSpecificValue) - let configuration = CameraTestUtils.createTestCameraConfiguration() - configuration.captureSessionQueue = captureSessionQueue - configuration.videoCaptureDeviceFactory = { _ in captureDeviceMock } - let cam = CameraTestUtils.createTestCamera(configuration) - - let filePath = "test" - let mockOutput = MockCapturePhotoOutput() - mockOutput.capturePhotoWithSettingsStub = { settings, photoDelegate in - let delegate = - cam.inProgressSavePhotoDelegates[settings.uniqueID] - // Completion runs on IO queue. - let ioQueue = DispatchQueue(label: "io_queue") - ioQueue.async { - delegate?.completionHandler(filePath, nil) - } - } - cam.capturePhotoOutput = mockOutput - - // `FLTCam::captureToFile` runs on capture session queue. - captureSessionQueue.async { - cam.setFlashMode(.torch) { _ in } - cam.captureToFile { result in - if let result = self.assertSuccess(result) { - XCTAssertEqual(result, filePath) - } - pathExpectation.fulfill() - } - } - - waitForExpectations(timeout: 30, handler: nil) - } - - func testCaptureToFile_mustSavePhotoToCameraPicturesDirectory() { - let expectedPath = "/tmp/camera/pictures/" - let expectation = self.expectation( - description: "Photo must be saved to \(expectedPath) directory.") - - let captureSessionQueue = DispatchQueue(label: "capture_session_queue") - captureSessionQueue.setSpecific( - key: captureSessionQueueSpecificKey, value: captureSessionQueueSpecificValue) - let cam = createCam(with: captureSessionQueue) - - let mockOutput = MockCapturePhotoOutput() - mockOutput.capturePhotoWithSettingsStub = { settings, photoDelegate in - let delegate = cam.inProgressSavePhotoDelegates[settings.uniqueID] - let ioQueue = DispatchQueue(label: "io_queue") - ioQueue.async { - delegate?.completionHandler(delegate?.filePath, nil) - } - } - cam.capturePhotoOutput = mockOutput - - captureSessionQueue.async { - cam.captureToFile { result in - if let filePath = self.assertSuccess(result) { - XCTAssertTrue( - filePath.contains(expectedPath) - ) - } - expectation.fulfill() - } - } - - waitForExpectations(timeout: 30, handler: nil) - } -} diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/QueueUtilsTests.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/QueueUtilsTests.swift deleted file mode 100644 index 29a7cc5b453c..000000000000 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/QueueUtilsTests.swift +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2013 The Flutter Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import XCTest - -@testable import camera_avfoundation - -final class QueueUtilsTests: XCTestCase { - func testShouldStayOnMainQueueIfCalledFromMainQueue() { - let expectation = expectation(description: "Block must be run on the main queue") - - ensureToRunOnMainQueue { - if Thread.isMainThread { - expectation.fulfill() - } - } - - waitForExpectations(timeout: 30) - } - - func testShouldDispatchToMainQueueIfCalledFromBackgroundQueue() { - let expectation = expectation(description: "Block must be run on the main queue") - - DispatchQueue.global(qos: .default).async { - ensureToRunOnMainQueue { - if Thread.isMainThread { - expectation.fulfill() - } - } - } - - waitForExpectations(timeout: 30) - } -} diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/RunnerTests-Bridging-Header.h b/packages/camera/camera_avfoundation/example/ios/RunnerTests/RunnerTests-Bridging-Header.h deleted file mode 100644 index 5b3a1852fb82..000000000000 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/RunnerTests-Bridging-Header.h +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright 2013 The Flutter Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#import "ExceptionCatcher.h" diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/RunnerTests.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/RunnerTests.swift new file mode 100644 index 000000000000..86a7c3b1b611 --- /dev/null +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/RunnerTests.swift @@ -0,0 +1,12 @@ +import Flutter +import UIKit +import XCTest + +class RunnerTests: XCTestCase { + + func testExample() { + // If you add code to the Runner application, consider adding tests here. + // See https://developer.apple.com/documentation/xctest for more information about using XCTest. + } + +} diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/SampleBufferTests.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/SampleBufferTests.swift deleted file mode 100644 index 3db6cd2c94da..000000000000 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/SampleBufferTests.swift +++ /dev/null @@ -1,542 +0,0 @@ -// Copyright 2013 The Flutter Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import AVFoundation -import XCTest - -@testable import camera_avfoundation - -private class FakeMediaSettingsAVWrapper: FLTCamMediaSettingsAVWrapper { - let inputMock: MockAssetWriterInput - - init(inputMock: MockAssetWriterInput) { - self.inputMock = inputMock - } - - override func lockDevice(_ captureDevice: CaptureDevice) throws { - // No-op. - } - - override func unlockDevice(_ captureDevice: CaptureDevice) { - // No-op. - } - - override func beginConfiguration(for videoCaptureSession: CaptureSession) { - // No-op. - } - - override func commitConfiguration(for videoCaptureSession: CaptureSession) { - // No-op. - } - - override func setMinFrameDuration(_ duration: CMTime, on captureDevice: CaptureDevice) { - // No-op. - } - - override func setMaxFrameDuration(_ duration: CMTime, on captureDevice: CaptureDevice) { - // No-op. - } - - override func assetWriterAudioInput(withOutputSettings outputSettings: [String: Any]?) - -> AssetWriterInput - { - return inputMock - } - - override func assetWriterVideoInput(withOutputSettings outputSettings: [String: Any]?) - -> AssetWriterInput - { - return inputMock - } - - override func addInput(_ writerInput: AssetWriterInput, to writer: AssetWriter) { - // No-op. - } - - override func recommendedVideoSettingsForAssetWriter( - withFileType fileType: AVFileType, for output: CaptureVideoDataOutput - ) -> [String: Any]? { - return [:] - } -} - -/// Includes test cases related to sample buffer handling for FLTCam class. -final class CameraSampleBufferTests: XCTestCase { - private func createCamera() -> ( - DefaultCamera, - MockAssetWriter, - MockAssetWriterInputPixelBufferAdaptor, - MockAssetWriterInput - ) { - let assetWriter = MockAssetWriter() - let adaptor = MockAssetWriterInputPixelBufferAdaptor() - let input = MockAssetWriterInput() - - let configuration = CameraTestUtils.createTestCameraConfiguration() - configuration.mediaSettings = PlatformMediaSettings( - resolutionPreset: .medium, - framesPerSecond: nil, - videoBitrate: nil, - audioBitrate: nil, - enableAudio: true) - configuration.mediaSettingsWrapper = FakeMediaSettingsAVWrapper(inputMock: input) - - configuration.assetWriterFactory = { url, fileType in - return assetWriter - } - configuration.inputPixelBufferAdaptorFactory = { input, settings in - return adaptor - } - - return ( - CameraTestUtils.createTestCamera(configuration), - assetWriter, - adaptor, - input - ) - } - - func testSampleBufferCallbackQueueMustBeCaptureSessionQueue() { - let captureSessionQueue = DispatchQueue(label: "testing") - let camera = CameraTestUtils.createCameraWithCaptureSessionQueue(captureSessionQueue) - XCTAssertEqual( - captureSessionQueue, camera.captureVideoOutput.avOutput.sampleBufferCallbackQueue, - "Sample buffer callback queue must be the capture session queue.") - } - - func testCopyPixelBuffer() { - let (camera, _, _, _) = createCamera() - let capturedSampleBuffer = CameraTestUtils.createTestSampleBuffer() - let capturedPixelBuffer = CMSampleBufferGetImageBuffer(capturedSampleBuffer)! - let testConnection = CameraTestUtils.createTestConnection(camera.captureVideoOutput.avOutput) - - // Mimic sample buffer callback when captured a new video sample. - camera.captureOutput( - camera.captureVideoOutput.avOutput, - didOutput: capturedSampleBuffer, - from: testConnection) - let deliveredPixelBuffer = camera.copyPixelBuffer()?.takeRetainedValue() - XCTAssertEqual( - deliveredPixelBuffer, capturedPixelBuffer, - "FLTCam must deliver the latest captured pixel buffer to copyPixelBuffer API.") - } - - func testDidOutputSampleBuffer_mustNotChangeSampleBufferRetainCountAfterPauseResumeRecording() { - let (camera, _, _, _) = createCamera() - let sampleBuffer = CameraTestUtils.createTestSampleBuffer() - let testConnection = CameraTestUtils.createTestConnection(camera.captureVideoOutput.avOutput) - - let initialRetainCount = CFGetRetainCount(sampleBuffer) - - // Pause then resume the recording. - camera.startVideoRecording(completion: { error in }, messengerForStreaming: nil) - camera.pauseVideoRecording() - camera.resumeVideoRecording() - - camera.captureOutput( - camera.captureVideoOutput.avOutput, - didOutput: sampleBuffer, - from: testConnection) - - let finalRetainCount = CFGetRetainCount(sampleBuffer) - XCTAssertEqual( - finalRetainCount, initialRetainCount, - "didOutputSampleBuffer must not change the sample buffer retain count after pause resume recording." - ) - } - - func testDidOutputSampleBufferIgnoreAudioSamplesBeforeVideoSamples() { - let (camera, writerMock, adaptorMock, inputMock) = createCamera() - var status = AVAssetWriter.Status.unknown - writerMock.startWritingStub = { - status = .writing - return true - } - writerMock.statusStub = { - return status - } - - let videoSample = CameraTestUtils.createTestSampleBuffer() - let testVideoConnection = CameraTestUtils.createTestConnection( - camera.captureVideoOutput.avOutput) - - let audioSample = CameraTestUtils.createTestAudioSampleBuffer() - let testAudioOutput = CameraTestUtils.createTestAudioOutput() - let testAudioConnection = CameraTestUtils.createTestConnection(testAudioOutput) - - var writtenSamples: [String] = [] - adaptorMock.appendStub = { buffer, time in - writtenSamples.append("video") - return true - } - inputMock.isReadyForMoreMediaData = true - inputMock.appendStub = { buffer in - writtenSamples.append("audio") - return true - } - - camera.startVideoRecording(completion: { error in }, messengerForStreaming: nil) - camera.captureOutput(testAudioOutput, didOutput: audioSample, from: testAudioConnection) - camera.captureOutput(testAudioOutput, didOutput: audioSample, from: testAudioConnection) - camera.captureOutput( - camera.captureVideoOutput.avOutput, - didOutput: videoSample, - from: testVideoConnection) - camera.captureOutput(testAudioOutput, didOutput: audioSample, from: testAudioConnection) - - let expectedSamples = ["video", "audio"] - XCTAssertEqual(writtenSamples, expectedSamples, "First appended sample must be video.") - } - - func testDidOutputSampleBufferSampleTimesMustBeNumericAfterPauseResume() { - let (camera, writerMock, adaptorMock, inputMock) = createCamera() - - let videoSample = CameraTestUtils.createTestSampleBuffer() - let testVideoConnection = CameraTestUtils.createTestConnection( - camera.captureVideoOutput.avOutput) - - let audioSample = CameraTestUtils.createTestAudioSampleBuffer() - let testAudioOutput = CameraTestUtils.createTestAudioOutput() - let testAudioConnection = CameraTestUtils.createTestConnection(testAudioOutput) - - var status = AVAssetWriter.Status.unknown - writerMock.startWritingStub = { - status = .writing - return true - } - writerMock.statusStub = { - return status - } - - var videoAppended = false - adaptorMock.appendStub = { buffer, time in - XCTAssert(CMTIME_IS_NUMERIC(time)) - videoAppended = true - return true - } - - var audioAppended = false - inputMock.isReadyForMoreMediaData = true - inputMock.appendStub = { buffer in - let sampleTime = CMSampleBufferGetPresentationTimeStamp(buffer) - XCTAssert(CMTIME_IS_NUMERIC(sampleTime)) - audioAppended = true - return true - } - - camera.startVideoRecording(completion: { error in }, messengerForStreaming: nil) - camera.pauseVideoRecording() - camera.resumeVideoRecording() - camera.captureOutput( - camera.captureVideoOutput.avOutput, - didOutput: videoSample, - from: testVideoConnection) - camera.captureOutput(testAudioOutput, didOutput: audioSample, from: testAudioConnection) - camera.captureOutput( - camera.captureVideoOutput.avOutput, - didOutput: videoSample, - from: testVideoConnection) - camera.captureOutput(testAudioOutput, didOutput: audioSample, from: testAudioConnection) - - XCTAssert(videoAppended && audioAppended, "Video or audio was not appended.") - } - - func testDidOutputSampleBufferMustNotAppendSampleWhenReadyForMoreMediaDataIsFalse() { - let (camera, _, adaptorMock, inputMock) = createCamera() - - let videoSample = CameraTestUtils.createTestSampleBuffer() - let testVideoConnection = CameraTestUtils.createTestConnection( - camera.captureVideoOutput.avOutput) - - var sampleAppended = false - adaptorMock.appendStub = { buffer, time in - sampleAppended = true - return true - } - - camera.startVideoRecording(completion: { error in }, messengerForStreaming: nil) - - inputMock.isReadyForMoreMediaData = true - sampleAppended = false - camera.captureOutput( - camera.captureVideoOutput.avOutput, - didOutput: videoSample, - from: testVideoConnection) - XCTAssertTrue(sampleAppended, "Sample was not appended.") - - inputMock.isReadyForMoreMediaData = false - sampleAppended = false - camera.captureOutput( - camera.captureVideoOutput.avOutput, - didOutput: videoSample, - from: testVideoConnection) - XCTAssertFalse(sampleAppended, "Sample cannot be appended when readyForMoreMediaData is NO.") - } - - func testStopVideoRecordingWithCompletionMustCallCompletion() { - let (camera, writerMock, _, _) = createCamera() - - var status = AVAssetWriter.Status.unknown - writerMock.startWritingStub = { - status = .writing - return true - } - writerMock.statusStub = { - return status - } - writerMock.finishWritingStub = { handler in - XCTAssert( - writerMock.status == .writing, - "Cannot call finishWritingWithCompletionHandler when status is not AVAssetWriter.Status.writing." - ) - handler() - } - - camera.startVideoRecording(completion: { error in }, messengerForStreaming: nil) - var completionCalled = false - camera.stopVideoRecording(completion: { result in - completionCalled = true - }) - - XCTAssert(completionCalled, "Completion was not called.") - } - - func testStartWritingShouldNotBeCalledBetweenSampleCreationAndAppending() { - let (camera, writerMock, adaptorMock, inputMock) = createCamera() - - let videoSample = CameraTestUtils.createTestSampleBuffer() - let testVideoConnection = CameraTestUtils.createTestConnection( - camera.captureVideoOutput.avOutput) - - var startWritingCalled = false - writerMock.startWritingStub = { - startWritingCalled = true - return true - - } - - var videoAppended = false - adaptorMock.appendStub = { buffer, time in - videoAppended = true - return true - } - - inputMock.isReadyForMoreMediaData = true - - camera.startVideoRecording(completion: { error in }, messengerForStreaming: nil) - - let startWritingCalledBefore = startWritingCalled - camera.captureOutput( - camera.captureVideoOutput.avOutput, - didOutput: videoSample, - from: testVideoConnection) - XCTAssert( - (startWritingCalledBefore && videoAppended) || (startWritingCalled && !videoAppended), - "The startWriting was called between sample creation and appending.") - - camera.captureOutput( - camera.captureVideoOutput.avOutput, - didOutput: videoSample, - from: testVideoConnection) - XCTAssert(videoAppended, "Video was not appended.") - } - - func testStartVideoRecordingWithCompletionShouldNotDisableMixWithOthers() { - let cam = CameraTestUtils.createCameraWithCaptureSessionQueue(DispatchQueue(label: "testing")) - - try? AVAudioSession.sharedInstance().setCategory(.playback, options: .mixWithOthers) - cam.startVideoRecording(completion: { error in }, messengerForStreaming: nil) - XCTAssert( - AVAudioSession.sharedInstance().categoryOptions.contains(.mixWithOthers), - "Flag MixWithOthers was removed.") - XCTAssert( - AVAudioSession.sharedInstance().category == .playAndRecord, - "Category should be PlayAndRecord.") - } - - func testDidOutputSampleBufferMustUseSingleOffsetForVideoAndAudio() { - let (camera, writerMock, adaptorMock, inputMock) = createCamera() - - let testVideoConnection = CameraTestUtils.createTestConnection( - camera.captureVideoOutput.avOutput) - let testAudioOutput = CameraTestUtils.createTestAudioOutput() - let testAudioConnection = CameraTestUtils.createTestConnection(testAudioOutput) - - var status = AVAssetWriter.Status.unknown - writerMock.startWritingStub = { - status = .writing - return true - } - writerMock.statusStub = { - return status - } - - var appendedTime = CMTime.invalid - - adaptorMock.appendStub = { buffer, time in - appendedTime = time - return true - } - - inputMock.isReadyForMoreMediaData = true - inputMock.appendStub = { buffer in - appendedTime = CMSampleBufferGetPresentationTimeStamp(buffer) - return true - } - - camera.startVideoRecording(completion: { error in }, messengerForStreaming: nil) - - let appendVideoSample = { (time: Int64) in - camera.captureOutput( - camera.captureVideoOutput.avOutput, - didOutput: CameraTestUtils.createTestSampleBuffer( - timestamp: CMTimeMake(value: time, timescale: 1), - duration: .invalid), - from: testVideoConnection) - } - - let appendAudioSample = { (time: Int64, duration: Int64) in - camera.captureOutput( - testAudioOutput, - didOutput: CameraTestUtils.createTestAudioSampleBuffer( - timestamp: CMTimeMake(value: time, timescale: 1), - duration: CMTimeMake(value: duration, timescale: 1)), - from: testAudioConnection) - } - - appendedTime = .invalid - camera.pauseVideoRecording() - camera.resumeVideoRecording() - appendVideoSample(1) - XCTAssertEqual(appendedTime, CMTimeMake(value: 1, timescale: 1)) - - appendedTime = .invalid - camera.pauseVideoRecording() - camera.resumeVideoRecording() - appendVideoSample(11) - XCTAssertEqual(appendedTime, .invalid) - appendVideoSample(12) - XCTAssertEqual(appendedTime, CMTimeMake(value: 2, timescale: 1)) - - appendedTime = .invalid - camera.pauseVideoRecording() - camera.resumeVideoRecording() - appendAudioSample(20, 2) - XCTAssertEqual(appendedTime, .invalid) - appendVideoSample(23) - XCTAssertEqual(appendedTime, CMTimeMake(value: 3, timescale: 1)) - - appendedTime = .invalid - camera.pauseVideoRecording() - camera.resumeVideoRecording() - appendVideoSample(28) - XCTAssertEqual(appendedTime, .invalid) - appendAudioSample(30, 2) - XCTAssertEqual(appendedTime, .invalid) - appendVideoSample(33) - XCTAssertEqual(appendedTime, .invalid) - appendAudioSample(32, 2) - XCTAssertEqual(appendedTime, CMTimeMake(value: 2, timescale: 1)) - } - - func testDidOutputSampleBufferMustConnectVideoAfterSessionInterruption() { - let (camera, writerMock, adaptorMock, inputMock) = createCamera() - - let testVideoConnection = CameraTestUtils.createTestConnection( - camera.captureVideoOutput.avOutput) - let testAudioOutput = CameraTestUtils.createTestAudioOutput() - let testAudioConnection = CameraTestUtils.createTestConnection(testAudioOutput) - - var status = AVAssetWriter.Status.unknown - writerMock.startWritingStub = { - status = .writing - return true - } - writerMock.statusStub = { - return status - } - - var appendedTime = CMTime.invalid - - adaptorMock.appendStub = { buffer, time in - appendedTime = time - return true - } - - inputMock.isReadyForMoreMediaData = true - inputMock.appendStub = { buffer in - appendedTime = CMSampleBufferGetPresentationTimeStamp(buffer) - return true - } - - camera.startVideoRecording(completion: { error in }, messengerForStreaming: nil) - - let appendVideoSample = { (time: Int64) in - camera.captureOutput( - camera.captureVideoOutput.avOutput, - didOutput: CameraTestUtils.createTestSampleBuffer( - timestamp: CMTimeMake(value: time, timescale: 1), - duration: .invalid), - from: testVideoConnection) - } - - let appendAudioSample = { (time: Int64, duration: Int64) in - camera.captureOutput( - testAudioOutput, - didOutput: CameraTestUtils.createTestAudioSampleBuffer( - timestamp: CMTimeMake(value: time, timescale: 1), - duration: CMTimeMake(value: duration, timescale: 1)), - from: testAudioConnection) - } - - appendVideoSample(1) - appendAudioSample(1, 1) - - NotificationCenter.default.post( - name: AVCaptureSession.wasInterruptedNotification, - object: camera.audioCaptureSession) - - appendedTime = .invalid - appendAudioSample(11, 1) - XCTAssertEqual(appendedTime, .invalid) - appendVideoSample(12) - XCTAssertEqual(appendedTime, CMTimeMake(value: 2, timescale: 1)) - appendedTime = .invalid - appendAudioSample(12, 1) - XCTAssertEqual(appendedTime, CMTimeMake(value: 2, timescale: 1)) - } - - func testStartVideoRecordingReportsErrorWhenStartWritingFails() { - let (camera, writerMock, _, _) = createCamera() - - // Configure the mock to return false for startWriting - writerMock.startWritingStub = { - return false - } - - // Configure a mock error - let mockError = NSError( - domain: "test", code: 123, userInfo: [NSLocalizedDescriptionKey: "Mock write error"]) - writerMock.error = mockError - - let expectation = self.expectation(description: "Completion handler called with error") - - camera.startVideoRecording( - completion: { result in - switch result { - case .failure(let error as PigeonError): - XCTAssertEqual(error.code, "IOError") - XCTAssertEqual(error.message, "AVAssetWriter failed to start writing") - XCTAssertEqual(error.details as? String, "Mock write error") - XCTAssertFalse(camera.isRecording) - expectation.fulfill() - default: - XCTFail("Expected PigeonError") - } - - }, messengerForStreaming: nil) - - waitForExpectations(timeout: 1.0, handler: nil) - } -} diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/SavePhotoDelegateTests.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/SavePhotoDelegateTests.swift deleted file mode 100644 index 76b4430dafed..000000000000 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/SavePhotoDelegateTests.swift +++ /dev/null @@ -1,99 +0,0 @@ -// Copyright 2013 The Flutter Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import AVFoundation -import XCTest - -@testable import camera_avfoundation - -final class SavePhotoDelegateTests: XCTestCase { - func testHandlePhotoCaptureResult_mustCompleteWithErrorIfFailedToCapture() { - let completionExpectation = expectation( - description: "Must complete with error if failed to capture photo.") - let captureError = NSError(domain: "test", code: 0, userInfo: nil) - let ioQueue = DispatchQueue(label: "test") - let delegate = SavePhotoDelegate(path: "test", ioQueue: ioQueue) { path, error in - XCTAssertEqual(captureError, error as NSError?) - XCTAssertNil(path) - completionExpectation.fulfill() - } - - delegate.handlePhotoCaptureResult(error: captureError) { nil } - - waitForExpectations(timeout: 30, handler: nil) - } - - func testHandlePhotoCaptureResult_mustCompleteWithErrorIfFailedToWrite() { - let completionExpectation = expectation( - description: "Must complete with error if failed to write file.") - let ioQueue = DispatchQueue(label: "test") - let ioError = NSError( - domain: "IOError", code: 0, userInfo: [NSLocalizedDescriptionKey: "Localized IO Error"]) - let delegate = SavePhotoDelegate(path: "test", ioQueue: ioQueue) { path, error in - XCTAssertEqual(ioError, error as NSError?) - XCTAssertNil(path) - completionExpectation.fulfill() - } - - let mockWritableData = MockWritableData() - mockWritableData.writeToFileStub = { path, options in - throw ioError - } - - delegate.handlePhotoCaptureResult(error: nil) { mockWritableData } - - waitForExpectations(timeout: 30, handler: nil) - } - - func testHandlePhotoCaptureResult_mustCompleteWithFilePathIfSuccessToWrite() { - let completionExpectation = expectation( - description: "Must complete with file path if succeeds to write file.") - let ioQueue = DispatchQueue(label: "test") - let filePath = "test" - let delegate = SavePhotoDelegate(path: filePath, ioQueue: ioQueue) { path, error in - XCTAssertNil(error) - XCTAssertEqual(filePath, path) - completionExpectation.fulfill() - } - - let mockWritableData = MockWritableData() - mockWritableData.writeToFileStub = { path, options in } - - delegate.handlePhotoCaptureResult(error: nil) { mockWritableData } - - waitForExpectations(timeout: 30, handler: nil) - } - - func testHandlePhotoCaptureResult_bothProvideDataAndSaveFileMustRunOnIOQueue() { - let dataProviderQueueExpectation = expectation( - description: "Data provider must run on io queue.") - let writeFileQueueExpectation = expectation(description: "File writing must run on io queue.") - let completionExpectation = expectation( - description: "Must complete with file path if success to write file.") - let ioQueue = DispatchQueue(label: "test") - let ioQueueSpecific = DispatchSpecificKey() - ioQueue.setSpecific(key: ioQueueSpecific, value: ()) - - let mockWritableData = MockWritableData() - mockWritableData.writeToFileStub = { path, options in - if DispatchQueue.getSpecific(key: ioQueueSpecific) != nil { - writeFileQueueExpectation.fulfill() - } - } - - let filePath = "test" - let delegate = SavePhotoDelegate(path: filePath, ioQueue: ioQueue) { path, error in - completionExpectation.fulfill() - } - - delegate.handlePhotoCaptureResult(error: nil) { - if DispatchQueue.getSpecific(key: ioQueueSpecific) != nil { - dataProviderQueueExpectation.fulfill() - } - return mockWritableData - } - - waitForExpectations(timeout: 30, handler: nil) - } -} diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/StreamingTests.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/StreamingTests.swift deleted file mode 100644 index b018a7cca12d..000000000000 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/StreamingTests.swift +++ /dev/null @@ -1,217 +0,0 @@ -// Copyright 2013 The Flutter Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import AVFoundation -import Flutter -import XCTest - -@testable import camera_avfoundation - -private class MockEventSink: PigeonEventSink { - var eventSinkSuccessStub: ((PlatformCameraImageData?) -> Void)? - - init() { - super.init({ event in }) - } - - override func success(_ event: PlatformCameraImageData?) { - eventSinkSuccessStub?(event) - } - - override func error(code: String, message: String?, details: Any?) {} - - override func endOfStream() {} -} - -private class MockImageStreamHandler: ImageDataStreamStreamHandler, ImageStreamHandler { - var mockEventSink = MockEventSink() - var captureSessionQueue: DispatchQueue { - preconditionFailure("Attempted to access unimplemented property: captureSessionQueue") - } - var eventSink: PigeonEventSink? { - set { - } - get { - return mockEventSink - } - } - - var eventSinkSuccessStub: ((PlatformCameraImageData?) -> Void)? { - set { - mockEventSink.eventSinkSuccessStub = newValue - } - get { - return mockEventSink.eventSinkSuccessStub - } - } - - override func onListen( - withArguments arguments: Any?, sink: PigeonEventSink - ) { - } - - override func onCancel(withArguments arguments: Any?) { - } -} - -final class StreamingTests: XCTestCase { - private func createCamera() -> ( - DefaultCamera, - AVCaptureOutput, - CMSampleBuffer, - CMSampleBuffer, - AVCaptureConnection - ) { - let captureSessionQueue = DispatchQueue(label: "testing") - let configuration = CameraTestUtils.createTestCameraConfiguration() - configuration.captureSessionQueue = captureSessionQueue - - let camera = CameraTestUtils.createTestCamera(configuration) - let testAudioOutput = CameraTestUtils.createTestAudioOutput() - let sampleBuffer = CameraTestUtils.createTestSampleBuffer() - let audioSampleBuffer = CameraTestUtils.createTestAudioSampleBuffer() - let testAudioConnection = CameraTestUtils.createTestConnection(testAudioOutput) - - return (camera, testAudioOutput, sampleBuffer, audioSampleBuffer, testAudioConnection) - } - - func testExceedMaxStreamingPendingFramesCount() { - let (camera, testAudioOutput, sampleBuffer, _, testAudioConnection) = createCamera() - let handlerMock = MockImageStreamHandler() - - let finishStartStreamExpectation = expectation( - description: "Finish startStream") - - let messenger = MockFlutterBinaryMessenger() - camera.startImageStream( - with: messenger, imageStreamHandler: handlerMock, - completion: { - _ in - finishStartStreamExpectation.fulfill() - }) - - waitForExpectations(timeout: 30, handler: nil) - - // Setup mocked event sink after the stream starts - let streamingExpectation = expectation( - description: "Must not call handler over maxStreamingPendingFramesCount") - - handlerMock.eventSinkSuccessStub = { event in - streamingExpectation.fulfill() - } - - waitForQueueRoundTrip(with: DispatchQueue.main) - XCTAssertEqual(camera.isStreamingImages, true) - - streamingExpectation.expectedFulfillmentCount = 4 - for _ in 0..<10 { - camera.captureOutput(testAudioOutput, didOutput: sampleBuffer, from: testAudioConnection) - } - - waitForExpectations(timeout: 30, handler: nil) - } - - func testReceivedImageStreamData() { - let (camera, testAudioOutput, sampleBuffer, _, testAudioConnection) = createCamera() - let handlerMock = MockImageStreamHandler() - - let finishStartStreamExpectation = expectation( - description: "Finish startStream") - - let messenger = MockFlutterBinaryMessenger() - camera.startImageStream( - with: messenger, imageStreamHandler: handlerMock, - completion: { - _ in - finishStartStreamExpectation.fulfill() - }) - - waitForExpectations(timeout: 30, handler: nil) - - // Setup mocked event sink after the stream starts - let streamingExpectation = expectation( - description: "Must be able to call the handler again when receivedImageStreamData is called") - handlerMock.eventSinkSuccessStub = { event in - streamingExpectation.fulfill() - } - - waitForQueueRoundTrip(with: DispatchQueue.main) - XCTAssertEqual(camera.isStreamingImages, true) - - streamingExpectation.expectedFulfillmentCount = 5 - for _ in 0..<10 { - camera.captureOutput(testAudioOutput, didOutput: sampleBuffer, from: testAudioConnection) - } - - camera.receivedImageStreamData() - camera.captureOutput(testAudioOutput, didOutput: sampleBuffer, from: testAudioConnection) - - waitForExpectations(timeout: 30, handler: nil) - } - - func testIgnoresNonImageBuffers() { - let (camera, testAudioOutput, _, audioSampleBuffer, testAudioConnection) = createCamera() - let handlerMock = MockImageStreamHandler() - handlerMock.eventSinkSuccessStub = { event in - XCTFail() - } - - let finishStartStreamExpectation = expectation( - description: "Finish startStream") - - let messenger = MockFlutterBinaryMessenger() - camera.startImageStream( - with: messenger, imageStreamHandler: handlerMock, - completion: { - _ in - finishStartStreamExpectation.fulfill() - }) - - waitForExpectations(timeout: 30, handler: nil) - XCTAssertEqual(camera.isStreamingImages, true) - - camera.captureOutput(testAudioOutput, didOutput: audioSampleBuffer, from: testAudioConnection) - - waitForQueueRoundTrip(with: DispatchQueue.main) - } - - func testImageStreamEventFormat() throws { - let (camera, testAudioOutput, sampleBuffer, _, testAudioConnection) = createCamera() - - let expectation = expectation(description: "Received a valid event") - - let handlerMock = MockImageStreamHandler() - handlerMock.eventSinkSuccessStub = { event in - guard let imageBuffer = event else { - XCTFail() - return - } - XCTAssertGreaterThan(imageBuffer.width, 0) - XCTAssertGreaterThan(imageBuffer.height, 0) - XCTAssertGreaterThan(imageBuffer.formatCode, 0) - XCTAssertGreaterThan(imageBuffer.lensAperture, 0) - XCTAssertGreaterThan(imageBuffer.sensorExposureTimeNanoseconds, 0) - XCTAssertGreaterThan(imageBuffer.sensorSensitivity, 0) - - let planes = imageBuffer.planes - let planeBuffer = planes[0] - - XCTAssertGreaterThan(planeBuffer.bytesPerRow, 0) - XCTAssertGreaterThan(planeBuffer.width, 0) - XCTAssertGreaterThan(planeBuffer.height, 0) - XCTAssertGreaterThan(planeBuffer.bytes.data.count, 0) - - expectation.fulfill() - } - let messenger = MockFlutterBinaryMessenger() - camera.startImageStream(with: messenger, imageStreamHandler: handlerMock) { _ in } - - waitForQueueRoundTrip(with: DispatchQueue.main) - XCTAssertEqual(camera.isStreamingImages, true) - - camera.captureOutput(testAudioOutput, didOutput: sampleBuffer, from: testAudioConnection) - - waitForExpectations(timeout: 30, handler: nil) - } -} From 8325062681807da402e0cb423b924bfe25be12a3 Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Wed, 18 Mar 2026 12:09:47 -0400 Subject: [PATCH 02/10] Restore RunnerTest files, minus unused files --- .../RunnerTests/AvailableCamerasTests.swift | 138 ++++ .../CameraInitRaceConditionsTests.swift | 92 +++ .../CameraMethodChannelTests.swift | 80 +++ .../RunnerTests/CameraOrientationTests.swift | 168 +++++ .../RunnerTests/CameraPermissionTests.swift | 237 +++++++ .../CameraPluginCreateCameraTests.swift | 131 ++++ .../CameraPluginDelegatingMethodTests.swift | 630 ++++++++++++++++++ .../CameraPluginInitializeCameraTests.swift | 105 +++ .../RunnerTests/CameraPreviewPauseTests.swift | 26 + .../RunnerTests/CameraPropertiesTests.swift | 73 ++ .../CameraSessionPresetsTests.swift | 97 +++ .../ios/RunnerTests/CameraSettingsTests.swift | 355 ++++++++++ .../ios/RunnerTests/CameraTestUtils.swift | 219 ++++++ .../ios/RunnerTests/FLTCamExposureTests.swift | 146 ++++ .../ios/RunnerTests/FLTCamFocusTests.swift | 166 +++++ .../FLTCamSetDeviceOrientationTests.swift | 108 +++ .../RunnerTests/FLTCamSetFlashModeTests.swift | 168 +++++ .../ios/RunnerTests/FLTCamZoomTests.swift | 111 +++ .../RunnerTests/Mocks/MockAssetWriter.swift | 33 + .../Mocks/MockAssetWriterInput.swift | 25 + ...ckAssetWriterInputPixelBufferAdaptor.swift | 17 + .../ios/RunnerTests/Mocks/MockCamera.swift | 233 +++++++ .../Mocks/MockCameraDeviceDiscoverer.swift | 29 + .../Mocks/MockCaptureConnection.swift | 27 + .../RunnerTests/Mocks/MockCaptureDevice.swift | 127 ++++ .../Mocks/MockCaptureDeviceFormat.swift | 43 ++ .../Mocks/MockCaptureDeviceInputFactory.swift | 13 + .../RunnerTests/Mocks/MockCaptureInput.swift | 17 + .../Mocks/MockCapturePhotoOutput.swift | 32 + .../Mocks/MockCaptureSession.swift | 87 +++ .../Mocks/MockCaptureVideoDataOutput.swift | 27 + .../Mocks/MockDeviceOrientationProvider.swift | 15 + .../MockFLTCameraPermissionManager.swift | 32 + .../Mocks/MockFlutterBinaryMessenger.swift | 26 + .../Mocks/MockFlutterTextureRegistry.swift | 16 + .../Mocks/MockFrameRateRange.swift | 17 + .../Mocks/MockGlobalEventApi.swift | 26 + .../RunnerTests/Mocks/MockWritableData.swift | 17 + .../ios/RunnerTests/PhotoCaptureTests.swift | 248 +++++++ .../ios/RunnerTests/QueueUtilsTests.swift | 35 + .../ios/RunnerTests/SampleBufferTests.swift | 542 +++++++++++++++ .../RunnerTests/SavePhotoDelegateTests.swift | 99 +++ .../ios/RunnerTests/StreamingTests.swift | 217 ++++++ 43 files changed, 5050 insertions(+) create mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/AvailableCamerasTests.swift create mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraInitRaceConditionsTests.swift create mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraMethodChannelTests.swift create mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraOrientationTests.swift create mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraPermissionTests.swift create mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraPluginCreateCameraTests.swift create mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraPluginDelegatingMethodTests.swift create mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraPluginInitializeCameraTests.swift create mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraPreviewPauseTests.swift create mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraPropertiesTests.swift create mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraSessionPresetsTests.swift create mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraSettingsTests.swift create mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraTestUtils.swift create mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamExposureTests.swift create mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamFocusTests.swift create mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamSetDeviceOrientationTests.swift create mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamSetFlashModeTests.swift create mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamZoomTests.swift create mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockAssetWriter.swift create mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockAssetWriterInput.swift create mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockAssetWriterInputPixelBufferAdaptor.swift create mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCamera.swift create mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCameraDeviceDiscoverer.swift create mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureConnection.swift create mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDevice.swift create mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDeviceFormat.swift create mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDeviceInputFactory.swift create mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureInput.swift create mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCapturePhotoOutput.swift create mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureSession.swift create mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureVideoDataOutput.swift create mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockDeviceOrientationProvider.swift create mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockFLTCameraPermissionManager.swift create mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockFlutterBinaryMessenger.swift create mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockFlutterTextureRegistry.swift create mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockFrameRateRange.swift create mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockGlobalEventApi.swift create mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockWritableData.swift create mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/PhotoCaptureTests.swift create mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/QueueUtilsTests.swift create mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/SampleBufferTests.swift create mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/SavePhotoDelegateTests.swift create mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/StreamingTests.swift diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/AvailableCamerasTests.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/AvailableCamerasTests.swift new file mode 100644 index 000000000000..4fbece5523d5 --- /dev/null +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/AvailableCamerasTests.swift @@ -0,0 +1,138 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import AVFoundation +import XCTest + +@testable import camera_avfoundation + +final class AvailableCamerasTest: XCTestCase { + private func createCameraPlugin(with deviceDiscoverer: MockCameraDeviceDiscoverer) -> CameraPlugin + { + return CameraPlugin( + registry: MockFlutterTextureRegistry(), + messenger: MockFlutterBinaryMessenger(), + globalAPI: MockGlobalEventApi(), + deviceDiscoverer: deviceDiscoverer, + permissionManager: MockCameraPermissionManager(), + deviceFactory: { _ in MockCaptureDevice() }, + captureSessionFactory: { MockCaptureSession() }, + captureDeviceInputFactory: MockCaptureDeviceInputFactory(), + captureSessionQueue: DispatchQueue(label: "io.flutter.camera.captureSessionQueue") + ) + } + + func testAvailableCamerasShouldReturnAllCamerasOnMultiCameraIPhone() { + let mockDeviceDiscoverer = MockCameraDeviceDiscoverer() + let cameraPlugin = createCameraPlugin(with: mockDeviceDiscoverer) + let expectation = self.expectation(description: "Result finished") + + mockDeviceDiscoverer.discoverySessionStub = { deviceTypes, mediaType, position in + // iPhone 13 Cameras: + let wideAngleCamera = MockCaptureDevice() + wideAngleCamera.uniqueID = "0" + wideAngleCamera.position = .back + + let frontFacingCamera = MockCaptureDevice() + frontFacingCamera.uniqueID = "1" + frontFacingCamera.position = .front + + let ultraWideCamera = MockCaptureDevice() + ultraWideCamera.uniqueID = "2" + ultraWideCamera.position = .back + + let telephotoCamera = MockCaptureDevice() + telephotoCamera.uniqueID = "3" + telephotoCamera.position = .back + + var requiredTypes: [AVCaptureDevice.DeviceType] = [ + .builtInWideAngleCamera, .builtInTelephotoCamera, .builtInUltraWideCamera, + ] + var cameras = [wideAngleCamera, frontFacingCamera, telephotoCamera, ultraWideCamera] + + XCTAssertEqual(deviceTypes, requiredTypes) + XCTAssertEqual(mediaType, .video) + XCTAssertEqual(position, .unspecified) + return cameras + } + + var resultValue: [PlatformCameraDescription]? + cameraPlugin.getAvailableCameras { result in + resultValue = self.assertSuccess(result) + expectation.fulfill() + } + waitForExpectations(timeout: 30, handler: nil) + + // Verify the result. + XCTAssertEqual(resultValue?.count, 4) + } + + func testAvailableCamerasShouldReturnTwoCamerasOnDualCameraIPhone() { + let mockDeviceDiscoverer = MockCameraDeviceDiscoverer() + let cameraPlugin = createCameraPlugin(with: mockDeviceDiscoverer) + let expectation = self.expectation(description: "Result finished") + + mockDeviceDiscoverer.discoverySessionStub = { deviceTypes, mediaType, position in + // iPhone 8 Cameras: + let wideAngleCamera = MockCaptureDevice() + wideAngleCamera.uniqueID = "0" + wideAngleCamera.position = .back + + let frontFacingCamera = MockCaptureDevice() + frontFacingCamera.uniqueID = "1" + frontFacingCamera.position = .front + + var requiredTypes: [AVCaptureDevice.DeviceType] = [ + .builtInWideAngleCamera, .builtInTelephotoCamera, .builtInUltraWideCamera, + ] + let cameras = [wideAngleCamera, frontFacingCamera] + + XCTAssertEqual(deviceTypes, requiredTypes) + XCTAssertEqual(mediaType, .video) + XCTAssertEqual(position, .unspecified) + return cameras + } + + var resultValue: [PlatformCameraDescription]? + cameraPlugin.getAvailableCameras { result in + resultValue = self.assertSuccess(result) + expectation.fulfill() + } + waitForExpectations(timeout: 30, handler: nil) + + // Verify the result. + XCTAssertEqual(resultValue?.count, 2) + } + + func testAvailableCamerasShouldReturnExternalLensDirectionForUnspecifiedCameraPosition() { + let mockDeviceDiscoverer = MockCameraDeviceDiscoverer() + let cameraPlugin = createCameraPlugin(with: mockDeviceDiscoverer) + let expectation = self.expectation(description: "Result finished") + + mockDeviceDiscoverer.discoverySessionStub = { deviceTypes, mediaType, position in + let unspecifiedCamera = MockCaptureDevice() + unspecifiedCamera.uniqueID = "0" + unspecifiedCamera.position = .unspecified + + var requiredTypes: [AVCaptureDevice.DeviceType] = [ + .builtInWideAngleCamera, .builtInTelephotoCamera, .builtInUltraWideCamera, + ] + let cameras = [unspecifiedCamera] + + XCTAssertEqual(deviceTypes, requiredTypes) + XCTAssertEqual(mediaType, .video) + XCTAssertEqual(position, .unspecified) + return cameras + } + + var resultValue: [PlatformCameraDescription]? + cameraPlugin.getAvailableCameras { result in + resultValue = self.assertSuccess(result) + expectation.fulfill() + } + waitForExpectations(timeout: 30, handler: nil) + + XCTAssertEqual(resultValue?.first?.lensDirection, .external) + } +} diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraInitRaceConditionsTests.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraInitRaceConditionsTests.swift new file mode 100644 index 000000000000..03f5fa3e9fab --- /dev/null +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraInitRaceConditionsTests.swift @@ -0,0 +1,92 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import XCTest + +@testable import camera_avfoundation + +final class CameraInitRaceConditionsTests: XCTestCase { + private func createCameraPlugin() -> (CameraPlugin, DispatchQueue) { + let captureSessionQueue = DispatchQueue(label: "io.flutter.camera.captureSessionQueue") + + let cameraPlugin = CameraPlugin( + registry: MockFlutterTextureRegistry(), + messenger: MockFlutterBinaryMessenger(), + globalAPI: MockGlobalEventApi(), + deviceDiscoverer: MockCameraDeviceDiscoverer(), + permissionManager: MockCameraPermissionManager(), + deviceFactory: { _ in MockCaptureDevice() }, + captureSessionFactory: { MockCaptureSession() }, + captureDeviceInputFactory: MockCaptureDeviceInputFactory(), + captureSessionQueue: captureSessionQueue + ) + + return (cameraPlugin, captureSessionQueue) + } + + func testFixForCaptureSessionQueueNullPointerCrashDueToRaceCondition() { + let (cameraPlugin, captureSessionQueue) = createCameraPlugin() + let disposeExpectation = expectation(description: "dispose's result block must be called") + let createExpectation = expectation(description: "create's result block must be called") + + // Mimic a dispose call followed by a create call, which can be triggered by slightly dragging the + // home bar, causing the app to be inactive, and immediately regain active. + cameraPlugin.dispose(cameraId: 0) { error in + disposeExpectation.fulfill() + } + + cameraPlugin.createCameraOnSessionQueue( + withName: "acamera", + settings: PlatformMediaSettings( + resolutionPreset: .medium, + framesPerSecond: nil, + videoBitrate: nil, + audioBitrate: nil, + enableAudio: true + ) + ) { result in + createExpectation.fulfill() + } + + waitForExpectations(timeout: 30, handler: nil) + + // `captureSessionQueue` must not be nil after `create` call. Otherwise a nil + // `captureSessionQueue` passed into `AVCaptureVideoDataOutput::setSampleBufferDelegate:queue:` + // API will cause a crash. + XCTAssertNotNil( + captureSessionQueue, "captureSessionQueue must not be nil after create method.") + } + + func testFlutterChannelInitializedWhenStartingImageStream() { + let (cameraPlugin, _captureSessionQueue) = createCameraPlugin() + let createExpectation = expectation(description: "create's result block must be called") + + cameraPlugin.createCameraOnSessionQueue( + withName: "acamera", + settings: PlatformMediaSettings( + resolutionPreset: .medium, + framesPerSecond: nil, + videoBitrate: nil, + audioBitrate: nil, + enableAudio: true + ) + ) { result in + createExpectation.fulfill() + } + + waitForExpectations(timeout: 30, handler: nil) + + // Start stream and wait for its completion. + let startStreamExpectation = expectation( + description: "startImageStream's result block must be called") + cameraPlugin.startImageStream(completion: { + _ in + startStreamExpectation.fulfill() + }) + + waitForExpectations(timeout: 30, handler: nil) + XCTAssertEqual(cameraPlugin.camera?.isStreamingImages, true) + } + +} diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraMethodChannelTests.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraMethodChannelTests.swift new file mode 100644 index 000000000000..80231393b5d4 --- /dev/null +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraMethodChannelTests.swift @@ -0,0 +1,80 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import AVFoundation +import XCTest + +@testable import camera_avfoundation + +final class CameraMethodChannelTests: XCTestCase { + private func createCameraPlugin(with session: MockCaptureSession) -> CameraPlugin { + return CameraPlugin( + registry: MockFlutterTextureRegistry(), + messenger: MockFlutterBinaryMessenger(), + globalAPI: MockGlobalEventApi(), + deviceDiscoverer: MockCameraDeviceDiscoverer(), + permissionManager: MockCameraPermissionManager(), + deviceFactory: { _ in MockCaptureDevice() }, + captureSessionFactory: { session }, + captureDeviceInputFactory: MockCaptureDeviceInputFactory(), + captureSessionQueue: DispatchQueue(label: "io.flutter.camera.captureSessionQueue") + ) + } + + func testCreate_ShouldCallResultOnMainThread() { + let avCaptureSessionMock = MockCaptureSession() + avCaptureSessionMock.canSetSessionPresetStub = { _ in true } + let camera = createCameraPlugin(with: avCaptureSessionMock) + let expectation = self.expectation(description: "Result finished") + + var resultValue: Int64? + camera.createCameraOnSessionQueue( + withName: "acamera", + settings: PlatformMediaSettings( + resolutionPreset: .medium, + framesPerSecond: nil, + videoBitrate: nil, + audioBitrate: nil, + enableAudio: true + ) + ) { result in + resultValue = self.assertSuccess(result) + expectation.fulfill() + } + + waitForExpectations(timeout: 30, handler: nil) + XCTAssertNotNil(resultValue) + } + + func testDisposeShouldDeallocCamera() { + let avCaptureSessionMock = MockCaptureSession() + avCaptureSessionMock.canSetSessionPresetStub = { _ in true } + let camera = createCameraPlugin(with: avCaptureSessionMock) + let createExpectation = self.expectation(description: "create's result block must be called") + + camera.createCameraOnSessionQueue( + withName: "acamera", + settings: PlatformMediaSettings( + resolutionPreset: .medium, + framesPerSecond: nil, + videoBitrate: nil, + audioBitrate: nil, + enableAudio: true + ) + ) { result in + createExpectation.fulfill() + } + + waitForExpectations(timeout: 30, handler: nil) + XCTAssertNotNil(camera.camera) + + let disposeExpectation = self.expectation(description: "dispose's result block must be called") + camera.dispose(cameraId: 0) { error in + disposeExpectation.fulfill() + } + + waitForExpectations(timeout: 30, handler: nil) + XCTAssertNil(camera.camera, "camera should be deallocated after dispose") + } +} diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraOrientationTests.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraOrientationTests.swift new file mode 100644 index 000000000000..4878cbe51d6f --- /dev/null +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraOrientationTests.swift @@ -0,0 +1,168 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import AVFoundation +import Flutter +import XCTest + +@testable import camera_avfoundation + +private final class MockUIDevice: UIDevice { + var mockOrientation: UIDeviceOrientation = .unknown + + override var orientation: UIDeviceOrientation { + return mockOrientation + } +} + +final class CameraOrientationTests: XCTestCase { + private func createCameraPlugin() -> ( + cameraPlugin: CameraPlugin, + mockCamera: MockCamera, + mockEventAPI: MockGlobalEventApi, + mockDevice: MockCaptureDevice, + mockDeviceDiscoverer: MockCameraDeviceDiscoverer, + captureSessionQueue: DispatchQueue + ) { + let mockDevice = MockCaptureDevice() + let mockCamera = MockCamera() + let mockEventAPI = MockGlobalEventApi() + let mockDeviceDiscoverer = MockCameraDeviceDiscoverer() + let captureSessionQueue = DispatchQueue(label: "io.flutter.camera.captureSessionQueue") + + let cameraPlugin = CameraPlugin( + registry: MockFlutterTextureRegistry(), + messenger: MockFlutterBinaryMessenger(), + globalAPI: mockEventAPI, + deviceDiscoverer: mockDeviceDiscoverer, + permissionManager: MockCameraPermissionManager(), + deviceFactory: { _ in mockDevice }, + captureSessionFactory: { MockCaptureSession() }, + captureDeviceInputFactory: MockCaptureDeviceInputFactory(), + captureSessionQueue: captureSessionQueue + ) + cameraPlugin.camera = mockCamera + + return ( + cameraPlugin, + mockCamera, + mockEventAPI, + mockDevice, + mockDeviceDiscoverer, + captureSessionQueue + ) + } + + private func sendOrientation( + _ orientation: UIDeviceOrientation, + to cameraPlugin: CameraPlugin, + captureSessionQueue: DispatchQueue + ) { + cameraPlugin.orientationChanged(createMockNotification(for: orientation)) + waitForQueueRoundTrip(with: captureSessionQueue) + } + + private func createMockNotification(for deviceOrientation: UIDeviceOrientation) -> Notification { + let mockDevice = MockUIDevice() + mockDevice.mockOrientation = deviceOrientation + return Notification(name: Notification.Name("orientation_test"), object: mockDevice) + } + + func testOrientationNotifications() { + let (cameraPlugin, _, mockEventAPI, _, _, captureSessionQueue) = createCameraPlugin() + + sendOrientation(.portraitUpsideDown, to: cameraPlugin, captureSessionQueue: captureSessionQueue) + XCTAssertEqual(mockEventAPI.lastOrientation, .portraitDown) + sendOrientation(.portrait, to: cameraPlugin, captureSessionQueue: captureSessionQueue) + XCTAssertEqual(mockEventAPI.lastOrientation, .portraitUp) + sendOrientation(.landscapeLeft, to: cameraPlugin, captureSessionQueue: captureSessionQueue) + XCTAssertEqual(mockEventAPI.lastOrientation, .landscapeLeft) + sendOrientation(.landscapeRight, to: cameraPlugin, captureSessionQueue: captureSessionQueue) + XCTAssertEqual(mockEventAPI.lastOrientation, .landscapeRight) + } + + func testOrientationNotificationsNotCalledForFaceUp() { + let (cameraPlugin, _, mockEventAPI, _, _, captureSessionQueue) = createCameraPlugin() + sendOrientation(.faceUp, to: cameraPlugin, captureSessionQueue: captureSessionQueue) + XCTAssertFalse(mockEventAPI.deviceOrientationChangedCalled) + } + + func testOrientationNotificationsNotCalledForFaceDown() { + let (cameraPlugin, _, mockEventAPI, _, _, captureSessionQueue) = createCameraPlugin() + sendOrientation(.faceDown, to: cameraPlugin, captureSessionQueue: captureSessionQueue) + XCTAssertFalse(mockEventAPI.deviceOrientationChangedCalled) + } + + func testOrientationUpdateMustBeOnCaptureSessionQueue() { + let queueExpectation = expectation( + description: "Orientation update must happen on the capture session queue") + let (cameraPlugin, mockCamera, _, _, _, captureSessionQueue) = createCameraPlugin() + let captureSessionQueueSpecific = DispatchSpecificKey() + captureSessionQueue.setSpecific( + key: captureSessionQueueSpecific, + value: ()) + + mockCamera.setDeviceOrientationStub = { orientation in + if DispatchQueue.getSpecific(key: captureSessionQueueSpecific) != nil { + queueExpectation.fulfill() + } + } + + cameraPlugin.orientationChanged(createMockNotification(for: .landscapeLeft)) + waitForExpectations(timeout: 30, handler: nil) + } + + func testOrientationChangedNoRetainCycle() { + let (_, mockCamera, mockEventAPI, mockDevice, mockDeviceDiscoverer, _) = createCameraPlugin() + let captureSessionQueue = DispatchQueue(label: "capture_session_queue") + weak var weakPlugin: CameraPlugin? + weak var weakDevice = mockDevice + + autoreleasepool { + let cameraPlugin = CameraPlugin( + registry: MockFlutterTextureRegistry(), + messenger: MockFlutterBinaryMessenger(), + globalAPI: mockEventAPI, + deviceDiscoverer: mockDeviceDiscoverer, + permissionManager: MockCameraPermissionManager(), + deviceFactory: { _ in weakDevice! }, + captureSessionFactory: { MockCaptureSession() }, + captureDeviceInputFactory: MockCaptureDeviceInputFactory(), + captureSessionQueue: captureSessionQueue + ) + weakPlugin = cameraPlugin + cameraPlugin.camera = mockCamera + + cameraPlugin.orientationChanged(createMockNotification(for: .landscapeLeft)) + } + + // Sanity check. + let cameraDeallocatedExpectation = self.expectation( + description: "Camera must have been deallocated.") + captureSessionQueue.async { + XCTAssertNil(weakPlugin) + cameraDeallocatedExpectation.fulfill() + } + // Awaiting expectation is needed. The test is flaky when checking for nil right away. + waitForExpectations(timeout: 1, handler: nil) + + var setDeviceOrientationCalled = false + mockCamera.setDeviceOrientationStub = { orientation in + if orientation == .landscapeLeft { + setDeviceOrientationCalled = true + } + } + + weak var weakEventAPI = mockEventAPI + // Must check in captureSessionQueue since orientationChanged dispatches to this queue. + let expectation = self.expectation(description: "Dispatched to capture session queue") + captureSessionQueue.async { + XCTAssertFalse(setDeviceOrientationCalled) + XCTAssertFalse(weakEventAPI?.deviceOrientationChangedCalled ?? false) + expectation.fulfill() + } + + waitForExpectations(timeout: 30, handler: nil) + } +} diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraPermissionTests.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraPermissionTests.swift new file mode 100644 index 000000000000..d8ca79f65eca --- /dev/null +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraPermissionTests.swift @@ -0,0 +1,237 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import AVFoundation +import Flutter +import XCTest + +@testable import camera_avfoundation + +private final class MockPermissionService: NSObject, PermissionServicing { + var authorizationStatusStub: ((AVMediaType) -> AVAuthorizationStatus)? + var requestAccessStub: ((AVMediaType, @escaping @Sendable (Bool) -> Void) -> Void)? + + func authorizationStatus(for mediaType: AVMediaType) -> AVAuthorizationStatus { + return authorizationStatusStub?(mediaType) ?? .notDetermined + } + + func requestAccess(for mediaType: AVMediaType, completion: @escaping @Sendable (Bool) -> Void) { + requestAccessStub?(mediaType, completion) + } +} + +final class CameraPermissionManagerTests: XCTestCase { + private func createSutAndMocks() -> (CameraPermissionManager, MockPermissionService) { + let mockPermissionService = MockPermissionService() + let permissionManager = CameraPermissionManager(permissionService: mockPermissionService) + + return (permissionManager, mockPermissionService) + } + + // MARK: - Camera permissions + + func testRequestCameraPermission_completeWithoutErrorIfPreviouslyAuthorized() { + let (permissionManager, mockPermissionService) = createSutAndMocks() + let expectation = self.expectation( + description: "Must complete without error if camera access was previously authorized.") + + mockPermissionService.authorizationStatusStub = { mediaType in + XCTAssertEqual(mediaType, .video) + return .authorized + } + permissionManager.requestCameraPermission { error in + XCTAssertNil(error) + expectation.fulfill() + } + + waitForExpectations(timeout: 30, handler: nil) + } + + func testRequestCameraPermission_completeWithErrorIfPreviouslyDenied() { + let (permissionManager, mockPermissionService) = createSutAndMocks() + let expectation = self.expectation( + description: "Must complete with error if camera access was previously denied.") + + mockPermissionService.authorizationStatusStub = { mediaType in + XCTAssertEqual(mediaType, .video) + return .denied + } + permissionManager.requestCameraPermission { error in + XCTAssertEqual(error?.code, "CameraAccessDeniedWithoutPrompt") + XCTAssertEqual( + error?.message, + "User has previously denied the camera access request. Go to Settings to enable camera access." + ) + expectation.fulfill() + } + + waitForExpectations(timeout: 30, handler: nil) + } + + func testRequestCameraPermission_completeWithErrorIfRestricted() { + let (permissionManager, mockPermissionService) = createSutAndMocks() + let expectation = self.expectation( + description: "Must complete with error if camera access is restricted.") + + mockPermissionService.authorizationStatusStub = { mediaType in + XCTAssertEqual(mediaType, .video) + return .restricted + } + permissionManager.requestCameraPermission { error in + XCTAssertEqual(error?.code, "CameraAccessRestricted") + XCTAssertEqual(error?.message, "Camera access is restricted.") + expectation.fulfill() + } + + waitForExpectations(timeout: 30, handler: nil) + } + + func testRequestCameraPermission_completeWithoutErrorIfUserGrantAccess() { + let (permissionManager, mockPermissionService) = createSutAndMocks() + let expectation = self.expectation( + description: "Must complete without error if user granted access.") + + mockPermissionService.authorizationStatusStub = { mediaType in + XCTAssertEqual(mediaType, .video) + return .notDetermined + } + mockPermissionService.requestAccessStub = { mediaType, handler in + XCTAssertEqual(mediaType, .video) + // Grant access. + handler(true) + } + permissionManager.requestCameraPermission { error in + XCTAssertNil(error) + expectation.fulfill() + } + + waitForExpectations(timeout: 30, handler: nil) + } + + func testRequestCameraPermission_completeWithErrorIfUserDenyAccess() { + let (permissionManager, mockPermissionService) = createSutAndMocks() + let expectation = self.expectation( + description: "Must complete with error if user denied access.") + + mockPermissionService.authorizationStatusStub = { mediaType in + XCTAssertEqual(mediaType, .video) + return .notDetermined + } + mockPermissionService.requestAccessStub = { mediaType, handler in + XCTAssertEqual(mediaType, .video) + // Deny access. + handler(false) + } + permissionManager.requestCameraPermission { error in + XCTAssertEqual(error?.code, "CameraAccessDenied") + XCTAssertEqual(error?.message, "User denied the camera access request.") + expectation.fulfill() + } + + waitForExpectations(timeout: 30, handler: nil) + } + + // MARK: - Audio permissions + + func testRequestAudioPermission_completeWithoutErrorIfPreviouslyAuthorized() { + let (permissionManager, mockPermissionService) = createSutAndMocks() + let expectation = self.expectation( + description: "Must complete without error if audio access was previously authorized.") + + mockPermissionService.authorizationStatusStub = { mediaType in + XCTAssertEqual(mediaType, .audio) + return .authorized + } + permissionManager.requestAudioPermission { error in + XCTAssertNil(error) + expectation.fulfill() + } + + waitForExpectations(timeout: 30, handler: nil) + } + + func testRequestAudioPermission_completeWithErrorIfPreviouslyDenied() { + let (permissionManager, mockPermissionService) = createSutAndMocks() + let expectation = self.expectation( + description: "Must complete with error if audio access was previously denied.") + + mockPermissionService.authorizationStatusStub = { mediaType in + XCTAssertEqual(mediaType, .audio) + return .denied + } + permissionManager.requestAudioPermission { error in + XCTAssertEqual(error?.code, "AudioAccessDeniedWithoutPrompt") + XCTAssertEqual( + error?.message, + "User has previously denied the audio access request. Go to Settings to enable audio access." + ) + expectation.fulfill() + } + + waitForExpectations(timeout: 30, handler: nil) + } + + func testRequestAudioPermission_completeWithErrorIfRestricted() { + let (permissionManager, mockPermissionService) = createSutAndMocks() + let expectation = self.expectation( + description: "Must complete with error if audio access is restricted.") + + mockPermissionService.authorizationStatusStub = { mediaType in + XCTAssertEqual(mediaType, .audio) + return .restricted + } + permissionManager.requestAudioPermission { error in + XCTAssertEqual(error?.code, "AudioAccessRestricted") + XCTAssertEqual(error?.message, "Audio access is restricted.") + expectation.fulfill() + } + + waitForExpectations(timeout: 30, handler: nil) + } + + func testRequestAudioPermission_completeWithoutErrorIfUserGrantAccess() { + let (permissionManager, mockPermissionService) = createSutAndMocks() + let expectation = self.expectation( + description: "Must complete without error if user granted access.") + + mockPermissionService.authorizationStatusStub = { mediaType in + XCTAssertEqual(mediaType, .audio) + return .notDetermined + } + mockPermissionService.requestAccessStub = { mediaType, handler in + XCTAssertEqual(mediaType, .audio) + // Grant access. + handler(true) + } + permissionManager.requestAudioPermission { error in + XCTAssertNil(error) + expectation.fulfill() + } + + waitForExpectations(timeout: 30, handler: nil) + } + + func testRequestAudioPermission_completeWithErrorIfUserDenyAccess() { + let (permissionManager, mockPermissionService) = createSutAndMocks() + let expectation = self.expectation( + description: "Must complete with error if user denied access") + + mockPermissionService.authorizationStatusStub = { mediaType in + XCTAssertEqual(mediaType, .audio) + return .notDetermined + } + mockPermissionService.requestAccessStub = { mediaType, handler in + XCTAssertEqual(mediaType, .audio) + // Deny access. + handler(false) + } + permissionManager.requestAudioPermission { error in + XCTAssertEqual(error?.code, "AudioAccessDenied") + XCTAssertEqual(error?.message, "User denied the audio access request.") + expectation.fulfill() + } + + waitForExpectations(timeout: 30, handler: nil) + } +} diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraPluginCreateCameraTests.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraPluginCreateCameraTests.swift new file mode 100644 index 000000000000..5eb2b61e8ea2 --- /dev/null +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraPluginCreateCameraTests.swift @@ -0,0 +1,131 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import XCTest + +@testable import camera_avfoundation + +final class CameraPluginCreateCameraTests: XCTestCase { + private func createCameraPlugin() -> ( + CameraPlugin, MockCameraPermissionManager, MockCaptureSession + ) { + let mockPermissionManager = MockCameraPermissionManager() + let mockCaptureSession = MockCaptureSession() + + let cameraPlugin = CameraPlugin( + registry: MockFlutterTextureRegistry(), + messenger: MockFlutterBinaryMessenger(), + globalAPI: MockGlobalEventApi(), + deviceDiscoverer: MockCameraDeviceDiscoverer(), + permissionManager: mockPermissionManager, + deviceFactory: { _ in MockCaptureDevice() }, + captureSessionFactory: { mockCaptureSession }, + captureDeviceInputFactory: MockCaptureDeviceInputFactory(), + captureSessionQueue: DispatchQueue(label: "io.flutter.camera.captureSessionQueue") + ) + + return (cameraPlugin, mockPermissionManager, mockCaptureSession) + } + + func testCreateCamera_requestsOnlyCameraPermissionWithAudioDisabled() { + let (cameraPlugin, mockPermissionManager, _) = createCameraPlugin() + let expectation = expectation(description: "Initialization completed") + + var requestCameraPermissionCalled = false + mockPermissionManager.requestCameraPermissionStub = { completion in + requestCameraPermissionCalled = true + // Permission is granted + completion(nil) + } + var requestAudioPermissionCalled = false + mockPermissionManager.requestAudioPermissionStub = { completion in + requestAudioPermissionCalled = true + // Permission is granted + completion(nil) + } + + cameraPlugin.create( + cameraName: "camera_name", + settings: PlatformMediaSettings( + resolutionPreset: .medium, + framesPerSecond: nil, + videoBitrate: nil, + audioBitrate: nil, + enableAudio: false) + ) { result in + expectation.fulfill() + } + + waitForExpectations(timeout: 30, handler: nil) + + XCTAssertTrue(requestCameraPermissionCalled) + XCTAssertFalse(requestAudioPermissionCalled) + } + + func testCreateCamera_requestsCameraAndAudioPermissionWithAudioEnabled() { + let (cameraPlugin, mockPermissionManager, _) = createCameraPlugin() + let expectation = expectation(description: "Initialization completed") + + var requestCameraPermissionCalled = false + mockPermissionManager.requestCameraPermissionStub = { completion in + requestCameraPermissionCalled = true + // Permission is granted + completion(nil) + } + var requestAudioPermissionCalled = false + mockPermissionManager.requestAudioPermissionStub = { completion in + requestAudioPermissionCalled = true + // Permission is granted + completion(nil) + } + + cameraPlugin.create( + cameraName: "camera_name", + settings: PlatformMediaSettings( + resolutionPreset: .medium, + framesPerSecond: nil, + videoBitrate: nil, + audioBitrate: nil, + enableAudio: true) + ) { result in + expectation.fulfill() + } + + waitForExpectations(timeout: 30, handler: nil) + + XCTAssertTrue(requestCameraPermissionCalled) + XCTAssertTrue(requestAudioPermissionCalled) + } + + func testCreateCamera_createsFLTCamSuccessfully() { + let (cameraPlugin, mockPermissionManager, mockCaptureSession) = createCameraPlugin() + let expectation = expectation(description: "Initialization completed") + + mockPermissionManager.requestCameraPermissionStub = { completion in + // Permission is granted + completion(nil) + } + mockPermissionManager.requestAudioPermissionStub = { completion in + // Permission is granted + completion(nil) + } + mockCaptureSession.canSetSessionPresetStub = { _ in true } + + cameraPlugin.create( + cameraName: "camera_name", + settings: PlatformMediaSettings( + resolutionPreset: .medium, + framesPerSecond: nil, + videoBitrate: nil, + audioBitrate: nil, + enableAudio: true) + ) { result in + expectation.fulfill() + } + + waitForExpectations(timeout: 30, handler: nil) + + XCTAssertNotNil(cameraPlugin.camera) + } +} diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraPluginDelegatingMethodTests.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraPluginDelegatingMethodTests.swift new file mode 100644 index 000000000000..4e3c5a377f06 --- /dev/null +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraPluginDelegatingMethodTests.swift @@ -0,0 +1,630 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import XCTest + +@testable import camera_avfoundation + +/// Tests of `CameraPlugin` methods delegating to `FLTCam` instance +final class CameraPluginDelegatingMethodTests: XCTestCase { + private func createCameraPlugin() -> (CameraPlugin, MockCamera) { + let mockCamera = MockCamera() + + let cameraPlugin = CameraPlugin( + registry: MockFlutterTextureRegistry(), + messenger: MockFlutterBinaryMessenger(), + globalAPI: MockGlobalEventApi(), + deviceDiscoverer: MockCameraDeviceDiscoverer(), + permissionManager: MockCameraPermissionManager(), + deviceFactory: { _ in MockCaptureDevice() }, + captureSessionFactory: { MockCaptureSession() }, + captureDeviceInputFactory: MockCaptureDeviceInputFactory(), + captureSessionQueue: DispatchQueue(label: "io.flutter.camera.captureSessionQueue") + ) + cameraPlugin.camera = mockCamera + + return (cameraPlugin, mockCamera) + } + + func testLockCapture_callsCameraLockCapture() { + let (cameraPlugin, mockCamera) = createCameraPlugin() + let expectation = expectation(description: "Call completed") + + let targetOrientation = PlatformDeviceOrientation.landscapeLeft + + var lockCaptureCalled = false + mockCamera.lockCaptureOrientationStub = { orientation in + XCTAssertEqual(orientation, targetOrientation) + lockCaptureCalled = true + } + + cameraPlugin.lockCaptureOrientation(orientation: targetOrientation) { result in + let _ = self.assertSuccess(result) + expectation.fulfill() + } + + waitForExpectations(timeout: 30, handler: nil) + + XCTAssertTrue(lockCaptureCalled) + } + + func testPausePreview_callsCameraPausePreview() { + let (cameraPlugin, mockCamera) = createCameraPlugin() + let expectation = expectation(description: "Call completed") + + var pausePreviewCalled = false + mockCamera.pausePreviewStub = { + pausePreviewCalled = true + } + + cameraPlugin.pausePreview { result in + let _ = self.assertSuccess(result) + expectation.fulfill() + } + + waitForExpectations(timeout: 30, handler: nil) + + XCTAssertTrue(pausePreviewCalled) + } + + func testPauseVideoRecording_callsCameraPauseVideoRecording() { + let (cameraPlugin, mockCamera) = createCameraPlugin() + let expectation = expectation(description: "Call completed") + + var pauseVideoRecordingCalled = false + mockCamera.pauseVideoRecordingStub = { + pauseVideoRecordingCalled = true + } + + cameraPlugin.pauseVideoRecording { result in + let _ = self.assertSuccess(result) + expectation.fulfill() + } + + waitForExpectations(timeout: 30, handler: nil) + + XCTAssertTrue(pauseVideoRecordingCalled) + } + + func testPrepareForVideoRecording_callsCameraSetUpCaptureSessionForAudioIfNeeded() { + let (cameraPlugin, mockCamera) = createCameraPlugin() + let expectation = expectation(description: "Call completed") + + var setUpCaptureSessionForAudioIfNeededCalled = false + mockCamera.setUpCaptureSessionForAudioIfNeededStub = { + setUpCaptureSessionForAudioIfNeededCalled = true + } + + cameraPlugin.prepareForVideoRecording { result in + let _ = self.assertSuccess(result) + expectation.fulfill() + } + + waitForExpectations(timeout: 30, handler: nil) + + XCTAssertTrue(setUpCaptureSessionForAudioIfNeededCalled) + } + + func testReceivedImageStreamData_callsCameraReceivedImageStreamData() { + let (cameraPlugin, mockCamera) = createCameraPlugin() + let expectation = expectation(description: "Call completed") + + var receivedImageStreamDataCalled = false + mockCamera.receivedImageStreamDataStub = { + receivedImageStreamDataCalled = true + } + + cameraPlugin.receivedImageStreamData { result in + let _ = self.assertSuccess(result) + expectation.fulfill() + } + + waitForExpectations(timeout: 30, handler: nil) + + XCTAssertTrue(receivedImageStreamDataCalled) + } + + func testResumeVideoRecording_callsCameraResumeVideoRecording() { + let (cameraPlugin, mockCamera) = createCameraPlugin() + let expectation = expectation(description: "Call completed") + + var resumeVideoRecordingCalled = false + mockCamera.resumeVideoRecordingStub = { + resumeVideoRecordingCalled = true + } + + cameraPlugin.resumeVideoRecording { result in + let _ = self.assertSuccess(result) + expectation.fulfill() + } + + waitForExpectations(timeout: 30, handler: nil) + + XCTAssertTrue(resumeVideoRecordingCalled) + } + + func testResumePreview_callsCameraResumePreview() { + let (cameraPlugin, mockCamera) = createCameraPlugin() + let expectation = expectation(description: "Call completed") + + var resumePreviewCalled = false + mockCamera.resumePreviewStub = { + resumePreviewCalled = true + } + + cameraPlugin.resumePreview { result in + let _ = self.assertSuccess(result) + expectation.fulfill() + } + + waitForExpectations(timeout: 30, handler: nil) + + XCTAssertTrue(resumePreviewCalled) + } + + func testSetExposureMode_callsCameraExposureMode() { + let (cameraPlugin, mockCamera) = createCameraPlugin() + let expectation = expectation(description: "Call completed") + + let targetExposureMode = PlatformExposureMode.locked + + var setExposureModeCalled = false + mockCamera.setExposureModeStub = { mode in + XCTAssertEqual(mode, targetExposureMode) + setExposureModeCalled = true + } + + cameraPlugin.setExposureMode(mode: targetExposureMode) { result in + let _ = self.assertSuccess(result) + expectation.fulfill() + } + + waitForExpectations(timeout: 30, handler: nil) + + XCTAssertTrue(setExposureModeCalled) + } + + func testSetExposureOffset_callsCameraSetExposureOffset() { + let (cameraPlugin, mockCamera) = createCameraPlugin() + let expectation = expectation(description: "Call completed") + + let targetExposureOffset = 1.0 + + var setExposureOffsetCalled = false + mockCamera.setExposureOffsetStub = { offset in + XCTAssertEqual(offset, targetExposureOffset) + setExposureOffsetCalled = true + } + + cameraPlugin.setExposureOffset(offset: targetExposureOffset) { result in + let _ = self.assertSuccess(result) + expectation.fulfill() + } + + waitForExpectations(timeout: 30, handler: nil) + + XCTAssertTrue(setExposureOffsetCalled) + } + + func testSetFocusMode_callsCameraSetFocusMode() { + let (cameraPlugin, mockCamera) = createCameraPlugin() + let expectation = expectation(description: "Call completed") + + let targetFocusMode = PlatformFocusMode.locked + + var setFocusModeCalled = false + mockCamera.setFocusModeStub = { mode in + XCTAssertEqual(mode, targetFocusMode) + setFocusModeCalled = true + } + + cameraPlugin.setFocusMode(mode: targetFocusMode) { result in + let _ = self.assertSuccess(result) + expectation.fulfill() + } + + waitForExpectations(timeout: 30, handler: nil) + + XCTAssertTrue(setFocusModeCalled) + } + + func testSetImageFileFormat_callsCameraSetImageFileFormat() { + let (cameraPlugin, mockCamera) = createCameraPlugin() + let expectation = expectation(description: "Call completed") + + let targetFileFormat = PlatformImageFileFormat.heif + + var setImageFileFormatCalled = false + mockCamera.setImageFileFormatStub = { fileFormat in + XCTAssertEqual(fileFormat, targetFileFormat) + setImageFileFormatCalled = true + } + + cameraPlugin.setImageFileFormat(format: targetFileFormat) { result in + let _ = self.assertSuccess(result) + expectation.fulfill() + } + + waitForExpectations(timeout: 30, handler: nil) + + XCTAssertTrue(setImageFileFormatCalled) + } + + func testStartImageStream_callsCameraStartImageStream() { + let (cameraPlugin, mockCamera) = createCameraPlugin() + let expectation = expectation(description: "Call completed") + + var startImageStreamCalled = false + mockCamera.startImageStreamStub = { messenger, completion in + startImageStreamCalled = true + completion(.success(())) + } + + cameraPlugin.startImageStream { result in + let _ = self.assertSuccess(result) + expectation.fulfill() + } + + waitForExpectations(timeout: 30, handler: nil) + + XCTAssertTrue(startImageStreamCalled) + } + + func testStopImageStream_callsCameraStopImageStream() { + let (cameraPlugin, mockCamera) = createCameraPlugin() + let expectation = expectation(description: "Call completed") + + var stopImageStreamCalled = false + mockCamera.stopImageStreamStub = { + stopImageStreamCalled = true + } + + cameraPlugin.stopImageStream { result in + let _ = self.assertSuccess(result) + expectation.fulfill() + } + + waitForExpectations(timeout: 30, handler: nil) + + XCTAssertTrue(stopImageStreamCalled) + } + + func testStartVideoRecording_withStreamingTrue_callsCameraStartVideoRecordingWithMessenger() { + let (cameraPlugin, mockCamera) = createCameraPlugin() + let expectation = expectation(description: "Call completed") + + var startVideoRecordingCalled = false + mockCamera.startVideoRecordingStub = { completion, messenger in + XCTAssertNotNil(messenger) + completion(.success(())) + startVideoRecordingCalled = true + } + + cameraPlugin.startVideoRecording(enableStream: true) { result in + let _ = self.assertSuccess(result) + expectation.fulfill() + } + + waitForExpectations(timeout: 30, handler: nil) + + XCTAssertTrue(startVideoRecordingCalled) + } + + func testStartVideoRecording_withStreamingFalse_callsCameraStartVideoRecordingWithoutMessenger() { + let (cameraPlugin, mockCamera) = createCameraPlugin() + let expectation = expectation(description: "Call completed") + + var startVideoRecordingCalled = false + mockCamera.startVideoRecordingStub = { completion, messenger in + XCTAssertNil(messenger) + completion(.success(())) + startVideoRecordingCalled = true + } + + cameraPlugin.startVideoRecording(enableStream: false) { result in + let _ = self.assertSuccess(result) + expectation.fulfill() + } + + waitForExpectations(timeout: 30, handler: nil) + + XCTAssertTrue(startVideoRecordingCalled) + } + + func testStopVideoRecording_callsCameraStopVideoRecording() { + let (cameraPlugin, mockCamera) = createCameraPlugin() + let expectation = expectation(description: "Call completed") + + let targetPath = "path" + + var stopVideoRecordingCalled = false + mockCamera.stopVideoRecordingStub = { completion in + completion(.success(targetPath)) + stopVideoRecordingCalled = true + } + + cameraPlugin.stopVideoRecording { result in + switch result { + case .success(let path): + XCTAssertEqual(path, targetPath) + case .failure: + XCTFail("Unexpected error") + } + expectation.fulfill() + } + + waitForExpectations(timeout: 30, handler: nil) + + XCTAssertTrue(stopVideoRecordingCalled) + } + + func testUnlockCaptureOrientation_callsCameraUnlockCaptureOrientation() { + let (cameraPlugin, mockCamera) = createCameraPlugin() + let expectation = expectation(description: "Call completed") + + var unlockCaptureOrientationCalled = false + mockCamera.unlockCaptureOrientationStub = { + unlockCaptureOrientationCalled = true + } + + cameraPlugin.unlockCaptureOrientation { result in + let _ = self.assertSuccess(result) + expectation.fulfill() + } + + waitForExpectations(timeout: 30, handler: nil) + + XCTAssertTrue(unlockCaptureOrientationCalled) + } + + func testSetExposurePoint_callsCameraSetExposurePoint() { + let (cameraPlugin, mockCamera) = createCameraPlugin() + let expectation = expectation(description: "Call completed") + + let targetExposurePoint = PlatformPoint(x: 1.0, y: 1.0) + + var setExposurePointCalled = false + mockCamera.setExposurePointStub = { point, completion in + XCTAssertEqual(point, targetExposurePoint) + completion(.success(())) + setExposurePointCalled = true + } + + cameraPlugin.setExposurePoint(point: targetExposurePoint) { result in + let _ = self.assertSuccess(result) + expectation.fulfill() + } + + waitForExpectations(timeout: 30, handler: nil) + + XCTAssertTrue(setExposurePointCalled) + } + + func testSetFlashMode_callsCameraSetFlashMode() { + let (cameraPlugin, mockCamera) = createCameraPlugin() + let expectation = expectation(description: "Call completed") + + let targetFlashMode = PlatformFlashMode.auto + + var setFlashModeCalled = false + mockCamera.setFlashModeStub = { mode, completion in + XCTAssertEqual(mode, targetFlashMode) + completion(.success(())) + setFlashModeCalled = true + } + + cameraPlugin.setFlashMode(mode: targetFlashMode) { result in + let _ = self.assertSuccess(result) + expectation.fulfill() + } + + waitForExpectations(timeout: 30, handler: nil) + + XCTAssertTrue(setFlashModeCalled) + } + + func testSetFocusPoint_callsCameraSetFocusPoint() { + let (cameraPlugin, mockCamera) = createCameraPlugin() + let expectation = expectation(description: "Call completed") + + let targetFocusPoint = PlatformPoint(x: 1.0, y: 1.0) + + var setFocusPointCalled = false + mockCamera.setFocusPointStub = { point, completion in + XCTAssertEqual(point, targetFocusPoint) + completion(.success(())) + setFocusPointCalled = true + } + + cameraPlugin.setFocusPoint(point: targetFocusPoint) { result in + let _ = self.assertSuccess(result) + expectation.fulfill() + } + + waitForExpectations(timeout: 30, handler: nil) + + XCTAssertTrue(setFocusPointCalled) + } + + func testSetZoomLevel_callsCameraSetZoomLevel() { + let (cameraPlugin, mockCamera) = createCameraPlugin() + let expectation = expectation(description: "Call completed") + + let targetZoomLevel = 1.0 + + var setZoomLevelCalled = false + mockCamera.setZoomLevelStub = { zoom, completion in + XCTAssertEqual(zoom, targetZoomLevel) + completion(.success(())) + setZoomLevelCalled = true + } + + cameraPlugin.setZoomLevel(zoom: targetZoomLevel) { result in + let _ = self.assertSuccess(result) + expectation.fulfill() + } + + waitForExpectations(timeout: 30, handler: nil) + + XCTAssertTrue(setZoomLevelCalled) + } + + func testTakePicture_callsCameraCaptureToFile() { + let (cameraPlugin, mockCamera) = createCameraPlugin() + let expectation = expectation(description: "Call completed") + + let targetPath = "path" + + var captureToFileCalled = false + mockCamera.captureToFileStub = { completion in + completion(.success(targetPath)) + captureToFileCalled = true + } + + cameraPlugin.takePicture { result in + switch result { + case .success(let path): + XCTAssertEqual(path, targetPath) + case .failure: + XCTFail("Unexpected error") + } + expectation.fulfill() + } + + waitForExpectations(timeout: 30, handler: nil) + + XCTAssertTrue(captureToFileCalled) + } + + func testUpdateDescriptionWhileRecording_callsCameraSetDescriptionWhileRecording() { + let (cameraPlugin, mockCamera) = createCameraPlugin() + let expectation = expectation(description: "Call completed") + + let targetCameraName = "camera_name" + + var setDescriptionWhileRecordingCalled = false + mockCamera.setDescriptionWhileRecordingStub = { cameraName, completion in + XCTAssertEqual(cameraName, targetCameraName) + completion(.success(())) + setDescriptionWhileRecordingCalled = true + } + + cameraPlugin.updateDescriptionWhileRecording(cameraName: targetCameraName) { result in + let _ = self.assertSuccess(result) + expectation.fulfill() + } + + waitForExpectations(timeout: 30, handler: nil) + + XCTAssertTrue(setDescriptionWhileRecordingCalled) + } + + func testGetMaxZoomLevel_returnsValueFromCameraGetMaximumAvailableZoomFactor() { + let (cameraPlugin, mockCamera) = createCameraPlugin() + let expectation = expectation(description: "Call completed") + + let targetMaximumZoomLevel = CGFloat(1.0) + + var getMaximumAvailableZoomFactorCalled = false + mockCamera.getMaximumAvailableZoomFactorStub = { + getMaximumAvailableZoomFactorCalled = true + return targetMaximumZoomLevel + } + + cameraPlugin.getMaxZoomLevel { result in + switch result { + case .success(let zoom): + XCTAssertEqual(zoom, targetMaximumZoomLevel) + case .failure: + XCTFail("Unexpected error") + } + expectation.fulfill() + } + + waitForExpectations(timeout: 30, handler: nil) + + XCTAssertTrue(getMaximumAvailableZoomFactorCalled) + } + + func testGetMinZoomLevel_returnsValueFromCameraGetMinimumAvailableZoomFactor() { + let (cameraPlugin, mockCamera) = createCameraPlugin() + let expectation = expectation(description: "Call completed") + + let targetMinimumZoomLevel = CGFloat(1.0) + + var getMinimumAvailableZoomFactorCalled = false + mockCamera.getMinimumAvailableZoomFactorStub = { + getMinimumAvailableZoomFactorCalled = true + return targetMinimumZoomLevel + } + + cameraPlugin.getMinZoomLevel { result in + switch result { + case .success(let zoom): + XCTAssertEqual(zoom, targetMinimumZoomLevel) + case .failure: + XCTFail("Unexpected error") + } + expectation.fulfill() + } + + waitForExpectations(timeout: 30, handler: nil) + + XCTAssertTrue(getMinimumAvailableZoomFactorCalled) + } + + func testGetMaxExposureOffset_returnsValueFromCameraGetMaximumExposureOffset() { + let (cameraPlugin, mockCamera) = createCameraPlugin() + let expectation = expectation(description: "Call completed") + + let targetMaximumExposureOffset = CGFloat(1.0) + + var getMaximumExposureOffsetCalled = false + mockCamera.getMaximumExposureOffsetStub = { + getMaximumExposureOffsetCalled = true + return targetMaximumExposureOffset + } + + cameraPlugin.getMaxExposureOffset { result in + switch result { + case .success(let offset): + XCTAssertEqual(offset, targetMaximumExposureOffset) + case .failure: + XCTFail("Unexpected error") + } + expectation.fulfill() + } + + waitForExpectations(timeout: 30, handler: nil) + + XCTAssertTrue(getMaximumExposureOffsetCalled) + } + + func testGetMinExposureOffset_returnsValueFromCameraGetMinimumExposureOffset() { + let (cameraPlugin, mockCamera) = createCameraPlugin() + let expectation = expectation(description: "Call completed") + + let targetMinimumExposureOffset = CGFloat(1.0) + + var getMinimumExposureOffsetCalled = false + mockCamera.getMinimumExposureOffsetStub = { + getMinimumExposureOffsetCalled = true + return targetMinimumExposureOffset + } + + cameraPlugin.getMinExposureOffset { result in + switch result { + case .success(let offset): + XCTAssertEqual(offset, targetMinimumExposureOffset) + case .failure: + XCTFail("Unexpected error") + } + expectation.fulfill() + } + + waitForExpectations(timeout: 30, handler: nil) + + XCTAssertTrue(getMinimumExposureOffsetCalled) + } +} diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraPluginInitializeCameraTests.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraPluginInitializeCameraTests.swift new file mode 100644 index 000000000000..979ff895cfed --- /dev/null +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraPluginInitializeCameraTests.swift @@ -0,0 +1,105 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import XCTest + +@testable import camera_avfoundation + +final class CameraPluginInitializeCameraTests: XCTestCase { + private func createCameraPlugin() -> ( + CameraPlugin, MockCamera, MockGlobalEventApi, DispatchQueue + ) { + let mockCamera = MockCamera() + let mockGlobalEventApi = MockGlobalEventApi() + let captureSessionQueue = DispatchQueue(label: "io.flutter.camera.captureSessionQueue") + + let cameraPlugin = CameraPlugin( + registry: MockFlutterTextureRegistry(), + messenger: MockFlutterBinaryMessenger(), + globalAPI: mockGlobalEventApi, + deviceDiscoverer: MockCameraDeviceDiscoverer(), + permissionManager: MockCameraPermissionManager(), + deviceFactory: { _ in MockCaptureDevice() }, + captureSessionFactory: { MockCaptureSession() }, + captureDeviceInputFactory: MockCaptureDeviceInputFactory(), + captureSessionQueue: captureSessionQueue + ) + cameraPlugin.camera = mockCamera + + return (cameraPlugin, mockCamera, mockGlobalEventApi, captureSessionQueue) + } + + func testInitializeCamera_setsCameraOnFrameAvailableCallback() { + let (cameraPlugin, mockCamera, _, _) = createCameraPlugin() + let expectation = expectation(description: "Initialization completed") + + var onFrameAvailableSet = false + mockCamera.setOnFrameAvailableStub = { callback in + onFrameAvailableSet = true + } + + cameraPlugin.initialize(cameraId: 0, imageFormat: PlatformImageFormatGroup.bgra8888) { + result in + let _ = self.assertSuccess(result) + expectation.fulfill() + } + + waitForExpectations(timeout: 30, handler: nil) + + XCTAssertTrue(onFrameAvailableSet) + } + + func testInitializeCamera_setsCameraDartAPI() { + let (cameraPlugin, mockCamera, _, _) = createCameraPlugin() + let expectation = expectation(description: "Initialization completed") + + var dartAPISet = false + mockCamera.setDartApiStub = { api in + dartAPISet = true + } + + cameraPlugin.initialize(cameraId: 0, imageFormat: PlatformImageFormatGroup.bgra8888) { + result in + let _ = self.assertSuccess(result) + expectation.fulfill() + } + + waitForExpectations(timeout: 30, handler: nil) + + XCTAssertTrue(dartAPISet) + } + + func testInitializeCamera_sendsDeviceOrientation() { + let (cameraPlugin, _, mockGlobalEventApi, captureSessionQueue) = createCameraPlugin() + + cameraPlugin.initialize(cameraId: 0, imageFormat: PlatformImageFormatGroup.bgra8888) { + result in + let _ = self.assertSuccess(result) + } + + waitForQueueRoundTrip(with: captureSessionQueue) + + XCTAssertTrue(mockGlobalEventApi.deviceOrientationChangedCalled) + } + + func testInitializeCamera_startsCamera() { + let (cameraPlugin, mockCamera, _, _) = createCameraPlugin() + let expectation = expectation(description: "Initialization completed") + + var startCalled = false + mockCamera.startStub = { + startCalled = true + } + + cameraPlugin.initialize(cameraId: 0, imageFormat: PlatformImageFormatGroup.bgra8888) { + result in + let _ = self.assertSuccess(result) + expectation.fulfill() + } + + waitForExpectations(timeout: 30, handler: nil) + + XCTAssertTrue(startCalled) + } +} diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraPreviewPauseTests.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraPreviewPauseTests.swift new file mode 100644 index 000000000000..7803ec38ec0a --- /dev/null +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraPreviewPauseTests.swift @@ -0,0 +1,26 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import AVFoundation +import XCTest + +@testable import camera_avfoundation + +final class CameraPreviewPauseTests: XCTestCase { + func testPausePreviewWithResult_shouldPausePreview() { + let camera = CameraTestUtils.createTestCamera() + + camera.pausePreview() + + XCTAssertTrue(camera.isPreviewPaused) + } + + func testResumePreviewWithResult_shouldResumePreview() { + let camera = CameraTestUtils.createTestCamera() + + camera.resumePreview() + + XCTAssertFalse(camera.isPreviewPaused) + } +} diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraPropertiesTests.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraPropertiesTests.swift new file mode 100644 index 000000000000..bac0ce6ed19e --- /dev/null +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraPropertiesTests.swift @@ -0,0 +1,73 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import AVFoundation +import Foundation +import XCTest + +@testable import camera_avfoundation + +final class CameraPropertiesTests: XCTestCase { + // MARK: - Flash Mode Tests + + func testGetAVCaptureFlashModeForPigeonFlashMode() { + XCTAssertEqual( + AVCaptureDevice.FlashMode.off, + getAVCaptureFlashMode(for: .off)) + XCTAssertEqual( + AVCaptureDevice.FlashMode.auto, + getAVCaptureFlashMode(for: .auto)) + XCTAssertEqual( + AVCaptureDevice.FlashMode.on, + getAVCaptureFlashMode(for: .always)) + } + + // MARK: - Video Format Tests + + func testGetPixelFormatForPigeonFormat() { + XCTAssertEqual( + kCVPixelFormatType_32BGRA, + getPixelFormat(for: .bgra8888)) + XCTAssertEqual( + kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange, + getPixelFormat(for: .yuv420)) + } + + // MARK: - Device Orientation Tests + + func testGetUIDeviceOrientationForPigeonDeviceOrientation() { + XCTAssertEqual( + UIDeviceOrientation.portraitUpsideDown, + getUIDeviceOrientation(for: .portraitDown) + ) + XCTAssertEqual( + UIDeviceOrientation.landscapeLeft, + getUIDeviceOrientation(for: .landscapeLeft)) + XCTAssertEqual( + UIDeviceOrientation.landscapeRight, + getUIDeviceOrientation(for: .landscapeRight)) + XCTAssertEqual( + UIDeviceOrientation.portrait, + getUIDeviceOrientation(for: .portraitUp)) + } + + func testGetPigeonDeviceOrientationForUIDeviceOrientation() { + XCTAssertEqual( + PlatformDeviceOrientation.portraitDown, + getPigeonDeviceOrientation(for: .portraitUpsideDown)) + XCTAssertEqual( + PlatformDeviceOrientation.landscapeLeft, + getPigeonDeviceOrientation(for: .landscapeLeft)) + XCTAssertEqual( + PlatformDeviceOrientation.landscapeRight, + getPigeonDeviceOrientation(for: .landscapeRight)) + XCTAssertEqual( + PlatformDeviceOrientation.portraitUp, + getPigeonDeviceOrientation(for: .portrait)) + // Test default case. + XCTAssertEqual( + PlatformDeviceOrientation.portraitUp, + getPigeonDeviceOrientation(for: .unknown)) + } +} diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraSessionPresetsTests.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraSessionPresetsTests.swift new file mode 100644 index 000000000000..b7b6a00734be --- /dev/null +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraSessionPresetsTests.swift @@ -0,0 +1,97 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import AVFoundation +import XCTest + +@testable import camera_avfoundation + +/// Includes test cases related to resolution presets setting operations for FLTCam class. +final class CameraSessionPresetsTests: XCTestCase { + func testResolutionPresetWithBestFormat_mustUpdateCaptureSessionPreset() { + let expectedPreset = AVCaptureSession.Preset.inputPriority + let presetExpectation = expectation(description: "Expected preset set") + let lockForConfigurationExpectation = expectation( + description: "Expected lockForConfiguration called") + + let videoSessionMock = MockCaptureSession() + videoSessionMock.canSetSessionPresetStub = { _ in true } + videoSessionMock.setSessionPresetStub = { preset in + if preset == expectedPreset { + presetExpectation.fulfill() + } + } + let captureFormatMock = MockCaptureDeviceFormat() + let captureDeviceMock = MockCaptureDevice() + captureDeviceMock.flutterFormats = [captureFormatMock] + var currentFormat: CaptureDeviceFormat = captureFormatMock + captureDeviceMock.activeFormatStub = { + return currentFormat + } + captureDeviceMock.lockForConfigurationStub = { + lockForConfigurationExpectation.fulfill() + } + + let configuration = CameraTestUtils.createTestCameraConfiguration() + configuration.videoCaptureDeviceFactory = { _ in captureDeviceMock } + configuration.videoDimensionsConverter = { _ in + return CMVideoDimensions(width: 4, height: 3) + } + configuration.videoCaptureSession = videoSessionMock + configuration.mediaSettings = CameraTestUtils.createDefaultMediaSettings( + resolutionPreset: PlatformResolutionPreset.max) + + let _ = CameraTestUtils.createTestCamera(configuration) + + waitForExpectations(timeout: 30, handler: nil) + } + + func testResolutionPresetWithCanSetSessionPresetMax_mustUpdateCaptureSessionPreset() { + let expectedPreset = AVCaptureSession.Preset.hd4K3840x2160 + let expectation = self.expectation(description: "Expected preset set") + + let videoSessionMock = MockCaptureSession() + // Make sure that setting resolution preset for session always succeeds. + videoSessionMock.canSetSessionPresetStub = { _ in true } + videoSessionMock.setSessionPresetStub = { preset in + if preset == expectedPreset { + expectation.fulfill() + } + } + + let configuration = CameraTestUtils.createTestCameraConfiguration() + configuration.videoCaptureSession = videoSessionMock + configuration.mediaSettings = CameraTestUtils.createDefaultMediaSettings( + resolutionPreset: PlatformResolutionPreset.max) + configuration.videoCaptureDeviceFactory = { _ in MockCaptureDevice() } + + let _ = CameraTestUtils.createTestCamera(configuration) + + waitForExpectations(timeout: 30, handler: nil) + } + + func testResolutionPresetWithCanSetSessionPresetUltraHigh_mustUpdateCaptureSessionPreset() { + let expectedPreset = AVCaptureSession.Preset.hd4K3840x2160 + let expectation = self.expectation(description: "Expected preset set") + + let videoSessionMock = MockCaptureSession() + // Make sure that setting resolution preset for session always succeeds. + videoSessionMock.canSetSessionPresetStub = { _ in true } + // Expect that setting "ultraHigh" resolutionPreset correctly updates videoCaptureSession. + videoSessionMock.setSessionPresetStub = { preset in + if preset == expectedPreset { + expectation.fulfill() + } + } + + let configuration = CameraTestUtils.createTestCameraConfiguration() + configuration.videoCaptureSession = videoSessionMock + configuration.mediaSettings = CameraTestUtils.createDefaultMediaSettings( + resolutionPreset: PlatformResolutionPreset.ultraHigh) + + let _ = CameraTestUtils.createTestCamera(configuration) + + waitForExpectations(timeout: 30, handler: nil) + } +} diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraSettingsTests.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraSettingsTests.swift new file mode 100644 index 000000000000..984549b06516 --- /dev/null +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraSettingsTests.swift @@ -0,0 +1,355 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import AVFoundation +import XCTest + +@testable import camera_avfoundation + +private let testResolutionPreset = PlatformResolutionPreset.medium +private let testFramesPerSecond: Int64 = 15 +private let testVideoBitrate: Int64 = 200000 +private let testAudioBitrate: Int64 = 32000 + +private final class TestMediaSettingsAVWrapper: FLTCamMediaSettingsAVWrapper { + let lockExpectation: XCTestExpectation + let unlockExpectation: XCTestExpectation + let minFrameDurationExpectation: XCTestExpectation + let maxFrameDurationExpectation: XCTestExpectation + let beginConfigurationExpectation: XCTestExpectation + let commitConfigurationExpectation: XCTestExpectation + let audioSettingsExpectation: XCTestExpectation + let videoSettingsExpectation: XCTestExpectation + + init(test: XCTestCase, expectAudio: Bool) { + lockExpectation = test.expectation(description: "lockExpectation") + unlockExpectation = test.expectation(description: "unlockExpectation") + minFrameDurationExpectation = test.expectation(description: "minFrameDurationExpectation") + maxFrameDurationExpectation = test.expectation(description: "maxFrameDurationExpectation") + beginConfigurationExpectation = test.expectation(description: "beginConfigurationExpectation") + commitConfigurationExpectation = test.expectation(description: "commitConfigurationExpectation") + audioSettingsExpectation = test.expectation(description: "audioSettingsExpectation") + audioSettingsExpectation.isInverted = !expectAudio + videoSettingsExpectation = test.expectation(description: "videoSettingsExpectation") + } + + override func lockDevice(_ captureDevice: CaptureDevice) throws { + lockExpectation.fulfill() + } + + override func unlockDevice(_ captureDevice: CaptureDevice) { + unlockExpectation.fulfill() + } + + override func beginConfiguration(for videoCaptureSession: CaptureSession) { + beginConfigurationExpectation.fulfill() + } + + override func commitConfiguration(for videoCaptureSession: CaptureSession) { + commitConfigurationExpectation.fulfill() + } + + override func setMinFrameDuration(_ duration: CMTime, on captureDevice: CaptureDevice) { + // FLTCam allows to set frame rate with 1/10 precision. + let expectedDuration = CMTimeMake(value: 10, timescale: Int32(testFramesPerSecond * 10)) + if duration == expectedDuration { + minFrameDurationExpectation.fulfill() + } + } + + override func setMaxFrameDuration(_ duration: CMTime, on captureDevice: CaptureDevice) { + // FLTCam allows to set frame rate with 1/10 precision. + let expectedDuration = CMTimeMake(value: 10, timescale: Int32(testFramesPerSecond * 10)) + if duration == expectedDuration { + maxFrameDurationExpectation.fulfill() + } + } + + override func assetWriterAudioInput(withOutputSettings outputSettings: [String: Any]?) + -> AssetWriterInput + { + if let bitrate = outputSettings?[AVEncoderBitRateKey] as? Int, bitrate == Int(testAudioBitrate) + { + audioSettingsExpectation.fulfill() + } + return MockAssetWriterInput() + } + + override func assetWriterVideoInput(withOutputSettings outputSettings: [String: Any]?) + -> AssetWriterInput + { + if let compressionProperties = outputSettings?[AVVideoCompressionPropertiesKey] + as? [String: Any], + let bitrate = compressionProperties[AVVideoAverageBitRateKey] as? Int, + let frameRate = compressionProperties[AVVideoExpectedSourceFrameRateKey] as? Double, + bitrate == testVideoBitrate, frameRate == Double(testFramesPerSecond) + { + videoSettingsExpectation.fulfill() + } + + // AVAssetWriterInput needs these three keys, otherwise it throws. + var outputSettingsWithRequiredKeys = outputSettings ?? [:] + outputSettingsWithRequiredKeys[AVVideoCodecKey] = AVVideoCodecType.h264 + outputSettingsWithRequiredKeys[AVVideoWidthKey] = 1280 + outputSettingsWithRequiredKeys[AVVideoHeightKey] = 720 + + return MockAssetWriterInput() + } + + override func addInput(_ writerInput: AssetWriterInput, to writer: AssetWriter) { + // No-op. + } + + override func recommendedVideoSettingsForAssetWriter( + withFileType fileType: AVFileType, for output: CaptureVideoDataOutput + ) -> [String: Any]? { + return [:] + } +} + +final class CameraSettingsTests: XCTestCase { + func testSettings_shouldPassConfigurationToCameraDeviceAndWriter() { + let enableAudio: Bool = true + let settings = PlatformMediaSettings( + resolutionPreset: testResolutionPreset, + framesPerSecond: testFramesPerSecond, + videoBitrate: testVideoBitrate, + audioBitrate: testAudioBitrate, + enableAudio: enableAudio + ) + let injectedWrapper = TestMediaSettingsAVWrapper(test: self, expectAudio: enableAudio) + + let configuration = CameraTestUtils.createTestCameraConfiguration() + configuration.mediaSettingsWrapper = injectedWrapper + configuration.mediaSettings = settings + let camera = CameraTestUtils.createTestCamera(configuration) + + // Expect FPS configuration is passed to camera device. + wait( + for: [ + injectedWrapper.lockExpectation, + injectedWrapper.beginConfigurationExpectation, + injectedWrapper.minFrameDurationExpectation, + injectedWrapper.maxFrameDurationExpectation, + injectedWrapper.commitConfigurationExpectation, + injectedWrapper.unlockExpectation, + ], timeout: 1, enforceOrder: true) + + camera.startVideoRecording( + completion: { error in + // No-op. + }, messengerForStreaming: nil) + + wait( + for: [ + injectedWrapper.audioSettingsExpectation, + injectedWrapper.videoSettingsExpectation, + ], timeout: 1) + } + + func testSettings_ShouldBeSupportedByMethodCall() { + let mockDevice = MockCaptureDevice() + let mockSession = MockCaptureSession() + mockSession.canSetSessionPresetStub = { _ in true } + let camera = CameraPlugin( + registry: MockFlutterTextureRegistry(), + messenger: MockFlutterBinaryMessenger(), + globalAPI: MockGlobalEventApi(), + deviceDiscoverer: MockCameraDeviceDiscoverer(), + permissionManager: MockCameraPermissionManager(), + deviceFactory: { _ in mockDevice }, + captureSessionFactory: { mockSession }, + captureDeviceInputFactory: MockCaptureDeviceInputFactory(), + captureSessionQueue: DispatchQueue(label: "io.flutter.camera.captureSessionQueue") + ) + + let expectation = self.expectation(description: "Result finished") + let mediaSettings = PlatformMediaSettings( + resolutionPreset: testResolutionPreset, + framesPerSecond: testFramesPerSecond, + videoBitrate: testVideoBitrate, + audioBitrate: testAudioBitrate, + enableAudio: false + ) + var resultValue: Int64? + camera.createCameraOnSessionQueue( + withName: "acamera", + settings: mediaSettings + ) { result in + resultValue = self.assertSuccess(result) + expectation.fulfill() + } + + waitForExpectations(timeout: 30, handler: nil) + XCTAssertNotNil(resultValue) + } + + func testSettings_ShouldSelectFormatWhichSupports60FPS() { + let settings = PlatformMediaSettings( + resolutionPreset: testResolutionPreset, + framesPerSecond: 60, + videoBitrate: testVideoBitrate, + audioBitrate: testAudioBitrate, + enableAudio: false + ) + + let configuration = CameraTestUtils.createTestCameraConfiguration() + configuration.mediaSettings = settings + let camera = CameraTestUtils.createTestCamera(configuration) + + let range = camera.captureDevice.flutterActiveFormat.flutterVideoSupportedFrameRateRanges[0] + XCTAssertLessThanOrEqual(range.minFrameRate, 60) + XCTAssertGreaterThanOrEqual(range.maxFrameRate, 60) + } + + func test_setUpCaptureSessionForAudioIfNeeded_skipsAudioSession_whenAudioDisabled() { + let settings = PlatformMediaSettings( + resolutionPreset: testResolutionPreset, + framesPerSecond: testFramesPerSecond, + videoBitrate: testVideoBitrate, + audioBitrate: testAudioBitrate, + enableAudio: false + ) + + let wrapper = TestMediaSettingsAVWrapper(test: self, expectAudio: false) + let mockAudioSession = MockCaptureSession() + + let configuration = CameraTestUtils.createTestCameraConfiguration() + configuration.mediaSettingsWrapper = wrapper + configuration.mediaSettings = settings + configuration.audioCaptureSession = mockAudioSession + let camera = CameraTestUtils.createTestCamera(configuration) + + wait( + for: [ + wrapper.lockExpectation, + wrapper.beginConfigurationExpectation, + wrapper.minFrameDurationExpectation, + wrapper.maxFrameDurationExpectation, + wrapper.commitConfigurationExpectation, + wrapper.unlockExpectation, + ], + timeout: 1, + enforceOrder: true + ) + + camera.startVideoRecording(completion: { _ in }, messengerForStreaming: nil) + + wait( + for: [ + wrapper.audioSettingsExpectation, + wrapper.videoSettingsExpectation, + ], + timeout: 1 + ) + + XCTAssertEqual( + mockAudioSession.addedAudioOutputCount, 0, + "Audio session should not receive AVCaptureAudioDataOutput when enableAudio is false" + ) + } + + func test_setUpCaptureSessionForAudioIfNeeded_addsAudioSession_whenAudioEnabled() { + let settings = PlatformMediaSettings( + resolutionPreset: testResolutionPreset, + framesPerSecond: testFramesPerSecond, + videoBitrate: testVideoBitrate, + audioBitrate: testAudioBitrate, + enableAudio: true + ) + + let wrapper = TestMediaSettingsAVWrapper(test: self, expectAudio: true) + let mockAudioSession = MockCaptureSession() + + let configuration = CameraTestUtils.createTestCameraConfiguration() + configuration.mediaSettingsWrapper = wrapper + configuration.mediaSettings = settings + configuration.audioCaptureSession = mockAudioSession + let camera = CameraTestUtils.createTestCamera(configuration) + + wait( + for: [ + wrapper.lockExpectation, + wrapper.beginConfigurationExpectation, + wrapper.minFrameDurationExpectation, + wrapper.maxFrameDurationExpectation, + wrapper.commitConfigurationExpectation, + wrapper.unlockExpectation, + ], + timeout: 1, + enforceOrder: true + ) + + camera.startVideoRecording(completion: { _ in }, messengerForStreaming: nil) + + wait( + for: [ + wrapper.audioSettingsExpectation, + wrapper.videoSettingsExpectation, + ], + timeout: 1 + ) + + XCTAssertGreaterThan( + mockAudioSession.addedAudioOutputCount, 0, + "Audio session should receive AVCaptureAudioDataOutput when enableAudio is true" + ) + } + + func testResolutionPresetWithMax_mustIgnoreLossyFormatsAndSquares() { + let videoSessionMock = MockCaptureSession() + videoSessionMock.canSetSessionPresetStub = { _ in true } + + let lossyFormat = MockCaptureDeviceFormat( + codecType: 1_651_798_066, // 'btp2' + width: 4224, + height: 3024 + ) + let squareFormat = MockCaptureDeviceFormat( + codecType: kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange, + width: 4032, + height: 4032 + ) + let safe4KFormat = MockCaptureDeviceFormat( + codecType: kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange, + width: 3840, + height: 2160 + ) + + let captureDeviceMock = MockCaptureDevice() + captureDeviceMock.flutterFormats = [lossyFormat, squareFormat, safe4KFormat] + + var currentFormat: CaptureDeviceFormat = safe4KFormat + captureDeviceMock.activeFormatStub = { currentFormat } + captureDeviceMock.setActiveFormatStub = { newFormat in currentFormat = newFormat } + + let configuration = CameraTestUtils.createTestCameraConfiguration() + configuration.videoCaptureDeviceFactory = { _ in captureDeviceMock } + configuration.videoCaptureSession = videoSessionMock + + configuration.videoDimensionsConverter = { format in + return CMVideoFormatDescriptionGetDimensions(format.formatDescription) + } + + configuration.mediaSettings = CameraTestUtils.createDefaultMediaSettings( + resolutionPreset: PlatformResolutionPreset.max + ) + + let _ = CameraTestUtils.createTestCamera(configuration) + + let selectedFormat = captureDeviceMock.flutterActiveFormat + let selectedDimensions = CMVideoFormatDescriptionGetDimensions(selectedFormat.formatDescription) + + XCTAssertEqual( + selectedDimensions.width, + 3840, + "Camera should have ignored the lossy and square formats, safely falling back to 4K." + ) + XCTAssertEqual( + selectedDimensions.height, + 2160, + "Camera should have ignored the lossy and square formats, safely falling back to 4K." + ) + } +} diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraTestUtils.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraTestUtils.swift new file mode 100644 index 000000000000..a46d23cfe7b1 --- /dev/null +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraTestUtils.swift @@ -0,0 +1,219 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import AVFoundation +import XCTest + +@testable import camera_avfoundation + +/// Utils for creating default class instances used in tests +enum CameraTestUtils { + /// This method provides a convenient way to create media settings with minimal configuration. + /// Audio is enabled by default, while other parameters use platform-specific defaults. + static func createDefaultMediaSettings(resolutionPreset: PlatformResolutionPreset) + -> PlatformMediaSettings + { + return PlatformMediaSettings( + resolutionPreset: resolutionPreset, + framesPerSecond: nil, + videoBitrate: nil, + audioBitrate: nil, + enableAudio: true) + } + + /// Creates a test `CameraConfiguration` with a default mock setup. + static func createTestCameraConfiguration() -> CameraConfiguration { + let captureSessionQueue = DispatchQueue(label: "capture_session_queue") + + let videoSessionMock = MockCaptureSession() + videoSessionMock.canSetSessionPresetStub = { _ in true } + + let audioSessionMock = MockCaptureSession() + audioSessionMock.canSetSessionPresetStub = { _ in true } + + let frameRateRangeMock1 = MockFrameRateRange.init(minFrameRate: 3, maxFrameRate: 30) + + let captureDeviceFormatMock1 = MockCaptureDeviceFormat() + captureDeviceFormatMock1.flutterVideoSupportedFrameRateRanges = [frameRateRangeMock1] + + let frameRateRangeMock2 = MockFrameRateRange.init(minFrameRate: 3, maxFrameRate: 60) + + let captureDeviceFormatMock2 = MockCaptureDeviceFormat() + captureDeviceFormatMock2.flutterVideoSupportedFrameRateRanges = [frameRateRangeMock2] + + let captureDeviceMock = MockCaptureDevice() + captureDeviceMock.flutterFormats = [captureDeviceFormatMock1, captureDeviceFormatMock2] + + var currentFormat: CaptureDeviceFormat = captureDeviceFormatMock1 + + captureDeviceMock.activeFormatStub = { currentFormat } + captureDeviceMock.setActiveFormatStub = { format in + currentFormat = format + } + + let configuration = CameraConfiguration( + mediaSettings: createDefaultMediaSettings( + resolutionPreset: PlatformResolutionPreset.medium), + mediaSettingsWrapper: FLTCamMediaSettingsAVWrapper(), + captureDeviceFactory: { _ in captureDeviceMock }, + audioCaptureDeviceFactory: { MockCaptureDevice() }, + captureSessionFactory: { videoSessionMock }, + captureSessionQueue: captureSessionQueue, + captureDeviceInputFactory: MockCaptureDeviceInputFactory(), + initialCameraName: "camera_name" + ) + + configuration.videoCaptureSession = videoSessionMock + configuration.audioCaptureSession = audioSessionMock + configuration.orientation = .portrait + + configuration.assetWriterFactory = { _, _ in MockAssetWriter() } + + configuration.inputPixelBufferAdaptorFactory = { _, _ in + MockAssetWriterInputPixelBufferAdaptor() + } + + return configuration + } + + static func createTestCamera(_ configuration: CameraConfiguration) -> DefaultCamera { + return (try? DefaultCamera(configuration: configuration))! + } + + static func createTestCamera() -> DefaultCamera { + return createTestCamera(createTestCameraConfiguration()) + } + + static func createCameraWithCaptureSessionQueue(_ captureSessionQueue: DispatchQueue) + -> DefaultCamera + { + let configuration = createTestCameraConfiguration() + configuration.captureSessionQueue = captureSessionQueue + return createTestCamera(configuration) + } + + /// Creates a test sample buffer. + /// @return a test sample buffer. + static func createTestSampleBuffer( + timestamp: CMTime = .zero, + duration: CMTime = CMTimeMake(value: 1, timescale: 44100) + ) -> CMSampleBuffer { + var pixelBuffer: CVPixelBuffer? + CVPixelBufferCreate(kCFAllocatorDefault, 100, 100, kCVPixelFormatType_32BGRA, nil, &pixelBuffer) + + var formatDescription: CMFormatDescription? + CMVideoFormatDescriptionCreateForImageBuffer( + allocator: kCFAllocatorDefault, + imageBuffer: pixelBuffer!, + formatDescriptionOut: &formatDescription) + + var timingInfo = CMSampleTimingInfo( + duration: duration, + presentationTimeStamp: timestamp, + decodeTimeStamp: .invalid) + + var sampleBuffer: CMSampleBuffer? + CMSampleBufferCreateReadyWithImageBuffer( + allocator: kCFAllocatorDefault, + imageBuffer: pixelBuffer!, + formatDescription: formatDescription!, + sampleTiming: &timingInfo, + sampleBufferOut: &sampleBuffer) + + return sampleBuffer! + } + + /// Creates a test audio sample buffer. + /// @return a test audio sample buffer. + static func createTestAudioSampleBuffer( + timestamp: CMTime = .zero, + duration: CMTime = CMTimeMake(value: 1, timescale: 44100) + ) -> CMSampleBuffer { + var blockBuffer: CMBlockBuffer? + CMBlockBufferCreateWithMemoryBlock( + allocator: kCFAllocatorDefault, + memoryBlock: nil, + blockLength: Int(duration.value), + blockAllocator: kCFAllocatorDefault, + customBlockSource: nil, + offsetToData: 0, + dataLength: Int(duration.value), + flags: kCMBlockBufferAssureMemoryNowFlag, + blockBufferOut: &blockBuffer) + + var formatDescription: CMFormatDescription? + var basicDescription = AudioStreamBasicDescription( + mSampleRate: Float64(duration.timescale), + mFormatID: kAudioFormatLinearPCM, + mFormatFlags: 0, + mBytesPerPacket: 1, + mFramesPerPacket: 1, + mBytesPerFrame: 1, + mChannelsPerFrame: 1, + mBitsPerChannel: 8, + mReserved: 0) + + CMAudioFormatDescriptionCreate( + allocator: kCFAllocatorDefault, + asbd: &basicDescription, + layoutSize: 0, + layout: nil, + magicCookieSize: 0, + magicCookie: nil, + extensions: nil, + formatDescriptionOut: &formatDescription) + + var sampleBuffer: CMSampleBuffer? + CMAudioSampleBufferCreateReadyWithPacketDescriptions( + allocator: kCFAllocatorDefault, + dataBuffer: blockBuffer!, + formatDescription: formatDescription!, + sampleCount: CMItemCount(duration.value), + presentationTimeStamp: timestamp, + packetDescriptions: nil, + sampleBufferOut: &sampleBuffer) + + return sampleBuffer! + } + + static func createTestAudioOutput() -> AVCaptureOutput { + return AVCaptureAudioDataOutput() + } + + static func createTestConnection(_ output: AVCaptureOutput) -> AVCaptureConnection { + return AVCaptureConnection(inputPorts: [], output: output) + } +} + +extension XCTestCase { + /// Wait until a round trip of a given `DispatchQueue` is complete. This allows for testing + /// side-effects of async functions that do not provide any notification of completion. + func waitForQueueRoundTrip(with queue: DispatchQueue) { + let expectation = expectation(description: "Queue flush") + + queue.async { + if queue == DispatchQueue.main { + expectation.fulfill() + } else { + DispatchQueue.main.async { + expectation.fulfill() + } + } + } + + wait(for: [expectation], timeout: 1) + } + + func assertSuccess( + _ result: Result, file: StaticString = #file, line: UInt = #line + ) -> T? { + switch result { + case .success(let value): + return value + case .failure(let error): + XCTFail("Expected success, but got failure: \(error)", file: file, line: line) + return nil + } + } +} diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamExposureTests.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamExposureTests.swift new file mode 100644 index 000000000000..33ee0325b8e0 --- /dev/null +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamExposureTests.swift @@ -0,0 +1,146 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import XCTest + +@testable import camera_avfoundation + +final class FLTCamExposureTests: XCTestCase { + private func createCamera() -> (Camera, MockCaptureDevice, MockDeviceOrientationProvider) { + let mockDevice = MockCaptureDevice() + let mockDeviceOrientationProvider = MockDeviceOrientationProvider() + + let configuration = CameraTestUtils.createTestCameraConfiguration() + configuration.videoCaptureDeviceFactory = { _ in mockDevice } + configuration.deviceOrientationProvider = mockDeviceOrientationProvider + let camera = CameraTestUtils.createTestCamera(configuration) + + return (camera, mockDevice, mockDeviceOrientationProvider) + } + + func testSetExposureModeLocked_setsAuthExposeMode() { + let (camera, mockDevice, _) = createCamera() + + mockDevice.setExposureModeStub = { mode in + // AVCaptureExposureModeAutoExpose automatically adjusts the exposure one time, and then + // locks exposure for the device + XCTAssertEqual(mode, .autoExpose) + } + + camera.setExposureMode(.locked) + } + + func testSetExposureModeAuto_setsContinousAutoExposureMode_ifSupported() { + let (camera, mockDevice, _) = createCamera() + + // All exposure modes are supported + mockDevice.isExposureModeSupportedStub = { _ in true } + + mockDevice.setExposureModeStub = { mode in + XCTAssertEqual(mode, .continuousAutoExposure) + } + + camera.setExposureMode(.auto) + } + + func testSetExposureModeAuto_setsAutoExposeMode_ifContinousAutoIsNotSupported() { + let (camera, mockDevice, _) = createCamera() + + // Continous auto exposure is not supported + mockDevice.isExposureModeSupportedStub = { mode in + mode != .continuousAutoExposure + } + + mockDevice.setExposureModeStub = { mode in + XCTAssertEqual(mode, .autoExpose) + } + + camera.setExposureMode(.auto) + } + + func testSetExposurePoint_setsExposurePointOfInterest() { + let (camera, mockDevice, mockDeviceOrientationProvider) = createCamera() + // UI is currently in landscape left orientation. + mockDeviceOrientationProvider.orientationStub = { .landscapeLeft } + // Exposure point of interest is supported. + mockDevice.isExposurePointOfInterestSupported = true + + // Verify the focus point of interest has been set. + var setPoint = CGPoint.zero + mockDevice.setExposurePointOfInterestStub = { point in + if point == CGPoint(x: 1, y: 1) { + setPoint = point + } + } + + let expectation = expectation(description: "Completion called") + camera.setExposurePoint(PlatformPoint(x: 1, y: 1)) { + result in + let _ = self.assertSuccess(result) + expectation.fulfill() + } + + waitForExpectations(timeout: 30, handler: nil) + XCTAssertEqual(setPoint, CGPoint(x: 1.0, y: 1.0)) + } + + func testSetExposurePoint_returnsError_ifNotSupported() { + let (camera, mockDevice, mockDeviceOrientationProvider) = createCamera() + // UI is currently in landscape left orientation. + mockDeviceOrientationProvider.orientationStub = { .landscapeLeft } + // Exposure point of interest is not supported. + mockDevice.isExposurePointOfInterestSupported = false + + let expectation = expectation(description: "Completion with error") + + camera.setExposurePoint(PlatformPoint(x: 1, y: 1)) { result in + switch result { + case .failure(let error as PigeonError): + XCTAssertEqual(error.code, "setExposurePointFailed") + XCTAssertEqual(error.message, "Device does not have exposure point capabilities") + default: + XCTFail("Expected failure") + } + expectation.fulfill() + } + + waitForExpectations(timeout: 30, handler: nil) + } + + func testSetExposureOffset_setsExposureTargetBias() { + let (camera, mockDevice, _) = createCamera() + + let targetOffset = CGFloat(1.0) + + var setExposureTargetBiasCalled = false + mockDevice.setExposureTargetBiasStub = { bias, handler in + XCTAssertEqual(bias, Float(targetOffset)) + setExposureTargetBiasCalled = true + } + + camera.setExposureOffset(targetOffset) + + XCTAssertTrue(setExposureTargetBiasCalled) + } + + func testMaximumExposureOffset_returnsDeviceMaxExposureTargetBias() { + let (camera, mockDevice, _) = createCamera() + + let targetOffset = CGFloat(1.0) + + mockDevice.maxExposureTargetBias = Float(targetOffset) + + XCTAssertEqual(camera.maximumExposureOffset, targetOffset) + } + + func testMinimumExposureOffset_returnsDeviceMinExposureTargetBias() { + let (camera, mockDevice, _) = createCamera() + + let targetOffset = CGFloat(1.0) + + mockDevice.minExposureTargetBias = Float(targetOffset) + + XCTAssertEqual(camera.minimumExposureOffset, targetOffset) + } +} diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamFocusTests.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamFocusTests.swift new file mode 100644 index 000000000000..00eaddf71faf --- /dev/null +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamFocusTests.swift @@ -0,0 +1,166 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import AVFoundation +import XCTest + +@testable import camera_avfoundation + +final class FLTCamSetFocusModeTests: XCTestCase { + private func createCamera() -> (Camera, MockCaptureDevice, MockDeviceOrientationProvider) { + let mockDevice = MockCaptureDevice() + let mockDeviceOrientationProvider = MockDeviceOrientationProvider() + + let configuration = CameraTestUtils.createTestCameraConfiguration() + configuration.videoCaptureDeviceFactory = { _ in mockDevice } + configuration.deviceOrientationProvider = mockDeviceOrientationProvider + let camera = CameraTestUtils.createTestCamera(configuration) + + return (camera, mockDevice, mockDeviceOrientationProvider) + } + + func testAutoFocusWithContinuousModeSupported_ShouldSetContinuousAutoFocus() { + let (camera, mockDevice, _) = createCamera() + // AVCaptureFocusModeContinuousAutoFocus and AVCaptureFocusModeAutoFocus are supported. + mockDevice.isFocusModeSupportedStub = { mode in + mode == .continuousAutoFocus || mode == .autoFocus + } + + var setFocusModeContinuousAutoFocusCalled = false + + mockDevice.setFocusModeStub = { mode in + // Don't expect setFocusMode:AVCaptureFocusModeAutoFocus. + if mode == .autoFocus { + XCTFail("Unexpected call to setFocusMode") + } else if mode == .continuousAutoFocus { + setFocusModeContinuousAutoFocusCalled = true + } + } + + camera.setFocusMode(.auto) + + XCTAssertTrue(setFocusModeContinuousAutoFocusCalled) + } + + func testAutoFocusWithContinuousModeNotSupported_ShouldSetAutoFocus() { + let (camera, mockDevice, _) = createCamera() + // AVCaptureFocusModeContinuousAutoFocus is not supported. + // AVCaptureFocusModeAutoFocus is supported. + mockDevice.isFocusModeSupportedStub = { mode in + mode == .autoFocus + } + + var setFocusModeAutoFocusCalled = false + + // Don't expect setFocusMode:AVCaptureFocusModeContinuousAutoFocus. + mockDevice.setFocusModeStub = { mode in + if mode == .continuousAutoFocus { + XCTFail("Unexpected call to setFocusMode") + } else if mode == .autoFocus { + setFocusModeAutoFocusCalled = true + } + } + + camera.setFocusMode(.auto) + + XCTAssertTrue(setFocusModeAutoFocusCalled) + } + + func testAutoFocusWithNoModeSupported_ShouldSetNothing() { + let (camera, mockDevice, _) = createCamera() + // No modes are supported. + mockDevice.isFocusModeSupportedStub = { _ in + false + } + + // Don't expect any setFocus. + mockDevice.setFocusModeStub = { + _ in XCTFail("Unexpected call to setFocusMode") + } + + camera.setFocusMode(.auto) + } + + func testLockedFocusWithModeSupported_ShouldSetModeAutoFocus() { + let (camera, mockDevice, _) = createCamera() + // AVCaptureFocusModeContinuousAutoFocus and AVCaptureFocusModeAutoFocus are supported. + mockDevice.isFocusModeSupportedStub = { mode in + mode == .continuousAutoFocus || mode == .autoFocus + } + + var setFocusModeAutoFocusCalled = false + + // AVCaptureFocusModeAutoFocus automatically adjusts the focus one time, and then locks focus + mockDevice.setFocusModeStub = { mode in + if mode == .continuousAutoFocus { + XCTFail("Unexpected call to setFocusMode") + } else if mode == .autoFocus { + setFocusModeAutoFocusCalled = true + } + } + + camera.setFocusMode(.locked) + + XCTAssertTrue(setFocusModeAutoFocusCalled) + } + + func testLockedFocusWithModeNotSupported_ShouldSetNothing() { + let (camera, mockDevice, _) = createCamera() + mockDevice.isFocusModeSupportedStub = { mode in + mode == .continuousAutoFocus + } + + // Don't expect any setFocus. + mockDevice.setFocusModeStub = { _ in + XCTFail("Unexpected call to setFocusMode") + } + + camera.setFocusMode(.locked) + } + + func testSetFocusPointWithResult_SetsFocusPointOfInterest() { + let (camera, mockDevice, mockDeviceOrientationProvider) = createCamera() + // UI is currently in landscape left orientation. + mockDeviceOrientationProvider.orientationStub = { .landscapeLeft } + // Focus point of interest is supported. + mockDevice.isFocusPointOfInterestSupported = true + + var setFocusPointOfInterestCalled = false + mockDevice.setFocusPointOfInterestStub = { point in + if point == CGPoint(x: 1.0, y: 1.0) { + setFocusPointOfInterestCalled = true + } + } + + camera.setFocusPoint(PlatformPoint(x: 1, y: 1)) { + result in + let _ = self.assertSuccess(result) + } + + XCTAssertTrue(setFocusPointOfInterestCalled) + } + + func testSetFocusPoint_WhenNotSupported_ReturnsError() { + let (camera, mockDevice, mockDeviceOrientationProvider) = createCamera() + // UI is currently in landscape left orientation. + mockDeviceOrientationProvider.orientationStub = { .landscapeLeft } + // Focus point of interest is not supported. + mockDevice.isFocusPointOfInterestSupported = false + + let expectation = self.expectation(description: "Completion with error") + + camera.setFocusPoint(PlatformPoint(x: 1, y: 1)) { result in + switch result { + case .failure(let error as PigeonError): + XCTAssertEqual(error.code, "setFocusPointFailed") + XCTAssertEqual(error.message, "Device does not have focus point capabilities") + default: + XCTFail("Expected failure") + } + expectation.fulfill() + } + + waitForExpectations(timeout: 30, handler: nil) + } +} diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamSetDeviceOrientationTests.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamSetDeviceOrientationTests.swift new file mode 100644 index 000000000000..ab688c9f5933 --- /dev/null +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamSetDeviceOrientationTests.swift @@ -0,0 +1,108 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import AVFoundation +import XCTest + +@testable import camera_avfoundation + +final class FLTCamSetDeviceOrientationTests: XCTestCase { + private func createCamera() -> (Camera, MockCaptureConnection, MockCaptureConnection) { + let camera = CameraTestUtils.createTestCamera() + + let mockCapturePhotoOutput = MockCapturePhotoOutput() + let mockPhotoCaptureConnection = MockCaptureConnection() + mockPhotoCaptureConnection.isVideoOrientationSupported = true + + mockCapturePhotoOutput.connectionWithMediaTypeStub = { _ in mockPhotoCaptureConnection } + camera.capturePhotoOutput = mockCapturePhotoOutput + + let mockCaptureVideoDataOutput = MockCaptureVideoDataOutput() + let mockVideoCaptureConnection = MockCaptureConnection() + mockVideoCaptureConnection.isVideoOrientationSupported = true + + mockCaptureVideoDataOutput.connectionWithMediaTypeStub = { _ in mockVideoCaptureConnection } + camera.captureVideoOutput = mockCaptureVideoDataOutput + + return (camera, mockPhotoCaptureConnection, mockVideoCaptureConnection) + } + + func testSetDeviceOrientation_setsOrientationsOfCaptureConnections() { + let (camera, mockPhotoCaptureConnection, mockVideoCaptureConnection) = createCamera() + var photoSetVideoOrientationCalled = false + mockPhotoCaptureConnection.setVideoOrientationStub = { orientation in + // Device orientation is flipped compared to video orientation. When UIDeviceOrientation + // is landscape left the video orientation should be landscape right. + XCTAssertEqual(orientation, .landscapeRight) + photoSetVideoOrientationCalled = true + } + + var videoSetVideoOrientationCalled = false + mockVideoCaptureConnection.setVideoOrientationStub = { orientation in + // Device orientation is flipped compared to video orientation. When UIDeviceOrientation + // is landscape left the video orientation should be landscape right. + XCTAssertEqual(orientation, .landscapeRight) + videoSetVideoOrientationCalled = true + } + + camera.deviceOrientation = .landscapeLeft + + XCTAssertTrue(photoSetVideoOrientationCalled) + XCTAssertTrue(videoSetVideoOrientationCalled) + } + + func + testSetDeviceOrientation_setsLockedOrientationsOfCaptureConnection_ifCaptureOrientationIsLocked() + { + let (camera, mockPhotoCaptureConnection, mockVideoCaptureConnection) = createCamera() + var photoSetVideoOrientationCalled = false + mockPhotoCaptureConnection.setVideoOrientationStub = { orientation in + XCTAssertEqual(orientation, .portraitUpsideDown) + photoSetVideoOrientationCalled = true + } + + var videoSetVideoOrientationCalled = false + mockVideoCaptureConnection.setVideoOrientationStub = { orientation in + XCTAssertEqual(orientation, .portraitUpsideDown) + videoSetVideoOrientationCalled = true + } + + camera.lockCaptureOrientation(PlatformDeviceOrientation.portraitDown) + + camera.deviceOrientation = .landscapeLeft + + XCTAssertTrue(photoSetVideoOrientationCalled) + XCTAssertTrue(videoSetVideoOrientationCalled) + } + + func testSetDeviceOrientation_doesNotSetOrientations_ifRecordingIsInProgress() { + let (camera, mockPhotoCaptureConnection, mockVideoCaptureConnection) = createCamera() + + camera.startVideoRecording(completion: { _ in }, messengerForStreaming: nil) + + mockPhotoCaptureConnection.setVideoOrientationStub = { _ in XCTFail() } + mockVideoCaptureConnection.setVideoOrientationStub = { _ in XCTFail() } + + camera.deviceOrientation = .landscapeLeft + } + + func testSetDeviceOrientation_doesNotSetOrientations_forDuplicateUpdates() { + let (camera, mockPhotoCaptureConnection, mockVideoCaptureConnection) = createCamera() + var photoSetVideoOrientationCallCount = 0 + mockPhotoCaptureConnection.setVideoOrientationStub = { _ in + photoSetVideoOrientationCallCount += 1 + } + + var videoSetVideoOrientationCallCount = 0 + mockVideoCaptureConnection.setVideoOrientationStub = { _ in + videoSetVideoOrientationCallCount += 1 + } + + camera.deviceOrientation = .landscapeRight + camera.deviceOrientation = .landscapeRight + + XCTAssertEqual(photoSetVideoOrientationCallCount, 1) + XCTAssertEqual(videoSetVideoOrientationCallCount, 1) + } +} diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamSetFlashModeTests.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamSetFlashModeTests.swift new file mode 100644 index 000000000000..0941a06d96e4 --- /dev/null +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamSetFlashModeTests.swift @@ -0,0 +1,168 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import AVFoundation +import XCTest + +@testable import camera_avfoundation + +final class FLTCamSetFlashModeTests: XCTestCase { + private func createCamera() -> (Camera, MockCaptureDevice, MockCapturePhotoOutput) { + let mockDevice = MockCaptureDevice() + let mockCapturePhotoOutput = MockCapturePhotoOutput() + + let configuration = CameraTestUtils.createTestCameraConfiguration() + configuration.videoCaptureDeviceFactory = { _ in mockDevice } + let camera = CameraTestUtils.createTestCamera(configuration) + camera.capturePhotoOutput = mockCapturePhotoOutput + + return (camera, mockDevice, mockCapturePhotoOutput) + } + + func testSetFlashModeWithTorchMode_setsTrochModeOn() { + let (camera, mockDevice, _) = createCamera() + + mockDevice.hasTorch = true + mockDevice.isTorchAvailable = true + + var setTorchModeCalled = false + mockDevice.setTorchModeStub = { torchMode in + XCTAssertEqual(torchMode, .on) + setTorchModeCalled = true + } + + let expectation = expectation(description: "Call completed") + + camera.setFlashMode(.torch) { + result in + let _ = self.assertSuccess(result) + expectation.fulfill() + } + + waitForExpectations(timeout: 30) + + XCTAssertTrue(setTorchModeCalled) + } + + func testSetFlashModeWithTorchMode_returnError_ifHasNoTorch() { + let (camera, mockDevice, _) = createCamera() + + mockDevice.hasTorch = false + + let expectation = expectation(description: "Call completed") + + camera.setFlashMode(.torch) { result in + switch result { + case .failure(let error as PigeonError): + XCTAssertEqual(error.code, "setFlashModeFailed") + XCTAssertEqual(error.message, "Device does not support torch mode") + default: + XCTFail("Expected failure") + } + expectation.fulfill() + } + + waitForExpectations(timeout: 30) + } + + func testSetFlashModeWithTorchMode_returnError_ifTorchIsNotAvailable() { + let (camera, mockDevice, _) = createCamera() + + mockDevice.hasTorch = true + mockDevice.isTorchAvailable = false + + let expectation = expectation(description: "Call completed") + + camera.setFlashMode(.torch) { result in + switch result { + case .failure(let error as PigeonError): + XCTAssertEqual(error.code, "setFlashModeFailed") + XCTAssertEqual(error.message, "Torch mode is currently not available") + default: + XCTFail("Expected failure") + } + expectation.fulfill() + } + + waitForExpectations(timeout: 30) + } + + func testSetFlashModeWithNonTorchMode_setsTrochModeOff_ifTorchModeIsEnabled() { + let (camera, mockDevice, mockCapturePhotoOutput) = createCamera() + + mockCapturePhotoOutput.supportedFlashModes = [.auto] + + mockDevice.hasFlash = true + // Torch mode is enabled + mockDevice.getTorchModeStub = { .on } + + var setTorchModeCalled = false + mockDevice.setTorchModeStub = { torchMode in + XCTAssertEqual(torchMode, .off) + setTorchModeCalled = true + } + + let expectation = expectation(description: "Call completed") + + camera.setFlashMode(.auto) { + result in + switch result { + case .success: + break + case .failure: + XCTFail("Unexpected failure") + } + expectation.fulfill() + } + + waitForExpectations(timeout: 30) + + XCTAssertTrue(setTorchModeCalled) + } + + func testSetFlashModeWithNonTorchMode_returnError_ifHasNoFlash() { + let (camera, mockDevice, _) = createCamera() + + mockDevice.hasFlash = false + + let expectation = expectation(description: "Call completed") + + camera.setFlashMode(.auto) { result in + switch result { + case .failure(let error as PigeonError): + XCTAssertEqual(error.code, "setFlashModeFailed") + XCTAssertEqual(error.message, "Device does not have flash capabilities") + default: + XCTFail("Expected failure") + } + expectation.fulfill() + } + + waitForExpectations(timeout: 30) + } + + func testSetFlashModeWithNonTorchMode_returnError_ifModeIsNotSupported() { + let (camera, mockDevice, mockCapturePhotoOutput) = createCamera() + + // No flash modes are supported + mockCapturePhotoOutput.supportedFlashModes = [] + + mockDevice.hasFlash = true + + let expectation = expectation(description: "Call completed") + + camera.setFlashMode(.auto) { result in + switch result { + case .failure(let error as PigeonError): + XCTAssertEqual(error.code, "setFlashModeFailed") + XCTAssertEqual(error.message, "Device does not support this specific flash mode") + default: + XCTFail("Expected failure") + } + expectation.fulfill() + } + + waitForExpectations(timeout: 30) + } +} diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamZoomTests.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamZoomTests.swift new file mode 100644 index 000000000000..46f302058b06 --- /dev/null +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamZoomTests.swift @@ -0,0 +1,111 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import AVFoundation +import XCTest + +@testable import camera_avfoundation + +final class FLTCamZoomTests: XCTestCase { + private func createCamera() -> (Camera, MockCaptureDevice) { + let mockDevice = MockCaptureDevice() + + let configuration = CameraTestUtils.createTestCameraConfiguration() + configuration.videoCaptureDeviceFactory = { _ in mockDevice } + let camera = CameraTestUtils.createTestCamera(configuration) + + return (camera, mockDevice) + } + + func testSetZoomLevel_setVideoZoomFactor() { + let (camera, mockDevice) = createCamera() + + mockDevice.maxAvailableVideoZoomFactor = 2.0 + mockDevice.minAvailableVideoZoomFactor = 0.0 + + let targetZoom = CGFloat(1.0) + + var setVideoZoomFactorCalled = false + mockDevice.setVideoZoomFactorStub = { zoom in + XCTAssertEqual(zoom, targetZoom) + setVideoZoomFactorCalled = true + } + + let expectation = expectation(description: "Call completed") + + camera.setZoomLevel(targetZoom) { + result in + let _ = self.assertSuccess(result) + expectation.fulfill() + } + + waitForExpectations(timeout: 30) + + XCTAssertTrue(setVideoZoomFactorCalled) + } + + func testSetZoomLevel_returnsError_forZoomLevelBlowMinimum() { + let (camera, mockDevice) = createCamera() + + // Allowed zoom range between 2.0 and 3.0 + mockDevice.maxAvailableVideoZoomFactor = 2.0 + mockDevice.minAvailableVideoZoomFactor = 3.0 + + let expectation = expectation(description: "Call completed") + + camera.setZoomLevel(CGFloat(1.0)) { result in + switch result { + case .failure(let error as PigeonError): + XCTAssertEqual(error.code, "ZOOM_ERROR") + default: + XCTFail("Expected failure") + } + expectation.fulfill() + } + + waitForExpectations(timeout: 30) + } + + func testSetZoomLevel_returnsError_forZoomLevelAboveMaximum() { + let (camera, mockDevice) = createCamera() + + // Allowed zoom range between 0.0 and 1.0 + mockDevice.maxAvailableVideoZoomFactor = 0.0 + mockDevice.minAvailableVideoZoomFactor = 1.0 + + let expectation = expectation(description: "Call completed") + + camera.setZoomLevel(CGFloat(2.0)) { result in + switch result { + case .failure(let error as PigeonError): + XCTAssertEqual(error.code, "ZOOM_ERROR") + default: + XCTFail("Expected failure") + } + expectation.fulfill() + } + + waitForExpectations(timeout: 30) + } + + func testMaximumAvailableZoomFactor_returnsDeviceMaxAvailableVideoZoomFactor() { + let (camera, mockDevice) = createCamera() + + let targetZoom = CGFloat(1.0) + + mockDevice.maxAvailableVideoZoomFactor = CGFloat(targetZoom) + + XCTAssertEqual(camera.maximumAvailableZoomFactor, targetZoom) + } + + func testMinimumAvailableZoomFactor_returnsDeviceMinAvailableVideoZoomFactor() { + let (camera, mockDevice) = createCamera() + + let targetZoom = CGFloat(1.0) + + mockDevice.minAvailableVideoZoomFactor = CGFloat(targetZoom) + + XCTAssertEqual(camera.minimumAvailableZoomFactor, targetZoom) + } +} diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockAssetWriter.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockAssetWriter.swift new file mode 100644 index 000000000000..2b345c00b3ab --- /dev/null +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockAssetWriter.swift @@ -0,0 +1,33 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import AVFoundation + +@testable import camera_avfoundation + +/// Mock implementation of `AssetWriter` protocol which allows injecting a custom +/// implementation. +final class MockAssetWriter: NSObject, AssetWriter { + var statusStub: (() -> AVAssetWriter.Status)? + var startWritingStub: (() -> Bool)? + var finishWritingStub: ((() -> Void) -> Void)? + + var status: AVAssetWriter.Status { + return statusStub?() ?? .unknown + } + + var error: Error? = nil + + func startWriting() -> Bool { + return startWritingStub?() ?? true + } + + func finishWriting(completionHandler handler: @escaping () -> Void) { + finishWritingStub?(handler) + } + + func startSession(atSourceTime startTime: CMTime) {} + + func add(_ input: AVAssetWriterInput) {} +} diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockAssetWriterInput.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockAssetWriterInput.swift new file mode 100644 index 000000000000..9e70646e2fb1 --- /dev/null +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockAssetWriterInput.swift @@ -0,0 +1,25 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import AVFoundation + +@testable import camera_avfoundation + +/// Mock implementation of `AssetWriterInput` protocol which allows injecting a custom +/// implementation. +final class MockAssetWriterInput: NSObject, AssetWriterInput { + var appendStub: ((CMSampleBuffer) -> Bool)? + + var avInput: AVAssetWriterInput { + preconditionFailure("Attempted to access unimplemented property: avInput") + } + + var expectsMediaDataInRealTime = false + + var isReadyForMoreMediaData = false + + func append(_ sampleBuffer: CMSampleBuffer) -> Bool { + return appendStub?(sampleBuffer) ?? false + } +} diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockAssetWriterInputPixelBufferAdaptor.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockAssetWriterInputPixelBufferAdaptor.swift new file mode 100644 index 000000000000..a27106e3a0a7 --- /dev/null +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockAssetWriterInputPixelBufferAdaptor.swift @@ -0,0 +1,17 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import AVFoundation + +@testable import camera_avfoundation + +/// Mock implementation of `AssetWriterInputPixelBufferAdaptor` protocol which allows injecting a custom +/// implementation. +final class MockAssetWriterInputPixelBufferAdaptor: NSObject, AssetWriterInputPixelBufferAdaptor { + var appendStub: ((CVPixelBuffer, CMTime) -> Bool)? + + func append(_ pixelBuffer: CVPixelBuffer, withPresentationTime presentationTime: CMTime) -> Bool { + appendStub?(pixelBuffer, presentationTime) ?? true + } +} diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCamera.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCamera.swift new file mode 100644 index 000000000000..ec6e6fd88f9c --- /dev/null +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCamera.swift @@ -0,0 +1,233 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import AVFoundation +import Flutter + +@testable import camera_avfoundation + +final class MockCamera: NSObject, Camera { + var setDartApiStub: ((CameraEventApi?) -> Void)? + var setOnFrameAvailableStub: (((() -> Void)?) -> Void)? + var getMinimumExposureOffsetStub: (() -> CGFloat)? + var getMaximumExposureOffsetStub: (() -> CGFloat)? + var getMinimumAvailableZoomFactorStub: (() -> CGFloat)? + var getMaximumAvailableZoomFactorStub: (() -> CGFloat)? + var setUpCaptureSessionForAudioIfNeededStub: (() -> Void)? + var receivedImageStreamDataStub: (() -> Void)? + var startStub: (() -> Void)? + var startVideoRecordingStub: + ((@escaping (Result) -> Void, FlutterBinaryMessenger?) -> Void)? + var pauseVideoRecordingStub: (() -> Void)? + var resumeVideoRecordingStub: (() -> Void)? + var stopVideoRecordingStub: ((@escaping (Result) -> Void) -> Void)? + var captureToFileStub: ((@escaping (Result) -> Void) -> Void)? + var setDeviceOrientationStub: ((UIDeviceOrientation) -> Void)? + var lockCaptureOrientationStub: ((PlatformDeviceOrientation) -> Void)? + var unlockCaptureOrientationStub: (() -> Void)? + var setImageFileFormatStub: ((PlatformImageFileFormat) -> Void)? + var setExposureModeStub: ((PlatformExposureMode) -> Void)? + var setExposureOffsetStub: ((Double) -> Void)? + var setExposurePointStub: ((PlatformPoint?, @escaping (Result) -> Void) -> Void)? + var setFocusModeStub: ((PlatformFocusMode) -> Void)? + var setFocusPointStub: ((PlatformPoint?, @escaping (Result) -> Void) -> Void)? + var setZoomLevelStub: ((CGFloat, @escaping (Result) -> Void) -> Void)? + var setFlashModeStub: ((PlatformFlashMode, @escaping (Result) -> Void) -> Void)? + var pausePreviewStub: (() -> Void)? + var resumePreviewStub: (() -> Void)? + var setDescriptionWhileRecordingStub: + ((String, @escaping (Result) -> Void) -> Void)? + var startImageStreamStub: + ((FlutterBinaryMessenger, @escaping (Result) -> Void) -> Void)? + var stopImageStreamStub: (() -> Void)? + var setVideoStabilizationModeStub: + ((PlatformVideoStabilizationMode, @escaping (Result) -> Void) -> Void)? + var getIsVideoStabilizationModeSupportedStub: ((PlatformVideoStabilizationMode) -> Bool)? + + var dartAPI: CameraEventApi? { + get { + preconditionFailure("Attempted to access unimplemented property: dartAPI") + } + set { + setDartApiStub?(newValue) + } + } + + var onFrameAvailable: (() -> Void)? { + get { + preconditionFailure("Attempted to access unimplemented property: onFrameAvailable") + } + set { + setOnFrameAvailableStub?(newValue) + } + } + + var videoFormat: FourCharCode = kCVPixelFormatType_32BGRA + + var isPreviewPaused: Bool = false + var isStreamingImages: Bool = false + + var deviceOrientation: UIDeviceOrientation { + get { + preconditionFailure("Attempted to access unimplemented property: deviceOrientation") + } + set { + setDeviceOrientationStub?(newValue) + } + } + + var minimumExposureOffset: CGFloat { + return getMinimumExposureOffsetStub?() ?? 0 + } + + var maximumExposureOffset: CGFloat { + return getMaximumExposureOffsetStub?() ?? 0 + } + + var minimumAvailableZoomFactor: CGFloat { + return getMinimumAvailableZoomFactorStub?() ?? 0 + } + + var maximumAvailableZoomFactor: CGFloat { + return getMaximumAvailableZoomFactorStub?() ?? 0 + } + + func setUpCaptureSessionForAudioIfNeeded() { + setUpCaptureSessionForAudioIfNeededStub?() + } + + func reportInitializationState() {} + + func receivedImageStreamData() { + receivedImageStreamDataStub?() + } + + func start() { + startStub?() + } + + func stop() {} + + func startVideoRecording( + completion: @escaping (Result) -> Void, + messengerForStreaming messenger: FlutterBinaryMessenger? + ) { + startVideoRecordingStub?(completion, messenger) + } + + func pauseVideoRecording() { + pauseVideoRecordingStub?() + } + + func resumeVideoRecording() { + resumeVideoRecordingStub?() + } + + func stopVideoRecording(completion: @escaping (Result) -> Void) { + stopVideoRecordingStub?(completion) + } + + func captureToFile(completion: @escaping (Result) -> Void) { + captureToFileStub?(completion) + } + + func lockCaptureOrientation(_ orientation: PlatformDeviceOrientation) { + lockCaptureOrientationStub?(orientation) + } + + func unlockCaptureOrientation() { + unlockCaptureOrientationStub?() + } + + func setImageFileFormat(_ fileFormat: PlatformImageFileFormat) { + setImageFileFormatStub?(fileFormat) + } + + func setExposureMode(_ mode: PlatformExposureMode) { + setExposureModeStub?(mode) + } + + func setExposureOffset(_ offset: Double) { + setExposureOffsetStub?(offset) + } + + func setExposurePoint( + _ point: PlatformPoint?, withCompletion: @escaping (Result) -> Void + ) { + setExposurePointStub?(point, withCompletion) + } + + func setFocusMode(_ mode: PlatformFocusMode) { + setFocusModeStub?(mode) + } + + func setFocusPoint( + _ point: PlatformPoint?, completion: @escaping (Result) -> Void + ) { + setFocusPointStub?(point, completion) + } + + func setZoomLevel( + _ zoom: CGFloat, + withCompletion completion: @escaping (Result) -> Void + ) { + setZoomLevelStub?(zoom, completion) + } + + func setFlashMode( + _ mode: PlatformFlashMode, + withCompletion completion: @escaping (Result) -> Void + ) { + setFlashModeStub?(mode, completion) + } + + func pausePreview() { + pausePreviewStub?() + } + + func resumePreview() { + resumePreviewStub?() + } + + func setVideoStabilizationMode( + _ mode: PlatformVideoStabilizationMode, + withCompletion completion: @escaping (Result) -> Void + ) { + setVideoStabilizationModeStub?(mode, completion) + } + + func isVideoStabilizationModeSupported(_ mode: PlatformVideoStabilizationMode) -> Bool { + return getIsVideoStabilizationModeSupportedStub?(mode) ?? false + } + + func setDescriptionWhileRecording( + _ cameraName: String, + withCompletion completion: @escaping (Result) -> Void + ) { + setDescriptionWhileRecordingStub?(cameraName, completion) + } + + func startImageStream( + with messenger: FlutterBinaryMessenger, + completion: @escaping (Result) -> Void + ) { + startImageStreamStub?(messenger, completion) + } + + func stopImageStream() { + stopImageStreamStub?() + } + + func captureOutput( + _ output: AVCaptureOutput, + didOutput sampleBuffer: CMSampleBuffer, + from connection: AVCaptureConnection + ) {} + + func close() {} + + func copyPixelBuffer() -> Unmanaged? { + return nil + } +} diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCameraDeviceDiscoverer.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCameraDeviceDiscoverer.swift new file mode 100644 index 000000000000..972f34ab8d5e --- /dev/null +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCameraDeviceDiscoverer.swift @@ -0,0 +1,29 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import AVFoundation + +@testable import camera_avfoundation + +/// Mock implementation of `FLTCameraDeviceDiscoverer` protocol which allows injecting a custom +/// implementation for session discovery. +final class MockCameraDeviceDiscoverer: NSObject, CameraDeviceDiscoverer { + var discoverySessionStub: + ( + ( + _ deviceTypes: [AVCaptureDevice.DeviceType], + _ mediaType: AVMediaType, + _ position: AVCaptureDevice.Position + ) -> [NSObject & CaptureDevice]? + )? + + /// A stub that replaces the default implementation of + /// `discoverySessionWithDeviceTypes:mediaType:position`. + func discoverySession( + withDeviceTypes deviceTypes: [AVCaptureDevice.DeviceType], mediaType: AVMediaType, + position: AVCaptureDevice.Position + ) -> [CaptureDevice] { + return discoverySessionStub?(deviceTypes, mediaType, position) ?? [] + } +} diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureConnection.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureConnection.swift new file mode 100644 index 000000000000..d6ea85f20e29 --- /dev/null +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureConnection.swift @@ -0,0 +1,27 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import AVFoundation + +@testable import camera_avfoundation + +/// A mock implementation of `CaptureConnection` that allows injecting a custom implementation. +final class MockCaptureConnection: NSObject, CaptureConnection { + var setVideoOrientationStub: ((AVCaptureVideoOrientation) -> Void)? + + var connection: AVCaptureConnection { + preconditionFailure("Attempted to access unimplemented property: connection") + } + var isVideoMirrored = false + var videoOrientation: AVCaptureVideoOrientation { + get { AVCaptureVideoOrientation.portrait } + set { + setVideoOrientationStub?(newValue) + } + } + var inputPorts: [AVCaptureInput.Port] = [] + var isVideoMirroringSupported = false + var isVideoOrientationSupported = false + var preferredVideoStabilizationMode = AVCaptureVideoStabilizationMode.off +} diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDevice.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDevice.swift new file mode 100644 index 000000000000..be6fc7dca28a --- /dev/null +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDevice.swift @@ -0,0 +1,127 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import AVFoundation + +@testable import camera_avfoundation + +/// A mock implementation of `FLTCaptureDevice` that allows mocking the class +/// properties. +class MockCaptureDevice: NSObject, CaptureDevice { + var activeFormatStub: (() -> CaptureDeviceFormat)? + var setActiveFormatStub: ((CaptureDeviceFormat) -> Void)? + var getTorchModeStub: (() -> AVCaptureDevice.TorchMode)? + var setTorchModeStub: ((AVCaptureDevice.TorchMode) -> Void)? + var isFocusModeSupportedStub: ((AVCaptureDevice.FocusMode) -> Bool)? + var setFocusModeStub: ((AVCaptureDevice.FocusMode) -> Void)? + var setFocusPointOfInterestStub: ((CGPoint) -> Void)? + var setExposureModeStub: ((AVCaptureDevice.ExposureMode) -> Void)? + var setExposurePointOfInterestStub: ((CGPoint) -> Void)? + var setExposureTargetBiasStub: ((Float, ((CMTime) -> Void)?) -> Void)? + var isExposureModeSupportedStub: ((AVCaptureDevice.ExposureMode) -> Bool)? + var setVideoZoomFactorStub: ((CGFloat) -> Void)? + var lockForConfigurationStub: (() throws -> Void)? + + var avDevice: AVCaptureDevice { + preconditionFailure("Attempted to access unimplemented property: device") + } + + var uniqueID = "" + var position = AVCaptureDevice.Position.unspecified + var deviceType = AVCaptureDevice.DeviceType.builtInWideAngleCamera + + var flutterActiveFormat: CaptureDeviceFormat { + get { + activeFormatStub?() ?? MockCaptureDeviceFormat() + } + set { + setActiveFormatStub?(newValue) + } + } + + var flutterFormats: [CaptureDeviceFormat] = [] + var hasFlash = false + var hasTorch = false + var isTorchAvailable = false + var torchMode: AVCaptureDevice.TorchMode { + get { + getTorchModeStub?() ?? .off + } + set { + setTorchModeStub?(newValue) + } + } + var isFocusPointOfInterestSupported = false + var maxAvailableVideoZoomFactor = CGFloat(0) + var minAvailableVideoZoomFactor = CGFloat(0) + var videoZoomFactor: CGFloat { + get { 0 } + set { + setVideoZoomFactorStub?(newValue) + } + } + var isExposurePointOfInterestSupported = false + var minExposureTargetBias = Float(0) + var maxExposureTargetBias = Float(0) + var activeVideoMinFrameDuration = CMTime(value: 1, timescale: 1) + var activeVideoMaxFrameDuration = CMTime(value: 1, timescale: 1) + + func isFlashModeSupported(_ mode: AVCaptureDevice.FlashMode) -> Bool { + return false + } + + func isFocusModeSupported(_ mode: AVCaptureDevice.FocusMode) -> Bool { + return isFocusModeSupportedStub?(mode) ?? false + } + + var focusMode: AVCaptureDevice.FocusMode { + get { .autoFocus } + set { setFocusModeStub?(newValue) } + } + + func setFocusMode(_ focusMode: AVCaptureDevice.FocusMode) { + setFocusModeStub?(focusMode) + } + + var focusPointOfInterest: CGPoint { + get { CGPoint.zero } + set { setFocusPointOfInterestStub?(newValue) } + } + + var exposureMode: AVCaptureDevice.ExposureMode { + get { .autoExpose } + set { setExposureModeStub?(newValue) } + } + + var exposurePointOfInterest: CGPoint { + get { CGPoint.zero } + set { setExposurePointOfInterestStub?(newValue) } + } + + func setExposureTargetBias(_ bias: Float, completionHandler handler: ((CMTime) -> Void)? = nil) { + setExposureTargetBiasStub?(bias, handler) + } + + func isExposureModeSupported(_ mode: AVCaptureDevice.ExposureMode) -> Bool { + return isExposureModeSupportedStub?(mode) ?? false + } + + var lensAperture: Float { 1.8 } + + var exposureDuration: CMTime { CMTime(value: 1, timescale: 1) } + + var iso: Float { 100 } + + func isVideoStabilizationModeSupported(_ videoStabilizationMode: AVCaptureVideoStabilizationMode) + -> Bool + { + return false + } + + func lockForConfiguration() throws { + try lockForConfigurationStub?() + } + + func unlockForConfiguration() {} +} diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDeviceFormat.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDeviceFormat.swift new file mode 100644 index 000000000000..557ff4ba7ca2 --- /dev/null +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDeviceFormat.swift @@ -0,0 +1,43 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import AVFoundation + +@testable import camera_avfoundation + +/// A mock implementation of `CaptureDeviceFormat` that allows mocking the class +/// properties. +final class MockCaptureDeviceFormat: NSObject, CaptureDeviceFormat { + + /// The format associated with the capture device. + var avFormat: AVCaptureDevice.Format { + preconditionFailure("Attempted to access unimplemented property: avFormat") + } + + var _formatDescription: CMVideoFormatDescription? + + /// The format description for the capture device. + var formatDescription: CMFormatDescription { + _formatDescription! + } + + /// The array of frame rate ranges supported by the video format. + var flutterVideoSupportedFrameRateRanges: [FrameRateRange] = [] + + override init() { + super.init() + + CMVideoFormatDescriptionCreate( + allocator: kCFAllocatorDefault, codecType: kCVPixelFormatType_32BGRA, width: 1920, + height: 1080, extensions: nil, formatDescriptionOut: &_formatDescription) + } + + init(codecType: OSType, width: Int32, height: Int32) { + super.init() + + CMVideoFormatDescriptionCreate( + allocator: kCFAllocatorDefault, codecType: codecType, width: width, + height: height, extensions: nil, formatDescriptionOut: &_formatDescription) + } +} diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDeviceInputFactory.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDeviceInputFactory.swift new file mode 100644 index 000000000000..9292b6256d7c --- /dev/null +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDeviceInputFactory.swift @@ -0,0 +1,13 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +@testable import camera_avfoundation + +///// A mocked implementation of FLTCaptureDeviceInputFactory which allows injecting a custom +///// implementation. +final class MockCaptureDeviceInputFactory: NSObject, CaptureDeviceInputFactory { + func deviceInput(with device: CaptureDevice) throws -> CaptureInput { + return MockCaptureInput() + } +} diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureInput.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureInput.swift new file mode 100644 index 000000000000..74d8742bd161 --- /dev/null +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureInput.swift @@ -0,0 +1,17 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import AVFoundation + +@testable import camera_avfoundation + +/// A mocked implementation of FLTCaptureInput which allows injecting a custom +/// implementation. +final class MockCaptureInput: NSObject, CaptureInput { + var avInput: AVCaptureInput { + preconditionFailure("Attempted to access unimplemented property: input") + } + + var ports: [AVCaptureInput.Port] = [] +} diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCapturePhotoOutput.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCapturePhotoOutput.swift new file mode 100644 index 000000000000..a0b2faee8c00 --- /dev/null +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCapturePhotoOutput.swift @@ -0,0 +1,32 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import AVFoundation + +@testable import camera_avfoundation + +/// Mock implementation of `FLTCapturePhotoOutput` protocol which allows injecting a custom +/// implementation. +final class MockCapturePhotoOutput: NSObject, CapturePhotoOutput { + var avOutput = AVCapturePhotoOutput() + var availablePhotoCodecTypes: [AVVideoCodecType] = [] + var isHighResolutionCaptureEnabled = false + var supportedFlashModes: [AVCaptureDevice.FlashMode] = [] + + // Stub that is called when the corresponding public method is called. + var capturePhotoWithSettingsStub: + ((_ settings: AVCapturePhotoSettings, _ delegate: AVCapturePhotoCaptureDelegate) -> Void)? + + // Stub that is called when the corresponding public method is called. + var connectionWithMediaTypeStub: ((_ mediaType: AVMediaType) -> CaptureConnection?)? + + func capturePhoto(with settings: AVCapturePhotoSettings, delegate: AVCapturePhotoCaptureDelegate) + { + capturePhotoWithSettingsStub?(settings, delegate) + } + + func connection(with mediaType: AVMediaType) -> CaptureConnection? { + return connectionWithMediaTypeStub?(mediaType) + } +} diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureSession.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureSession.swift new file mode 100644 index 000000000000..08d2427b4438 --- /dev/null +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureSession.swift @@ -0,0 +1,87 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import AVFoundation + +@testable import camera_avfoundation + +/// Mock implementation of `FLTCaptureSession` protocol which allows injecting a custom +/// implementation. +final class MockCaptureSession: NSObject, CaptureSession { + var setSessionPresetStub: ((AVCaptureSession.Preset) -> Void)? + var beginConfigurationStub: (() -> Void)? + var commitConfigurationStub: (() -> Void)? + var startRunningStub: (() -> Void)? + var stopRunningStub: (() -> Void)? + var canSetSessionPresetStub: ((AVCaptureSession.Preset) -> Bool)? + + var _sessionPreset = AVCaptureSession.Preset.high + var inputs = [AVCaptureInput]() + var outputs = [AVCaptureOutput]() + + private(set) var addedAudioOutputCount: Int = 0 + + var automaticallyConfiguresApplicationAudioSession = false + var isRunning = true + + var sessionPreset: AVCaptureSession.Preset { + get { + return _sessionPreset + } + set { + setSessionPresetStub?(newValue) + } + } + + func beginConfiguration() { + beginConfigurationStub?() + } + + func commitConfiguration() { + commitConfigurationStub?() + } + + func startRunning() { + startRunningStub?() + } + + func stopRunning() { + stopRunningStub?() + } + + func canSetSessionPreset(_ preset: AVCaptureSession.Preset) -> Bool { + return canSetSessionPresetStub?(preset) ?? true + } + + func addInputWithNoConnections(_ input: CaptureInput) {} + + func addOutputWithNoConnections(_ output: AVCaptureOutput) {} + + func addConnection(_: AVCaptureConnection) {} + + func addInput(_: CaptureInput) {} + + func addOutput(_ output: AVCaptureOutput) { + + if output is AVCaptureAudioDataOutput { + addedAudioOutputCount += 1 + } + } + + func removeInput(_: CaptureInput) {} + + func removeOutput(_: AVCaptureOutput) {} + + func canAddInput(_: CaptureInput) -> Bool { + return true + } + + func canAddOutput(_: AVCaptureOutput) -> Bool { + return true + } + + func canAddConnection(_: AVCaptureConnection) -> Bool { + return true + } +} diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureVideoDataOutput.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureVideoDataOutput.swift new file mode 100644 index 000000000000..c36397321201 --- /dev/null +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureVideoDataOutput.swift @@ -0,0 +1,27 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import AVFoundation + +@testable import camera_avfoundation + +/// Mock implementation of `FLTCaptureVideoDataOutput` protocol which allows injecting a custom +/// implementation. +class MockCaptureVideoDataOutput: NSObject, CaptureVideoDataOutput { + var avOutput = AVCaptureVideoDataOutput() + var alwaysDiscardsLateVideoFrames = false + var videoSettings: [String: Any]! = [:] + var availableVideoPixelFormatTypes: [FourCharCode] = [] + + var connectionWithMediaTypeStub: ((AVMediaType) -> CaptureConnection?)? + + func connection(with mediaType: AVMediaType) -> CaptureConnection? { + return connectionWithMediaTypeStub?(mediaType) + } + + func setSampleBufferDelegate( + _ sampleBufferDelegate: AVCaptureVideoDataOutputSampleBufferDelegate?, + queue sampleBufferCallbackQueue: DispatchQueue? + ) {} +} diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockDeviceOrientationProvider.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockDeviceOrientationProvider.swift new file mode 100644 index 000000000000..034eafc4d184 --- /dev/null +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockDeviceOrientationProvider.swift @@ -0,0 +1,15 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import UIKit + +@testable import camera_avfoundation + +final class MockDeviceOrientationProvider: NSObject, DeviceOrientationProvider { + var orientationStub: (() -> UIDeviceOrientation)? + + var orientation: UIDeviceOrientation { + return orientationStub?() ?? .unknown + } +} diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockFLTCameraPermissionManager.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockFLTCameraPermissionManager.swift new file mode 100644 index 000000000000..73f991f43a38 --- /dev/null +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockFLTCameraPermissionManager.swift @@ -0,0 +1,32 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import Flutter + +@testable import camera_avfoundation + +final class MockCameraPermissionManager: CameraPermissionManager { + var requestCameraPermissionStub: ((@escaping CameraPermissionRequestCompletionHandler) -> Void)? + var requestAudioPermissionStub: ((@escaping CameraPermissionRequestCompletionHandler) -> Void)? + + init() { + super.init(permissionService: DefaultPermissionService()) + } + + override func requestCameraPermission(completionHandler: @escaping (PigeonError?) -> Void) { + if let stub = requestCameraPermissionStub { + stub(completionHandler) + } else { + super.requestCameraPermission(completionHandler: completionHandler) + } + } + + override func requestAudioPermission(completionHandler: @escaping (PigeonError?) -> Void) { + if let stub = requestAudioPermissionStub { + stub(completionHandler) + } else { + super.requestAudioPermission(completionHandler: completionHandler) + } + } +} diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockFlutterBinaryMessenger.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockFlutterBinaryMessenger.swift new file mode 100644 index 000000000000..7aad9804a1ba --- /dev/null +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockFlutterBinaryMessenger.swift @@ -0,0 +1,26 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import Flutter + +/// Mocked implementation of `FlutterBinaryMessenger` protocol that exists to allow constructing +/// a `CameraPlugin` instance for testing. It contains an empty implementation for all protocol +/// methods. +final class MockFlutterBinaryMessenger: NSObject, FlutterBinaryMessenger { + func send(onChannel channel: String, message: Data?) {} + + func send( + onChannel channel: + String, + message: + Data?, binaryReply callback: FlutterBinaryReply? = nil + ) {} + + func setMessageHandlerOnChannel( + _ channel: String, + binaryMessageHandler handler: FlutterBinaryMessageHandler? = nil + ) -> FlutterBinaryMessengerConnection { 0 } + + func cleanUpConnection(_ connection: FlutterBinaryMessengerConnection) {} +} diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockFlutterTextureRegistry.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockFlutterTextureRegistry.swift new file mode 100644 index 000000000000..a798e55cced6 --- /dev/null +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockFlutterTextureRegistry.swift @@ -0,0 +1,16 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import Flutter + +/// Mocked implementation of `FlutterTextureRegistry` protocol that exists to allow constructing +/// a `CameraPlugin` instance for testing. It contains an empty implementation for all protocol +/// methods. +final class MockFlutterTextureRegistry: NSObject, FlutterTextureRegistry { + func register(_ texture: FlutterTexture) -> Int64 { 0 } + + func textureFrameAvailable(_ textureId: Int64) {} + + func unregisterTexture(_ textureId: Int64) {} +} diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockFrameRateRange.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockFrameRateRange.swift new file mode 100644 index 000000000000..1130a35937e7 --- /dev/null +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockFrameRateRange.swift @@ -0,0 +1,17 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +@testable import camera_avfoundation + +/// A mock implementation of `FrameRateRange` that allows mocking the class properties. +final class MockFrameRateRange: NSObject, FrameRateRange { + var minFrameRate: Float64 + var maxFrameRate: Float64 + + /// Initializes a `MockFrameRateRange` with the given frame rate range. + init(minFrameRate: Float64, maxFrameRate: Float64) { + self.minFrameRate = minFrameRate + self.maxFrameRate = maxFrameRate + } +} diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockGlobalEventApi.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockGlobalEventApi.swift new file mode 100644 index 000000000000..1a95e4278216 --- /dev/null +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockGlobalEventApi.swift @@ -0,0 +1,26 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import Flutter + +@testable import camera_avfoundation + +/// A mock implementation of `CameraGlobalEventApi` that captures received +/// `deviceOrientationChanged` events and exposes whether they were received to the testing code. +final class MockGlobalEventApi: CameraGlobalEventApiProtocol { + /// Whether the `deviceOrientationChanged` callback was called. + var deviceOrientationChangedCalled = false + + /// The last orientation received by the `deviceOrientationChanged` callback. + var lastOrientation = PlatformDeviceOrientation.portraitUp + + func deviceOrientationChanged( + orientation orientationArg: PlatformDeviceOrientation, + completion: @escaping (Result) -> Void + ) { + deviceOrientationChangedCalled = true + lastOrientation = orientationArg + completion(.success(())) + } +} diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockWritableData.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockWritableData.swift new file mode 100644 index 000000000000..9feb13e3f997 --- /dev/null +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockWritableData.swift @@ -0,0 +1,17 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +@testable import camera_avfoundation + +/// A mock implementation of `WritableData` that allows injecting a custom implementation +/// for writing to a file. +final class MockWritableData: WritableData { + var writeToFileStub: ((String, Data.WritingOptions) throws -> Void)? + + func writeToPath(_ path: String, options: Data.WritingOptions) throws { + if let stub = self.writeToFileStub { + try stub(path, options) + } + } +} diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/PhotoCaptureTests.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/PhotoCaptureTests.swift new file mode 100644 index 000000000000..e20a15dba9d3 --- /dev/null +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/PhotoCaptureTests.swift @@ -0,0 +1,248 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import AVFoundation +import XCTest + +@testable import camera_avfoundation + +/// Includes test cases related to photo capture operations for FLTCam class. +final class PhotoCaptureTests: XCTestCase { + private func createCam(with captureSessionQueue: DispatchQueue) -> DefaultCamera { + let configuration = CameraTestUtils.createTestCameraConfiguration() + configuration.captureSessionQueue = captureSessionQueue + return CameraTestUtils.createTestCamera(configuration) + } + + func testCaptureToFile_mustReportErrorToResultIfSavePhotoDelegateCompletionsWithError() { + let errorExpectation = expectation( + description: "Must send error to result if save photo delegate completes with error.") + let captureSessionQueue = DispatchQueue(label: "capture_session_queue") + captureSessionQueue.setSpecific( + key: captureSessionQueueSpecificKey, value: captureSessionQueueSpecificValue) + let cam = createCam(with: captureSessionQueue) + let error = NSError(domain: "test", code: 0, userInfo: nil) + + let mockOutput = MockCapturePhotoOutput() + mockOutput.capturePhotoWithSettingsStub = { settings, photoDelegate in + let delegate = + cam.inProgressSavePhotoDelegates[settings.uniqueID] + // Completion runs on IO queue. + let ioQueue = DispatchQueue(label: "io_queue") + ioQueue.async { + delegate?.completionHandler(nil, error) + } + } + cam.capturePhotoOutput = mockOutput + + // `FLTCam::captureToFile` runs on capture session queue. + captureSessionQueue.async { + cam.captureToFile { result in + switch result { + case .success(_): + XCTFail("Expected failure") + case .failure(_): + break + } + errorExpectation.fulfill() + } + } + + waitForExpectations(timeout: 30, handler: nil) + } + + func testCaptureToFile_mustReportPathToResultIfSavePhotoDelegateCompletionsWithPath() { + let pathExpectation = expectation( + description: "Must send file path to result if save photo delegate completes with file path.") + let captureSessionQueue = DispatchQueue(label: "capture_session_queue") + captureSessionQueue.setSpecific( + key: captureSessionQueueSpecificKey, value: captureSessionQueueSpecificValue) + let cam = createCam(with: captureSessionQueue) + let filePath = "test" + + let mockOutput = MockCapturePhotoOutput() + mockOutput.capturePhotoWithSettingsStub = { settings, photoDelegate in + let delegate = + cam.inProgressSavePhotoDelegates[settings.uniqueID] + // Completion runs on IO queue. + let ioQueue = DispatchQueue(label: "io_queue") + ioQueue.async { + delegate?.completionHandler(filePath, nil) + } + } + cam.capturePhotoOutput = mockOutput + + // `FLTCam::captureToFile` runs on capture session queue. + captureSessionQueue.async { + cam.captureToFile { result in + switch result { + case .success(let result): + XCTAssertEqual(result, filePath) + case .failure(_): + XCTFail("Unexpected failure") + } + pathExpectation.fulfill() + } + } + + waitForExpectations(timeout: 30, handler: nil) + } + + func testCaptureToFile_mustReportFileExtensionWithHeifWhenHEVCIsAvailableAndFileFormatIsHEIF() { + let expectation = self.expectation( + description: "Test must set extension to heif if availablePhotoCodecTypes contains HEVC.") + + let captureSessionQueue = DispatchQueue(label: "capture_session_queue") + captureSessionQueue.setSpecific( + key: captureSessionQueueSpecificKey, value: captureSessionQueueSpecificValue) + let cam = createCam(with: captureSessionQueue) + cam.setImageFileFormat(PlatformImageFileFormat.heif) + + let mockOutput = MockCapturePhotoOutput() + mockOutput.availablePhotoCodecTypes = [AVVideoCodecType.hevc] + mockOutput.capturePhotoWithSettingsStub = { settings, photoDelegate in + let delegate = + cam.inProgressSavePhotoDelegates[settings.uniqueID] + // Completion runs on IO queue. + let ioQueue = DispatchQueue(label: "io_queue") + ioQueue.async { + delegate?.completionHandler(delegate?.filePath, nil) + } + } + cam.capturePhotoOutput = mockOutput + + // `FLTCam::captureToFile` runs on capture session queue. + captureSessionQueue.async { + cam.captureToFile { result in + if let filePath = self.assertSuccess(result) { + XCTAssertEqual((filePath as NSString).pathExtension, "heif") + } + expectation.fulfill() + } + } + + waitForExpectations(timeout: 30, handler: nil) + } + + func testCaptureToFile_mustReportFileExtensionWithJpgWhenHEVCNotAvailableAndFileFormatIsHEIF() { + let expectation = self.expectation( + description: + "Test must set extension to jpg if availablePhotoCodecTypes does not contain HEVC.") + + let captureSessionQueue = DispatchQueue(label: "capture_session_queue") + captureSessionQueue.setSpecific( + key: captureSessionQueueSpecificKey, value: captureSessionQueueSpecificValue) + let cam = createCam(with: captureSessionQueue) + cam.setImageFileFormat(PlatformImageFileFormat.heif) + + let mockOutput = MockCapturePhotoOutput() + mockOutput.capturePhotoWithSettingsStub = { settings, photoDelegate in + let delegate = + cam.inProgressSavePhotoDelegates[settings.uniqueID] + // Completion runs on IO queue. + let ioQueue = DispatchQueue(label: "io_queue") + ioQueue.async { + delegate?.completionHandler(delegate?.filePath, nil) + } + } + cam.capturePhotoOutput = mockOutput + + // `FLTCam::captureToFile` runs on capture session queue. + captureSessionQueue.async { + cam.captureToFile { result in + if let filePath = self.assertSuccess(result) { + XCTAssertEqual((filePath as NSString).pathExtension, "jpg") + } + expectation.fulfill() + } + } + + waitForExpectations(timeout: 30, handler: nil) + } + + func testCaptureToFile_handlesTorchMode() { + let pathExpectation = expectation( + description: "Must send file path to result if save photo delegate completes with file path.") + let setTorchExpectation = expectation( + description: "Should set torch mode to AVCaptureTorchModeOn.") + + let captureDeviceMock = MockCaptureDevice() + captureDeviceMock.hasTorch = true + captureDeviceMock.isTorchAvailable = true + captureDeviceMock.getTorchModeStub = { .auto } + captureDeviceMock.setTorchModeStub = { mode in + if mode == .on { + setTorchExpectation.fulfill() + } + } + + let captureSessionQueue = DispatchQueue(label: "capture_session_queue") + captureSessionQueue.setSpecific( + key: captureSessionQueueSpecificKey, value: captureSessionQueueSpecificValue) + let configuration = CameraTestUtils.createTestCameraConfiguration() + configuration.captureSessionQueue = captureSessionQueue + configuration.videoCaptureDeviceFactory = { _ in captureDeviceMock } + let cam = CameraTestUtils.createTestCamera(configuration) + + let filePath = "test" + let mockOutput = MockCapturePhotoOutput() + mockOutput.capturePhotoWithSettingsStub = { settings, photoDelegate in + let delegate = + cam.inProgressSavePhotoDelegates[settings.uniqueID] + // Completion runs on IO queue. + let ioQueue = DispatchQueue(label: "io_queue") + ioQueue.async { + delegate?.completionHandler(filePath, nil) + } + } + cam.capturePhotoOutput = mockOutput + + // `FLTCam::captureToFile` runs on capture session queue. + captureSessionQueue.async { + cam.setFlashMode(.torch) { _ in } + cam.captureToFile { result in + if let result = self.assertSuccess(result) { + XCTAssertEqual(result, filePath) + } + pathExpectation.fulfill() + } + } + + waitForExpectations(timeout: 30, handler: nil) + } + + func testCaptureToFile_mustSavePhotoToCameraPicturesDirectory() { + let expectedPath = "/tmp/camera/pictures/" + let expectation = self.expectation( + description: "Photo must be saved to \(expectedPath) directory.") + + let captureSessionQueue = DispatchQueue(label: "capture_session_queue") + captureSessionQueue.setSpecific( + key: captureSessionQueueSpecificKey, value: captureSessionQueueSpecificValue) + let cam = createCam(with: captureSessionQueue) + + let mockOutput = MockCapturePhotoOutput() + mockOutput.capturePhotoWithSettingsStub = { settings, photoDelegate in + let delegate = cam.inProgressSavePhotoDelegates[settings.uniqueID] + let ioQueue = DispatchQueue(label: "io_queue") + ioQueue.async { + delegate?.completionHandler(delegate?.filePath, nil) + } + } + cam.capturePhotoOutput = mockOutput + + captureSessionQueue.async { + cam.captureToFile { result in + if let filePath = self.assertSuccess(result) { + XCTAssertTrue( + filePath.contains(expectedPath) + ) + } + expectation.fulfill() + } + } + + waitForExpectations(timeout: 30, handler: nil) + } +} diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/QueueUtilsTests.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/QueueUtilsTests.swift new file mode 100644 index 000000000000..29a7cc5b453c --- /dev/null +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/QueueUtilsTests.swift @@ -0,0 +1,35 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import XCTest + +@testable import camera_avfoundation + +final class QueueUtilsTests: XCTestCase { + func testShouldStayOnMainQueueIfCalledFromMainQueue() { + let expectation = expectation(description: "Block must be run on the main queue") + + ensureToRunOnMainQueue { + if Thread.isMainThread { + expectation.fulfill() + } + } + + waitForExpectations(timeout: 30) + } + + func testShouldDispatchToMainQueueIfCalledFromBackgroundQueue() { + let expectation = expectation(description: "Block must be run on the main queue") + + DispatchQueue.global(qos: .default).async { + ensureToRunOnMainQueue { + if Thread.isMainThread { + expectation.fulfill() + } + } + } + + waitForExpectations(timeout: 30) + } +} diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/SampleBufferTests.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/SampleBufferTests.swift new file mode 100644 index 000000000000..3db6cd2c94da --- /dev/null +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/SampleBufferTests.swift @@ -0,0 +1,542 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import AVFoundation +import XCTest + +@testable import camera_avfoundation + +private class FakeMediaSettingsAVWrapper: FLTCamMediaSettingsAVWrapper { + let inputMock: MockAssetWriterInput + + init(inputMock: MockAssetWriterInput) { + self.inputMock = inputMock + } + + override func lockDevice(_ captureDevice: CaptureDevice) throws { + // No-op. + } + + override func unlockDevice(_ captureDevice: CaptureDevice) { + // No-op. + } + + override func beginConfiguration(for videoCaptureSession: CaptureSession) { + // No-op. + } + + override func commitConfiguration(for videoCaptureSession: CaptureSession) { + // No-op. + } + + override func setMinFrameDuration(_ duration: CMTime, on captureDevice: CaptureDevice) { + // No-op. + } + + override func setMaxFrameDuration(_ duration: CMTime, on captureDevice: CaptureDevice) { + // No-op. + } + + override func assetWriterAudioInput(withOutputSettings outputSettings: [String: Any]?) + -> AssetWriterInput + { + return inputMock + } + + override func assetWriterVideoInput(withOutputSettings outputSettings: [String: Any]?) + -> AssetWriterInput + { + return inputMock + } + + override func addInput(_ writerInput: AssetWriterInput, to writer: AssetWriter) { + // No-op. + } + + override func recommendedVideoSettingsForAssetWriter( + withFileType fileType: AVFileType, for output: CaptureVideoDataOutput + ) -> [String: Any]? { + return [:] + } +} + +/// Includes test cases related to sample buffer handling for FLTCam class. +final class CameraSampleBufferTests: XCTestCase { + private func createCamera() -> ( + DefaultCamera, + MockAssetWriter, + MockAssetWriterInputPixelBufferAdaptor, + MockAssetWriterInput + ) { + let assetWriter = MockAssetWriter() + let adaptor = MockAssetWriterInputPixelBufferAdaptor() + let input = MockAssetWriterInput() + + let configuration = CameraTestUtils.createTestCameraConfiguration() + configuration.mediaSettings = PlatformMediaSettings( + resolutionPreset: .medium, + framesPerSecond: nil, + videoBitrate: nil, + audioBitrate: nil, + enableAudio: true) + configuration.mediaSettingsWrapper = FakeMediaSettingsAVWrapper(inputMock: input) + + configuration.assetWriterFactory = { url, fileType in + return assetWriter + } + configuration.inputPixelBufferAdaptorFactory = { input, settings in + return adaptor + } + + return ( + CameraTestUtils.createTestCamera(configuration), + assetWriter, + adaptor, + input + ) + } + + func testSampleBufferCallbackQueueMustBeCaptureSessionQueue() { + let captureSessionQueue = DispatchQueue(label: "testing") + let camera = CameraTestUtils.createCameraWithCaptureSessionQueue(captureSessionQueue) + XCTAssertEqual( + captureSessionQueue, camera.captureVideoOutput.avOutput.sampleBufferCallbackQueue, + "Sample buffer callback queue must be the capture session queue.") + } + + func testCopyPixelBuffer() { + let (camera, _, _, _) = createCamera() + let capturedSampleBuffer = CameraTestUtils.createTestSampleBuffer() + let capturedPixelBuffer = CMSampleBufferGetImageBuffer(capturedSampleBuffer)! + let testConnection = CameraTestUtils.createTestConnection(camera.captureVideoOutput.avOutput) + + // Mimic sample buffer callback when captured a new video sample. + camera.captureOutput( + camera.captureVideoOutput.avOutput, + didOutput: capturedSampleBuffer, + from: testConnection) + let deliveredPixelBuffer = camera.copyPixelBuffer()?.takeRetainedValue() + XCTAssertEqual( + deliveredPixelBuffer, capturedPixelBuffer, + "FLTCam must deliver the latest captured pixel buffer to copyPixelBuffer API.") + } + + func testDidOutputSampleBuffer_mustNotChangeSampleBufferRetainCountAfterPauseResumeRecording() { + let (camera, _, _, _) = createCamera() + let sampleBuffer = CameraTestUtils.createTestSampleBuffer() + let testConnection = CameraTestUtils.createTestConnection(camera.captureVideoOutput.avOutput) + + let initialRetainCount = CFGetRetainCount(sampleBuffer) + + // Pause then resume the recording. + camera.startVideoRecording(completion: { error in }, messengerForStreaming: nil) + camera.pauseVideoRecording() + camera.resumeVideoRecording() + + camera.captureOutput( + camera.captureVideoOutput.avOutput, + didOutput: sampleBuffer, + from: testConnection) + + let finalRetainCount = CFGetRetainCount(sampleBuffer) + XCTAssertEqual( + finalRetainCount, initialRetainCount, + "didOutputSampleBuffer must not change the sample buffer retain count after pause resume recording." + ) + } + + func testDidOutputSampleBufferIgnoreAudioSamplesBeforeVideoSamples() { + let (camera, writerMock, adaptorMock, inputMock) = createCamera() + var status = AVAssetWriter.Status.unknown + writerMock.startWritingStub = { + status = .writing + return true + } + writerMock.statusStub = { + return status + } + + let videoSample = CameraTestUtils.createTestSampleBuffer() + let testVideoConnection = CameraTestUtils.createTestConnection( + camera.captureVideoOutput.avOutput) + + let audioSample = CameraTestUtils.createTestAudioSampleBuffer() + let testAudioOutput = CameraTestUtils.createTestAudioOutput() + let testAudioConnection = CameraTestUtils.createTestConnection(testAudioOutput) + + var writtenSamples: [String] = [] + adaptorMock.appendStub = { buffer, time in + writtenSamples.append("video") + return true + } + inputMock.isReadyForMoreMediaData = true + inputMock.appendStub = { buffer in + writtenSamples.append("audio") + return true + } + + camera.startVideoRecording(completion: { error in }, messengerForStreaming: nil) + camera.captureOutput(testAudioOutput, didOutput: audioSample, from: testAudioConnection) + camera.captureOutput(testAudioOutput, didOutput: audioSample, from: testAudioConnection) + camera.captureOutput( + camera.captureVideoOutput.avOutput, + didOutput: videoSample, + from: testVideoConnection) + camera.captureOutput(testAudioOutput, didOutput: audioSample, from: testAudioConnection) + + let expectedSamples = ["video", "audio"] + XCTAssertEqual(writtenSamples, expectedSamples, "First appended sample must be video.") + } + + func testDidOutputSampleBufferSampleTimesMustBeNumericAfterPauseResume() { + let (camera, writerMock, adaptorMock, inputMock) = createCamera() + + let videoSample = CameraTestUtils.createTestSampleBuffer() + let testVideoConnection = CameraTestUtils.createTestConnection( + camera.captureVideoOutput.avOutput) + + let audioSample = CameraTestUtils.createTestAudioSampleBuffer() + let testAudioOutput = CameraTestUtils.createTestAudioOutput() + let testAudioConnection = CameraTestUtils.createTestConnection(testAudioOutput) + + var status = AVAssetWriter.Status.unknown + writerMock.startWritingStub = { + status = .writing + return true + } + writerMock.statusStub = { + return status + } + + var videoAppended = false + adaptorMock.appendStub = { buffer, time in + XCTAssert(CMTIME_IS_NUMERIC(time)) + videoAppended = true + return true + } + + var audioAppended = false + inputMock.isReadyForMoreMediaData = true + inputMock.appendStub = { buffer in + let sampleTime = CMSampleBufferGetPresentationTimeStamp(buffer) + XCTAssert(CMTIME_IS_NUMERIC(sampleTime)) + audioAppended = true + return true + } + + camera.startVideoRecording(completion: { error in }, messengerForStreaming: nil) + camera.pauseVideoRecording() + camera.resumeVideoRecording() + camera.captureOutput( + camera.captureVideoOutput.avOutput, + didOutput: videoSample, + from: testVideoConnection) + camera.captureOutput(testAudioOutput, didOutput: audioSample, from: testAudioConnection) + camera.captureOutput( + camera.captureVideoOutput.avOutput, + didOutput: videoSample, + from: testVideoConnection) + camera.captureOutput(testAudioOutput, didOutput: audioSample, from: testAudioConnection) + + XCTAssert(videoAppended && audioAppended, "Video or audio was not appended.") + } + + func testDidOutputSampleBufferMustNotAppendSampleWhenReadyForMoreMediaDataIsFalse() { + let (camera, _, adaptorMock, inputMock) = createCamera() + + let videoSample = CameraTestUtils.createTestSampleBuffer() + let testVideoConnection = CameraTestUtils.createTestConnection( + camera.captureVideoOutput.avOutput) + + var sampleAppended = false + adaptorMock.appendStub = { buffer, time in + sampleAppended = true + return true + } + + camera.startVideoRecording(completion: { error in }, messengerForStreaming: nil) + + inputMock.isReadyForMoreMediaData = true + sampleAppended = false + camera.captureOutput( + camera.captureVideoOutput.avOutput, + didOutput: videoSample, + from: testVideoConnection) + XCTAssertTrue(sampleAppended, "Sample was not appended.") + + inputMock.isReadyForMoreMediaData = false + sampleAppended = false + camera.captureOutput( + camera.captureVideoOutput.avOutput, + didOutput: videoSample, + from: testVideoConnection) + XCTAssertFalse(sampleAppended, "Sample cannot be appended when readyForMoreMediaData is NO.") + } + + func testStopVideoRecordingWithCompletionMustCallCompletion() { + let (camera, writerMock, _, _) = createCamera() + + var status = AVAssetWriter.Status.unknown + writerMock.startWritingStub = { + status = .writing + return true + } + writerMock.statusStub = { + return status + } + writerMock.finishWritingStub = { handler in + XCTAssert( + writerMock.status == .writing, + "Cannot call finishWritingWithCompletionHandler when status is not AVAssetWriter.Status.writing." + ) + handler() + } + + camera.startVideoRecording(completion: { error in }, messengerForStreaming: nil) + var completionCalled = false + camera.stopVideoRecording(completion: { result in + completionCalled = true + }) + + XCTAssert(completionCalled, "Completion was not called.") + } + + func testStartWritingShouldNotBeCalledBetweenSampleCreationAndAppending() { + let (camera, writerMock, adaptorMock, inputMock) = createCamera() + + let videoSample = CameraTestUtils.createTestSampleBuffer() + let testVideoConnection = CameraTestUtils.createTestConnection( + camera.captureVideoOutput.avOutput) + + var startWritingCalled = false + writerMock.startWritingStub = { + startWritingCalled = true + return true + + } + + var videoAppended = false + adaptorMock.appendStub = { buffer, time in + videoAppended = true + return true + } + + inputMock.isReadyForMoreMediaData = true + + camera.startVideoRecording(completion: { error in }, messengerForStreaming: nil) + + let startWritingCalledBefore = startWritingCalled + camera.captureOutput( + camera.captureVideoOutput.avOutput, + didOutput: videoSample, + from: testVideoConnection) + XCTAssert( + (startWritingCalledBefore && videoAppended) || (startWritingCalled && !videoAppended), + "The startWriting was called between sample creation and appending.") + + camera.captureOutput( + camera.captureVideoOutput.avOutput, + didOutput: videoSample, + from: testVideoConnection) + XCTAssert(videoAppended, "Video was not appended.") + } + + func testStartVideoRecordingWithCompletionShouldNotDisableMixWithOthers() { + let cam = CameraTestUtils.createCameraWithCaptureSessionQueue(DispatchQueue(label: "testing")) + + try? AVAudioSession.sharedInstance().setCategory(.playback, options: .mixWithOthers) + cam.startVideoRecording(completion: { error in }, messengerForStreaming: nil) + XCTAssert( + AVAudioSession.sharedInstance().categoryOptions.contains(.mixWithOthers), + "Flag MixWithOthers was removed.") + XCTAssert( + AVAudioSession.sharedInstance().category == .playAndRecord, + "Category should be PlayAndRecord.") + } + + func testDidOutputSampleBufferMustUseSingleOffsetForVideoAndAudio() { + let (camera, writerMock, adaptorMock, inputMock) = createCamera() + + let testVideoConnection = CameraTestUtils.createTestConnection( + camera.captureVideoOutput.avOutput) + let testAudioOutput = CameraTestUtils.createTestAudioOutput() + let testAudioConnection = CameraTestUtils.createTestConnection(testAudioOutput) + + var status = AVAssetWriter.Status.unknown + writerMock.startWritingStub = { + status = .writing + return true + } + writerMock.statusStub = { + return status + } + + var appendedTime = CMTime.invalid + + adaptorMock.appendStub = { buffer, time in + appendedTime = time + return true + } + + inputMock.isReadyForMoreMediaData = true + inputMock.appendStub = { buffer in + appendedTime = CMSampleBufferGetPresentationTimeStamp(buffer) + return true + } + + camera.startVideoRecording(completion: { error in }, messengerForStreaming: nil) + + let appendVideoSample = { (time: Int64) in + camera.captureOutput( + camera.captureVideoOutput.avOutput, + didOutput: CameraTestUtils.createTestSampleBuffer( + timestamp: CMTimeMake(value: time, timescale: 1), + duration: .invalid), + from: testVideoConnection) + } + + let appendAudioSample = { (time: Int64, duration: Int64) in + camera.captureOutput( + testAudioOutput, + didOutput: CameraTestUtils.createTestAudioSampleBuffer( + timestamp: CMTimeMake(value: time, timescale: 1), + duration: CMTimeMake(value: duration, timescale: 1)), + from: testAudioConnection) + } + + appendedTime = .invalid + camera.pauseVideoRecording() + camera.resumeVideoRecording() + appendVideoSample(1) + XCTAssertEqual(appendedTime, CMTimeMake(value: 1, timescale: 1)) + + appendedTime = .invalid + camera.pauseVideoRecording() + camera.resumeVideoRecording() + appendVideoSample(11) + XCTAssertEqual(appendedTime, .invalid) + appendVideoSample(12) + XCTAssertEqual(appendedTime, CMTimeMake(value: 2, timescale: 1)) + + appendedTime = .invalid + camera.pauseVideoRecording() + camera.resumeVideoRecording() + appendAudioSample(20, 2) + XCTAssertEqual(appendedTime, .invalid) + appendVideoSample(23) + XCTAssertEqual(appendedTime, CMTimeMake(value: 3, timescale: 1)) + + appendedTime = .invalid + camera.pauseVideoRecording() + camera.resumeVideoRecording() + appendVideoSample(28) + XCTAssertEqual(appendedTime, .invalid) + appendAudioSample(30, 2) + XCTAssertEqual(appendedTime, .invalid) + appendVideoSample(33) + XCTAssertEqual(appendedTime, .invalid) + appendAudioSample(32, 2) + XCTAssertEqual(appendedTime, CMTimeMake(value: 2, timescale: 1)) + } + + func testDidOutputSampleBufferMustConnectVideoAfterSessionInterruption() { + let (camera, writerMock, adaptorMock, inputMock) = createCamera() + + let testVideoConnection = CameraTestUtils.createTestConnection( + camera.captureVideoOutput.avOutput) + let testAudioOutput = CameraTestUtils.createTestAudioOutput() + let testAudioConnection = CameraTestUtils.createTestConnection(testAudioOutput) + + var status = AVAssetWriter.Status.unknown + writerMock.startWritingStub = { + status = .writing + return true + } + writerMock.statusStub = { + return status + } + + var appendedTime = CMTime.invalid + + adaptorMock.appendStub = { buffer, time in + appendedTime = time + return true + } + + inputMock.isReadyForMoreMediaData = true + inputMock.appendStub = { buffer in + appendedTime = CMSampleBufferGetPresentationTimeStamp(buffer) + return true + } + + camera.startVideoRecording(completion: { error in }, messengerForStreaming: nil) + + let appendVideoSample = { (time: Int64) in + camera.captureOutput( + camera.captureVideoOutput.avOutput, + didOutput: CameraTestUtils.createTestSampleBuffer( + timestamp: CMTimeMake(value: time, timescale: 1), + duration: .invalid), + from: testVideoConnection) + } + + let appendAudioSample = { (time: Int64, duration: Int64) in + camera.captureOutput( + testAudioOutput, + didOutput: CameraTestUtils.createTestAudioSampleBuffer( + timestamp: CMTimeMake(value: time, timescale: 1), + duration: CMTimeMake(value: duration, timescale: 1)), + from: testAudioConnection) + } + + appendVideoSample(1) + appendAudioSample(1, 1) + + NotificationCenter.default.post( + name: AVCaptureSession.wasInterruptedNotification, + object: camera.audioCaptureSession) + + appendedTime = .invalid + appendAudioSample(11, 1) + XCTAssertEqual(appendedTime, .invalid) + appendVideoSample(12) + XCTAssertEqual(appendedTime, CMTimeMake(value: 2, timescale: 1)) + appendedTime = .invalid + appendAudioSample(12, 1) + XCTAssertEqual(appendedTime, CMTimeMake(value: 2, timescale: 1)) + } + + func testStartVideoRecordingReportsErrorWhenStartWritingFails() { + let (camera, writerMock, _, _) = createCamera() + + // Configure the mock to return false for startWriting + writerMock.startWritingStub = { + return false + } + + // Configure a mock error + let mockError = NSError( + domain: "test", code: 123, userInfo: [NSLocalizedDescriptionKey: "Mock write error"]) + writerMock.error = mockError + + let expectation = self.expectation(description: "Completion handler called with error") + + camera.startVideoRecording( + completion: { result in + switch result { + case .failure(let error as PigeonError): + XCTAssertEqual(error.code, "IOError") + XCTAssertEqual(error.message, "AVAssetWriter failed to start writing") + XCTAssertEqual(error.details as? String, "Mock write error") + XCTAssertFalse(camera.isRecording) + expectation.fulfill() + default: + XCTFail("Expected PigeonError") + } + + }, messengerForStreaming: nil) + + waitForExpectations(timeout: 1.0, handler: nil) + } +} diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/SavePhotoDelegateTests.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/SavePhotoDelegateTests.swift new file mode 100644 index 000000000000..76b4430dafed --- /dev/null +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/SavePhotoDelegateTests.swift @@ -0,0 +1,99 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import AVFoundation +import XCTest + +@testable import camera_avfoundation + +final class SavePhotoDelegateTests: XCTestCase { + func testHandlePhotoCaptureResult_mustCompleteWithErrorIfFailedToCapture() { + let completionExpectation = expectation( + description: "Must complete with error if failed to capture photo.") + let captureError = NSError(domain: "test", code: 0, userInfo: nil) + let ioQueue = DispatchQueue(label: "test") + let delegate = SavePhotoDelegate(path: "test", ioQueue: ioQueue) { path, error in + XCTAssertEqual(captureError, error as NSError?) + XCTAssertNil(path) + completionExpectation.fulfill() + } + + delegate.handlePhotoCaptureResult(error: captureError) { nil } + + waitForExpectations(timeout: 30, handler: nil) + } + + func testHandlePhotoCaptureResult_mustCompleteWithErrorIfFailedToWrite() { + let completionExpectation = expectation( + description: "Must complete with error if failed to write file.") + let ioQueue = DispatchQueue(label: "test") + let ioError = NSError( + domain: "IOError", code: 0, userInfo: [NSLocalizedDescriptionKey: "Localized IO Error"]) + let delegate = SavePhotoDelegate(path: "test", ioQueue: ioQueue) { path, error in + XCTAssertEqual(ioError, error as NSError?) + XCTAssertNil(path) + completionExpectation.fulfill() + } + + let mockWritableData = MockWritableData() + mockWritableData.writeToFileStub = { path, options in + throw ioError + } + + delegate.handlePhotoCaptureResult(error: nil) { mockWritableData } + + waitForExpectations(timeout: 30, handler: nil) + } + + func testHandlePhotoCaptureResult_mustCompleteWithFilePathIfSuccessToWrite() { + let completionExpectation = expectation( + description: "Must complete with file path if succeeds to write file.") + let ioQueue = DispatchQueue(label: "test") + let filePath = "test" + let delegate = SavePhotoDelegate(path: filePath, ioQueue: ioQueue) { path, error in + XCTAssertNil(error) + XCTAssertEqual(filePath, path) + completionExpectation.fulfill() + } + + let mockWritableData = MockWritableData() + mockWritableData.writeToFileStub = { path, options in } + + delegate.handlePhotoCaptureResult(error: nil) { mockWritableData } + + waitForExpectations(timeout: 30, handler: nil) + } + + func testHandlePhotoCaptureResult_bothProvideDataAndSaveFileMustRunOnIOQueue() { + let dataProviderQueueExpectation = expectation( + description: "Data provider must run on io queue.") + let writeFileQueueExpectation = expectation(description: "File writing must run on io queue.") + let completionExpectation = expectation( + description: "Must complete with file path if success to write file.") + let ioQueue = DispatchQueue(label: "test") + let ioQueueSpecific = DispatchSpecificKey() + ioQueue.setSpecific(key: ioQueueSpecific, value: ()) + + let mockWritableData = MockWritableData() + mockWritableData.writeToFileStub = { path, options in + if DispatchQueue.getSpecific(key: ioQueueSpecific) != nil { + writeFileQueueExpectation.fulfill() + } + } + + let filePath = "test" + let delegate = SavePhotoDelegate(path: filePath, ioQueue: ioQueue) { path, error in + completionExpectation.fulfill() + } + + delegate.handlePhotoCaptureResult(error: nil) { + if DispatchQueue.getSpecific(key: ioQueueSpecific) != nil { + dataProviderQueueExpectation.fulfill() + } + return mockWritableData + } + + waitForExpectations(timeout: 30, handler: nil) + } +} diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/StreamingTests.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/StreamingTests.swift new file mode 100644 index 000000000000..b018a7cca12d --- /dev/null +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/StreamingTests.swift @@ -0,0 +1,217 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import AVFoundation +import Flutter +import XCTest + +@testable import camera_avfoundation + +private class MockEventSink: PigeonEventSink { + var eventSinkSuccessStub: ((PlatformCameraImageData?) -> Void)? + + init() { + super.init({ event in }) + } + + override func success(_ event: PlatformCameraImageData?) { + eventSinkSuccessStub?(event) + } + + override func error(code: String, message: String?, details: Any?) {} + + override func endOfStream() {} +} + +private class MockImageStreamHandler: ImageDataStreamStreamHandler, ImageStreamHandler { + var mockEventSink = MockEventSink() + var captureSessionQueue: DispatchQueue { + preconditionFailure("Attempted to access unimplemented property: captureSessionQueue") + } + var eventSink: PigeonEventSink? { + set { + } + get { + return mockEventSink + } + } + + var eventSinkSuccessStub: ((PlatformCameraImageData?) -> Void)? { + set { + mockEventSink.eventSinkSuccessStub = newValue + } + get { + return mockEventSink.eventSinkSuccessStub + } + } + + override func onListen( + withArguments arguments: Any?, sink: PigeonEventSink + ) { + } + + override func onCancel(withArguments arguments: Any?) { + } +} + +final class StreamingTests: XCTestCase { + private func createCamera() -> ( + DefaultCamera, + AVCaptureOutput, + CMSampleBuffer, + CMSampleBuffer, + AVCaptureConnection + ) { + let captureSessionQueue = DispatchQueue(label: "testing") + let configuration = CameraTestUtils.createTestCameraConfiguration() + configuration.captureSessionQueue = captureSessionQueue + + let camera = CameraTestUtils.createTestCamera(configuration) + let testAudioOutput = CameraTestUtils.createTestAudioOutput() + let sampleBuffer = CameraTestUtils.createTestSampleBuffer() + let audioSampleBuffer = CameraTestUtils.createTestAudioSampleBuffer() + let testAudioConnection = CameraTestUtils.createTestConnection(testAudioOutput) + + return (camera, testAudioOutput, sampleBuffer, audioSampleBuffer, testAudioConnection) + } + + func testExceedMaxStreamingPendingFramesCount() { + let (camera, testAudioOutput, sampleBuffer, _, testAudioConnection) = createCamera() + let handlerMock = MockImageStreamHandler() + + let finishStartStreamExpectation = expectation( + description: "Finish startStream") + + let messenger = MockFlutterBinaryMessenger() + camera.startImageStream( + with: messenger, imageStreamHandler: handlerMock, + completion: { + _ in + finishStartStreamExpectation.fulfill() + }) + + waitForExpectations(timeout: 30, handler: nil) + + // Setup mocked event sink after the stream starts + let streamingExpectation = expectation( + description: "Must not call handler over maxStreamingPendingFramesCount") + + handlerMock.eventSinkSuccessStub = { event in + streamingExpectation.fulfill() + } + + waitForQueueRoundTrip(with: DispatchQueue.main) + XCTAssertEqual(camera.isStreamingImages, true) + + streamingExpectation.expectedFulfillmentCount = 4 + for _ in 0..<10 { + camera.captureOutput(testAudioOutput, didOutput: sampleBuffer, from: testAudioConnection) + } + + waitForExpectations(timeout: 30, handler: nil) + } + + func testReceivedImageStreamData() { + let (camera, testAudioOutput, sampleBuffer, _, testAudioConnection) = createCamera() + let handlerMock = MockImageStreamHandler() + + let finishStartStreamExpectation = expectation( + description: "Finish startStream") + + let messenger = MockFlutterBinaryMessenger() + camera.startImageStream( + with: messenger, imageStreamHandler: handlerMock, + completion: { + _ in + finishStartStreamExpectation.fulfill() + }) + + waitForExpectations(timeout: 30, handler: nil) + + // Setup mocked event sink after the stream starts + let streamingExpectation = expectation( + description: "Must be able to call the handler again when receivedImageStreamData is called") + handlerMock.eventSinkSuccessStub = { event in + streamingExpectation.fulfill() + } + + waitForQueueRoundTrip(with: DispatchQueue.main) + XCTAssertEqual(camera.isStreamingImages, true) + + streamingExpectation.expectedFulfillmentCount = 5 + for _ in 0..<10 { + camera.captureOutput(testAudioOutput, didOutput: sampleBuffer, from: testAudioConnection) + } + + camera.receivedImageStreamData() + camera.captureOutput(testAudioOutput, didOutput: sampleBuffer, from: testAudioConnection) + + waitForExpectations(timeout: 30, handler: nil) + } + + func testIgnoresNonImageBuffers() { + let (camera, testAudioOutput, _, audioSampleBuffer, testAudioConnection) = createCamera() + let handlerMock = MockImageStreamHandler() + handlerMock.eventSinkSuccessStub = { event in + XCTFail() + } + + let finishStartStreamExpectation = expectation( + description: "Finish startStream") + + let messenger = MockFlutterBinaryMessenger() + camera.startImageStream( + with: messenger, imageStreamHandler: handlerMock, + completion: { + _ in + finishStartStreamExpectation.fulfill() + }) + + waitForExpectations(timeout: 30, handler: nil) + XCTAssertEqual(camera.isStreamingImages, true) + + camera.captureOutput(testAudioOutput, didOutput: audioSampleBuffer, from: testAudioConnection) + + waitForQueueRoundTrip(with: DispatchQueue.main) + } + + func testImageStreamEventFormat() throws { + let (camera, testAudioOutput, sampleBuffer, _, testAudioConnection) = createCamera() + + let expectation = expectation(description: "Received a valid event") + + let handlerMock = MockImageStreamHandler() + handlerMock.eventSinkSuccessStub = { event in + guard let imageBuffer = event else { + XCTFail() + return + } + XCTAssertGreaterThan(imageBuffer.width, 0) + XCTAssertGreaterThan(imageBuffer.height, 0) + XCTAssertGreaterThan(imageBuffer.formatCode, 0) + XCTAssertGreaterThan(imageBuffer.lensAperture, 0) + XCTAssertGreaterThan(imageBuffer.sensorExposureTimeNanoseconds, 0) + XCTAssertGreaterThan(imageBuffer.sensorSensitivity, 0) + + let planes = imageBuffer.planes + let planeBuffer = planes[0] + + XCTAssertGreaterThan(planeBuffer.bytesPerRow, 0) + XCTAssertGreaterThan(planeBuffer.width, 0) + XCTAssertGreaterThan(planeBuffer.height, 0) + XCTAssertGreaterThan(planeBuffer.bytes.data.count, 0) + + expectation.fulfill() + } + let messenger = MockFlutterBinaryMessenger() + camera.startImageStream(with: messenger, imageStreamHandler: handlerMock) { _ in } + + waitForQueueRoundTrip(with: DispatchQueue.main) + XCTAssertEqual(camera.isStreamingImages, true) + + camera.captureOutput(testAudioOutput, didOutput: sampleBuffer, from: testAudioConnection) + + waitForExpectations(timeout: 30, handler: nil) + } +} From 950bda4d48ec0a0d55de8eb789d1c66d3329675d Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Wed, 18 Mar 2026 12:13:02 -0400 Subject: [PATCH 03/10] Re-add test files to project --- .../ios/Runner.xcodeproj/project.pbxproj | 186 +++++++++++++++++- .../example/ios/RunnerTests/RunnerTests.swift | 12 -- 2 files changed, 181 insertions(+), 17 deletions(-) delete mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/RunnerTests.swift diff --git a/packages/camera/camera_avfoundation/example/ios/Runner.xcodeproj/project.pbxproj b/packages/camera/camera_avfoundation/example/ios/Runner.xcodeproj/project.pbxproj index 420851afb872..f98c4f5f9a74 100644 --- a/packages/camera/camera_avfoundation/example/ios/Runner.xcodeproj/project.pbxproj +++ b/packages/camera/camera_avfoundation/example/ios/Runner.xcodeproj/project.pbxproj @@ -3,12 +3,54 @@ archiveVersion = 1; classes = { }; - objectVersion = 54; + objectVersion = 60; objects = { /* Begin PBXBuildFile section */ 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; - 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; }; + 335A7B032F6B061D005902FE /* FLTCamZoomTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7AE82F6B061D005902FE /* FLTCamZoomTests.swift */; }; + 335A7B042F6B061D005902FE /* AvailableCamerasTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7AD72F6B061D005902FE /* AvailableCamerasTests.swift */; }; + 335A7B052F6B061D005902FE /* PhotoCaptureTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7AFE2F6B061D005902FE /* PhotoCaptureTests.swift */; }; + 335A7B062F6B061D005902FE /* SavePhotoDelegateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7B012F6B061D005902FE /* SavePhotoDelegateTests.swift */; }; + 335A7B072F6B061D005902FE /* MockCameraDeviceDiscoverer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7AED2F6B061D005902FE /* MockCameraDeviceDiscoverer.swift */; }; + 335A7B082F6B061D005902FE /* MockFlutterTextureRegistry.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7AF92F6B061D005902FE /* MockFlutterTextureRegistry.swift */; }; + 335A7B092F6B061D005902FE /* QueueUtilsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7AFF2F6B061D005902FE /* QueueUtilsTests.swift */; }; + 335A7B0A2F6B061D005902FE /* CameraPreviewPauseTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7ADF2F6B061D005902FE /* CameraPreviewPauseTests.swift */; }; + 335A7B0B2F6B061D005902FE /* CameraPluginCreateCameraTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7ADC2F6B061D005902FE /* CameraPluginCreateCameraTests.swift */; }; + 335A7B0C2F6B061D005902FE /* MockCaptureDevice.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7AEF2F6B061D005902FE /* MockCaptureDevice.swift */; }; + 335A7B0D2F6B061D005902FE /* MockWritableData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7AFC2F6B061D005902FE /* MockWritableData.swift */; }; + 335A7B0E2F6B061D005902FE /* CameraOrientationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7ADA2F6B061D005902FE /* CameraOrientationTests.swift */; }; + 335A7B0F2F6B061D005902FE /* FLTCamSetFlashModeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7AE72F6B061D005902FE /* FLTCamSetFlashModeTests.swift */; }; + 335A7B102F6B061D005902FE /* CameraSettingsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7AE22F6B061D005902FE /* CameraSettingsTests.swift */; }; + 335A7B112F6B061D005902FE /* FLTCamExposureTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7AE42F6B061D005902FE /* FLTCamExposureTests.swift */; }; + 335A7B122F6B061D005902FE /* CameraMethodChannelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7AD92F6B061D005902FE /* CameraMethodChannelTests.swift */; }; + 335A7B132F6B061D005902FE /* MockGlobalEventApi.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7AFB2F6B061D005902FE /* MockGlobalEventApi.swift */; }; + 335A7B142F6B061D005902FE /* MockAssetWriter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7AE92F6B061D005902FE /* MockAssetWriter.swift */; }; + 335A7B152F6B061D005902FE /* MockCapturePhotoOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7AF32F6B061D005902FE /* MockCapturePhotoOutput.swift */; }; + 335A7B162F6B061D005902FE /* FLTCamFocusTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7AE52F6B061D005902FE /* FLTCamFocusTests.swift */; }; + 335A7B172F6B061D005902FE /* CameraPluginInitializeCameraTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7ADE2F6B061D005902FE /* CameraPluginInitializeCameraTests.swift */; }; + 335A7B182F6B061D005902FE /* CameraPluginDelegatingMethodTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7ADD2F6B061D005902FE /* CameraPluginDelegatingMethodTests.swift */; }; + 335A7B192F6B061D005902FE /* MockAssetWriterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7AEA2F6B061D005902FE /* MockAssetWriterInput.swift */; }; + 335A7B1A2F6B061D005902FE /* CameraTestUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7AE32F6B061D005902FE /* CameraTestUtils.swift */; }; + 335A7B1B2F6B061D005902FE /* MockAssetWriterInputPixelBufferAdaptor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7AEB2F6B061D005902FE /* MockAssetWriterInputPixelBufferAdaptor.swift */; }; + 335A7B1C2F6B061D005902FE /* MockFrameRateRange.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7AFA2F6B061D005902FE /* MockFrameRateRange.swift */; }; + 335A7B1D2F6B061D005902FE /* MockDeviceOrientationProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7AF62F6B061D005902FE /* MockDeviceOrientationProvider.swift */; }; + 335A7B1E2F6B061D005902FE /* MockCaptureSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7AF42F6B061D005902FE /* MockCaptureSession.swift */; }; + 335A7B1F2F6B061D005902FE /* CameraPermissionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7ADB2F6B061D005902FE /* CameraPermissionTests.swift */; }; + 335A7B202F6B061D005902FE /* MockCaptureDeviceInputFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7AF12F6B061D005902FE /* MockCaptureDeviceInputFactory.swift */; }; + 335A7B212F6B061D005902FE /* SampleBufferTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7B002F6B061D005902FE /* SampleBufferTests.swift */; }; + 335A7B222F6B061D005902FE /* MockCaptureInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7AF22F6B061D005902FE /* MockCaptureInput.swift */; }; + 335A7B232F6B061D005902FE /* FLTCamSetDeviceOrientationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7AE62F6B061D005902FE /* FLTCamSetDeviceOrientationTests.swift */; }; + 335A7B242F6B061D005902FE /* MockCamera.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7AEC2F6B061D005902FE /* MockCamera.swift */; }; + 335A7B252F6B061D005902FE /* MockCaptureDeviceFormat.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7AF02F6B061D005902FE /* MockCaptureDeviceFormat.swift */; }; + 335A7B262F6B061D005902FE /* MockFLTCameraPermissionManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7AF72F6B061D005902FE /* MockFLTCameraPermissionManager.swift */; }; + 335A7B272F6B061D005902FE /* CameraPropertiesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7AE02F6B061D005902FE /* CameraPropertiesTests.swift */; }; + 335A7B282F6B061D005902FE /* CameraSessionPresetsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7AE12F6B061D005902FE /* CameraSessionPresetsTests.swift */; }; + 335A7B292F6B061D005902FE /* MockFlutterBinaryMessenger.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7AF82F6B061D005902FE /* MockFlutterBinaryMessenger.swift */; }; + 335A7B2A2F6B061D005902FE /* CameraInitRaceConditionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7AD82F6B061D005902FE /* CameraInitRaceConditionsTests.swift */; }; + 335A7B2B2F6B061D005902FE /* MockCaptureConnection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7AEE2F6B061D005902FE /* MockCaptureConnection.swift */; }; + 335A7B2C2F6B061D005902FE /* StreamingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7B022F6B061D005902FE /* StreamingTests.swift */; }; + 335A7B2D2F6B061D005902FE /* MockCaptureVideoDataOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7AF52F6B061D005902FE /* MockCaptureVideoDataOutput.swift */; }; 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; 7884E8682EC3CC0700C636F2 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7884E8672EC3CC0400C636F2 /* SceneDelegate.swift */; }; @@ -44,8 +86,50 @@ /* Begin PBXFileReference section */ 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; - 331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; 331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 335A7AD72F6B061D005902FE /* AvailableCamerasTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AvailableCamerasTests.swift; sourceTree = ""; }; + 335A7AD82F6B061D005902FE /* CameraInitRaceConditionsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CameraInitRaceConditionsTests.swift; sourceTree = ""; }; + 335A7AD92F6B061D005902FE /* CameraMethodChannelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CameraMethodChannelTests.swift; sourceTree = ""; }; + 335A7ADA2F6B061D005902FE /* CameraOrientationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CameraOrientationTests.swift; sourceTree = ""; }; + 335A7ADB2F6B061D005902FE /* CameraPermissionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CameraPermissionTests.swift; sourceTree = ""; }; + 335A7ADC2F6B061D005902FE /* CameraPluginCreateCameraTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CameraPluginCreateCameraTests.swift; sourceTree = ""; }; + 335A7ADD2F6B061D005902FE /* CameraPluginDelegatingMethodTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CameraPluginDelegatingMethodTests.swift; sourceTree = ""; }; + 335A7ADE2F6B061D005902FE /* CameraPluginInitializeCameraTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CameraPluginInitializeCameraTests.swift; sourceTree = ""; }; + 335A7ADF2F6B061D005902FE /* CameraPreviewPauseTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CameraPreviewPauseTests.swift; sourceTree = ""; }; + 335A7AE02F6B061D005902FE /* CameraPropertiesTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CameraPropertiesTests.swift; sourceTree = ""; }; + 335A7AE12F6B061D005902FE /* CameraSessionPresetsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CameraSessionPresetsTests.swift; sourceTree = ""; }; + 335A7AE22F6B061D005902FE /* CameraSettingsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CameraSettingsTests.swift; sourceTree = ""; }; + 335A7AE32F6B061D005902FE /* CameraTestUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CameraTestUtils.swift; sourceTree = ""; }; + 335A7AE42F6B061D005902FE /* FLTCamExposureTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FLTCamExposureTests.swift; sourceTree = ""; }; + 335A7AE52F6B061D005902FE /* FLTCamFocusTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FLTCamFocusTests.swift; sourceTree = ""; }; + 335A7AE62F6B061D005902FE /* FLTCamSetDeviceOrientationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FLTCamSetDeviceOrientationTests.swift; sourceTree = ""; }; + 335A7AE72F6B061D005902FE /* FLTCamSetFlashModeTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FLTCamSetFlashModeTests.swift; sourceTree = ""; }; + 335A7AE82F6B061D005902FE /* FLTCamZoomTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FLTCamZoomTests.swift; sourceTree = ""; }; + 335A7AE92F6B061D005902FE /* MockAssetWriter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockAssetWriter.swift; sourceTree = ""; }; + 335A7AEA2F6B061D005902FE /* MockAssetWriterInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockAssetWriterInput.swift; sourceTree = ""; }; + 335A7AEB2F6B061D005902FE /* MockAssetWriterInputPixelBufferAdaptor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockAssetWriterInputPixelBufferAdaptor.swift; sourceTree = ""; }; + 335A7AEC2F6B061D005902FE /* MockCamera.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockCamera.swift; sourceTree = ""; }; + 335A7AED2F6B061D005902FE /* MockCameraDeviceDiscoverer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockCameraDeviceDiscoverer.swift; sourceTree = ""; }; + 335A7AEE2F6B061D005902FE /* MockCaptureConnection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockCaptureConnection.swift; sourceTree = ""; }; + 335A7AEF2F6B061D005902FE /* MockCaptureDevice.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockCaptureDevice.swift; sourceTree = ""; }; + 335A7AF02F6B061D005902FE /* MockCaptureDeviceFormat.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockCaptureDeviceFormat.swift; sourceTree = ""; }; + 335A7AF12F6B061D005902FE /* MockCaptureDeviceInputFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockCaptureDeviceInputFactory.swift; sourceTree = ""; }; + 335A7AF22F6B061D005902FE /* MockCaptureInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockCaptureInput.swift; sourceTree = ""; }; + 335A7AF32F6B061D005902FE /* MockCapturePhotoOutput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockCapturePhotoOutput.swift; sourceTree = ""; }; + 335A7AF42F6B061D005902FE /* MockCaptureSession.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockCaptureSession.swift; sourceTree = ""; }; + 335A7AF52F6B061D005902FE /* MockCaptureVideoDataOutput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockCaptureVideoDataOutput.swift; sourceTree = ""; }; + 335A7AF62F6B061D005902FE /* MockDeviceOrientationProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockDeviceOrientationProvider.swift; sourceTree = ""; }; + 335A7AF72F6B061D005902FE /* MockFLTCameraPermissionManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockFLTCameraPermissionManager.swift; sourceTree = ""; }; + 335A7AF82F6B061D005902FE /* MockFlutterBinaryMessenger.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockFlutterBinaryMessenger.swift; sourceTree = ""; }; + 335A7AF92F6B061D005902FE /* MockFlutterTextureRegistry.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockFlutterTextureRegistry.swift; sourceTree = ""; }; + 335A7AFA2F6B061D005902FE /* MockFrameRateRange.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockFrameRateRange.swift; sourceTree = ""; }; + 335A7AFB2F6B061D005902FE /* MockGlobalEventApi.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockGlobalEventApi.swift; sourceTree = ""; }; + 335A7AFC2F6B061D005902FE /* MockWritableData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockWritableData.swift; sourceTree = ""; }; + 335A7AFE2F6B061D005902FE /* PhotoCaptureTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhotoCaptureTests.swift; sourceTree = ""; }; + 335A7AFF2F6B061D005902FE /* QueueUtilsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QueueUtilsTests.swift; sourceTree = ""; }; + 335A7B002F6B061D005902FE /* SampleBufferTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SampleBufferTests.swift; sourceTree = ""; }; + 335A7B012F6B061D005902FE /* SavePhotoDelegateTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SavePhotoDelegateTests.swift; sourceTree = ""; }; + 335A7B022F6B061D005902FE /* StreamingTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StreamingTests.swift; sourceTree = ""; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; @@ -76,11 +160,61 @@ 331C8082294A63A400263BE5 /* RunnerTests */ = { isa = PBXGroup; children = ( - 331C807B294A618700263BE5 /* RunnerTests.swift */, + 335A7AD72F6B061D005902FE /* AvailableCamerasTests.swift */, + 335A7AD82F6B061D005902FE /* CameraInitRaceConditionsTests.swift */, + 335A7AD92F6B061D005902FE /* CameraMethodChannelTests.swift */, + 335A7ADA2F6B061D005902FE /* CameraOrientationTests.swift */, + 335A7ADB2F6B061D005902FE /* CameraPermissionTests.swift */, + 335A7ADC2F6B061D005902FE /* CameraPluginCreateCameraTests.swift */, + 335A7ADD2F6B061D005902FE /* CameraPluginDelegatingMethodTests.swift */, + 335A7ADE2F6B061D005902FE /* CameraPluginInitializeCameraTests.swift */, + 335A7ADF2F6B061D005902FE /* CameraPreviewPauseTests.swift */, + 335A7AE02F6B061D005902FE /* CameraPropertiesTests.swift */, + 335A7AE12F6B061D005902FE /* CameraSessionPresetsTests.swift */, + 335A7AE22F6B061D005902FE /* CameraSettingsTests.swift */, + 335A7AE32F6B061D005902FE /* CameraTestUtils.swift */, + 335A7AE42F6B061D005902FE /* FLTCamExposureTests.swift */, + 335A7AE52F6B061D005902FE /* FLTCamFocusTests.swift */, + 335A7AE62F6B061D005902FE /* FLTCamSetDeviceOrientationTests.swift */, + 335A7AE72F6B061D005902FE /* FLTCamSetFlashModeTests.swift */, + 335A7AE82F6B061D005902FE /* FLTCamZoomTests.swift */, + 335A7AFE2F6B061D005902FE /* PhotoCaptureTests.swift */, + 335A7AFF2F6B061D005902FE /* QueueUtilsTests.swift */, + 335A7B002F6B061D005902FE /* SampleBufferTests.swift */, + 335A7B012F6B061D005902FE /* SavePhotoDelegateTests.swift */, + 335A7B022F6B061D005902FE /* StreamingTests.swift */, + 335A7AFD2F6B061D005902FE /* Mocks */, ); path = RunnerTests; sourceTree = ""; }; + 335A7AFD2F6B061D005902FE /* Mocks */ = { + isa = PBXGroup; + children = ( + 335A7AE92F6B061D005902FE /* MockAssetWriter.swift */, + 335A7AEA2F6B061D005902FE /* MockAssetWriterInput.swift */, + 335A7AEB2F6B061D005902FE /* MockAssetWriterInputPixelBufferAdaptor.swift */, + 335A7AEC2F6B061D005902FE /* MockCamera.swift */, + 335A7AED2F6B061D005902FE /* MockCameraDeviceDiscoverer.swift */, + 335A7AEE2F6B061D005902FE /* MockCaptureConnection.swift */, + 335A7AEF2F6B061D005902FE /* MockCaptureDevice.swift */, + 335A7AF02F6B061D005902FE /* MockCaptureDeviceFormat.swift */, + 335A7AF12F6B061D005902FE /* MockCaptureDeviceInputFactory.swift */, + 335A7AF22F6B061D005902FE /* MockCaptureInput.swift */, + 335A7AF32F6B061D005902FE /* MockCapturePhotoOutput.swift */, + 335A7AF42F6B061D005902FE /* MockCaptureSession.swift */, + 335A7AF52F6B061D005902FE /* MockCaptureVideoDataOutput.swift */, + 335A7AF62F6B061D005902FE /* MockDeviceOrientationProvider.swift */, + 335A7AF72F6B061D005902FE /* MockFLTCameraPermissionManager.swift */, + 335A7AF82F6B061D005902FE /* MockFlutterBinaryMessenger.swift */, + 335A7AF92F6B061D005902FE /* MockFlutterTextureRegistry.swift */, + 335A7AFA2F6B061D005902FE /* MockFrameRateRange.swift */, + 335A7AFB2F6B061D005902FE /* MockGlobalEventApi.swift */, + 335A7AFC2F6B061D005902FE /* MockWritableData.swift */, + ); + path = Mocks; + sourceTree = ""; + }; 9740EEB11CF90186004384FC /* Flutter */ = { isa = PBXGroup; children = ( @@ -273,7 +407,49 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */, + 335A7B032F6B061D005902FE /* FLTCamZoomTests.swift in Sources */, + 335A7B042F6B061D005902FE /* AvailableCamerasTests.swift in Sources */, + 335A7B052F6B061D005902FE /* PhotoCaptureTests.swift in Sources */, + 335A7B062F6B061D005902FE /* SavePhotoDelegateTests.swift in Sources */, + 335A7B072F6B061D005902FE /* MockCameraDeviceDiscoverer.swift in Sources */, + 335A7B082F6B061D005902FE /* MockFlutterTextureRegistry.swift in Sources */, + 335A7B092F6B061D005902FE /* QueueUtilsTests.swift in Sources */, + 335A7B0A2F6B061D005902FE /* CameraPreviewPauseTests.swift in Sources */, + 335A7B0B2F6B061D005902FE /* CameraPluginCreateCameraTests.swift in Sources */, + 335A7B0C2F6B061D005902FE /* MockCaptureDevice.swift in Sources */, + 335A7B0D2F6B061D005902FE /* MockWritableData.swift in Sources */, + 335A7B0E2F6B061D005902FE /* CameraOrientationTests.swift in Sources */, + 335A7B0F2F6B061D005902FE /* FLTCamSetFlashModeTests.swift in Sources */, + 335A7B102F6B061D005902FE /* CameraSettingsTests.swift in Sources */, + 335A7B112F6B061D005902FE /* FLTCamExposureTests.swift in Sources */, + 335A7B122F6B061D005902FE /* CameraMethodChannelTests.swift in Sources */, + 335A7B132F6B061D005902FE /* MockGlobalEventApi.swift in Sources */, + 335A7B142F6B061D005902FE /* MockAssetWriter.swift in Sources */, + 335A7B152F6B061D005902FE /* MockCapturePhotoOutput.swift in Sources */, + 335A7B162F6B061D005902FE /* FLTCamFocusTests.swift in Sources */, + 335A7B172F6B061D005902FE /* CameraPluginInitializeCameraTests.swift in Sources */, + 335A7B182F6B061D005902FE /* CameraPluginDelegatingMethodTests.swift in Sources */, + 335A7B192F6B061D005902FE /* MockAssetWriterInput.swift in Sources */, + 335A7B1A2F6B061D005902FE /* CameraTestUtils.swift in Sources */, + 335A7B1B2F6B061D005902FE /* MockAssetWriterInputPixelBufferAdaptor.swift in Sources */, + 335A7B1C2F6B061D005902FE /* MockFrameRateRange.swift in Sources */, + 335A7B1D2F6B061D005902FE /* MockDeviceOrientationProvider.swift in Sources */, + 335A7B1E2F6B061D005902FE /* MockCaptureSession.swift in Sources */, + 335A7B1F2F6B061D005902FE /* CameraPermissionTests.swift in Sources */, + 335A7B202F6B061D005902FE /* MockCaptureDeviceInputFactory.swift in Sources */, + 335A7B212F6B061D005902FE /* SampleBufferTests.swift in Sources */, + 335A7B222F6B061D005902FE /* MockCaptureInput.swift in Sources */, + 335A7B232F6B061D005902FE /* FLTCamSetDeviceOrientationTests.swift in Sources */, + 335A7B242F6B061D005902FE /* MockCamera.swift in Sources */, + 335A7B252F6B061D005902FE /* MockCaptureDeviceFormat.swift in Sources */, + 335A7B262F6B061D005902FE /* MockFLTCameraPermissionManager.swift in Sources */, + 335A7B272F6B061D005902FE /* CameraPropertiesTests.swift in Sources */, + 335A7B282F6B061D005902FE /* CameraSessionPresetsTests.swift in Sources */, + 335A7B292F6B061D005902FE /* MockFlutterBinaryMessenger.swift in Sources */, + 335A7B2A2F6B061D005902FE /* CameraInitRaceConditionsTests.swift in Sources */, + 335A7B2B2F6B061D005902FE /* MockCaptureConnection.swift in Sources */, + 335A7B2C2F6B061D005902FE /* StreamingTests.swift in Sources */, + 335A7B2D2F6B061D005902FE /* MockCaptureVideoDataOutput.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/RunnerTests.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/RunnerTests.swift deleted file mode 100644 index 86a7c3b1b611..000000000000 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/RunnerTests.swift +++ /dev/null @@ -1,12 +0,0 @@ -import Flutter -import UIKit -import XCTest - -class RunnerTests: XCTestCase { - - func testExample() { - // If you add code to the Runner application, consider adding tests here. - // See https://developer.apple.com/documentation/xctest for more information about using XCTest. - } - -} From 306745b8c52d57b989314d82c10921313a469709 Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Wed, 18 Mar 2026 12:13:28 -0400 Subject: [PATCH 04/10] Copyright headers --- .../camera_avfoundation/example/ios/Runner/AppDelegate.swift | 4 ++++ .../example/ios/Runner/SceneDelegate.swift | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/packages/camera/camera_avfoundation/example/ios/Runner/AppDelegate.swift b/packages/camera/camera_avfoundation/example/ios/Runner/AppDelegate.swift index c30b367ec0a9..81eca8683601 100644 --- a/packages/camera/camera_avfoundation/example/ios/Runner/AppDelegate.swift +++ b/packages/camera/camera_avfoundation/example/ios/Runner/AppDelegate.swift @@ -1,3 +1,7 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + import Flutter import UIKit diff --git a/packages/camera/camera_avfoundation/example/ios/Runner/SceneDelegate.swift b/packages/camera/camera_avfoundation/example/ios/Runner/SceneDelegate.swift index b9ce8ea2b2ad..8c7b10c639d1 100644 --- a/packages/camera/camera_avfoundation/example/ios/Runner/SceneDelegate.swift +++ b/packages/camera/camera_avfoundation/example/ios/Runner/SceneDelegate.swift @@ -1,3 +1,7 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + import Flutter import UIKit From 7e4229d5ffd0c870dc0e5f966318a5cd92a20650 Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Wed, 18 Mar 2026 12:23:29 -0400 Subject: [PATCH 05/10] Clean up obsolete FLT references --- .../ios/Runner.xcodeproj/project.pbxproj | 40 +++++++++---------- ...eTests.swift => CameraExposureTests.swift} | 2 +- .../CameraPluginCreateCameraTests.swift | 2 +- .../CameraPluginDelegatingMethodTests.swift | 2 +- .../CameraSessionPresetsTests.swift | 2 +- ... => CameraSetDeviceOrientationTests.swift} | 2 +- ...ts.swift => CameraSetFlashModeTests.swift} | 2 +- ...ts.swift => CameraSetFocusModeTests.swift} | 2 +- .../ios/RunnerTests/CameraSettingsTests.swift | 4 +- ...mZoomTests.swift => CameraZoomTests.swift} | 2 +- .../Mocks/MockCameraDeviceDiscoverer.swift | 2 +- .../RunnerTests/Mocks/MockCaptureDevice.swift | 2 +- .../Mocks/MockCaptureDeviceInputFactory.swift | 2 +- .../RunnerTests/Mocks/MockCaptureInput.swift | 2 +- .../Mocks/MockCapturePhotoOutput.swift | 2 +- .../Mocks/MockCaptureSession.swift | 2 +- .../Mocks/MockCaptureVideoDataOutput.swift | 2 +- .../ios/RunnerTests/PhotoCaptureTests.swift | 12 +++--- .../ios/RunnerTests/SampleBufferTests.swift | 4 +- 19 files changed, 45 insertions(+), 45 deletions(-) rename packages/camera/camera_avfoundation/example/ios/RunnerTests/{FLTCamExposureTests.swift => CameraExposureTests.swift} (99%) rename packages/camera/camera_avfoundation/example/ios/RunnerTests/{FLTCamSetDeviceOrientationTests.swift => CameraSetDeviceOrientationTests.swift} (98%) rename packages/camera/camera_avfoundation/example/ios/RunnerTests/{FLTCamSetFlashModeTests.swift => CameraSetFlashModeTests.swift} (98%) rename packages/camera/camera_avfoundation/example/ios/RunnerTests/{FLTCamFocusTests.swift => CameraSetFocusModeTests.swift} (99%) rename packages/camera/camera_avfoundation/example/ios/RunnerTests/{FLTCamZoomTests.swift => CameraZoomTests.swift} (98%) diff --git a/packages/camera/camera_avfoundation/example/ios/Runner.xcodeproj/project.pbxproj b/packages/camera/camera_avfoundation/example/ios/Runner.xcodeproj/project.pbxproj index f98c4f5f9a74..332495ba1b8f 100644 --- a/packages/camera/camera_avfoundation/example/ios/Runner.xcodeproj/project.pbxproj +++ b/packages/camera/camera_avfoundation/example/ios/Runner.xcodeproj/project.pbxproj @@ -8,7 +8,7 @@ /* Begin PBXBuildFile section */ 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; - 335A7B032F6B061D005902FE /* FLTCamZoomTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7AE82F6B061D005902FE /* FLTCamZoomTests.swift */; }; + 335A7B032F6B061D005902FE /* CameraZoomTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7AE82F6B061D005902FE /* CameraZoomTests.swift */; }; 335A7B042F6B061D005902FE /* AvailableCamerasTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7AD72F6B061D005902FE /* AvailableCamerasTests.swift */; }; 335A7B052F6B061D005902FE /* PhotoCaptureTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7AFE2F6B061D005902FE /* PhotoCaptureTests.swift */; }; 335A7B062F6B061D005902FE /* SavePhotoDelegateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7B012F6B061D005902FE /* SavePhotoDelegateTests.swift */; }; @@ -20,14 +20,14 @@ 335A7B0C2F6B061D005902FE /* MockCaptureDevice.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7AEF2F6B061D005902FE /* MockCaptureDevice.swift */; }; 335A7B0D2F6B061D005902FE /* MockWritableData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7AFC2F6B061D005902FE /* MockWritableData.swift */; }; 335A7B0E2F6B061D005902FE /* CameraOrientationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7ADA2F6B061D005902FE /* CameraOrientationTests.swift */; }; - 335A7B0F2F6B061D005902FE /* FLTCamSetFlashModeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7AE72F6B061D005902FE /* FLTCamSetFlashModeTests.swift */; }; + 335A7B0F2F6B061D005902FE /* CameraSetFlashModeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7AE72F6B061D005902FE /* CameraSetFlashModeTests.swift */; }; 335A7B102F6B061D005902FE /* CameraSettingsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7AE22F6B061D005902FE /* CameraSettingsTests.swift */; }; - 335A7B112F6B061D005902FE /* FLTCamExposureTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7AE42F6B061D005902FE /* FLTCamExposureTests.swift */; }; + 335A7B112F6B061D005902FE /* CameraExposureTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7AE42F6B061D005902FE /* CameraExposureTests.swift */; }; 335A7B122F6B061D005902FE /* CameraMethodChannelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7AD92F6B061D005902FE /* CameraMethodChannelTests.swift */; }; 335A7B132F6B061D005902FE /* MockGlobalEventApi.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7AFB2F6B061D005902FE /* MockGlobalEventApi.swift */; }; 335A7B142F6B061D005902FE /* MockAssetWriter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7AE92F6B061D005902FE /* MockAssetWriter.swift */; }; 335A7B152F6B061D005902FE /* MockCapturePhotoOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7AF32F6B061D005902FE /* MockCapturePhotoOutput.swift */; }; - 335A7B162F6B061D005902FE /* FLTCamFocusTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7AE52F6B061D005902FE /* FLTCamFocusTests.swift */; }; + 335A7B162F6B061D005902FE /* CameraSetFocusModeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7AE52F6B061D005902FE /* CameraSetFocusModeTests.swift */; }; 335A7B172F6B061D005902FE /* CameraPluginInitializeCameraTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7ADE2F6B061D005902FE /* CameraPluginInitializeCameraTests.swift */; }; 335A7B182F6B061D005902FE /* CameraPluginDelegatingMethodTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7ADD2F6B061D005902FE /* CameraPluginDelegatingMethodTests.swift */; }; 335A7B192F6B061D005902FE /* MockAssetWriterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7AEA2F6B061D005902FE /* MockAssetWriterInput.swift */; }; @@ -40,7 +40,7 @@ 335A7B202F6B061D005902FE /* MockCaptureDeviceInputFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7AF12F6B061D005902FE /* MockCaptureDeviceInputFactory.swift */; }; 335A7B212F6B061D005902FE /* SampleBufferTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7B002F6B061D005902FE /* SampleBufferTests.swift */; }; 335A7B222F6B061D005902FE /* MockCaptureInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7AF22F6B061D005902FE /* MockCaptureInput.swift */; }; - 335A7B232F6B061D005902FE /* FLTCamSetDeviceOrientationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7AE62F6B061D005902FE /* FLTCamSetDeviceOrientationTests.swift */; }; + 335A7B232F6B061D005902FE /* CameraSetDeviceOrientationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7AE62F6B061D005902FE /* CameraSetDeviceOrientationTests.swift */; }; 335A7B242F6B061D005902FE /* MockCamera.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7AEC2F6B061D005902FE /* MockCamera.swift */; }; 335A7B252F6B061D005902FE /* MockCaptureDeviceFormat.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7AF02F6B061D005902FE /* MockCaptureDeviceFormat.swift */; }; 335A7B262F6B061D005902FE /* MockFLTCameraPermissionManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335A7AF72F6B061D005902FE /* MockFLTCameraPermissionManager.swift */; }; @@ -100,11 +100,11 @@ 335A7AE12F6B061D005902FE /* CameraSessionPresetsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CameraSessionPresetsTests.swift; sourceTree = ""; }; 335A7AE22F6B061D005902FE /* CameraSettingsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CameraSettingsTests.swift; sourceTree = ""; }; 335A7AE32F6B061D005902FE /* CameraTestUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CameraTestUtils.swift; sourceTree = ""; }; - 335A7AE42F6B061D005902FE /* FLTCamExposureTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FLTCamExposureTests.swift; sourceTree = ""; }; - 335A7AE52F6B061D005902FE /* FLTCamFocusTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FLTCamFocusTests.swift; sourceTree = ""; }; - 335A7AE62F6B061D005902FE /* FLTCamSetDeviceOrientationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FLTCamSetDeviceOrientationTests.swift; sourceTree = ""; }; - 335A7AE72F6B061D005902FE /* FLTCamSetFlashModeTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FLTCamSetFlashModeTests.swift; sourceTree = ""; }; - 335A7AE82F6B061D005902FE /* FLTCamZoomTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FLTCamZoomTests.swift; sourceTree = ""; }; + 335A7AE42F6B061D005902FE /* CameraExposureTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CameraExposureTests.swift; sourceTree = ""; }; + 335A7AE52F6B061D005902FE /* CameraSetFocusModeTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CameraSetFocusModeTests.swift; sourceTree = ""; }; + 335A7AE62F6B061D005902FE /* CameraSetDeviceOrientationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CameraSetDeviceOrientationTests.swift; sourceTree = ""; }; + 335A7AE72F6B061D005902FE /* CameraSetFlashModeTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CameraSetFlashModeTests.swift; sourceTree = ""; }; + 335A7AE82F6B061D005902FE /* CameraZoomTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CameraZoomTests.swift; sourceTree = ""; }; 335A7AE92F6B061D005902FE /* MockAssetWriter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockAssetWriter.swift; sourceTree = ""; }; 335A7AEA2F6B061D005902FE /* MockAssetWriterInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockAssetWriterInput.swift; sourceTree = ""; }; 335A7AEB2F6B061D005902FE /* MockAssetWriterInputPixelBufferAdaptor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockAssetWriterInputPixelBufferAdaptor.swift; sourceTree = ""; }; @@ -161,7 +161,9 @@ isa = PBXGroup; children = ( 335A7AD72F6B061D005902FE /* AvailableCamerasTests.swift */, + 335A7AE42F6B061D005902FE /* CameraExposureTests.swift */, 335A7AD82F6B061D005902FE /* CameraInitRaceConditionsTests.swift */, + 335A7AE52F6B061D005902FE /* CameraSetFocusModeTests.swift */, 335A7AD92F6B061D005902FE /* CameraMethodChannelTests.swift */, 335A7ADA2F6B061D005902FE /* CameraOrientationTests.swift */, 335A7ADB2F6B061D005902FE /* CameraPermissionTests.swift */, @@ -171,13 +173,11 @@ 335A7ADF2F6B061D005902FE /* CameraPreviewPauseTests.swift */, 335A7AE02F6B061D005902FE /* CameraPropertiesTests.swift */, 335A7AE12F6B061D005902FE /* CameraSessionPresetsTests.swift */, + 335A7AE62F6B061D005902FE /* CameraSetDeviceOrientationTests.swift */, + 335A7AE72F6B061D005902FE /* CameraSetFlashModeTests.swift */, 335A7AE22F6B061D005902FE /* CameraSettingsTests.swift */, 335A7AE32F6B061D005902FE /* CameraTestUtils.swift */, - 335A7AE42F6B061D005902FE /* FLTCamExposureTests.swift */, - 335A7AE52F6B061D005902FE /* FLTCamFocusTests.swift */, - 335A7AE62F6B061D005902FE /* FLTCamSetDeviceOrientationTests.swift */, - 335A7AE72F6B061D005902FE /* FLTCamSetFlashModeTests.swift */, - 335A7AE82F6B061D005902FE /* FLTCamZoomTests.swift */, + 335A7AE82F6B061D005902FE /* CameraZoomTests.swift */, 335A7AFE2F6B061D005902FE /* PhotoCaptureTests.swift */, 335A7AFF2F6B061D005902FE /* QueueUtilsTests.swift */, 335A7B002F6B061D005902FE /* SampleBufferTests.swift */, @@ -407,7 +407,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 335A7B032F6B061D005902FE /* FLTCamZoomTests.swift in Sources */, + 335A7B032F6B061D005902FE /* CameraZoomTests.swift in Sources */, 335A7B042F6B061D005902FE /* AvailableCamerasTests.swift in Sources */, 335A7B052F6B061D005902FE /* PhotoCaptureTests.swift in Sources */, 335A7B062F6B061D005902FE /* SavePhotoDelegateTests.swift in Sources */, @@ -419,14 +419,14 @@ 335A7B0C2F6B061D005902FE /* MockCaptureDevice.swift in Sources */, 335A7B0D2F6B061D005902FE /* MockWritableData.swift in Sources */, 335A7B0E2F6B061D005902FE /* CameraOrientationTests.swift in Sources */, - 335A7B0F2F6B061D005902FE /* FLTCamSetFlashModeTests.swift in Sources */, + 335A7B0F2F6B061D005902FE /* CameraSetFlashModeTests.swift in Sources */, 335A7B102F6B061D005902FE /* CameraSettingsTests.swift in Sources */, - 335A7B112F6B061D005902FE /* FLTCamExposureTests.swift in Sources */, + 335A7B112F6B061D005902FE /* CameraExposureTests.swift in Sources */, 335A7B122F6B061D005902FE /* CameraMethodChannelTests.swift in Sources */, 335A7B132F6B061D005902FE /* MockGlobalEventApi.swift in Sources */, 335A7B142F6B061D005902FE /* MockAssetWriter.swift in Sources */, 335A7B152F6B061D005902FE /* MockCapturePhotoOutput.swift in Sources */, - 335A7B162F6B061D005902FE /* FLTCamFocusTests.swift in Sources */, + 335A7B162F6B061D005902FE /* CameraSetFocusModeTests.swift in Sources */, 335A7B172F6B061D005902FE /* CameraPluginInitializeCameraTests.swift in Sources */, 335A7B182F6B061D005902FE /* CameraPluginDelegatingMethodTests.swift in Sources */, 335A7B192F6B061D005902FE /* MockAssetWriterInput.swift in Sources */, @@ -439,7 +439,7 @@ 335A7B202F6B061D005902FE /* MockCaptureDeviceInputFactory.swift in Sources */, 335A7B212F6B061D005902FE /* SampleBufferTests.swift in Sources */, 335A7B222F6B061D005902FE /* MockCaptureInput.swift in Sources */, - 335A7B232F6B061D005902FE /* FLTCamSetDeviceOrientationTests.swift in Sources */, + 335A7B232F6B061D005902FE /* CameraSetDeviceOrientationTests.swift in Sources */, 335A7B242F6B061D005902FE /* MockCamera.swift in Sources */, 335A7B252F6B061D005902FE /* MockCaptureDeviceFormat.swift in Sources */, 335A7B262F6B061D005902FE /* MockFLTCameraPermissionManager.swift in Sources */, diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamExposureTests.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraExposureTests.swift similarity index 99% rename from packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamExposureTests.swift rename to packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraExposureTests.swift index 33ee0325b8e0..da5531b652bb 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamExposureTests.swift +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraExposureTests.swift @@ -6,7 +6,7 @@ import XCTest @testable import camera_avfoundation -final class FLTCamExposureTests: XCTestCase { +final class CameraExposureTests: XCTestCase { private func createCamera() -> (Camera, MockCaptureDevice, MockDeviceOrientationProvider) { let mockDevice = MockCaptureDevice() let mockDeviceOrientationProvider = MockDeviceOrientationProvider() diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraPluginCreateCameraTests.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraPluginCreateCameraTests.swift index 5eb2b61e8ea2..269ba03067b0 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraPluginCreateCameraTests.swift +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraPluginCreateCameraTests.swift @@ -98,7 +98,7 @@ final class CameraPluginCreateCameraTests: XCTestCase { XCTAssertTrue(requestAudioPermissionCalled) } - func testCreateCamera_createsFLTCamSuccessfully() { + func testCreateCamera_createsCameraSuccessfully() { let (cameraPlugin, mockPermissionManager, mockCaptureSession) = createCameraPlugin() let expectation = expectation(description: "Initialization completed") diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraPluginDelegatingMethodTests.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraPluginDelegatingMethodTests.swift index 4e3c5a377f06..34a306b511d7 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraPluginDelegatingMethodTests.swift +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraPluginDelegatingMethodTests.swift @@ -6,7 +6,7 @@ import XCTest @testable import camera_avfoundation -/// Tests of `CameraPlugin` methods delegating to `FLTCam` instance +/// Tests of `CameraPlugin` methods delegating to `Camera` instance final class CameraPluginDelegatingMethodTests: XCTestCase { private func createCameraPlugin() -> (CameraPlugin, MockCamera) { let mockCamera = MockCamera() diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraSessionPresetsTests.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraSessionPresetsTests.swift index b7b6a00734be..5d56567959f0 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraSessionPresetsTests.swift +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraSessionPresetsTests.swift @@ -7,7 +7,7 @@ import XCTest @testable import camera_avfoundation -/// Includes test cases related to resolution presets setting operations for FLTCam class. +/// Includes test cases related to resolution presets setting operations for Camera class. final class CameraSessionPresetsTests: XCTestCase { func testResolutionPresetWithBestFormat_mustUpdateCaptureSessionPreset() { let expectedPreset = AVCaptureSession.Preset.inputPriority diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamSetDeviceOrientationTests.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraSetDeviceOrientationTests.swift similarity index 98% rename from packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamSetDeviceOrientationTests.swift rename to packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraSetDeviceOrientationTests.swift index ab688c9f5933..c6ca992d236b 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamSetDeviceOrientationTests.swift +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraSetDeviceOrientationTests.swift @@ -7,7 +7,7 @@ import XCTest @testable import camera_avfoundation -final class FLTCamSetDeviceOrientationTests: XCTestCase { +final class CameraSetDeviceOrientationTests: XCTestCase { private func createCamera() -> (Camera, MockCaptureConnection, MockCaptureConnection) { let camera = CameraTestUtils.createTestCamera() diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamSetFlashModeTests.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraSetFlashModeTests.swift similarity index 98% rename from packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamSetFlashModeTests.swift rename to packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraSetFlashModeTests.swift index 0941a06d96e4..7a931a7f1e25 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamSetFlashModeTests.swift +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraSetFlashModeTests.swift @@ -7,7 +7,7 @@ import XCTest @testable import camera_avfoundation -final class FLTCamSetFlashModeTests: XCTestCase { +final class CameraSetFlashModeTests: XCTestCase { private func createCamera() -> (Camera, MockCaptureDevice, MockCapturePhotoOutput) { let mockDevice = MockCaptureDevice() let mockCapturePhotoOutput = MockCapturePhotoOutput() diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamFocusTests.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraSetFocusModeTests.swift similarity index 99% rename from packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamFocusTests.swift rename to packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraSetFocusModeTests.swift index 00eaddf71faf..75c1cf38e6fb 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamFocusTests.swift +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraSetFocusModeTests.swift @@ -7,7 +7,7 @@ import XCTest @testable import camera_avfoundation -final class FLTCamSetFocusModeTests: XCTestCase { +final class CameraSetFocusModeTests: XCTestCase { private func createCamera() -> (Camera, MockCaptureDevice, MockDeviceOrientationProvider) { let mockDevice = MockCaptureDevice() let mockDeviceOrientationProvider = MockDeviceOrientationProvider() diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraSettingsTests.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraSettingsTests.swift index 984549b06516..409667fce057 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraSettingsTests.swift +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraSettingsTests.swift @@ -51,7 +51,7 @@ private final class TestMediaSettingsAVWrapper: FLTCamMediaSettingsAVWrapper { } override func setMinFrameDuration(_ duration: CMTime, on captureDevice: CaptureDevice) { - // FLTCam allows to set frame rate with 1/10 precision. + // Camera allows to set frame rate with 1/10 precision. let expectedDuration = CMTimeMake(value: 10, timescale: Int32(testFramesPerSecond * 10)) if duration == expectedDuration { minFrameDurationExpectation.fulfill() @@ -59,7 +59,7 @@ private final class TestMediaSettingsAVWrapper: FLTCamMediaSettingsAVWrapper { } override func setMaxFrameDuration(_ duration: CMTime, on captureDevice: CaptureDevice) { - // FLTCam allows to set frame rate with 1/10 precision. + // Camera allows to set frame rate with 1/10 precision. let expectedDuration = CMTimeMake(value: 10, timescale: Int32(testFramesPerSecond * 10)) if duration == expectedDuration { maxFrameDurationExpectation.fulfill() diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamZoomTests.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraZoomTests.swift similarity index 98% rename from packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamZoomTests.swift rename to packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraZoomTests.swift index 46f302058b06..f0c62add69fb 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamZoomTests.swift +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraZoomTests.swift @@ -7,7 +7,7 @@ import XCTest @testable import camera_avfoundation -final class FLTCamZoomTests: XCTestCase { +final class CameraZoomTests: XCTestCase { private func createCamera() -> (Camera, MockCaptureDevice) { let mockDevice = MockCaptureDevice() diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCameraDeviceDiscoverer.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCameraDeviceDiscoverer.swift index 972f34ab8d5e..f621aa620b5c 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCameraDeviceDiscoverer.swift +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCameraDeviceDiscoverer.swift @@ -6,7 +6,7 @@ import AVFoundation @testable import camera_avfoundation -/// Mock implementation of `FLTCameraDeviceDiscoverer` protocol which allows injecting a custom +/// Mock implementation of `CameraDeviceDiscoverer` protocol which allows injecting a custom /// implementation for session discovery. final class MockCameraDeviceDiscoverer: NSObject, CameraDeviceDiscoverer { var discoverySessionStub: diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDevice.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDevice.swift index be6fc7dca28a..71fe2fc8f7da 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDevice.swift +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDevice.swift @@ -6,7 +6,7 @@ import AVFoundation @testable import camera_avfoundation -/// A mock implementation of `FLTCaptureDevice` that allows mocking the class +/// A mock implementation of `CaptureDevice` that allows mocking the class /// properties. class MockCaptureDevice: NSObject, CaptureDevice { var activeFormatStub: (() -> CaptureDeviceFormat)? diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDeviceInputFactory.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDeviceInputFactory.swift index 9292b6256d7c..c332d4dbf54a 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDeviceInputFactory.swift +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDeviceInputFactory.swift @@ -4,7 +4,7 @@ @testable import camera_avfoundation -///// A mocked implementation of FLTCaptureDeviceInputFactory which allows injecting a custom +///// A mocked implementation of CaptureDeviceInputFactory which allows injecting a custom ///// implementation. final class MockCaptureDeviceInputFactory: NSObject, CaptureDeviceInputFactory { func deviceInput(with device: CaptureDevice) throws -> CaptureInput { diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureInput.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureInput.swift index 74d8742bd161..394dbf9b5b67 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureInput.swift +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureInput.swift @@ -6,7 +6,7 @@ import AVFoundation @testable import camera_avfoundation -/// A mocked implementation of FLTCaptureInput which allows injecting a custom +/// A mocked implementation of CaptureInput which allows injecting a custom /// implementation. final class MockCaptureInput: NSObject, CaptureInput { var avInput: AVCaptureInput { diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCapturePhotoOutput.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCapturePhotoOutput.swift index a0b2faee8c00..184fd0be36b2 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCapturePhotoOutput.swift +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCapturePhotoOutput.swift @@ -6,7 +6,7 @@ import AVFoundation @testable import camera_avfoundation -/// Mock implementation of `FLTCapturePhotoOutput` protocol which allows injecting a custom +/// Mock implementation of `CapturePhotoOutput` protocol which allows injecting a custom /// implementation. final class MockCapturePhotoOutput: NSObject, CapturePhotoOutput { var avOutput = AVCapturePhotoOutput() diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureSession.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureSession.swift index 08d2427b4438..23ce72bbe9f8 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureSession.swift +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureSession.swift @@ -6,7 +6,7 @@ import AVFoundation @testable import camera_avfoundation -/// Mock implementation of `FLTCaptureSession` protocol which allows injecting a custom +/// Mock implementation of `CaptureSession` protocol which allows injecting a custom /// implementation. final class MockCaptureSession: NSObject, CaptureSession { var setSessionPresetStub: ((AVCaptureSession.Preset) -> Void)? diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureVideoDataOutput.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureVideoDataOutput.swift index c36397321201..23e54734f853 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureVideoDataOutput.swift +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureVideoDataOutput.swift @@ -6,7 +6,7 @@ import AVFoundation @testable import camera_avfoundation -/// Mock implementation of `FLTCaptureVideoDataOutput` protocol which allows injecting a custom +/// Mock implementation of `CaptureVideoDataOutput` protocol which allows injecting a custom /// implementation. class MockCaptureVideoDataOutput: NSObject, CaptureVideoDataOutput { var avOutput = AVCaptureVideoDataOutput() diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/PhotoCaptureTests.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/PhotoCaptureTests.swift index e20a15dba9d3..1113fb424450 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/PhotoCaptureTests.swift +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/PhotoCaptureTests.swift @@ -7,7 +7,7 @@ import XCTest @testable import camera_avfoundation -/// Includes test cases related to photo capture operations for FLTCam class. +/// Includes test cases related to photo capture operations for Camera class. final class PhotoCaptureTests: XCTestCase { private func createCam(with captureSessionQueue: DispatchQueue) -> DefaultCamera { let configuration = CameraTestUtils.createTestCameraConfiguration() @@ -36,7 +36,7 @@ final class PhotoCaptureTests: XCTestCase { } cam.capturePhotoOutput = mockOutput - // `FLTCam::captureToFile` runs on capture session queue. + // `Camera.captureToFile` runs on capture session queue. captureSessionQueue.async { cam.captureToFile { result in switch result { @@ -73,7 +73,7 @@ final class PhotoCaptureTests: XCTestCase { } cam.capturePhotoOutput = mockOutput - // `FLTCam::captureToFile` runs on capture session queue. + // `Camera.captureToFile` runs on capture session queue. captureSessionQueue.async { cam.captureToFile { result in switch result { @@ -112,7 +112,7 @@ final class PhotoCaptureTests: XCTestCase { } cam.capturePhotoOutput = mockOutput - // `FLTCam::captureToFile` runs on capture session queue. + // `Camera.captureToFile` runs on capture session queue. captureSessionQueue.async { cam.captureToFile { result in if let filePath = self.assertSuccess(result) { @@ -148,7 +148,7 @@ final class PhotoCaptureTests: XCTestCase { } cam.capturePhotoOutput = mockOutput - // `FLTCam::captureToFile` runs on capture session queue. + // `Camera.captureToFile` runs on capture session queue. captureSessionQueue.async { cam.captureToFile { result in if let filePath = self.assertSuccess(result) { @@ -198,7 +198,7 @@ final class PhotoCaptureTests: XCTestCase { } cam.capturePhotoOutput = mockOutput - // `FLTCam::captureToFile` runs on capture session queue. + // `Camera.captureToFile` runs on capture session queue. captureSessionQueue.async { cam.setFlashMode(.torch) { _ in } cam.captureToFile { result in diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/SampleBufferTests.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/SampleBufferTests.swift index 3db6cd2c94da..98759f16caba 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/SampleBufferTests.swift +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/SampleBufferTests.swift @@ -61,7 +61,7 @@ private class FakeMediaSettingsAVWrapper: FLTCamMediaSettingsAVWrapper { } } -/// Includes test cases related to sample buffer handling for FLTCam class. +/// Includes test cases related to sample buffer handling for Camera class. final class CameraSampleBufferTests: XCTestCase { private func createCamera() -> ( DefaultCamera, @@ -119,7 +119,7 @@ final class CameraSampleBufferTests: XCTestCase { let deliveredPixelBuffer = camera.copyPixelBuffer()?.takeRetainedValue() XCTAssertEqual( deliveredPixelBuffer, capturedPixelBuffer, - "FLTCam must deliver the latest captured pixel buffer to copyPixelBuffer API.") + "Camera must deliver the latest captured pixel buffer to copyPixelBuffer API.") } func testDidOutputSampleBuffer_mustNotChangeSampleBufferRetainCountAfterPauseResumeRecording() { From 43f13cd70992cb293e0796558908b57f7c325001 Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Wed, 18 Mar 2026 12:37:03 -0400 Subject: [PATCH 06/10] Restore Info.plist entries --- .../camera/camera_avfoundation/example/ios/Runner/Info.plist | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/camera/camera_avfoundation/example/ios/Runner/Info.plist b/packages/camera/camera_avfoundation/example/ios/Runner/Info.plist index 6a472255099c..90a69cb598b5 100644 --- a/packages/camera/camera_avfoundation/example/ios/Runner/Info.plist +++ b/packages/camera/camera_avfoundation/example/ios/Runner/Info.plist @@ -26,6 +26,10 @@ $(FLUTTER_BUILD_NUMBER) LSRequiresIPhoneOS + NSCameraUsageDescription + Can I use the camera please? Only for demo purpose of the app + NSMicrophoneUsageDescription + Only for demo purpose of the app UIApplicationSceneManifest UIApplicationSupportsMultipleScenes From 148f3205771b65a58a9d0386a0b4333fd4df1050 Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Wed, 18 Mar 2026 12:37:36 -0400 Subject: [PATCH 07/10] Restore the unit test behavior that was in main.m --- .../example/ios/Runner/AppDelegate.swift | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/packages/camera/camera_avfoundation/example/ios/Runner/AppDelegate.swift b/packages/camera/camera_avfoundation/example/ios/Runner/AppDelegate.swift index 81eca8683601..ba78d5879052 100644 --- a/packages/camera/camera_avfoundation/example/ios/Runner/AppDelegate.swift +++ b/packages/camera/camera_avfoundation/example/ios/Runner/AppDelegate.swift @@ -15,6 +15,13 @@ import UIKit } func didInitializeImplicitFlutterEngine(_ engineBridge: FlutterImplicitEngineBridge) { + // Plugin registration eventually sends camera operations on the background queue, which + // would run concurrently with the test cases during unit tests, making the debugging + // process confusing. This setup is actually not necessary for the unit tests, so + // skip it when running unit tests. + if NSClassFromString("XCTestCase") != nil { + return + } GeneratedPluginRegistrant.register(with: engineBridge.pluginRegistry) } } From bc80058060ecd808d9bd4e37a5c12780f025d1a8 Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Wed, 18 Mar 2026 12:37:56 -0400 Subject: [PATCH 08/10] Add missing imports --- .../example/ios/RunnerTests/CameraSettingsTests.swift | 1 + .../ios/RunnerTests/Mocks/MockCaptureDeviceInputFactory.swift | 2 ++ .../example/ios/RunnerTests/Mocks/MockFrameRateRange.swift | 2 ++ .../example/ios/RunnerTests/Mocks/MockWritableData.swift | 2 ++ 4 files changed, 7 insertions(+) diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraSettingsTests.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraSettingsTests.swift index 409667fce057..0c9f45e5e50a 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraSettingsTests.swift +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraSettingsTests.swift @@ -3,6 +3,7 @@ // found in the LICENSE file. import AVFoundation +import Flutter import XCTest @testable import camera_avfoundation diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDeviceInputFactory.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDeviceInputFactory.swift index c332d4dbf54a..0222750a43e1 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDeviceInputFactory.swift +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDeviceInputFactory.swift @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import Foundation + @testable import camera_avfoundation ///// A mocked implementation of CaptureDeviceInputFactory which allows injecting a custom diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockFrameRateRange.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockFrameRateRange.swift index 1130a35937e7..d4bfbda30385 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockFrameRateRange.swift +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockFrameRateRange.swift @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import Foundation + @testable import camera_avfoundation /// A mock implementation of `FrameRateRange` that allows mocking the class properties. diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockWritableData.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockWritableData.swift index 9feb13e3f997..8666c4d96093 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockWritableData.swift +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockWritableData.swift @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import Foundation + @testable import camera_avfoundation /// A mock implementation of `WritableData` that allows injecting a custom implementation From 24eaebcd3c6294ebb7871c913a2c7cf43fc1aa7f Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Wed, 18 Mar 2026 12:46:18 -0400 Subject: [PATCH 09/10] Remove team --- .../example/ios/Runner.xcodeproj/project.pbxproj | 3 --- 1 file changed, 3 deletions(-) diff --git a/packages/camera/camera_avfoundation/example/ios/Runner.xcodeproj/project.pbxproj b/packages/camera/camera_avfoundation/example/ios/Runner.xcodeproj/project.pbxproj index 332495ba1b8f..94bbaa417925 100644 --- a/packages/camera/camera_avfoundation/example/ios/Runner.xcodeproj/project.pbxproj +++ b/packages/camera/camera_avfoundation/example/ios/Runner.xcodeproj/project.pbxproj @@ -552,7 +552,6 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - DEVELOPMENT_TEAM = EQHXZ8M8AV; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -732,7 +731,6 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - DEVELOPMENT_TEAM = EQHXZ8M8AV; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -755,7 +753,6 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - DEVELOPMENT_TEAM = EQHXZ8M8AV; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( From f5729fcd2aeb45eaeeb2b60a15c9d19e983e0610 Mon Sep 17 00:00:00 2001 From: stuartmorgan-g Date: Wed, 18 Mar 2026 13:33:42 -0400 Subject: [PATCH 10/10] License for bridging header --- .../example/ios/Runner/Runner-Bridging-Header.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/camera/camera_avfoundation/example/ios/Runner/Runner-Bridging-Header.h b/packages/camera/camera_avfoundation/example/ios/Runner/Runner-Bridging-Header.h index 308a2a560b42..ba04211afd0a 100644 --- a/packages/camera/camera_avfoundation/example/ios/Runner/Runner-Bridging-Header.h +++ b/packages/camera/camera_avfoundation/example/ios/Runner/Runner-Bridging-Header.h @@ -1 +1,5 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + #import "GeneratedPluginRegistrant.h"