Skip to content

Commit 73857c6

Browse files
authored
[camera] Remove OCMock from CameraExposureTests and CameraFocusTests (#8351)
Extracted from #8342 to keep PRs smaller - Introduces `FLTDeviceOrientationProviding` and `FLTCaptureDeviceControlling` protocols - Removes `OCMock.h` reference from `CameraExposureTests.h` and `CameraFocusTests.h`
1 parent 3d28a90 commit 73857c6

25 files changed

+857
-148
lines changed

packages/camera/camera_avfoundation/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 0.9.18+1
2+
3+
* Refactors implementations to reduce usage of OCMock in internal testing.
4+
15
## 0.9.18
26

37
* Adds API support query for image streaming.

packages/camera/camera_avfoundation/example/ios/Runner.xcodeproj/project.pbxproj

Lines changed: 62 additions & 23 deletions
Large diffs are not rendered by default.

packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraExposureTests.m

Lines changed: 55 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -5,51 +5,79 @@
55
@import camera_avfoundation;
66
@import XCTest;
77
@import AVFoundation;
8-
#import <OCMock/OCMock.h>
98

10-
@interface FLTCam : NSObject <FlutterTexture,
11-
AVCaptureVideoDataOutputSampleBufferDelegate,
12-
AVCaptureAudioDataOutputSampleBufferDelegate>
13-
14-
- (void)setExposurePointWithResult:(FlutterResult)result x:(double)x y:(double)y;
15-
@end
9+
#import "CameraTestUtils.h"
10+
#import "MockCaptureDeviceController.h"
11+
#import "MockDeviceOrientationProvider.h"
1612

1713
@interface CameraExposureTests : XCTestCase
1814
@property(readonly, nonatomic) FLTCam *camera;
19-
@property(readonly, nonatomic) id mockDevice;
20-
@property(readonly, nonatomic) id mockUIDevice;
15+
@property(readonly, nonatomic) MockCaptureDeviceController *mockDevice;
16+
@property(readonly, nonatomic) MockDeviceOrientationProvider *mockDeviceOrientationProvider;
2117
@end
2218

2319
@implementation CameraExposureTests
2420

2521
- (void)setUp {
26-
_camera = [[FLTCam alloc] init];
27-
_mockDevice = OCMClassMock([AVCaptureDevice class]);
28-
_mockUIDevice = OCMPartialMock([UIDevice currentDevice]);
29-
}
22+
MockCaptureDeviceController *mockDevice = [[MockCaptureDeviceController alloc] init];
23+
_mockDeviceOrientationProvider = [[MockDeviceOrientationProvider alloc] init];
24+
_mockDevice = mockDevice;
3025

31-
- (void)tearDown {
32-
[_mockDevice stopMocking];
33-
[_mockUIDevice stopMocking];
26+
_camera = FLTCreateCamWithCaptureSessionQueueAndMediaSettings(
27+
nil, nil, nil,
28+
^id<FLTCaptureDeviceControlling>(void) {
29+
return mockDevice;
30+
},
31+
_mockDeviceOrientationProvider);
3432
}
3533

36-
- (void)testSetExpsourePointWithResult_SetsExposurePointOfInterest {
34+
- (void)testSetExposurePointWithResult_SetsExposurePointOfInterest {
3735
// UI is currently in landscape left orientation
38-
OCMStub([(UIDevice *)_mockUIDevice orientation]).andReturn(UIDeviceOrientationLandscapeLeft);
36+
_mockDeviceOrientationProvider.orientation = UIDeviceOrientationLandscapeLeft;
3937
// Exposure point of interest is supported
40-
OCMStub([_mockDevice isExposurePointOfInterestSupported]).andReturn(true);
41-
// Set mock device as the current capture device
42-
[_camera setValue:_mockDevice forKey:@"captureDevice"];
38+
_mockDevice.exposurePointOfInterestSupported = YES;
39+
40+
// Verify the focus point of interest has been set
41+
__block CGPoint setPoint = CGPointZero;
42+
_mockDevice.setExposurePointOfInterestStub = ^(CGPoint point) {
43+
if (CGPointEqualToPoint(CGPointMake(1, 1), point)) {
44+
setPoint = point;
45+
}
46+
};
4347

4448
// Run test
49+
XCTestExpectation *completionExpectation = [self expectationWithDescription:@"Completion called"];
50+
[_camera setExposurePoint:[FCPPlatformPoint makeWithX:1 y:1]
51+
withCompletion:^(FlutterError *_Nullable error) {
52+
XCTAssertNil(error);
53+
[completionExpectation fulfill];
54+
}];
55+
56+
[self waitForExpectationsWithTimeout:1 handler:nil];
57+
XCTAssertEqual(setPoint.x, 1.0);
58+
XCTAssertEqual(setPoint.y, 1.0);
59+
}
60+
61+
- (void)testSetExposurePoint_WhenNotSupported_ReturnsError {
62+
// UI is currently in landscape left orientation
63+
_mockDeviceOrientationProvider.orientation = UIDeviceOrientationLandscapeLeft;
64+
// Exposure point of interest is not supported
65+
_mockDevice.exposurePointOfInterestSupported = NO;
66+
67+
XCTestExpectation *expectation = [self expectationWithDescription:@"Completion with error"];
68+
69+
// Run
4570
[_camera
46-
setExposurePointWithResult:^void(id _Nullable result) {
47-
}
48-
x:1
49-
y:1];
71+
setExposurePoint:[FCPPlatformPoint makeWithX:1 y:1]
72+
withCompletion:^(FlutterError *_Nullable error) {
73+
XCTAssertNotNil(error);
74+
XCTAssertEqualObjects(error.code, @"setExposurePointFailed");
75+
XCTAssertEqualObjects(error.message, @"Device does not have exposure point capabilities");
76+
[expectation fulfill];
77+
}];
5078

51-
// Verify the focus point of interest has been set
52-
OCMVerify([_mockDevice setExposurePointOfInterest:CGPointMake(1, 1)]);
79+
// Verify
80+
[self waitForExpectationsWithTimeout:1 handler:nil];
5381
}
5482

5583
@end

packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraFocusTests.m

Lines changed: 106 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -8,120 +8,174 @@
88
#endif
99
@import XCTest;
1010
@import AVFoundation;
11-
#import <OCMock/OCMock.h>
11+
12+
#import "CameraTestUtils.h"
13+
#import "MockCaptureDeviceController.h"
14+
#import "MockDeviceOrientationProvider.h"
1215

1316
@interface CameraFocusTests : XCTestCase
1417
@property(readonly, nonatomic) FLTCam *camera;
15-
@property(readonly, nonatomic) id mockDevice;
16-
@property(readonly, nonatomic) id mockUIDevice;
18+
@property(readonly, nonatomic) MockCaptureDeviceController *mockDevice;
19+
@property(readonly, nonatomic) MockDeviceOrientationProvider *mockDeviceOrientationProvider;
1720
@end
1821

1922
@implementation CameraFocusTests
2023

2124
- (void)setUp {
22-
_camera = [[FLTCam alloc] init];
23-
_mockDevice = OCMClassMock([AVCaptureDevice class]);
24-
_mockUIDevice = OCMPartialMock([UIDevice currentDevice]);
25-
}
26-
27-
- (void)tearDown {
28-
[_mockDevice stopMocking];
29-
[_mockUIDevice stopMocking];
25+
MockCaptureDeviceController *mockDevice = [[MockCaptureDeviceController alloc] init];
26+
_mockDevice = mockDevice;
27+
_mockDeviceOrientationProvider = [[MockDeviceOrientationProvider alloc] init];
28+
29+
_camera = FLTCreateCamWithCaptureSessionQueueAndMediaSettings(
30+
nil, nil, nil,
31+
^id<FLTCaptureDeviceControlling>(void) {
32+
return mockDevice;
33+
},
34+
_mockDeviceOrientationProvider);
3035
}
3136

3237
- (void)testAutoFocusWithContinuousModeSupported_ShouldSetContinuousAutoFocus {
33-
// AVCaptureFocusModeContinuousAutoFocus is supported
34-
OCMStub([_mockDevice isFocusModeSupported:AVCaptureFocusModeContinuousAutoFocus]).andReturn(true);
35-
// AVCaptureFocusModeContinuousAutoFocus is supported
36-
OCMStub([_mockDevice isFocusModeSupported:AVCaptureFocusModeAutoFocus]).andReturn(true);
37-
38-
// Don't expect setFocusMode:AVCaptureFocusModeAutoFocus
39-
[[_mockDevice reject] setFocusMode:AVCaptureFocusModeAutoFocus];
38+
// AVCaptureFocusModeContinuousAutoFocus and AVCaptureFocusModeContinuousAutoFocus are supported
39+
_mockDevice.isFocusModeSupportedStub = ^BOOL(AVCaptureFocusMode mode) {
40+
return mode == AVCaptureFocusModeContinuousAutoFocus || mode == AVCaptureFocusModeAutoFocus;
41+
};
42+
43+
__block BOOL setFocusModeContinuousAutoFocusCalled = NO;
44+
45+
_mockDevice.setFocusModeStub = ^(AVCaptureFocusMode mode) {
46+
// Don't expect setFocusMode:AVCaptureFocusModeAutoFocus
47+
if (mode == AVCaptureFocusModeAutoFocus) {
48+
XCTFail(@"Unexpected call to setFocusMode");
49+
} else if (mode == AVCaptureFocusModeContinuousAutoFocus) {
50+
setFocusModeContinuousAutoFocusCalled = YES;
51+
}
52+
};
4053

4154
// Run test
4255
[_camera applyFocusMode:FCPPlatformFocusModeAuto onDevice:_mockDevice];
4356

4457
// Expect setFocusMode:AVCaptureFocusModeContinuousAutoFocus
45-
OCMVerify([_mockDevice setFocusMode:AVCaptureFocusModeContinuousAutoFocus]);
58+
XCTAssertTrue(setFocusModeContinuousAutoFocusCalled);
4659
}
4760

4861
- (void)testAutoFocusWithContinuousModeNotSupported_ShouldSetAutoFocus {
4962
// AVCaptureFocusModeContinuousAutoFocus is not supported
50-
OCMStub([_mockDevice isFocusModeSupported:AVCaptureFocusModeContinuousAutoFocus])
51-
.andReturn(false);
52-
// AVCaptureFocusModeContinuousAutoFocus is supported
53-
OCMStub([_mockDevice isFocusModeSupported:AVCaptureFocusModeAutoFocus]).andReturn(true);
63+
// AVCaptureFocusModeAutoFocus is supported
64+
_mockDevice.isFocusModeSupportedStub = ^BOOL(AVCaptureFocusMode mode) {
65+
return mode == AVCaptureFocusModeAutoFocus;
66+
};
67+
68+
__block BOOL setFocusModeAutoFocusCalled = NO;
5469

5570
// Don't expect setFocusMode:AVCaptureFocusModeContinuousAutoFocus
56-
[[_mockDevice reject] setFocusMode:AVCaptureFocusModeContinuousAutoFocus];
71+
_mockDevice.setFocusModeStub = ^(AVCaptureFocusMode mode) {
72+
if (mode == AVCaptureFocusModeContinuousAutoFocus) {
73+
XCTFail(@"Unexpected call to setFocusMode");
74+
} else if (mode == AVCaptureFocusModeAutoFocus) {
75+
setFocusModeAutoFocusCalled = YES;
76+
}
77+
};
5778

5879
// Run test
5980
[_camera applyFocusMode:FCPPlatformFocusModeAuto onDevice:_mockDevice];
6081

6182
// Expect setFocusMode:AVCaptureFocusModeAutoFocus
62-
OCMVerify([_mockDevice setFocusMode:AVCaptureFocusModeAutoFocus]);
83+
XCTAssertTrue(setFocusModeAutoFocusCalled);
6384
}
6485

6586
- (void)testAutoFocusWithNoModeSupported_ShouldSetNothing {
66-
// AVCaptureFocusModeContinuousAutoFocus is not supported
67-
OCMStub([_mockDevice isFocusModeSupported:AVCaptureFocusModeContinuousAutoFocus])
68-
.andReturn(false);
69-
// AVCaptureFocusModeContinuousAutoFocus is not supported
70-
OCMStub([_mockDevice isFocusModeSupported:AVCaptureFocusModeAutoFocus]).andReturn(false);
87+
// No modes are supported
88+
_mockDevice.isFocusModeSupportedStub = ^BOOL(AVCaptureFocusMode mode) {
89+
return NO;
90+
};
7191

7292
// Don't expect any setFocus
73-
[[_mockDevice reject] setFocusMode:AVCaptureFocusModeContinuousAutoFocus];
74-
[[_mockDevice reject] setFocusMode:AVCaptureFocusModeAutoFocus];
93+
_mockDevice.setFocusModeStub = ^(AVCaptureFocusMode mode) {
94+
XCTFail(@"Unexpected call to setFocusMode");
95+
};
7596

7697
// Run test
7798
[_camera applyFocusMode:FCPPlatformFocusModeAuto onDevice:_mockDevice];
7899
}
79100

80101
- (void)testLockedFocusWithModeSupported_ShouldSetModeAutoFocus {
81-
// AVCaptureFocusModeContinuousAutoFocus is supported
82-
OCMStub([_mockDevice isFocusModeSupported:AVCaptureFocusModeContinuousAutoFocus]).andReturn(true);
83-
// AVCaptureFocusModeContinuousAutoFocus is supported
84-
OCMStub([_mockDevice isFocusModeSupported:AVCaptureFocusModeAutoFocus]).andReturn(true);
85-
86-
// Don't expect any setFocus
87-
[[_mockDevice reject] setFocusMode:AVCaptureFocusModeContinuousAutoFocus];
102+
// AVCaptureFocusModeContinuousAutoFocus and AVCaptureFocusModeAutoFocus are supported
103+
_mockDevice.isFocusModeSupportedStub = ^BOOL(AVCaptureFocusMode mode) {
104+
return mode == AVCaptureFocusModeContinuousAutoFocus || mode == AVCaptureFocusModeAutoFocus;
105+
};
106+
107+
__block BOOL setFocusModeAutoFocusCalled = NO;
108+
109+
// Expect only setFocusMode:AVCaptureFocusModeAutoFocus
110+
_mockDevice.setFocusModeStub = ^(AVCaptureFocusMode mode) {
111+
if (mode == AVCaptureFocusModeContinuousAutoFocus) {
112+
XCTFail(@"Unexpected call to setFocusMode");
113+
} else if (mode == AVCaptureFocusModeAutoFocus) {
114+
setFocusModeAutoFocusCalled = YES;
115+
}
116+
};
88117

89118
// Run test
90119
[_camera applyFocusMode:FCPPlatformFocusModeLocked onDevice:_mockDevice];
91120

92-
// Expect setFocusMode:AVCaptureFocusModeAutoFocus
93-
OCMVerify([_mockDevice setFocusMode:AVCaptureFocusModeAutoFocus]);
121+
XCTAssertTrue(setFocusModeAutoFocusCalled);
94122
}
95123

96124
- (void)testLockedFocusWithModeNotSupported_ShouldSetNothing {
97-
// AVCaptureFocusModeContinuousAutoFocus is supported
98-
OCMStub([_mockDevice isFocusModeSupported:AVCaptureFocusModeContinuousAutoFocus]).andReturn(true);
99-
// AVCaptureFocusModeContinuousAutoFocus is not supported
100-
OCMStub([_mockDevice isFocusModeSupported:AVCaptureFocusModeAutoFocus]).andReturn(false);
125+
_mockDevice.isFocusModeSupportedStub = ^BOOL(AVCaptureFocusMode mode) {
126+
return mode == AVCaptureFocusModeContinuousAutoFocus;
127+
};
101128

102129
// Don't expect any setFocus
103-
[[_mockDevice reject] setFocusMode:AVCaptureFocusModeContinuousAutoFocus];
104-
[[_mockDevice reject] setFocusMode:AVCaptureFocusModeAutoFocus];
130+
_mockDevice.setFocusModeStub = ^(AVCaptureFocusMode mode) {
131+
XCTFail(@"Unexpected call to setFocusMode");
132+
};
105133

106134
// Run test
107135
[_camera applyFocusMode:FCPPlatformFocusModeLocked onDevice:_mockDevice];
108136
}
109137

110138
- (void)testSetFocusPointWithResult_SetsFocusPointOfInterest {
111139
// UI is currently in landscape left orientation
112-
OCMStub([(UIDevice *)_mockUIDevice orientation]).andReturn(UIDeviceOrientationLandscapeLeft);
140+
_mockDeviceOrientationProvider.orientation = UIDeviceOrientationLandscapeLeft;
113141
// Focus point of interest is supported
114-
OCMStub([_mockDevice isFocusPointOfInterestSupported]).andReturn(true);
115-
// Set mock device as the current capture device
116-
[_camera setValue:_mockDevice forKey:@"captureDevice"];
142+
_mockDevice.focusPointOfInterestSupported = YES;
143+
144+
__block BOOL setFocusPointOfInterestCalled = NO;
145+
_mockDevice.setFocusPointOfInterestStub = ^(CGPoint point) {
146+
if (point.x == 1 && point.y == 1) {
147+
setFocusPointOfInterestCalled = YES;
148+
}
149+
};
117150

118151
// Run test
119152
[_camera setFocusPoint:[FCPPlatformPoint makeWithX:1 y:1]
120153
withCompletion:^(FlutterError *_Nullable error){
121154
}];
122155

123156
// Verify the focus point of interest has been set
124-
OCMVerify([_mockDevice setFocusPointOfInterest:CGPointMake(1, 1)]);
157+
XCTAssertTrue(setFocusPointOfInterestCalled);
158+
}
159+
160+
- (void)testSetFocusPoint_WhenNotSupported_ReturnsError {
161+
// UI is currently in landscape left orientation
162+
_mockDeviceOrientationProvider.orientation = UIDeviceOrientationLandscapeLeft;
163+
// Exposure point of interest is not supported
164+
_mockDevice.focusPointOfInterestSupported = NO;
165+
166+
XCTestExpectation *expectation = [self expectationWithDescription:@"Completion with error"];
167+
168+
// Run
169+
[_camera setFocusPoint:[FCPPlatformPoint makeWithX:1 y:1]
170+
withCompletion:^(FlutterError *_Nullable error) {
171+
XCTAssertNotNil(error);
172+
XCTAssertEqualObjects(error.code, @"setFocusPointFailed");
173+
XCTAssertEqualObjects(error.message, @"Device does not have focus point capabilities");
174+
[expectation fulfill];
175+
}];
176+
177+
// Verify
178+
[self waitForExpectationsWithTimeout:1 handler:nil];
125179
}
126180

127181
@end

packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraOrientationTests.m

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111

1212
#import <OCMock/OCMock.h>
1313

14+
#import "MockCaptureDeviceController.h"
15+
1416
@interface StubGlobalEventApi : FCPCameraGlobalEventApi
1517
@property(nonatomic) BOOL called;
1618
@property(nonatomic) FCPPlatformDeviceOrientation lastOrientation;
@@ -35,10 +37,21 @@ - (FlutterBinaryMessengerConnection)setMessageHandlerOnChannel:(nonnull NSString
3537
#pragma mark -
3638

3739
@interface CameraOrientationTests : XCTestCase
40+
@property(readonly, nonatomic) FLTCam *camera;
41+
@property(readonly, nonatomic) MockCaptureDeviceController *mockDevice;
42+
@property(readonly, nonatomic) StubGlobalEventApi *eventAPI;
3843
@end
3944

4045
@implementation CameraOrientationTests
4146

47+
- (void)setUp {
48+
[super setUp];
49+
_mockDevice = [[MockCaptureDeviceController alloc] init];
50+
_camera = [[FLTCam alloc] init];
51+
52+
[_camera setValue:_mockDevice forKey:@"captureDevice"];
53+
}
54+
4255
// Ensure that the given queue and then the main queue have both cycled, to wait for any pending
4356
// async events that may have been bounced between them.
4457
- (void)waitForRoundTripWithQueue:(dispatch_queue_t)queue {
@@ -97,13 +110,13 @@ - (void)testOrientationNotificationsNotCalledForFaceDown {
97110
- (void)testOrientationUpdateMustBeOnCaptureSessionQueue {
98111
XCTestExpectation *queueExpectation = [self
99112
expectationWithDescription:@"Orientation update must happen on the capture session queue"];
100-
101113
CameraPlugin *camera = [[CameraPlugin alloc] initWithRegistry:nil messenger:nil];
102114
const char *captureSessionQueueSpecific = "capture_session_queue";
103115
dispatch_queue_set_specific(camera.captureSessionQueue, captureSessionQueueSpecific,
104116
(void *)captureSessionQueueSpecific, NULL);
105117
FLTCam *mockCam = OCMClassMock([FLTCam class]);
106118
camera.camera = mockCam;
119+
107120
OCMStub([mockCam setDeviceOrientation:UIDeviceOrientationLandscapeLeft])
108121
.andDo(^(NSInvocation *invocation) {
109122
if (dispatch_get_specific(captureSessionQueueSpecific)) {

packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraPreviewPauseTests.m

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
#endif
99
@import XCTest;
1010
@import AVFoundation;
11-
#import <OCMock/OCMock.h>
1211

1312
@interface CameraPreviewPauseTests : XCTestCase
1413
@end

0 commit comments

Comments
 (0)