From 50e5a40ede8d0fcb5fce2bd813d71692f74c738a Mon Sep 17 00:00:00 2001 From: Marcin Chudy Date: Sat, 8 Feb 2025 20:29:45 +0100 Subject: [PATCH 1/6] Refactor CameraTestUtils and introduce new protocols --- .../ios/Runner.xcodeproj/project.pbxproj | 6 + .../ios/RunnerTests/CameraExposureTests.m | 14 +- .../ios/RunnerTests/CameraFocusTests.m | 14 +- .../RunnerTests/CameraMethodChannelTests.m | 45 ++-- .../RunnerTests/CameraSessionPresetsTests.m | 125 +++++++---- .../ios/RunnerTests/CameraSettingsTests.m | 53 +++-- .../example/ios/RunnerTests/CameraTestUtils.h | 36 +-- .../example/ios/RunnerTests/CameraTestUtils.m | 210 +++++------------- .../ios/RunnerTests/FLTCamPhotoCaptureTests.m | 28 ++- .../ios/RunnerTests/Mocks/MockCaptureDevice.h | 6 +- .../ios/RunnerTests/Mocks/MockCaptureDevice.m | 9 +- .../Mocks/MockCaptureDeviceFormat.h | 38 ++++ .../Mocks/MockCaptureDeviceFormat.m | 37 +++ .../example/ios/RunnerTests/StreamingTest.m | 5 +- .../Sources/camera_avfoundation/FLTCam.m | 16 +- .../camera_avfoundation/FLTCamConfiguration.m | 2 +- .../camera_avfoundation/FLTCaptureDevice.m | 12 +- .../FLTCaptureDeviceFormat.m | 58 +++++ .../include/CameraPlugin.modulemap | 1 + .../camera_avfoundation/FLTCamConfiguration.h | 2 +- .../camera_avfoundation/FLTCaptureDevice.h | 8 +- .../FLTCaptureDeviceFormat.h | 49 ++++ 22 files changed, 453 insertions(+), 321 deletions(-) create mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDeviceFormat.h create mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDeviceFormat.m create mode 100644 packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCaptureDeviceFormat.m create mode 100644 packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCaptureDeviceFormat.h 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 0b28b4557b8..ff66b930f4e 100644 --- a/packages/camera/camera_avfoundation/example/ios/Runner.xcodeproj/project.pbxproj +++ b/packages/camera/camera_avfoundation/example/ios/Runner.xcodeproj/project.pbxproj @@ -29,6 +29,7 @@ 7FA99E592D22C75300582559 /* CameraExposureTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 7FA99E582D22C75300582559 /* CameraExposureTests.m */; }; 7FCEDD352D43C2B900EA1CA8 /* MockDeviceOrientationProvider.m in Sources */ = {isa = PBXBuildFile; fileRef = 7FCEDD342D43C2B900EA1CA8 /* MockDeviceOrientationProvider.m */; }; 7FCEDD362D43C2B900EA1CA8 /* MockCaptureDevice.m in Sources */ = {isa = PBXBuildFile; fileRef = 7FCEDD322D43C2B900EA1CA8 /* MockCaptureDevice.m */; }; + 7FD582352D57D97C003B1200 /* MockCaptureDeviceFormat.m in Sources */ = {isa = PBXBuildFile; fileRef = 7FD582342D57D97C003B1200 /* MockCaptureDeviceFormat.m */; }; 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */; }; 97C146F31CF9000F007C117D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 97C146F21CF9000F007C117D /* main.m */; }; 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; @@ -102,6 +103,8 @@ 7FCEDD322D43C2B900EA1CA8 /* MockCaptureDevice.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MockCaptureDevice.m; sourceTree = ""; }; 7FCEDD332D43C2B900EA1CA8 /* MockDeviceOrientationProvider.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MockDeviceOrientationProvider.h; sourceTree = ""; }; 7FCEDD342D43C2B900EA1CA8 /* MockDeviceOrientationProvider.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MockDeviceOrientationProvider.m; sourceTree = ""; }; + 7FD582342D57D97C003B1200 /* MockCaptureDeviceFormat.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MockCaptureDeviceFormat.m; sourceTree = ""; }; + 7FD582362D57D989003B1200 /* MockCaptureDeviceFormat.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MockCaptureDeviceFormat.h; 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 = ""; }; 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -199,6 +202,8 @@ 7F8FD2272D4BFA8D001AF2C1 /* MockGlobalEventApi.h */, 7FCEDD312D43C2B900EA1CA8 /* MockCaptureDevice.h */, 7FCEDD322D43C2B900EA1CA8 /* MockCaptureDevice.m */, + 7FD582362D57D989003B1200 /* MockCaptureDeviceFormat.h */, + 7FD582342D57D97C003B1200 /* MockCaptureDeviceFormat.m */, 7FCEDD332D43C2B900EA1CA8 /* MockDeviceOrientationProvider.h */, 7FCEDD342D43C2B900EA1CA8 /* MockDeviceOrientationProvider.m */, 7F29EB282D26A59000740257 /* MockCameraDeviceDiscoverer.m */, @@ -506,6 +511,7 @@ 7FA99E592D22C75300582559 /* CameraExposureTests.m in Sources */, E487C86026D686A10034AC92 /* CameraPreviewPauseTests.m in Sources */, E071CF7427B31DE4006EF3BA /* FLTCamSampleBufferTests.m in Sources */, + 7FD582352D57D97C003B1200 /* MockCaptureDeviceFormat.m in Sources */, 7F29EB222D269ED500740257 /* MockEventChannel.m in Sources */, 7F8FD22F2D4D0B88001AF2C1 /* MockFlutterBinaryMessenger.m in Sources */, E04F108627A87CA600573D0C /* FLTSavePhotoDelegateTests.m in Sources */, diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraExposureTests.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraExposureTests.m index e0969ad703d..b93a13d48fc 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraExposureTests.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraExposureTests.m @@ -22,13 +22,13 @@ - (void)setUp { MockCaptureDevice *mockDevice = [[MockCaptureDevice alloc] init]; _mockDeviceOrientationProvider = [[MockDeviceOrientationProvider alloc] init]; _mockDevice = mockDevice; - - _camera = FLTCreateCamWithCaptureSessionQueueAndMediaSettings( - nil, nil, nil, - ^NSObject *(void) { - return mockDevice; - }, - _mockDeviceOrientationProvider); + + FLTCamConfiguration *configuration = FLTCreateTestCameraConfiguration(); + configuration.captureDeviceFactory = ^NSObject * _Nonnull{ + return mockDevice; + }; + configuration.deviceOrientationProvider = _mockDeviceOrientationProvider; + _camera = FLTCreateCamWithConfiguration(configuration); } - (void)testSetExposurePointWithResult_SetsExposurePointOfInterest { diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraFocusTests.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraFocusTests.m index 5f52c9bc5ee..9ed475d7441 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraFocusTests.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraFocusTests.m @@ -25,13 +25,13 @@ - (void)setUp { MockCaptureDevice *mockDevice = [[MockCaptureDevice alloc] init]; _mockDevice = mockDevice; _mockDeviceOrientationProvider = [[MockDeviceOrientationProvider alloc] init]; - - _camera = FLTCreateCamWithCaptureSessionQueueAndMediaSettings( - nil, nil, nil, - ^NSObject *(void) { - return mockDevice; - }, - _mockDeviceOrientationProvider); + + FLTCamConfiguration *configuration = FLTCreateTestCameraConfiguration(); + configuration.captureDeviceFactory = ^NSObject * _Nonnull{ + return mockDevice; + }; + configuration.deviceOrientationProvider = _mockDeviceOrientationProvider; + _camera = FLTCreateCamWithConfiguration(configuration); } - (void)testAutoFocusWithContinuousModeSupported_ShouldSetContinuousAutoFocus { diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraMethodChannelTests.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraMethodChannelTests.m index 0acc392545f..539e830d3fc 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraMethodChannelTests.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraMethodChannelTests.m @@ -8,35 +8,41 @@ #endif @import XCTest; @import AVFoundation; -#import +#import "MockCameraDeviceDiscoverer.h" +#import "MockCaptureDevice.h" +#import "MockCaptureSession.h" #import "MockFlutterBinaryMessenger.h" #import "MockFlutterTextureRegistry.h" +#import "MockGlobalEventApi.h" @interface CameraMethodChannelTests : XCTestCase @end @implementation CameraMethodChannelTests -- (CameraPlugin *)createCameraPlugin { +- (CameraPlugin *)createCameraPluginWithSession:(MockCaptureSession *)mockSession { return [[CameraPlugin alloc] initWithRegistry:[[MockFlutterTextureRegistry alloc] init] - messenger:[[MockFlutterBinaryMessenger alloc] init]]; + messenger:[[MockFlutterBinaryMessenger alloc] init] + globalAPI:[[MockGlobalEventApi alloc] init] + deviceDiscoverer:[[MockCameraDeviceDiscoverer alloc] init] + deviceFactory:^NSObject *(NSString *name) { + return [[MockCaptureDevice alloc] init]; + } + captureSessionFactory:^NSObject *_Nonnull { + return mockSession; + } + captureDeviceInputFactory:[[MockCaptureDeviceInputFactory alloc] init]]; } - (void)testCreate_ShouldCallResultOnMainThread { - CameraPlugin *camera = [self createCameraPlugin]; + MockCaptureSession *avCaptureSessionMock = [[MockCaptureSession alloc] init]; + avCaptureSessionMock.canSetSessionPreset = YES; + + CameraPlugin *camera = [self createCameraPluginWithSession:avCaptureSessionMock]; XCTestExpectation *expectation = [self expectationWithDescription:@"Result finished"]; - // Set up mocks for initWithCameraName method - id avCaptureDeviceInputMock = OCMClassMock([AVCaptureDeviceInput class]); - OCMStub([avCaptureDeviceInputMock deviceInputWithDevice:[OCMArg any] error:[OCMArg anyObjectRef]]) - .andReturn([AVCaptureInput alloc]); - - id avCaptureSessionMock = OCMClassMock([AVCaptureSession class]); - OCMStub([avCaptureSessionMock alloc]).andReturn(avCaptureSessionMock); - OCMStub([avCaptureSessionMock canSetSessionPreset:[OCMArg any]]).andReturn(YES); - // Set up method call __block NSNumber *resultValue; [camera createCameraOnSessionQueueWithName:@"acamera" @@ -59,15 +65,10 @@ - (void)testCreate_ShouldCallResultOnMainThread { } - (void)testDisposeShouldDeallocCamera { - CameraPlugin *camera = [self createCameraPlugin]; - - id avCaptureDeviceInputMock = OCMClassMock([AVCaptureDeviceInput class]); - OCMStub([avCaptureDeviceInputMock deviceInputWithDevice:[OCMArg any] error:[OCMArg anyObjectRef]]) - .andReturn([AVCaptureInput alloc]); - - id avCaptureSessionMock = OCMClassMock([AVCaptureSession class]); - OCMStub([avCaptureSessionMock alloc]).andReturn(avCaptureSessionMock); - OCMStub([avCaptureSessionMock canSetSessionPreset:[OCMArg any]]).andReturn(YES); + MockCaptureSession *avCaptureSessionMock = [[MockCaptureSession alloc] init]; + avCaptureSessionMock.canSetSessionPreset = YES; + + CameraPlugin *camera = [self createCameraPluginWithSession:avCaptureSessionMock]; XCTestExpectation *createExpectation = [self expectationWithDescription:@"create's result block must be called"]; diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraSessionPresetsTests.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraSessionPresetsTests.m index 9f7092f6e52..740176143f4 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraSessionPresetsTests.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraSessionPresetsTests.m @@ -10,7 +10,11 @@ @import AVFoundation; @import XCTest; #import + #import "CameraTestUtils.h" +#import "MockCaptureDevice.h" +#import "MockCaptureDeviceFormat.h" +#import "MockCaptureSession.h" /// Includes test cases related to resolution presets setting operations for FLTCam class. @interface FLTCamSessionPresetsTest : XCTestCase @@ -20,62 +24,95 @@ @implementation FLTCamSessionPresetsTest - (void)testResolutionPresetWithBestFormat_mustUpdateCaptureSessionPreset { NSString *expectedPreset = AVCaptureSessionPresetInputPriority; - - id videoSessionMock = OCMProtocolMock(@protocol(FLTCaptureSession)); - OCMStub([videoSessionMock addInputWithNoConnections:[OCMArg any]]); - - id captureFormatMock = OCMClassMock([AVCaptureDeviceFormat class]); - id captureDeviceMock = OCMProtocolMock(@protocol(FLTCaptureDevice)); - OCMStub([captureDeviceMock formats]).andReturn(@[ captureFormatMock ]); - - OCMExpect([captureDeviceMock activeFormat]).andReturn(captureFormatMock); - OCMExpect([captureDeviceMock lockForConfiguration:NULL]).andReturn(YES); - OCMExpect([videoSessionMock setSessionPreset:expectedPreset]); - - FLTCreateCamWithVideoDimensionsForFormat(videoSessionMock, FCPPlatformResolutionPresetMax, - captureDeviceMock, - ^CMVideoDimensions(AVCaptureDeviceFormat *format) { - CMVideoDimensions videoDimensions; - videoDimensions.width = 1; - videoDimensions.height = 1; - return videoDimensions; - }); - - OCMVerifyAll(captureDeviceMock); - OCMVerifyAll(videoSessionMock); + XCTestExpectation *presetExpectation = [self expectationWithDescription:@"Expected preset set"]; + XCTestExpectation *lockForConfigurationExpectation = [self expectationWithDescription:@"Expected lockForConfiguration called"]; + + MockCaptureSession *videoSessionMock = [[MockCaptureSession alloc] init]; + videoSessionMock.setSessionPresetStub = ^(NSString *preset) { + if (preset == expectedPreset) { + [presetExpectation fulfill]; + } + }; + + MockCaptureDeviceFormat *captureFormatMock = [[MockCaptureDeviceFormat alloc] init]; + + + MockCaptureDevice *captureDeviceMock = [[MockCaptureDevice alloc] init]; + captureDeviceMock.formats = @[ captureFormatMock ]; + captureDeviceMock.activeFormat = captureFormatMock; + captureDeviceMock.lockForConfigurationStub = ^BOOL(NSError *__autoreleasing _Nullable * _Nullable error) { + [lockForConfigurationExpectation fulfill]; + return YES; + }; + + FLTCamConfiguration *configuration = FLTCreateTestCameraConfiguration(); + configuration.captureDeviceFactory = ^NSObject * _Nonnull{ + return captureDeviceMock; + }; + configuration.videoDimensionsForFormat = ^CMVideoDimensions(NSObject *format) { + CMVideoDimensions videoDimensions; + videoDimensions.width = 1; + videoDimensions.height = 1; + return videoDimensions; + }; + configuration.videoCaptureSession = videoSessionMock; + configuration.mediaSettings = FCPGetDefaultMediaSettings(FCPPlatformResolutionPresetMax); + + FLTCreateCamWithConfiguration(configuration); + + [self waitForExpectationsWithTimeout:1 handler:nil]; } - (void)testResolutionPresetWithCanSetSessionPresetMax_mustUpdateCaptureSessionPreset { NSString *expectedPreset = AVCaptureSessionPreset3840x2160; - - id videoSessionMock = OCMProtocolMock(@protocol(FLTCaptureSession)); - OCMStub([videoSessionMock addInputWithNoConnections:[OCMArg any]]); - + XCTestExpectation *expectation = [self expectationWithDescription:@"Expected preset set"]; + + MockCaptureSession *videoSessionMock = [[MockCaptureSession alloc] init]; + // Make sure that setting resolution preset for session always succeeds. - OCMStub([videoSessionMock canSetSessionPreset:[OCMArg any]]).andReturn(YES); - - OCMExpect([videoSessionMock setSessionPreset:expectedPreset]); - - FLTCreateCamWithVideoCaptureSession(videoSessionMock, FCPPlatformResolutionPresetMax); - - OCMVerifyAll(videoSessionMock); + videoSessionMock.canSetSessionPreset = YES; + + videoSessionMock.setSessionPresetStub = ^(NSString *preset) { + if (preset == expectedPreset) { + [expectation fulfill]; + } + }; + + FLTCamConfiguration *configuration = FLTCreateTestCameraConfiguration(); + configuration.videoCaptureSession = videoSessionMock; + configuration.mediaSettings = FCPGetDefaultMediaSettings(FCPPlatformResolutionPresetMax); + configuration.captureDeviceFactory = ^NSObject * { + return [[MockCaptureDevice alloc] init]; + }; + + FLTCreateCamWithConfiguration(configuration); + + [self waitForExpectationsWithTimeout:1 handler:nil]; } - (void)testResolutionPresetWithCanSetSessionPresetUltraHigh_mustUpdateCaptureSessionPreset { NSString *expectedPreset = AVCaptureSessionPreset3840x2160; - - id videoSessionMock = OCMProtocolMock(@protocol(FLTCaptureSession)); - OCMStub([videoSessionMock addInputWithNoConnections:[OCMArg any]]); - + XCTestExpectation *expectation = [self expectationWithDescription:@"Expected preset set"]; + + MockCaptureSession *videoSessionMock = [[MockCaptureSession alloc] init]; + // Make sure that setting resolution preset for session always succeeds. - OCMStub([videoSessionMock canSetSessionPreset:[OCMArg any]]).andReturn(YES); + videoSessionMock.canSetSessionPreset = YES; // Expect that setting "ultraHigh" resolutionPreset correctly updates videoCaptureSession. - OCMExpect([videoSessionMock setSessionPreset:expectedPreset]); - - FLTCreateCamWithVideoCaptureSession(videoSessionMock, FCPPlatformResolutionPresetUltraHigh); - - OCMVerifyAll(videoSessionMock); + videoSessionMock.setSessionPresetStub = ^(NSString *preset) { + if (preset == expectedPreset) { + [expectation fulfill]; + } + }; + + FLTCamConfiguration *configuration = FLTCreateTestCameraConfiguration(); + configuration.videoCaptureSession = videoSessionMock; + configuration.mediaSettings = FCPGetDefaultMediaSettings(FCPPlatformResolutionPresetUltraHigh); + + FLTCreateCamWithConfiguration(configuration); + + [self waitForExpectationsWithTimeout:1 handler:nil]; } @end diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraSettingsTests.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraSettingsTests.m index 873cc212a8a..60aab003828 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraSettingsTests.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraSettingsTests.m @@ -8,11 +8,14 @@ #endif @import XCTest; @import AVFoundation; -#import #import "CameraTestUtils.h" +#import "MockCaptureDevice.h" +#import "MockCaptureSession.h" +#import "MockCameraDeviceDiscoverer.h" #import "MockFlutterBinaryMessenger.h" #import "MockFlutterTextureRegistry.h" +#import "MockGlobalEventApi.h" static const FCPPlatformResolutionPreset gTestResolutionPreset = FCPPlatformResolutionPresetMedium; static const int gTestFramesPerSecond = 15; @@ -68,11 +71,11 @@ - (void)unlockDevice:(AVCaptureDevice *)captureDevice { [_unlockExpectation fulfill]; } -- (void)beginConfigurationForSession:(AVCaptureSession *)videoCaptureSession { +- (void)beginConfigurationForSession:(NSObject *)videoCaptureSession { [_beginConfigurationExpectation fulfill]; } -- (void)commitConfigurationForSession:(AVCaptureSession *)videoCaptureSession { +- (void)commitConfigurationForSession:(NSObject *)videoCaptureSession { [_commitConfigurationExpectation fulfill]; } @@ -145,10 +148,12 @@ - (void)testSettings_shouldPassConfigurationToCameraDeviceAndWriter { enableAudio:gTestEnableAudio]; TestMediaSettingsAVWrapper *injectedWrapper = [[TestMediaSettingsAVWrapper alloc] initWithTestCase:self]; - - FLTCam *camera = FLTCreateCamWithCaptureSessionQueueAndMediaSettings( - dispatch_queue_create("test", NULL), settings, injectedWrapper, nil, nil); - + + FLTCamConfiguration *configuration = FLTCreateTestCameraConfiguration(); + configuration.mediaSettingsWrapper = injectedWrapper; + configuration.mediaSettings = settings; + FLTCam *camera = FLTCreateCamWithConfiguration(configuration); + // Expect FPS configuration is passed to camera device. [self waitForExpectations:@[ injectedWrapper.lockExpectation, injectedWrapper.beginConfigurationExpectation, @@ -170,21 +175,24 @@ - (void)testSettings_shouldPassConfigurationToCameraDeviceAndWriter { } - (void)testSettings_ShouldBeSupportedByMethodCall { - CameraPlugin *camera = - [[CameraPlugin alloc] initWithRegistry:[[MockFlutterTextureRegistry alloc] init] - messenger:[[MockFlutterBinaryMessenger alloc] init]]; + MockCaptureDevice *mockDevice = [[MockCaptureDevice alloc] init]; + MockCaptureSession *mockSession = [[MockCaptureSession alloc] init]; + mockSession.canSetSessionPreset = YES; + + CameraPlugin *camera = [[CameraPlugin alloc] initWithRegistry:[[MockFlutterTextureRegistry alloc] init] + messenger:[[MockFlutterBinaryMessenger alloc] init] + globalAPI:[[MockGlobalEventApi alloc] init] + deviceDiscoverer:[[MockCameraDeviceDiscoverer alloc] init] + deviceFactory:^NSObject * (NSString *name) { + return mockDevice; + } + captureSessionFactory:^NSObject * _Nonnull{ + return mockSession; + } + captureDeviceInputFactory:[[MockCaptureDeviceInputFactory alloc] init]]; XCTestExpectation *expectation = [self expectationWithDescription:@"Result finished"]; - // Set up mocks for initWithCameraName method - id avCaptureDeviceInputMock = OCMClassMock([AVCaptureDeviceInput class]); - OCMStub([avCaptureDeviceInputMock deviceInputWithDevice:[OCMArg any] error:[OCMArg anyObjectRef]]) - .andReturn([AVCaptureInput alloc]); - - id avCaptureSessionMock = OCMClassMock([AVCaptureSession class]); - OCMStub([avCaptureSessionMock alloc]).andReturn(avCaptureSessionMock); - OCMStub([avCaptureSessionMock canSetSessionPreset:[OCMArg any]]).andReturn(YES); - // Set up method call FCPPlatformMediaSettings *mediaSettings = [FCPPlatformMediaSettings makeWithResolutionPreset:gTestResolutionPreset @@ -215,10 +223,11 @@ - (void)testSettings_ShouldSelectFormatWhichSupports60FPS { audioBitrate:@(gTestAudioBitrate) enableAudio:gTestEnableAudio]; - FLTCam *camera = FLTCreateCamWithCaptureSessionQueueAndMediaSettings( - dispatch_queue_create("test", NULL), settings, nil, nil, nil); + FLTCamConfiguration *configuration = FLTCreateTestCameraConfiguration(); + configuration.mediaSettings = settings; + FLTCam *camera = FLTCreateCamWithConfiguration(configuration); - AVFrameRateRange *range = camera.captureDevice.activeFormat.videoSupportedFrameRateRanges[0]; + NSObject *range = camera.captureDevice.activeFormat.videoSupportedFrameRateRanges[0]; XCTAssertLessThanOrEqual(range.minFrameRate, 60); XCTAssertGreaterThanOrEqual(range.maxFrameRate, 60); } diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraTestUtils.h b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraTestUtils.h index c8a5b230453..421ef82fdf6 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraTestUtils.h +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraTestUtils.h @@ -9,39 +9,15 @@ NS_ASSUME_NONNULL_BEGIN -/// Creates an `FLTCam` that runs its capture session operations on a given queue. -/// @param captureSessionQueue the capture session queue -/// @param mediaSettings media settings configuration parameters -/// @param mediaSettingsAVWrapper provider to perform media settings operations (for unit test -/// dependency injection). -/// @param captureDeviceFactory a callback to create capture device instances -/// @return an FLTCam object. -extern FLTCam *_Nullable FLTCreateCamWithCaptureSessionQueueAndMediaSettings( - dispatch_queue_t _Nullable captureSessionQueue, - FCPPlatformMediaSettings *_Nullable mediaSettings, - FLTCamMediaSettingsAVWrapper *_Nullable mediaSettingsAVWrapper, - CaptureDeviceFactory _Nullable captureDeviceFactory, - id _Nullable deviceOrientationProvider); +extern FCPPlatformMediaSettings *FCPGetDefaultMediaSettings(FCPPlatformResolutionPreset resolutionPreset); + +/// Creates a test `FLTCamConfiguration` with a default mock setup. +extern FLTCamConfiguration *FLTCreateTestCameraConfiguration(void); extern FLTCam *FLTCreateCamWithCaptureSessionQueue(dispatch_queue_t captureSessionQueue); -/// Creates an `FLTCam` with a given captureSession and resolutionPreset -/// @param captureSession AVCaptureSession for video -/// @param resolutionPreset preset for camera's captureSession resolution -/// @return an FLTCam object. -extern FLTCam *FLTCreateCamWithVideoCaptureSession(NSObject *captureSession, - FCPPlatformResolutionPreset resolutionPreset); - -/// Creates an `FLTCam` with a given captureSession and resolutionPreset. -/// Allows to inject a capture device and a block to compute the video dimensions. -/// @param captureSession AVCaptureSession for video -/// @param resolutionPreset preset for camera's captureSession resolution -/// @param captureDevice AVCaptureDevice to be used -/// @param videoDimensionsForFormat custom code to determine video dimensions -/// @return an FLTCam object. -extern FLTCam *FLTCreateCamWithVideoDimensionsForFormat( - AVCaptureSession *captureSession, FCPPlatformResolutionPreset resolutionPreset, - AVCaptureDevice *captureDevice, VideoDimensionsForFormat videoDimensionsForFormat); +/// Creates an `FLTCam` with a test configuration. +extern FLTCam *FLTCreateCamWithConfiguration(FLTCamConfiguration *configuration); /// Creates a test sample buffer. /// @return a test sample buffer. diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraTestUtils.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraTestUtils.m index 67d4432d2f4..750e6118171 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraTestUtils.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraTestUtils.m @@ -9,11 +9,12 @@ @import camera_avfoundation; #import "MockCaptureDevice.h" +#import "MockCaptureDeviceFormat.h" #import "MockCaptureSession.h" #import "MockDeviceOrientationProvider.h" -static FCPPlatformMediaSettings *FCPGetDefaultMediaSettings( - FCPPlatformResolutionPreset resolutionPreset) { +FCPPlatformMediaSettings *FCPGetDefaultMediaSettings( + FCPPlatformResolutionPreset resolutionPreset) { return [FCPPlatformMediaSettings makeWithResolutionPreset:resolutionPreset framesPerSecond:nil videoBitrate:nil @@ -21,113 +22,75 @@ enableAudio:YES]; } -FLTCam *FLTCreateCamWithCaptureSessionQueue(dispatch_queue_t captureSessionQueue) { - return FLTCreateCamWithCaptureSessionQueueAndMediaSettings(captureSessionQueue, nil, nil, nil, - nil); -} - -FLTCam *FLTCreateCamWithCaptureSessionQueueAndMediaSettings( - dispatch_queue_t captureSessionQueue, FCPPlatformMediaSettings *mediaSettings, - FLTCamMediaSettingsAVWrapper *mediaSettingsAVWrapper, CaptureDeviceFactory captureDeviceFactory, - NSObject *deviceOrientationProvider) { - if (!mediaSettings) { - mediaSettings = FCPGetDefaultMediaSettings(FCPPlatformResolutionPresetMedium); - } - - if (!mediaSettingsAVWrapper) { - mediaSettingsAVWrapper = [[FLTCamMediaSettingsAVWrapper alloc] init]; - } - - if (!deviceOrientationProvider) { - deviceOrientationProvider = [[MockDeviceOrientationProvider alloc] init]; - } - - if (!captureSessionQueue) { - captureSessionQueue = dispatch_queue_create("capture_session_queue", NULL); - } - - id videoSessionMock = OCMProtocolMock(@protocol(FLTCaptureSession)); - OCMStub([videoSessionMock beginConfiguration]) - .andDo(^(NSInvocation *invocation){ - }); - OCMStub([videoSessionMock commitConfiguration]) - .andDo(^(NSInvocation *invocation){ - }); - - OCMStub([videoSessionMock addInputWithNoConnections:[OCMArg any]]); - OCMStub([videoSessionMock canSetSessionPreset:[OCMArg any]]).andReturn(YES); - - id audioSessionMock = OCMProtocolMock(@protocol(FLTCaptureSession)); - OCMStub([audioSessionMock addInputWithNoConnections:[OCMArg any]]); - OCMStub([audioSessionMock canSetSessionPreset:[OCMArg any]]).andReturn(YES); - - id frameRateRangeMock1 = OCMClassMock([AVFrameRateRange class]); - OCMStub([frameRateRangeMock1 minFrameRate]).andReturn(3); - OCMStub([frameRateRangeMock1 maxFrameRate]).andReturn(30); - id captureDeviceFormatMock1 = OCMClassMock([AVCaptureDeviceFormat class]); - OCMStub([captureDeviceFormatMock1 videoSupportedFrameRateRanges]).andReturn(@[ - frameRateRangeMock1 - ]); - - id frameRateRangeMock2 = OCMClassMock([AVFrameRateRange class]); - OCMStub([frameRateRangeMock2 minFrameRate]).andReturn(3); - OCMStub([frameRateRangeMock2 maxFrameRate]).andReturn(60); - id captureDeviceFormatMock2 = OCMClassMock([AVCaptureDeviceFormat class]); - OCMStub([captureDeviceFormatMock2 videoSupportedFrameRateRanges]).andReturn(@[ - frameRateRangeMock2 - ]); - - id captureDeviceMock = OCMProtocolMock(@protocol(FLTCaptureDevice)); - OCMStub([captureDeviceMock lockForConfiguration:[OCMArg setTo:nil]]).andReturn(YES); - OCMStub([captureDeviceMock formats]).andReturn((@[ - captureDeviceFormatMock1, captureDeviceFormatMock2 - ])); - __block AVCaptureDeviceFormat *format = captureDeviceFormatMock1; - OCMStub([captureDeviceMock setActiveFormat:[OCMArg any]]).andDo(^(NSInvocation *invocation) { - [invocation retainArguments]; - [invocation getArgument:&format atIndex:2]; - }); - OCMStub([captureDeviceMock activeFormat]).andDo(^(NSInvocation *invocation) { - [invocation setReturnValue:&format]; - }); - - FLTCamConfiguration *configuration = [[FLTCamConfiguration alloc] initWithMediaSettings:mediaSettings - mediaSettingsWrapper:mediaSettingsAVWrapper - captureDeviceFactory:captureDeviceFactory ?: ^NSObject *(void) { +FLTCamConfiguration *FLTCreateTestCameraConfiguration(void) { + dispatch_queue_t captureSessionQueue = dispatch_queue_create("capture_session_queue", NULL); + + MockCaptureSession *videoSessionMock = [[MockCaptureSession alloc] init]; + videoSessionMock.canSetSessionPreset = YES; + + MockCaptureSession *audioSessionMock = [[MockCaptureSession alloc] init]; + audioSessionMock.canSetSessionPreset = YES; + + MockFrameRateRange *frameRateRangeMock1 = [[MockFrameRateRange alloc] initWithMinFrameRate:3 maxFrameRate:30]; + MockCaptureDeviceFormat *captureDeviceFormatMock1 = [[MockCaptureDeviceFormat alloc] init]; + captureDeviceFormatMock1.videoSupportedFrameRateRanges = @[frameRateRangeMock1]; + + MockFrameRateRange *frameRateRangeMock2 = [[MockFrameRateRange alloc] initWithMinFrameRate:3 maxFrameRate:60]; + MockCaptureDeviceFormat *captureDeviceFormatMock2 = [[MockCaptureDeviceFormat alloc] init]; + captureDeviceFormatMock2.videoSupportedFrameRateRanges = @[frameRateRangeMock2]; + + MockCaptureDevice *captureDeviceMock = [[MockCaptureDevice alloc] init]; + captureDeviceMock.lockForConfigurationStub = ^BOOL(NSError **error) { + return YES; + }; + captureDeviceMock.formats = @[captureDeviceFormatMock1, captureDeviceFormatMock2]; + + __block NSObject *currentFormat = captureDeviceFormatMock1; + captureDeviceMock.activeFormatStub = ^NSObject * { + return currentFormat; + }; + captureDeviceMock.setActiveFormatStub = ^(NSObject *format) { + currentFormat = format; + }; + + FLTCamConfiguration *configuration = [[FLTCamConfiguration alloc] initWithMediaSettings:FCPGetDefaultMediaSettings(FCPPlatformResolutionPresetMedium) + mediaSettingsWrapper:[[FLTCamMediaSettingsAVWrapper alloc] init] + captureDeviceFactory:^NSObject *(void) { return captureDeviceMock; } - captureSessionFactory:^NSObject *_Nonnull{ - return videoSessionMock; + captureSessionFactory:^NSObject *_Nonnull { + return videoSessionMock; } - captureSessionQueue:captureSessionQueue + captureSessionQueue:captureSessionQueue captureDeviceInputFactory:[[MockCaptureDeviceInputFactory alloc] init]]; - - configuration.videoDimensionsForFormat = ^CMVideoDimensions(AVCaptureDeviceFormat *format) { - return CMVideoFormatDescriptionGetDimensions(format.formatDescription); - }; - configuration.deviceOrientationProvider = deviceOrientationProvider; configuration.videoCaptureSession = videoSessionMock; configuration.audioCaptureSession = audioSessionMock; + configuration.orientation = UIDeviceOrientationPortrait; + + return configuration; +} + +FLTCam *FLTCreateCamWithCaptureSessionQueue(dispatch_queue_t captureSessionQueue) { + FLTCamConfiguration *configuration = FLTCreateTestCameraConfiguration(); + configuration.captureSessionQueue = captureSessionQueue; + return FLTCreateCamWithConfiguration(configuration); +} - id fltCam = [[FLTCam alloc] initWithConfiguration:configuration error:nil]; +FLTCam *FLTCreateCamWithConfiguration(FLTCamConfiguration *configuration) { id captureVideoDataOutputMock = [OCMockObject niceMockForClass:[AVCaptureVideoDataOutput class]]; - OCMStub([captureVideoDataOutputMock new]).andReturn(captureVideoDataOutputMock); - OCMStub([captureVideoDataOutputMock recommendedVideoSettingsForAssetWriterWithOutputFileType:AVFileTypeMPEG4]) .andReturn(@{}); - - OCMStub([captureVideoDataOutputMock sampleBufferCallbackQueue]).andReturn(captureSessionQueue); - + OCMStub([captureVideoDataOutputMock sampleBufferCallbackQueue]).andReturn(configuration.captureSessionQueue); + id videoMock = OCMClassMock([AVAssetWriterInputPixelBufferAdaptor class]); OCMStub([videoMock assetWriterInputPixelBufferAdaptorWithAssetWriterInput:OCMOCK_ANY sourcePixelBufferAttributes:OCMOCK_ANY]) .andReturn(videoMock); id writerInputMock = [OCMockObject niceMockForClass:[AVAssetWriterInput class]]; - OCMStub([writerInputMock assetWriterInputWithMediaType:AVMediaTypeAudio outputSettings:[OCMArg any]]) .andReturn(writerInputMock); @@ -135,72 +98,7 @@ OCMStub([writerInputMock assetWriterInputWithMediaType:AVMediaTypeVideo outputSettings:[OCMArg any]]) .andReturn(writerInputMock); - - return fltCam; -} - -FLTCam *FLTCreateCamWithVideoCaptureSession(NSObject *captureSession, - FCPPlatformResolutionPreset resolutionPreset) { - id inputMock = OCMClassMock([AVCaptureDeviceInput class]); - OCMStub([inputMock deviceInputWithDevice:[OCMArg any] error:[OCMArg setTo:nil]]) - .andReturn(inputMock); - - id audioSessionMock = OCMProtocolMock(@protocol(FLTCaptureSession)); - OCMStub([audioSessionMock addInputWithNoConnections:[OCMArg any]]); - OCMStub([audioSessionMock canSetSessionPreset:[OCMArg any]]).andReturn(YES); - - id captureDeviceMock = OCMProtocolMock(@protocol(FLTCaptureDevice)); - - FLTCamConfiguration *configuration = [[FLTCamConfiguration alloc] - initWithMediaSettings:FCPGetDefaultMediaSettings(resolutionPreset) - mediaSettingsWrapper:[[FLTCamMediaSettingsAVWrapper alloc] init] - captureDeviceFactory:^NSObject *(void) { - return captureDeviceMock; - } - captureSessionFactory:^NSObject *_Nonnull { - return captureSession; - } - captureSessionQueue:dispatch_queue_create("capture_session_queue", NULL) - captureDeviceInputFactory:[[MockCaptureDeviceInputFactory alloc] init]]; - - configuration.orientation = UIDeviceOrientationPortrait; - configuration.videoCaptureSession = captureSession; - configuration.audioCaptureSession = audioSessionMock; - - return [[FLTCam alloc] initWithConfiguration:configuration error:nil]; -} - -FLTCam *FLTCreateCamWithVideoDimensionsForFormat( - AVCaptureSession *captureSession, FCPPlatformResolutionPreset resolutionPreset, - AVCaptureDevice *captureDevice, VideoDimensionsForFormat videoDimensionsForFormat) { - id inputMock = OCMClassMock([AVCaptureDeviceInput class]); - OCMStub([inputMock deviceInputWithDevice:[OCMArg any] error:[OCMArg setTo:nil]]) - .andReturn(inputMock); - - id audioSessionMock = OCMProtocolMock(@protocol(FLTCaptureSession)); - OCMStub([audioSessionMock addInputWithNoConnections:[OCMArg any]]); - OCMStub([audioSessionMock canSetSessionPreset:[OCMArg any]]).andReturn(YES); - - FLTCamConfiguration *configuration = [[FLTCamConfiguration alloc] - initWithMediaSettings:FCPGetDefaultMediaSettings(resolutionPreset) - mediaSettingsWrapper:[[FLTCamMediaSettingsAVWrapper alloc] init] - captureDeviceFactory:^NSObject *(void) { - return [[FLTDefaultCaptureDevice alloc] initWithDevice:captureDevice]; - } - captureSessionFactory:^NSObject *_Nonnull { - return [[FLTDefaultCaptureSession alloc] - initWithCaptureSession:[[AVCaptureSession alloc] init]]; - } - captureSessionQueue:dispatch_queue_create("capture_session_queue", NULL) - captureDeviceInputFactory:[[MockCaptureDeviceInputFactory alloc] init]]; - - configuration.videoDimensionsForFormat = videoDimensionsForFormat; - configuration.deviceOrientationProvider = [[MockDeviceOrientationProvider alloc] init]; - configuration.videoCaptureSession = - [[FLTDefaultCaptureSession alloc] initWithCaptureSession:captureSession]; - configuration.audioCaptureSession = audioSessionMock; - configuration.orientation = UIDeviceOrientationPortrait; - + return [[FLTCam alloc] initWithConfiguration:configuration error:nil]; } diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamPhotoCaptureTests.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamPhotoCaptureTests.m index dc6fd86a8b6..9df87a8a6ea 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamPhotoCaptureTests.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamPhotoCaptureTests.m @@ -18,6 +18,12 @@ @interface FLTCamPhotoCaptureTests : XCTestCase @implementation FLTCamPhotoCaptureTests +- (FLTCam *)createCamWithCaptureSessionQueue:(dispatch_queue_t)captureSessionQueue { + FLTCamConfiguration *configuration = FLTCreateTestCameraConfiguration(); + configuration.captureSessionQueue = captureSessionQueue; + return FLTCreateCamWithConfiguration(configuration); +} + - (void)testCaptureToFile_mustReportErrorToResultIfSavePhotoDelegateCompletionsWithError { XCTestExpectation *errorExpectation = [self expectationWithDescription: @@ -26,7 +32,7 @@ - (void)testCaptureToFile_mustReportErrorToResultIfSavePhotoDelegateCompletionsW dispatch_queue_t captureSessionQueue = dispatch_queue_create("capture_session_queue", NULL); dispatch_queue_set_specific(captureSessionQueue, FLTCaptureSessionQueueSpecific, (void *)FLTCaptureSessionQueueSpecific, NULL); - FLTCam *cam = FLTCreateCamWithCaptureSessionQueue(captureSessionQueue); + FLTCam *cam = [self createCamWithCaptureSessionQueue:captureSessionQueue]; AVCapturePhotoSettings *settings = [AVCapturePhotoSettings photoSettings]; id mockSettings = OCMClassMock([AVCapturePhotoSettings class]); OCMStub([mockSettings photoSettings]).andReturn(settings); @@ -65,7 +71,7 @@ - (void)testCaptureToFile_mustReportPathToResultIfSavePhotoDelegateCompletionsWi dispatch_queue_t captureSessionQueue = dispatch_queue_create("capture_session_queue", NULL); dispatch_queue_set_specific(captureSessionQueue, FLTCaptureSessionQueueSpecific, (void *)FLTCaptureSessionQueueSpecific, NULL); - FLTCam *cam = FLTCreateCamWithCaptureSessionQueue(captureSessionQueue); + FLTCam *cam = [self createCamWithCaptureSessionQueue:captureSessionQueue]; AVCapturePhotoSettings *settings = [AVCapturePhotoSettings photoSettings]; id mockSettings = OCMClassMock([AVCapturePhotoSettings class]); @@ -102,7 +108,7 @@ - (void)testCaptureToFile_mustReportFileExtensionWithHeifWhenHEVCIsAvailableAndF dispatch_queue_t captureSessionQueue = dispatch_queue_create("capture_session_queue", NULL); dispatch_queue_set_specific(captureSessionQueue, FLTCaptureSessionQueueSpecific, (void *)FLTCaptureSessionQueueSpecific, NULL); - FLTCam *cam = FLTCreateCamWithCaptureSessionQueue(captureSessionQueue); + FLTCam *cam = [self createCamWithCaptureSessionQueue:captureSessionQueue]; [cam setImageFileFormat:FCPPlatformImageFileFormatHeif]; AVCapturePhotoSettings *settings = @@ -143,7 +149,7 @@ - (void)testCaptureToFile_mustReportFileExtensionWithJpgWhenHEVCNotAvailableAndF dispatch_queue_t captureSessionQueue = dispatch_queue_create("capture_session_queue", NULL); dispatch_queue_set_specific(captureSessionQueue, FLTCaptureSessionQueueSpecific, (void *)FLTCaptureSessionQueueSpecific, NULL); - FLTCam *cam = FLTCreateCamWithCaptureSessionQueue(captureSessionQueue); + FLTCam *cam = [self createCamWithCaptureSessionQueue:captureSessionQueue]; [cam setImageFileFormat:FCPPlatformImageFileFormatHeif]; AVCapturePhotoSettings *settings = [AVCapturePhotoSettings photoSettings]; @@ -186,13 +192,13 @@ - (void)testCaptureToFile_handlesTorchMode { dispatch_queue_t captureSessionQueue = dispatch_queue_create("capture_session_queue", NULL); dispatch_queue_set_specific(captureSessionQueue, FLTCaptureSessionQueueSpecific, (void *)FLTCaptureSessionQueueSpecific, NULL); - - FLTCam *cam = FLTCreateCamWithCaptureSessionQueueAndMediaSettings( - captureSessionQueue, nil, nil, - ^NSObject *(void) { - return captureDeviceMock; - }, - nil); + + FLTCamConfiguration *configuration = FLTCreateTestCameraConfiguration(); + configuration.captureSessionQueue = captureSessionQueue; + configuration.captureDeviceFactory = ^NSObject *{ + return captureDeviceMock; + }; + FLTCam *cam = FLTCreateCamWithConfiguration(configuration); AVCapturePhotoSettings *settings = [AVCapturePhotoSettings photoSettings]; id mockSettings = OCMClassMock([AVCapturePhotoSettings class]); diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDevice.h b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDevice.h index 89dd1648827..ab8de0d3252 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDevice.h +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDevice.h @@ -18,11 +18,11 @@ NS_ASSUME_NONNULL_BEGIN @property(nonatomic, assign) AVCaptureDevicePosition position; // Format/Configuration -@property(nonatomic, strong) AVCaptureDeviceFormat *activeFormat; -@property(nonatomic, strong) NSArray *formats; +@property(nonatomic, strong) NSArray *> *formats; +@property(nonatomic, copy) NSObject * (^activeFormatStub)(void); /// Overrides the default implementation of setting active format. /// @param format The format being set -@property(nonatomic, copy) void (^setActiveFormatStub)(AVCaptureDeviceFormat *format); +@property(nonatomic, copy) void (^setActiveFormatStub)(NSObject *format); // Flash/Torch @property(nonatomic, assign) BOOL hasFlash; diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDevice.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDevice.m index 8114be864b7..0f7f2de2461 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDevice.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDevice.m @@ -12,7 +12,14 @@ @implementation MockCaptureDevice -- (void)setActiveFormat:(AVCaptureDeviceFormat *)format { +- (NSObject *)activeFormat { + if (self.activeFormatStub) { + return self.activeFormatStub(); + } + return nil; +} + +- (void)setActiveFormat:(NSObject *)format { if (self.setActiveFormatStub) { self.setActiveFormatStub(format); } diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDeviceFormat.h b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDeviceFormat.h new file mode 100644 index 00000000000..0436de9da48 --- /dev/null +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDeviceFormat.h @@ -0,0 +1,38 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +@import camera_avfoundation; +#if __has_include() +@import camera_avfoundation.Test; +#endif +@import AVFoundation; + +NS_ASSUME_NONNULL_BEGIN + +/// A mock implementation of `FLTDeviceOrientationProviding` that allows mocking the class properties. +@interface MockCaptureDeviceFormat : NSObject + +/// Initializes a `MockCaptureDeviceFormat` with the given dimensions. +- (instancetype)initWithDimensions:(CMVideoDimensions)dimensions; + +// Properties redeclared as read/write to allow mocking. +@property(nonatomic, strong) AVCaptureDeviceFormat *format; +@property(nonatomic, strong) NSArray *> *videoSupportedFrameRateRanges; +@property(nonatomic, assign) CMFormatDescriptionRef formatDescription; + +@end + +/// A mock implementation of `FLTFrameRateRange` that allows mocking the class properties. +@interface MockFrameRateRange : NSObject + +/// Initializes a `MockFrameRateRange` with the given frame rate range. +- (instancetype)initWithMinFrameRate:(float)minFrameRate maxFrameRate:(float)maxFrameRate; + +// Properties redeclared as read/write to allow mocking. +@property(nonatomic, assign) float minFrameRate; +@property(nonatomic, assign) float maxFrameRate; + +@end + +NS_ASSUME_NONNULL_END diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDeviceFormat.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDeviceFormat.m new file mode 100644 index 00000000000..fb2b31a4ee6 --- /dev/null +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDeviceFormat.m @@ -0,0 +1,37 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "MockCaptureDeviceFormat.h" + +@implementation MockCaptureDeviceFormat + +- (instancetype)initWithDimensions:(CMVideoDimensions)dimensions { + self = [super init]; + if (self) { + CMVideoFormatDescriptionCreate(kCFAllocatorDefault, kCVPixelFormatType_32BGRA, dimensions.width, + dimensions.height, NULL, &_formatDescription); + } + return self; +} + +- (void)dealloc { + if (_formatDescription) { + CFRelease(_formatDescription); + } +} + +@end + +@implementation MockFrameRateRange + +- (instancetype)initWithMinFrameRate:(float)minFrameRate maxFrameRate:(float)maxFrameRate { + self = [super init]; + if (self) { + _minFrameRate = minFrameRate; + _maxFrameRate = maxFrameRate; + } + return self; +} + +@end diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/StreamingTest.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/StreamingTest.m index 53c7c1da2c7..0b73f757bcd 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/StreamingTest.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/StreamingTest.m @@ -20,7 +20,10 @@ @implementation StreamingTests - (void)setUp { dispatch_queue_t captureSessionQueue = dispatch_queue_create("testing", NULL); - _camera = FLTCreateCamWithCaptureSessionQueue(captureSessionQueue); + FLTCamConfiguration *configuration = FLTCreateTestCameraConfiguration(); + configuration.captureSessionQueue = captureSessionQueue; + + _camera = FLTCreateCamWithConfiguration(configuration); _sampleBuffer = FLTCreateTestSampleBuffer(); } diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m index 9007e767b14..6d8272c90ef 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m @@ -119,10 +119,10 @@ @implementation FLTCam NSString *const errorMethod = @"error"; // Returns frame rate supported by format closest to targetFrameRate. -static double bestFrameRateForFormat(AVCaptureDeviceFormat *format, double targetFrameRate) { +static double bestFrameRateForFormat(NSObject *format, double targetFrameRate) { double bestFrameRate = 0; double minDistance = DBL_MAX; - for (AVFrameRateRange *range in format.videoSupportedFrameRateRanges) { + for (NSObject *range in format.videoSupportedFrameRateRanges) { double frameRate = MIN(MAX(targetFrameRate, range.minFrameRate), range.maxFrameRate); double distance = fabs(frameRate - targetFrameRate); if (distance < minDistance) { @@ -145,11 +145,11 @@ static void selectBestFormatForRequestedFrameRate( double targetFrameRate = mediaSettings.framesPerSecond.doubleValue; FourCharCode preferredSubType = CMFormatDescriptionGetMediaSubType(captureDevice.activeFormat.formatDescription); - AVCaptureDeviceFormat *bestFormat = captureDevice.activeFormat; + NSObject *bestFormat = captureDevice.activeFormat; double bestFrameRate = bestFrameRateForFormat(bestFormat, targetFrameRate); double minDistance = fabs(bestFrameRate - targetFrameRate); BOOL isBestSubTypePreferred = YES; - for (AVCaptureDeviceFormat *format in captureDevice.formats) { + for (NSObject *format in captureDevice.formats) { CMVideoDimensions resolution = videoDimensionsForFormat(format); if (resolution.width != targetResolution.width || resolution.height != targetResolution.height) { @@ -486,7 +486,7 @@ - (BOOL)setCaptureSessionPreset:(FCPPlatformResolutionPreset)resolutionPreset withError:(NSError **)error { switch (resolutionPreset) { case FCPPlatformResolutionPresetMax: { - AVCaptureDeviceFormat *bestFormat = + NSObject *bestFormat = [self highestResolutionFormatForCaptureDevice:_captureDevice]; if (bestFormat) { _videoCaptureSession.sessionPreset = AVCaptureSessionPresetInputPriority; @@ -551,14 +551,14 @@ - (BOOL)setCaptureSessionPreset:(FCPPlatformResolutionPreset)resolutionPreset /// Finds the highest available resolution in terms of pixel count for the given device. /// Preferred are formats with the same subtype as current activeFormat. -- (AVCaptureDeviceFormat *)highestResolutionFormatForCaptureDevice: +- (NSObject *)highestResolutionFormatForCaptureDevice: (NSObject *)captureDevice { FourCharCode preferredSubType = CMFormatDescriptionGetMediaSubType(_captureDevice.activeFormat.formatDescription); - AVCaptureDeviceFormat *bestFormat = nil; + NSObject *bestFormat = nil; NSUInteger maxPixelCount = 0; BOOL isBestSubTypePreferred = NO; - for (AVCaptureDeviceFormat *format in _captureDevice.formats) { + for (NSObject *format in _captureDevice.formats) { CMVideoDimensions res = self.videoDimensionsForFormat(format); NSUInteger height = res.height; NSUInteger width = res.width; diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCamConfiguration.m b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCamConfiguration.m index c9c2a7ca257..2feb4d2f3be 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCamConfiguration.m +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCamConfiguration.m @@ -23,7 +23,7 @@ - (instancetype)initWithMediaSettings:(FCPPlatformMediaSettings *)mediaSettings _captureDeviceFactory = captureDeviceFactory; _orientation = [[UIDevice currentDevice] orientation]; _deviceOrientationProvider = [[FLTDefaultDeviceOrientationProvider alloc] init]; - _videoDimensionsForFormat = ^CMVideoDimensions(AVCaptureDeviceFormat *format) { + _videoDimensionsForFormat = ^CMVideoDimensions(NSObject *format) { return CMVideoFormatDescriptionGetDimensions(format.formatDescription); }; _captureDeviceInputFactory = captureDeviceInputFactory; diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCaptureDevice.m b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCaptureDevice.m index d9badbfe94a..d531d5fe20b 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCaptureDevice.m +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCaptureDevice.m @@ -31,12 +31,16 @@ - (AVCaptureDevicePosition)position { } // Format/Configuration -- (AVCaptureDeviceFormat *)activeFormat { - return self.device.activeFormat; +- (NSObject *)activeFormat { + return [[FLTDefaultCaptureDeviceFormat alloc] initWithFormat:self.device.activeFormat]; } -- (NSArray *)formats { - return self.device.formats; +- (NSArray *> *)formats { + NSMutableArray> *wrappedFormats = [NSMutableArray arrayWithCapacity:self.device.formats.count]; + for (AVCaptureDeviceFormat *format in self.device.formats) { + [wrappedFormats addObject:[[FLTDefaultCaptureDeviceFormat alloc] initWithFormat:format]]; + } + return wrappedFormats; } - (void)setActiveFormat:(AVCaptureDeviceFormat *)format { diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCaptureDeviceFormat.m b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCaptureDeviceFormat.m new file mode 100644 index 00000000000..93ed080c30d --- /dev/null +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCaptureDeviceFormat.m @@ -0,0 +1,58 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "FLTCaptureDeviceFormat.h" + +@interface FLTDefaultFrameRateRange () +@property(nonatomic, strong) AVFrameRateRange *range; +@end + +@implementation FLTDefaultFrameRateRange + +- (instancetype)initWithRange:(AVFrameRateRange *)range { + self = [super init]; + if (self) { + _range = range; + } + return self; +} + +- (float)minFrameRate { + return _range.minFrameRate; +} + +- (float)maxFrameRate { + return _range.maxFrameRate; +} + +@end + +@interface FLTDefaultCaptureDeviceFormat () +@property(nonatomic, strong) AVCaptureDeviceFormat *format; +@end + +@implementation FLTDefaultCaptureDeviceFormat + +- (instancetype)initWithFormat:(AVCaptureDeviceFormat *)format { + self = [super init]; + if (self) { + _format = format; + } + return self; +} + +- (CMFormatDescriptionRef)formatDescription { + return _format.formatDescription; +} + +- (NSArray *> *)videoSupportedFrameRateRanges { + NSMutableArray> *ranges = [NSMutableArray arrayWithCapacity:_format.videoSupportedFrameRateRanges.count]; + for (AVFrameRateRange *range in _format.videoSupportedFrameRateRanges) { + FLTDefaultFrameRateRange *wrapper = [[FLTDefaultFrameRateRange alloc] initWithRange:range]; + [ranges addObject:wrapper]; + } + return ranges; +} + +@end diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/CameraPlugin.modulemap b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/CameraPlugin.modulemap index 394fba5d570..7bb58e16f23 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/CameraPlugin.modulemap +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/CameraPlugin.modulemap @@ -7,6 +7,7 @@ framework module camera_avfoundation { explicit module Test { header "FLTCameraDeviceDiscovering.h" header "FLTCaptureDevice.h" + header "FLTCaptureDeviceFormat.h" header "FLTCaptureSession.h" header "FLTDeviceOrientationProviding.h" header "FLTEventChannel.h" diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCamConfiguration.h b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCamConfiguration.h index 36393009b7a..148818b24d5 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCamConfiguration.h +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCamConfiguration.h @@ -22,7 +22,7 @@ typedef NSObject *_Nonnull (^CaptureSessionFactory)(void); /// Determines the video dimensions (width and height) for a given capture device format. /// Used in tests to mock CMVideoFormatDescriptionGetDimensions. -typedef CMVideoDimensions (^VideoDimensionsForFormat)(AVCaptureDeviceFormat *); +typedef CMVideoDimensions (^VideoDimensionsForFormat)(NSObject *); /// A configuration object that centralizes dependencies for `FLTCam`. @interface FLTCamConfiguration : NSObject diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCaptureDevice.h b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCaptureDevice.h index 09344600a86..6f5d6df0c20 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCaptureDevice.h +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCaptureDevice.h @@ -5,6 +5,8 @@ @import AVFoundation; @import Foundation; +#import "FLTCaptureDeviceFormat.h" + NS_ASSUME_NONNULL_BEGIN /// A protocol which is a direct passthrough to AVCaptureDevice. @@ -23,9 +25,9 @@ NS_ASSUME_NONNULL_BEGIN - (AVCaptureDevicePosition)position; // Format/Configuration -- (AVCaptureDeviceFormat *)activeFormat; -- (NSArray *)formats; -- (void)setActiveFormat:(AVCaptureDeviceFormat *)format; +- (NSObject *)activeFormat; +- (NSArray *> *)formats; +- (void)setActiveFormat:(NSObject *)format; // Flash/Torch - (BOOL)hasFlash; diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCaptureDeviceFormat.h b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCaptureDeviceFormat.h new file mode 100644 index 00000000000..6e82395b950 --- /dev/null +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCaptureDeviceFormat.h @@ -0,0 +1,49 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +@import AVFoundation; +@import Foundation; + +NS_ASSUME_NONNULL_BEGIN + +/// A protocol which is a direct passthrough to `FLTFrameRateRange`. It exists to allow replacing +/// `AVFrameRateRange` in tests as it has no public initializer. +@protocol FLTFrameRateRange + +@property(readonly, nonatomic) float minFrameRate; +@property(readonly, nonatomic) float maxFrameRate; + +@end + +/// A protocol which is a direct passthrough to `AVCaptureDeviceFormat`. It exists to allow replacing +/// `AVCaptureDeviceFormat` in tests as it has no public initializer. +@protocol FLTCaptureDeviceFormat + +/// The underlying `AVCaptureDeviceFormat` instance that this object wraps. +@property(nonatomic, readonly) AVCaptureDeviceFormat *format; + +@property(nonatomic, readonly) CMFormatDescriptionRef formatDescription; +@property(nonatomic, readonly) NSArray *> *videoSupportedFrameRateRanges; + +@end + +/// A default implementation of `FLTFrameRateRange` that wraps an `AVFrameRateRange` instance. +@interface FLTDefaultFrameRateRange : NSObject + +/// Initializes the object with an `AVFrameRateRange` instance. All method and property calls are +/// forwarded to this wrapped instance. +- (instancetype)initWithRange:(AVFrameRateRange *)range; + +@end + +/// A default implementation of `FLTCaptureDeviceFormat` that wraps an `AVCaptureDeviceFormat` instance. +@interface FLTDefaultCaptureDeviceFormat : NSObject + +/// Initializes the object with an `AVCaptureDeviceFormat` instance. All method and property calls are +/// forwarded to this wrapped instance. +- (instancetype)initWithFormat:(AVCaptureDeviceFormat *)format; + +@end + +NS_ASSUME_NONNULL_END From 8d35b3b85a203c2bef67aeb234b0f2209e29ce47 Mon Sep 17 00:00:00 2001 From: Marcin Chudy Date: Sat, 8 Feb 2025 20:35:04 +0100 Subject: [PATCH 2/6] Fix formatting --- .../ios/RunnerTests/CameraExposureTests.m | 6 +- .../ios/RunnerTests/CameraFocusTests.m | 6 +- .../RunnerTests/CameraMethodChannelTests.m | 4 +- .../RunnerTests/CameraSessionPresetsTests.m | 53 ++++++++-------- .../ios/RunnerTests/CameraSettingsTests.m | 34 ++++++----- .../example/ios/RunnerTests/CameraTestUtils.h | 3 +- .../example/ios/RunnerTests/CameraTestUtils.m | 60 ++++++++++--------- .../ios/RunnerTests/FLTCamPhotoCaptureTests.m | 6 +- .../Mocks/MockCaptureDeviceFormat.h | 3 +- .../example/ios/RunnerTests/StreamingTest.m | 4 +- .../Sources/camera_avfoundation/FLTCam.m | 3 +- .../camera_avfoundation/FLTCaptureDevice.m | 3 +- .../FLTCaptureDeviceFormat.m | 3 +- .../FLTCaptureDeviceFormat.h | 14 +++-- 14 files changed, 104 insertions(+), 98 deletions(-) diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraExposureTests.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraExposureTests.m index b93a13d48fc..2f0bc5db100 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraExposureTests.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraExposureTests.m @@ -22,11 +22,9 @@ - (void)setUp { MockCaptureDevice *mockDevice = [[MockCaptureDevice alloc] init]; _mockDeviceOrientationProvider = [[MockDeviceOrientationProvider alloc] init]; _mockDevice = mockDevice; - + FLTCamConfiguration *configuration = FLTCreateTestCameraConfiguration(); - configuration.captureDeviceFactory = ^NSObject * _Nonnull{ - return mockDevice; - }; + configuration.captureDeviceFactory = ^NSObject *_Nonnull { return mockDevice; }; configuration.deviceOrientationProvider = _mockDeviceOrientationProvider; _camera = FLTCreateCamWithConfiguration(configuration); } diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraFocusTests.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraFocusTests.m index 9ed475d7441..81008410811 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraFocusTests.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraFocusTests.m @@ -25,11 +25,9 @@ - (void)setUp { MockCaptureDevice *mockDevice = [[MockCaptureDevice alloc] init]; _mockDevice = mockDevice; _mockDeviceOrientationProvider = [[MockDeviceOrientationProvider alloc] init]; - + FLTCamConfiguration *configuration = FLTCreateTestCameraConfiguration(); - configuration.captureDeviceFactory = ^NSObject * _Nonnull{ - return mockDevice; - }; + configuration.captureDeviceFactory = ^NSObject *_Nonnull { return mockDevice; }; configuration.deviceOrientationProvider = _mockDeviceOrientationProvider; _camera = FLTCreateCamWithConfiguration(configuration); } diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraMethodChannelTests.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraMethodChannelTests.m index 539e830d3fc..1f084f5ba75 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraMethodChannelTests.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraMethodChannelTests.m @@ -38,7 +38,7 @@ - (CameraPlugin *)createCameraPluginWithSession:(MockCaptureSession *)mockSessio - (void)testCreate_ShouldCallResultOnMainThread { MockCaptureSession *avCaptureSessionMock = [[MockCaptureSession alloc] init]; avCaptureSessionMock.canSetSessionPreset = YES; - + CameraPlugin *camera = [self createCameraPluginWithSession:avCaptureSessionMock]; XCTestExpectation *expectation = [self expectationWithDescription:@"Result finished"]; @@ -67,7 +67,7 @@ - (void)testCreate_ShouldCallResultOnMainThread { - (void)testDisposeShouldDeallocCamera { MockCaptureSession *avCaptureSessionMock = [[MockCaptureSession alloc] init]; avCaptureSessionMock.canSetSessionPreset = YES; - + CameraPlugin *camera = [self createCameraPluginWithSession:avCaptureSessionMock]; XCTestExpectation *createExpectation = diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraSessionPresetsTests.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraSessionPresetsTests.m index 740176143f4..6540b872a2c 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraSessionPresetsTests.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraSessionPresetsTests.m @@ -9,7 +9,6 @@ @import AVFoundation; @import XCTest; -#import #import "CameraTestUtils.h" #import "MockCaptureDevice.h" @@ -25,7 +24,8 @@ @implementation FLTCamSessionPresetsTest - (void)testResolutionPresetWithBestFormat_mustUpdateCaptureSessionPreset { NSString *expectedPreset = AVCaptureSessionPresetInputPriority; XCTestExpectation *presetExpectation = [self expectationWithDescription:@"Expected preset set"]; - XCTestExpectation *lockForConfigurationExpectation = [self expectationWithDescription:@"Expected lockForConfiguration called"]; + XCTestExpectation *lockForConfigurationExpectation = + [self expectationWithDescription:@"Expected lockForConfiguration called"]; MockCaptureSession *videoSessionMock = [[MockCaptureSession alloc] init]; videoSessionMock.setSessionPresetStub = ^(NSString *preset) { @@ -33,31 +33,32 @@ - (void)testResolutionPresetWithBestFormat_mustUpdateCaptureSessionPreset { [presetExpectation fulfill]; } }; - + MockCaptureDeviceFormat *captureFormatMock = [[MockCaptureDeviceFormat alloc] init]; - - + MockCaptureDevice *captureDeviceMock = [[MockCaptureDevice alloc] init]; captureDeviceMock.formats = @[ captureFormatMock ]; captureDeviceMock.activeFormat = captureFormatMock; - captureDeviceMock.lockForConfigurationStub = ^BOOL(NSError *__autoreleasing _Nullable * _Nullable error) { - [lockForConfigurationExpectation fulfill]; - return YES; - }; - + captureDeviceMock.lockForConfigurationStub = + ^BOOL(NSError *__autoreleasing _Nullable *_Nullable error) { + [lockForConfigurationExpectation fulfill]; + return YES; + }; + FLTCamConfiguration *configuration = FLTCreateTestCameraConfiguration(); - configuration.captureDeviceFactory = ^NSObject * _Nonnull{ + configuration.captureDeviceFactory = ^NSObject *_Nonnull { return captureDeviceMock; }; - configuration.videoDimensionsForFormat = ^CMVideoDimensions(NSObject *format) { - CMVideoDimensions videoDimensions; - videoDimensions.width = 1; - videoDimensions.height = 1; - return videoDimensions; - }; + configuration.videoDimensionsForFormat = + ^CMVideoDimensions(NSObject *format) { + CMVideoDimensions videoDimensions; + videoDimensions.width = 1; + videoDimensions.height = 1; + return videoDimensions; + }; configuration.videoCaptureSession = videoSessionMock; configuration.mediaSettings = FCPGetDefaultMediaSettings(FCPPlatformResolutionPresetMax); - + FLTCreateCamWithConfiguration(configuration); [self waitForExpectationsWithTimeout:1 handler:nil]; @@ -66,18 +67,18 @@ - (void)testResolutionPresetWithBestFormat_mustUpdateCaptureSessionPreset { - (void)testResolutionPresetWithCanSetSessionPresetMax_mustUpdateCaptureSessionPreset { NSString *expectedPreset = AVCaptureSessionPreset3840x2160; XCTestExpectation *expectation = [self expectationWithDescription:@"Expected preset set"]; - + MockCaptureSession *videoSessionMock = [[MockCaptureSession alloc] init]; - + // Make sure that setting resolution preset for session always succeeds. videoSessionMock.canSetSessionPreset = YES; - + videoSessionMock.setSessionPresetStub = ^(NSString *preset) { if (preset == expectedPreset) { [expectation fulfill]; } }; - + FLTCamConfiguration *configuration = FLTCreateTestCameraConfiguration(); configuration.videoCaptureSession = videoSessionMock; configuration.mediaSettings = FCPGetDefaultMediaSettings(FCPPlatformResolutionPresetMax); @@ -93,9 +94,9 @@ - (void)testResolutionPresetWithCanSetSessionPresetMax_mustUpdateCaptureSessionP - (void)testResolutionPresetWithCanSetSessionPresetUltraHigh_mustUpdateCaptureSessionPreset { NSString *expectedPreset = AVCaptureSessionPreset3840x2160; XCTestExpectation *expectation = [self expectationWithDescription:@"Expected preset set"]; - + MockCaptureSession *videoSessionMock = [[MockCaptureSession alloc] init]; - + // Make sure that setting resolution preset for session always succeeds. videoSessionMock.canSetSessionPreset = YES; @@ -105,11 +106,11 @@ - (void)testResolutionPresetWithCanSetSessionPresetUltraHigh_mustUpdateCaptureSe [expectation fulfill]; } }; - + FLTCamConfiguration *configuration = FLTCreateTestCameraConfiguration(); configuration.videoCaptureSession = videoSessionMock; configuration.mediaSettings = FCPGetDefaultMediaSettings(FCPPlatformResolutionPresetUltraHigh); - + FLTCreateCamWithConfiguration(configuration); [self waitForExpectationsWithTimeout:1 handler:nil]; diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraSettingsTests.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraSettingsTests.m index 60aab003828..fb07cc3c9d8 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraSettingsTests.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraSettingsTests.m @@ -10,9 +10,9 @@ @import AVFoundation; #import "CameraTestUtils.h" +#import "MockCameraDeviceDiscoverer.h" #import "MockCaptureDevice.h" #import "MockCaptureSession.h" -#import "MockCameraDeviceDiscoverer.h" #import "MockFlutterBinaryMessenger.h" #import "MockFlutterTextureRegistry.h" #import "MockGlobalEventApi.h" @@ -148,12 +148,12 @@ - (void)testSettings_shouldPassConfigurationToCameraDeviceAndWriter { enableAudio:gTestEnableAudio]; TestMediaSettingsAVWrapper *injectedWrapper = [[TestMediaSettingsAVWrapper alloc] initWithTestCase:self]; - + FLTCamConfiguration *configuration = FLTCreateTestCameraConfiguration(); configuration.mediaSettingsWrapper = injectedWrapper; configuration.mediaSettings = settings; FLTCam *camera = FLTCreateCamWithConfiguration(configuration); - + // Expect FPS configuration is passed to camera device. [self waitForExpectations:@[ injectedWrapper.lockExpectation, injectedWrapper.beginConfigurationExpectation, @@ -178,18 +178,19 @@ - (void)testSettings_ShouldBeSupportedByMethodCall { MockCaptureDevice *mockDevice = [[MockCaptureDevice alloc] init]; MockCaptureSession *mockSession = [[MockCaptureSession alloc] init]; mockSession.canSetSessionPreset = YES; - - CameraPlugin *camera = [[CameraPlugin alloc] initWithRegistry:[[MockFlutterTextureRegistry alloc] init] - messenger:[[MockFlutterBinaryMessenger alloc] init] - globalAPI:[[MockGlobalEventApi alloc] init] - deviceDiscoverer:[[MockCameraDeviceDiscoverer alloc] init] - deviceFactory:^NSObject * (NSString *name) { - return mockDevice; - } - captureSessionFactory:^NSObject * _Nonnull{ - return mockSession; - } - captureDeviceInputFactory:[[MockCaptureDeviceInputFactory alloc] init]]; + + CameraPlugin *camera = + [[CameraPlugin alloc] initWithRegistry:[[MockFlutterTextureRegistry alloc] init] + messenger:[[MockFlutterBinaryMessenger alloc] init] + globalAPI:[[MockGlobalEventApi alloc] init] + deviceDiscoverer:[[MockCameraDeviceDiscoverer alloc] init] + deviceFactory:^NSObject *(NSString *name) { + return mockDevice; + } + captureSessionFactory:^NSObject *_Nonnull { + return mockSession; + } + captureDeviceInputFactory:[[MockCaptureDeviceInputFactory alloc] init]]; XCTestExpectation *expectation = [self expectationWithDescription:@"Result finished"]; @@ -227,7 +228,8 @@ - (void)testSettings_ShouldSelectFormatWhichSupports60FPS { configuration.mediaSettings = settings; FLTCam *camera = FLTCreateCamWithConfiguration(configuration); - NSObject *range = camera.captureDevice.activeFormat.videoSupportedFrameRateRanges[0]; + NSObject *range = + camera.captureDevice.activeFormat.videoSupportedFrameRateRanges[0]; XCTAssertLessThanOrEqual(range.minFrameRate, 60); XCTAssertGreaterThanOrEqual(range.maxFrameRate, 60); } diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraTestUtils.h b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraTestUtils.h index 421ef82fdf6..902e8e78fbc 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraTestUtils.h +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraTestUtils.h @@ -9,7 +9,8 @@ NS_ASSUME_NONNULL_BEGIN -extern FCPPlatformMediaSettings *FCPGetDefaultMediaSettings(FCPPlatformResolutionPreset resolutionPreset); +extern FCPPlatformMediaSettings *FCPGetDefaultMediaSettings( + FCPPlatformResolutionPreset resolutionPreset); /// Creates a test `FLTCamConfiguration` with a default mock setup. extern FLTCamConfiguration *FLTCreateTestCameraConfiguration(void); diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraTestUtils.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraTestUtils.m index 750e6118171..dbb247b5333 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraTestUtils.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraTestUtils.m @@ -13,8 +13,7 @@ #import "MockCaptureSession.h" #import "MockDeviceOrientationProvider.h" -FCPPlatformMediaSettings *FCPGetDefaultMediaSettings( - FCPPlatformResolutionPreset resolutionPreset) { +FCPPlatformMediaSettings *FCPGetDefaultMediaSettings(FCPPlatformResolutionPreset resolutionPreset) { return [FCPPlatformMediaSettings makeWithResolutionPreset:resolutionPreset framesPerSecond:nil videoBitrate:nil @@ -24,27 +23,29 @@ FLTCamConfiguration *FLTCreateTestCameraConfiguration(void) { dispatch_queue_t captureSessionQueue = dispatch_queue_create("capture_session_queue", NULL); - + MockCaptureSession *videoSessionMock = [[MockCaptureSession alloc] init]; videoSessionMock.canSetSessionPreset = YES; - + MockCaptureSession *audioSessionMock = [[MockCaptureSession alloc] init]; audioSessionMock.canSetSessionPreset = YES; - - MockFrameRateRange *frameRateRangeMock1 = [[MockFrameRateRange alloc] initWithMinFrameRate:3 maxFrameRate:30]; + + MockFrameRateRange *frameRateRangeMock1 = [[MockFrameRateRange alloc] initWithMinFrameRate:3 + maxFrameRate:30]; MockCaptureDeviceFormat *captureDeviceFormatMock1 = [[MockCaptureDeviceFormat alloc] init]; - captureDeviceFormatMock1.videoSupportedFrameRateRanges = @[frameRateRangeMock1]; - - MockFrameRateRange *frameRateRangeMock2 = [[MockFrameRateRange alloc] initWithMinFrameRate:3 maxFrameRate:60]; + captureDeviceFormatMock1.videoSupportedFrameRateRanges = @[ frameRateRangeMock1 ]; + + MockFrameRateRange *frameRateRangeMock2 = [[MockFrameRateRange alloc] initWithMinFrameRate:3 + maxFrameRate:60]; MockCaptureDeviceFormat *captureDeviceFormatMock2 = [[MockCaptureDeviceFormat alloc] init]; - captureDeviceFormatMock2.videoSupportedFrameRateRanges = @[frameRateRangeMock2]; - + captureDeviceFormatMock2.videoSupportedFrameRateRanges = @[ frameRateRangeMock2 ]; + MockCaptureDevice *captureDeviceMock = [[MockCaptureDevice alloc] init]; captureDeviceMock.lockForConfigurationStub = ^BOOL(NSError **error) { return YES; }; - captureDeviceMock.formats = @[captureDeviceFormatMock1, captureDeviceFormatMock2]; - + captureDeviceMock.formats = @[ captureDeviceFormatMock1, captureDeviceFormatMock2 ]; + __block NSObject *currentFormat = captureDeviceFormatMock1; captureDeviceMock.activeFormatStub = ^NSObject * { return currentFormat; @@ -52,21 +53,22 @@ captureDeviceMock.setActiveFormatStub = ^(NSObject *format) { currentFormat = format; }; - - FLTCamConfiguration *configuration = [[FLTCamConfiguration alloc] initWithMediaSettings:FCPGetDefaultMediaSettings(FCPPlatformResolutionPresetMedium) - mediaSettingsWrapper:[[FLTCamMediaSettingsAVWrapper alloc] init] - captureDeviceFactory:^NSObject *(void) { - return captureDeviceMock; - } - captureSessionFactory:^NSObject *_Nonnull { - return videoSessionMock; - } - captureSessionQueue:captureSessionQueue - captureDeviceInputFactory:[[MockCaptureDeviceInputFactory alloc] init]]; + + FLTCamConfiguration *configuration = [[FLTCamConfiguration alloc] + initWithMediaSettings:FCPGetDefaultMediaSettings(FCPPlatformResolutionPresetMedium) + mediaSettingsWrapper:[[FLTCamMediaSettingsAVWrapper alloc] init] + captureDeviceFactory:^NSObject *(void) { + return captureDeviceMock; + } + captureSessionFactory:^NSObject *_Nonnull { + return videoSessionMock; + } + captureSessionQueue:captureSessionQueue + captureDeviceInputFactory:[[MockCaptureDeviceInputFactory alloc] init]]; configuration.videoCaptureSession = videoSessionMock; configuration.audioCaptureSession = audioSessionMock; configuration.orientation = UIDeviceOrientationPortrait; - + return configuration; } @@ -76,15 +78,15 @@ return FLTCreateCamWithConfiguration(configuration); } - FLTCam *FLTCreateCamWithConfiguration(FLTCamConfiguration *configuration) { id captureVideoDataOutputMock = [OCMockObject niceMockForClass:[AVCaptureVideoDataOutput class]]; OCMStub([captureVideoDataOutputMock new]).andReturn(captureVideoDataOutputMock); OCMStub([captureVideoDataOutputMock recommendedVideoSettingsForAssetWriterWithOutputFileType:AVFileTypeMPEG4]) .andReturn(@{}); - OCMStub([captureVideoDataOutputMock sampleBufferCallbackQueue]).andReturn(configuration.captureSessionQueue); - + OCMStub([captureVideoDataOutputMock sampleBufferCallbackQueue]) + .andReturn(configuration.captureSessionQueue); + id videoMock = OCMClassMock([AVAssetWriterInputPixelBufferAdaptor class]); OCMStub([videoMock assetWriterInputPixelBufferAdaptorWithAssetWriterInput:OCMOCK_ANY sourcePixelBufferAttributes:OCMOCK_ANY]) @@ -98,7 +100,7 @@ OCMStub([writerInputMock assetWriterInputWithMediaType:AVMediaTypeVideo outputSettings:[OCMArg any]]) .andReturn(writerInputMock); - + return [[FLTCam alloc] initWithConfiguration:configuration error:nil]; } diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamPhotoCaptureTests.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamPhotoCaptureTests.m index 9df87a8a6ea..b3c4b2c1d97 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamPhotoCaptureTests.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamPhotoCaptureTests.m @@ -192,12 +192,10 @@ - (void)testCaptureToFile_handlesTorchMode { dispatch_queue_t captureSessionQueue = dispatch_queue_create("capture_session_queue", NULL); dispatch_queue_set_specific(captureSessionQueue, FLTCaptureSessionQueueSpecific, (void *)FLTCaptureSessionQueueSpecific, NULL); - + FLTCamConfiguration *configuration = FLTCreateTestCameraConfiguration(); configuration.captureSessionQueue = captureSessionQueue; - configuration.captureDeviceFactory = ^NSObject *{ - return captureDeviceMock; - }; + configuration.captureDeviceFactory = ^NSObject * { return captureDeviceMock; }; FLTCam *cam = FLTCreateCamWithConfiguration(configuration); AVCapturePhotoSettings *settings = [AVCapturePhotoSettings photoSettings]; diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDeviceFormat.h b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDeviceFormat.h index 0436de9da48..4e4a0221ad0 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDeviceFormat.h +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDeviceFormat.h @@ -10,7 +10,8 @@ NS_ASSUME_NONNULL_BEGIN -/// A mock implementation of `FLTDeviceOrientationProviding` that allows mocking the class properties. +/// A mock implementation of `FLTDeviceOrientationProviding` that allows mocking the class +/// properties. @interface MockCaptureDeviceFormat : NSObject /// Initializes a `MockCaptureDeviceFormat` with the given dimensions. diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/StreamingTest.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/StreamingTest.m index 0b73f757bcd..1f192a37693 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/StreamingTest.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/StreamingTest.m @@ -20,9 +20,9 @@ @implementation StreamingTests - (void)setUp { dispatch_queue_t captureSessionQueue = dispatch_queue_create("testing", NULL); - FLTCamConfiguration *configuration = FLTCreateTestCameraConfiguration(); + FLTCamConfiguration *configuration = FLTCreateTestCameraConfiguration(); configuration.captureSessionQueue = captureSessionQueue; - + _camera = FLTCreateCamWithConfiguration(configuration); _sampleBuffer = FLTCreateTestSampleBuffer(); } diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m index 6d8272c90ef..d12fd4a052b 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m @@ -119,7 +119,8 @@ @implementation FLTCam NSString *const errorMethod = @"error"; // Returns frame rate supported by format closest to targetFrameRate. -static double bestFrameRateForFormat(NSObject *format, double targetFrameRate) { +static double bestFrameRateForFormat(NSObject *format, + double targetFrameRate) { double bestFrameRate = 0; double minDistance = DBL_MAX; for (NSObject *range in format.videoSupportedFrameRateRanges) { diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCaptureDevice.m b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCaptureDevice.m index d531d5fe20b..f142a49dc4f 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCaptureDevice.m +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCaptureDevice.m @@ -36,7 +36,8 @@ - (AVCaptureDevicePosition)position { } - (NSArray *> *)formats { - NSMutableArray> *wrappedFormats = [NSMutableArray arrayWithCapacity:self.device.formats.count]; + NSMutableArray> *wrappedFormats = + [NSMutableArray arrayWithCapacity:self.device.formats.count]; for (AVCaptureDeviceFormat *format in self.device.formats) { [wrappedFormats addObject:[[FLTDefaultCaptureDeviceFormat alloc] initWithFormat:format]]; } diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCaptureDeviceFormat.m b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCaptureDeviceFormat.m index 93ed080c30d..2882c500c32 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCaptureDeviceFormat.m +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCaptureDeviceFormat.m @@ -47,7 +47,8 @@ - (CMFormatDescriptionRef)formatDescription { } - (NSArray *> *)videoSupportedFrameRateRanges { - NSMutableArray> *ranges = [NSMutableArray arrayWithCapacity:_format.videoSupportedFrameRateRanges.count]; + NSMutableArray> *ranges = + [NSMutableArray arrayWithCapacity:_format.videoSupportedFrameRateRanges.count]; for (AVFrameRateRange *range in _format.videoSupportedFrameRateRanges) { FLTDefaultFrameRateRange *wrapper = [[FLTDefaultFrameRateRange alloc] initWithRange:range]; [ranges addObject:wrapper]; diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCaptureDeviceFormat.h b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCaptureDeviceFormat.h index 6e82395b950..4b8ecb58365 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCaptureDeviceFormat.h +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCaptureDeviceFormat.h @@ -16,15 +16,16 @@ NS_ASSUME_NONNULL_BEGIN @end -/// A protocol which is a direct passthrough to `AVCaptureDeviceFormat`. It exists to allow replacing -/// `AVCaptureDeviceFormat` in tests as it has no public initializer. +/// A protocol which is a direct passthrough to `AVCaptureDeviceFormat`. It exists to allow +/// replacing `AVCaptureDeviceFormat` in tests as it has no public initializer. @protocol FLTCaptureDeviceFormat /// The underlying `AVCaptureDeviceFormat` instance that this object wraps. @property(nonatomic, readonly) AVCaptureDeviceFormat *format; @property(nonatomic, readonly) CMFormatDescriptionRef formatDescription; -@property(nonatomic, readonly) NSArray *> *videoSupportedFrameRateRanges; +@property(nonatomic, readonly) + NSArray *> *videoSupportedFrameRateRanges; @end @@ -37,11 +38,12 @@ NS_ASSUME_NONNULL_BEGIN @end -/// A default implementation of `FLTCaptureDeviceFormat` that wraps an `AVCaptureDeviceFormat` instance. +/// A default implementation of `FLTCaptureDeviceFormat` that wraps an `AVCaptureDeviceFormat` +/// instance. @interface FLTDefaultCaptureDeviceFormat : NSObject -/// Initializes the object with an `AVCaptureDeviceFormat` instance. All method and property calls are -/// forwarded to this wrapped instance. +/// Initializes the object with an `AVCaptureDeviceFormat` instance. All method and property calls +/// are forwarded to this wrapped instance. - (instancetype)initWithFormat:(AVCaptureDeviceFormat *)format; @end From 46e31f028333bd5e3f846a8bcd2be237dcd45376 Mon Sep 17 00:00:00 2001 From: Marcin Chudy Date: Sat, 8 Feb 2025 20:45:53 +0100 Subject: [PATCH 3/6] Update version --- packages/camera/camera_avfoundation/CHANGELOG.md | 4 ++++ packages/camera/camera_avfoundation/pubspec.yaml | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/camera/camera_avfoundation/CHANGELOG.md b/packages/camera/camera_avfoundation/CHANGELOG.md index 86f432a2933..8d778252f63 100644 --- a/packages/camera/camera_avfoundation/CHANGELOG.md +++ b/packages/camera/camera_avfoundation/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.9.18+3 + +* Refactors implementations to reduce usage of OCMock in internal testing. + ## 0.9.18+2 * Refactors implementations to reduce usage of OCMock in internal testing. diff --git a/packages/camera/camera_avfoundation/pubspec.yaml b/packages/camera/camera_avfoundation/pubspec.yaml index 2c5c86e5b29..58387148653 100644 --- a/packages/camera/camera_avfoundation/pubspec.yaml +++ b/packages/camera/camera_avfoundation/pubspec.yaml @@ -2,7 +2,7 @@ name: camera_avfoundation description: iOS implementation of the camera plugin. repository: https://github.com/flutter/packages/tree/main/packages/camera/camera_avfoundation issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+camera%22 -version: 0.9.18+2 +version: 0.9.18+3 environment: sdk: ^3.4.0 From dc8e41f3b711f561199e13dfa600dd84af9d6513 Mon Sep 17 00:00:00 2001 From: Marcin Chudy Date: Mon, 10 Feb 2025 15:33:32 +0100 Subject: [PATCH 4/6] Update version --- packages/camera/camera_avfoundation/CHANGELOG.md | 4 ++++ packages/camera/camera_avfoundation/pubspec.yaml | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/camera/camera_avfoundation/CHANGELOG.md b/packages/camera/camera_avfoundation/CHANGELOG.md index 8d778252f63..2388f101e24 100644 --- a/packages/camera/camera_avfoundation/CHANGELOG.md +++ b/packages/camera/camera_avfoundation/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.9.18+4 + +* Refactors implementations to reduce usage of OCMock in internal testing. + ## 0.9.18+3 * Refactors implementations to reduce usage of OCMock in internal testing. diff --git a/packages/camera/camera_avfoundation/pubspec.yaml b/packages/camera/camera_avfoundation/pubspec.yaml index 58387148653..56cd44cc6ac 100644 --- a/packages/camera/camera_avfoundation/pubspec.yaml +++ b/packages/camera/camera_avfoundation/pubspec.yaml @@ -2,7 +2,7 @@ name: camera_avfoundation description: iOS implementation of the camera plugin. repository: https://github.com/flutter/packages/tree/main/packages/camera/camera_avfoundation issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+camera%22 -version: 0.9.18+3 +version: 0.9.18+4 environment: sdk: ^3.4.0 From 35966a1f21d70bde4fe7f19527213291baaeec18 Mon Sep 17 00:00:00 2001 From: Marcin Chudy Date: Mon, 10 Feb 2025 17:47:29 +0100 Subject: [PATCH 5/6] Improve docs --- .../example/ios/RunnerTests/CameraTestUtils.h | 2 ++ .../example/ios/RunnerTests/Mocks/MockCaptureDevice.h | 1 + 2 files changed, 3 insertions(+) diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraTestUtils.h b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraTestUtils.h index 902e8e78fbc..a44e3aedcd0 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraTestUtils.h +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraTestUtils.h @@ -9,6 +9,8 @@ NS_ASSUME_NONNULL_BEGIN +/// 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. extern FCPPlatformMediaSettings *FCPGetDefaultMediaSettings( FCPPlatformResolutionPreset resolutionPreset); diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDevice.h b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDevice.h index ab8de0d3252..b7e803d37d0 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDevice.h +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDevice.h @@ -19,6 +19,7 @@ NS_ASSUME_NONNULL_BEGIN // Format/Configuration @property(nonatomic, strong) NSArray *> *formats; +/// Overrides the default implementation of getting the active format. @property(nonatomic, copy) NSObject * (^activeFormatStub)(void); /// Overrides the default implementation of setting active format. /// @param format The format being set From 80ad336497ff69325a741e54885248b4b1a15953 Mon Sep 17 00:00:00 2001 From: Marcin Chudy Date: Mon, 10 Feb 2025 17:52:28 +0100 Subject: [PATCH 6/6] Change expectation timeouts from 1s to 30s --- .../ios/RunnerTests/CameraExposureTests.m | 4 ++-- .../ios/RunnerTests/CameraFocusTests.m | 2 +- .../ios/RunnerTests/CameraOrientationTests.m | 2 +- .../ios/RunnerTests/CameraPermissionTests.m | 20 +++++++++---------- .../RunnerTests/CameraSessionPresetsTests.m | 6 +++--- .../ios/RunnerTests/FLTCamPhotoCaptureTests.m | 10 +++++----- .../RunnerTests/FLTSavePhotoDelegateTests.m | 8 ++++---- .../example/ios/RunnerTests/QueueUtilsTests.m | 4 ++-- .../example/ios/RunnerTests/StreamingTest.m | 4 ++-- .../RunnerTests/ThreadSafeEventChannelTests.m | 6 +++--- 10 files changed, 33 insertions(+), 33 deletions(-) diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraExposureTests.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraExposureTests.m index 2f0bc5db100..8b6b7964f9f 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraExposureTests.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraExposureTests.m @@ -51,7 +51,7 @@ - (void)testSetExposurePointWithResult_SetsExposurePointOfInterest { [completionExpectation fulfill]; }]; - [self waitForExpectationsWithTimeout:1 handler:nil]; + [self waitForExpectationsWithTimeout:30 handler:nil]; XCTAssertEqual(setPoint.x, 1.0); XCTAssertEqual(setPoint.y, 1.0); } @@ -75,7 +75,7 @@ - (void)testSetExposurePoint_WhenNotSupported_ReturnsError { }]; // Verify - [self waitForExpectationsWithTimeout:1 handler:nil]; + [self waitForExpectationsWithTimeout:30 handler:nil]; } @end diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraFocusTests.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraFocusTests.m index 81008410811..fab96850a3a 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraFocusTests.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraFocusTests.m @@ -173,7 +173,7 @@ - (void)testSetFocusPoint_WhenNotSupported_ReturnsError { }]; // Verify - [self waitForExpectationsWithTimeout:1 handler:nil]; + [self waitForExpectationsWithTimeout:30 handler:nil]; } @end diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraOrientationTests.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraOrientationTests.m index 09f57551f0f..9f988c2cdfd 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraOrientationTests.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraOrientationTests.m @@ -139,7 +139,7 @@ - (void)testOrientationUpdateMustBeOnCaptureSessionQueue { [plugin orientationChanged: [self createMockNotificationForOrientation:UIDeviceOrientationLandscapeLeft]]; - [self waitForExpectationsWithTimeout:1 handler:nil]; + [self waitForExpectationsWithTimeout:30 handler:nil]; } - (void)testOrientationChanged_noRetainCycle { diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraPermissionTests.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraPermissionTests.m index ec753038102..095b0453298 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraPermissionTests.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraPermissionTests.m @@ -60,7 +60,7 @@ - (void)testRequestCameraPermission_completeWithoutErrorIfPreviouslyAuthorized { [expectation fulfill]; } }]; - [self waitForExpectationsWithTimeout:1 handler:nil]; + [self waitForExpectationsWithTimeout:30 handler:nil]; } - (void)testRequestCameraPermission_completeWithErrorIfPreviouslyDenied { XCTestExpectation *expectation = @@ -82,7 +82,7 @@ - (void)testRequestCameraPermission_completeWithErrorIfPreviouslyDenied { [expectation fulfill]; } }]; - [self waitForExpectationsWithTimeout:1 handler:nil]; + [self waitForExpectationsWithTimeout:30 handler:nil]; } - (void)testRequestCameraPermission_completeWithErrorIfRestricted { @@ -102,7 +102,7 @@ - (void)testRequestCameraPermission_completeWithErrorIfRestricted { [expectation fulfill]; } }]; - [self waitForExpectationsWithTimeout:1 handler:nil]; + [self waitForExpectationsWithTimeout:30 handler:nil]; } - (void)testRequestCameraPermission_completeWithoutErrorIfUserGrantAccess { @@ -125,7 +125,7 @@ - (void)testRequestCameraPermission_completeWithoutErrorIfUserGrantAccess { [grantedExpectation fulfill]; } }]; - [self waitForExpectationsWithTimeout:1 handler:nil]; + [self waitForExpectationsWithTimeout:30 handler:nil]; } - (void)testRequestCameraPermission_completeWithErrorIfUserDenyAccess { @@ -153,7 +153,7 @@ - (void)testRequestCameraPermission_completeWithErrorIfUserDenyAccess { } }]; - [self waitForExpectationsWithTimeout:1 handler:nil]; + [self waitForExpectationsWithTimeout:30 handler:nil]; } #pragma mark - audio permissions @@ -173,7 +173,7 @@ - (void)testRequestAudioPermission_completeWithoutErrorIfPrevoiuslyAuthorized { [expectation fulfill]; } }]; - [self waitForExpectationsWithTimeout:1 handler:nil]; + [self waitForExpectationsWithTimeout:30 handler:nil]; } - (void)testRequestAudioPermission_completeWithErrorIfPreviouslyDenied { @@ -196,7 +196,7 @@ - (void)testRequestAudioPermission_completeWithErrorIfPreviouslyDenied { [expectation fulfill]; } }]; - [self waitForExpectationsWithTimeout:1 handler:nil]; + [self waitForExpectationsWithTimeout:30 handler:nil]; } - (void)testRequestAudioPermission_completeWithErrorIfRestricted { @@ -216,7 +216,7 @@ - (void)testRequestAudioPermission_completeWithErrorIfRestricted { [expectation fulfill]; } }]; - [self waitForExpectationsWithTimeout:1 handler:nil]; + [self waitForExpectationsWithTimeout:30 handler:nil]; } - (void)testRequestAudioPermission_completeWithoutErrorIfUserGrantAccess { @@ -239,7 +239,7 @@ - (void)testRequestAudioPermission_completeWithoutErrorIfUserGrantAccess { [grantedExpectation fulfill]; } }]; - [self waitForExpectationsWithTimeout:1 handler:nil]; + [self waitForExpectationsWithTimeout:30 handler:nil]; } - (void)testRequestAudioPermission_completeWithErrorIfUserDenyAccess { @@ -265,7 +265,7 @@ - (void)testRequestAudioPermission_completeWithErrorIfUserDenyAccess { [expectation fulfill]; } }]; - [self waitForExpectationsWithTimeout:1 handler:nil]; + [self waitForExpectationsWithTimeout:30 handler:nil]; } @end diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraSessionPresetsTests.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraSessionPresetsTests.m index 6540b872a2c..14b4f2e9bcc 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraSessionPresetsTests.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraSessionPresetsTests.m @@ -61,7 +61,7 @@ - (void)testResolutionPresetWithBestFormat_mustUpdateCaptureSessionPreset { FLTCreateCamWithConfiguration(configuration); - [self waitForExpectationsWithTimeout:1 handler:nil]; + [self waitForExpectationsWithTimeout:30 handler:nil]; } - (void)testResolutionPresetWithCanSetSessionPresetMax_mustUpdateCaptureSessionPreset { @@ -88,7 +88,7 @@ - (void)testResolutionPresetWithCanSetSessionPresetMax_mustUpdateCaptureSessionP FLTCreateCamWithConfiguration(configuration); - [self waitForExpectationsWithTimeout:1 handler:nil]; + [self waitForExpectationsWithTimeout:30 handler:nil]; } - (void)testResolutionPresetWithCanSetSessionPresetUltraHigh_mustUpdateCaptureSessionPreset { @@ -113,7 +113,7 @@ - (void)testResolutionPresetWithCanSetSessionPresetUltraHigh_mustUpdateCaptureSe FLTCreateCamWithConfiguration(configuration); - [self waitForExpectationsWithTimeout:1 handler:nil]; + [self waitForExpectationsWithTimeout:30 handler:nil]; } @end diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamPhotoCaptureTests.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamPhotoCaptureTests.m index 21513627749..425481d263d 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamPhotoCaptureTests.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamPhotoCaptureTests.m @@ -59,7 +59,7 @@ - (void)testCaptureToFile_mustReportErrorToResultIfSavePhotoDelegateCompletionsW }]; }); - [self waitForExpectationsWithTimeout:1 handler:nil]; + [self waitForExpectationsWithTimeout:30 handler:nil]; } - (void)testCaptureToFile_mustReportPathToResultIfSavePhotoDelegateCompletionsWithPath { @@ -93,7 +93,7 @@ - (void)testCaptureToFile_mustReportPathToResultIfSavePhotoDelegateCompletionsWi [pathExpectation fulfill]; }]; }); - [self waitForExpectationsWithTimeout:1 handler:nil]; + [self waitForExpectationsWithTimeout:30 handler:nil]; } - (void)testCaptureToFile_mustReportFileExtensionWithHeifWhenHEVCIsAvailableAndFileFormatIsHEIF { @@ -126,7 +126,7 @@ - (void)testCaptureToFile_mustReportFileExtensionWithHeifWhenHEVCIsAvailableAndF [expectation fulfill]; }]; }); - [self waitForExpectationsWithTimeout:1 handler:nil]; + [self waitForExpectationsWithTimeout:30 handler:nil]; } - (void)testCaptureToFile_mustReportFileExtensionWithJpgWhenHEVCNotAvailableAndFileFormatIsHEIF { @@ -158,7 +158,7 @@ - (void)testCaptureToFile_mustReportFileExtensionWithJpgWhenHEVCNotAvailableAndF [expectation fulfill]; }]; }); - [self waitForExpectationsWithTimeout:1 handler:nil]; + [self waitForExpectationsWithTimeout:30 handler:nil]; } - (void)testCaptureToFile_handlesTorchMode { @@ -211,6 +211,6 @@ - (void)testCaptureToFile_handlesTorchMode { [pathExpectation fulfill]; }]; }); - [self waitForExpectationsWithTimeout:1 handler:nil]; + [self waitForExpectationsWithTimeout:30 handler:nil]; } @end diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTSavePhotoDelegateTests.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTSavePhotoDelegateTests.m index 2b22ce1bb69..94354df696b 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTSavePhotoDelegateTests.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTSavePhotoDelegateTests.m @@ -36,7 +36,7 @@ - (void)testHandlePhotoCaptureResult_mustCompleteWithErrorIfFailedToCapture { photoDataProvider:^NSData * { return nil; }]; - [self waitForExpectationsWithTimeout:1 handler:nil]; + [self waitForExpectationsWithTimeout:30 handler:nil]; } - (void)testHandlePhotoCaptureResult_mustCompleteWithErrorIfFailedToWrite { @@ -67,7 +67,7 @@ - (void)testHandlePhotoCaptureResult_mustCompleteWithErrorIfFailedToWrite { photoDataProvider:^NSObject * { return mockWritableData; }]; - [self waitForExpectationsWithTimeout:1 handler:nil]; + [self waitForExpectationsWithTimeout:30 handler:nil]; } - (void)testHandlePhotoCaptureResult_mustCompleteWithFilePathIfSuccessToWrite { @@ -95,7 +95,7 @@ - (void)testHandlePhotoCaptureResult_mustCompleteWithFilePathIfSuccessToWrite { photoDataProvider:^NSObject * { return mockWritableData; }]; - [self waitForExpectationsWithTimeout:1 handler:nil]; + [self waitForExpectationsWithTimeout:30 handler:nil]; } - (void)testHandlePhotoCaptureResult_bothProvideDataAndSaveFileMustRunOnIOQueue { @@ -135,7 +135,7 @@ - (void)testHandlePhotoCaptureResult_bothProvideDataAndSaveFileMustRunOnIOQueue return mockWritableData; }]; - [self waitForExpectationsWithTimeout:1 handler:nil]; + [self waitForExpectationsWithTimeout:30 handler:nil]; } @end diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/QueueUtilsTests.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/QueueUtilsTests.m index 57b508093d9..8bcf5045787 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/QueueUtilsTests.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/QueueUtilsTests.m @@ -22,7 +22,7 @@ - (void)testShouldStayOnMainQueueIfCalledFromMainQueue { [expectation fulfill]; } }); - [self waitForExpectationsWithTimeout:1 handler:nil]; + [self waitForExpectationsWithTimeout:30 handler:nil]; } - (void)testShouldDispatchToMainQueueIfCalledFromBackgroundQueue { @@ -35,7 +35,7 @@ - (void)testShouldDispatchToMainQueueIfCalledFromBackgroundQueue { } }); }); - [self waitForExpectationsWithTimeout:1 handler:nil]; + [self waitForExpectationsWithTimeout:30 handler:nil]; } @end diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/StreamingTest.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/StreamingTest.m index 7574976b3cc..a3786b2079d 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/StreamingTest.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/StreamingTest.m @@ -72,7 +72,7 @@ - (void)testExceedMaxStreamingPendingFramesCount { [_camera captureOutput:nil didOutputSampleBuffer:self.sampleBuffer fromConnection:nil]; } - [self waitForExpectationsWithTimeout:1.0 handler:nil]; + [self waitForExpectationsWithTimeout:30 handler:nil]; } - (void)testReceivedImageStreamData { @@ -102,7 +102,7 @@ - (void)testReceivedImageStreamData { [_camera receivedImageStreamData]; [_camera captureOutput:nil didOutputSampleBuffer:self.sampleBuffer fromConnection:nil]; - [self waitForExpectationsWithTimeout:1.0 handler:nil]; + [self waitForExpectationsWithTimeout:30 handler:nil]; } @end diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/ThreadSafeEventChannelTests.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/ThreadSafeEventChannelTests.m index 64450207266..7c845892d55 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/ThreadSafeEventChannelTests.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/ThreadSafeEventChannelTests.m @@ -39,7 +39,7 @@ - (void)testSetStreamHandler_shouldStayOnMainThreadIfCalledFromMainThread { [mainThreadCompletionExpectation fulfill]; } }]; - [self waitForExpectationsWithTimeout:1 handler:nil]; + [self waitForExpectationsWithTimeout:30 handler:nil]; } - (void)testSetStreamHandler_shouldDispatchToMainThreadIfCalledFromBackgroundThread { @@ -67,7 +67,7 @@ - (void)testSetStreamHandler_shouldDispatchToMainThreadIfCalledFromBackgroundThr } }]; }); - [self waitForExpectationsWithTimeout:1 handler:nil]; + [self waitForExpectationsWithTimeout:30 handler:nil]; } - (void)testEventChannel_shouldBeKeptAliveWhenDispatchingBackToMainThread { @@ -86,7 +86,7 @@ - (void)testEventChannel_shouldBeKeptAliveWhenDispatchingBackToMainThread { }]; }); - [self waitForExpectationsWithTimeout:1 handler:nil]; + [self waitForExpectationsWithTimeout:30 handler:nil]; } @end