88#endif
99@import AVFoundation;
1010@import XCTest;
11- # import < OCMock/OCMock.h >
11+
1212#import " CameraTestUtils.h"
1313
14- @interface CameraPermissionTests : XCTestCase
14+ @interface MockPermissionService : NSObject <FLTPermissionServicing>
15+ @property (nonatomic , copy ) AVAuthorizationStatus (^authorizationStatusStub)(AVMediaType mediaType);
16+ @property (nonatomic , copy ) void (^requestAccessStub)(AVMediaType mediaType, void (^handler)(BOOL ));
17+ @end
1518
19+ @implementation MockPermissionService
20+ - (AVAuthorizationStatus)authorizationStatusForMediaType : (AVMediaType)mediaType {
21+ return self.authorizationStatusStub ? self.authorizationStatusStub (mediaType)
22+ : AVAuthorizationStatusNotDetermined;
23+ }
24+
25+ - (void )requestAccessForMediaType : (AVMediaType)mediaType completionHandler : (void (^)(BOOL ))handler {
26+ if (self.requestAccessStub ) {
27+ self.requestAccessStub (mediaType, handler);
28+ }
29+ }
1630@end
1731
18- @implementation CameraPermissionTests
32+ @interface FLTCameraPermissionManagerTests : XCTestCase
33+ @property (nonatomic , strong ) FLTCameraPermissionManager *permissionManager;
34+ @property (nonatomic , strong ) MockPermissionService *mockService;
35+ @end
36+
37+ @implementation FLTCameraPermissionManagerTests
38+
39+ - (void )setUp {
40+ [super setUp ];
41+ self.mockService = [[MockPermissionService alloc ] init ];
42+ self.permissionManager =
43+ [[FLTCameraPermissionManager alloc ] initWithPermissionService: self .mockService];
44+ }
1945
2046#pragma mark - camera permissions
2147
22- - (void )testRequestCameraPermission_completeWithoutErrorIfPrevoiuslyAuthorized {
48+ - (void )testRequestCameraPermission_completeWithoutErrorIfPreviouslyAuthorized {
2349 XCTestExpectation *expectation =
2450 [self expectationWithDescription:
2551 @" Must copmlete without error if camera access was previously authorized." ];
2652
27- id mockDevice = OCMClassMock ([AVCaptureDevice class ]);
28- OCMStub ([mockDevice authorizationStatusForMediaType: AVMediaTypeVideo])
29- .andReturn (AVAuthorizationStatusAuthorized);
53+ self.mockService .authorizationStatusStub = ^AVAuthorizationStatus (AVMediaType mediaType) {
54+ XCTAssertEqualObjects (mediaType, AVMediaTypeVideo);
55+ return AVAuthorizationStatusAuthorized;
56+ };
3057
31- FLTRequestCameraPermissionWithCompletionHandler ( ^(FlutterError *error) {
58+ [ self .permissionManager requestCameraPermissionWithCompletionHandler: ^(FlutterError *error) {
3259 if (error == nil ) {
3360 [expectation fulfill ];
3461 }
35- }) ;
62+ }] ;
3663 [self waitForExpectationsWithTimeout: 1 handler: nil ];
3764}
3865- (void )testRequestCameraPermission_completeWithErrorIfPreviouslyDenied {
@@ -45,14 +72,16 @@ - (void)testRequestCameraPermission_completeWithErrorIfPreviouslyDenied {
4572 @" Settings to enable camera access."
4673 details: nil ];
4774
48- id mockDevice = OCMClassMock ([AVCaptureDevice class ]);
49- OCMStub ([mockDevice authorizationStatusForMediaType: AVMediaTypeVideo])
50- .andReturn (AVAuthorizationStatusDenied);
51- FLTRequestCameraPermissionWithCompletionHandler (^(FlutterError *error) {
75+ self.mockService .authorizationStatusStub = ^AVAuthorizationStatus (AVMediaType mediaType) {
76+ XCTAssertEqualObjects (mediaType, AVMediaTypeVideo);
77+ return AVAuthorizationStatusDenied;
78+ };
79+
80+ [self .permissionManager requestCameraPermissionWithCompletionHandler: ^(FlutterError *error) {
5281 if ([error isEqual: expectedError]) {
5382 [expectation fulfill ];
5483 }
55- }) ;
84+ }] ;
5685 [self waitForExpectationsWithTimeout: 1 handler: nil ];
5786}
5887
@@ -63,37 +92,39 @@ - (void)testRequestCameraPermission_completeWithErrorIfRestricted {
6392 message: @" Camera access is restricted. "
6493 details: nil ];
6594
66- id mockDevice = OCMClassMock ([AVCaptureDevice class ]);
67- OCMStub ([mockDevice authorizationStatusForMediaType: AVMediaTypeVideo])
68- .andReturn (AVAuthorizationStatusRestricted);
95+ self.mockService .authorizationStatusStub = ^AVAuthorizationStatus (AVMediaType mediaType) {
96+ XCTAssertEqualObjects (mediaType, AVMediaTypeVideo);
97+ return AVAuthorizationStatusRestricted;
98+ };
6999
70- FLTRequestCameraPermissionWithCompletionHandler ( ^(FlutterError *error) {
100+ [ self .permissionManager requestCameraPermissionWithCompletionHandler: ^(FlutterError *error) {
71101 if ([error isEqual: expectedError]) {
72102 [expectation fulfill ];
73103 }
74- }) ;
104+ }] ;
75105 [self waitForExpectationsWithTimeout: 1 handler: nil ];
76106}
77107
78108- (void )testRequestCameraPermission_completeWithoutErrorIfUserGrantAccess {
79109 XCTestExpectation *grantedExpectation = [self
80110 expectationWithDescription: @" Must complete without error if user choose to grant access" ];
81111
82- id mockDevice = OCMClassMock ([AVCaptureDevice class ]);
83- OCMStub ([mockDevice authorizationStatusForMediaType: AVMediaTypeVideo])
84- .andReturn (AVAuthorizationStatusNotDetermined);
112+ self.mockService .authorizationStatusStub = ^AVAuthorizationStatus (AVMediaType mediaType) {
113+ XCTAssertEqualObjects (mediaType, AVMediaTypeVideo);
114+ return AVAuthorizationStatusNotDetermined;
115+ };
116+
85117 // Mimic user choosing "allow" in permission dialog.
86- OCMStub ([mockDevice requestAccessForMediaType: AVMediaTypeVideo
87- completionHandler: [OCMArg checkWithBlock: ^BOOL (void (^block)(BOOL )) {
88- block (YES );
89- return YES ;
90- }]]);
118+ self.mockService .requestAccessStub = ^(AVMediaType mediaType, void (^handler)(BOOL )) {
119+ XCTAssertEqualObjects (mediaType, AVMediaTypeVideo);
120+ handler (YES );
121+ };
91122
92- FLTRequestCameraPermissionWithCompletionHandler ( ^(FlutterError *error) {
123+ [ self .permissionManager requestCameraPermissionWithCompletionHandler: ^(FlutterError *error) {
93124 if (error == nil ) {
94125 [grantedExpectation fulfill ];
95126 }
96- }) ;
127+ }] ;
97128 [self waitForExpectationsWithTimeout: 1 handler: nil ];
98129}
99130
@@ -105,21 +136,22 @@ - (void)testRequestCameraPermission_completeWithErrorIfUserDenyAccess {
105136 message: @" User denied the camera access request."
106137 details: nil ];
107138
108- id mockDevice = OCMClassMock ([AVCaptureDevice class ]);
109- OCMStub ([mockDevice authorizationStatusForMediaType: AVMediaTypeVideo])
110- .andReturn (AVAuthorizationStatusNotDetermined);
139+ self.mockService .authorizationStatusStub = ^AVAuthorizationStatus (AVMediaType mediaType) {
140+ XCTAssertEqualObjects (mediaType, AVMediaTypeVideo);
141+ return AVAuthorizationStatusNotDetermined;
142+ };
111143
112144 // Mimic user choosing "deny" in permission dialog.
113- OCMStub ([mockDevice requestAccessForMediaType: AVMediaTypeVideo
114- completionHandler: [OCMArg checkWithBlock: ^ BOOL ( void (^block)( BOOL )) {
115- block (NO );
116- return YES ;
117- }]]);
118- FLTRequestCameraPermissionWithCompletionHandler ( ^(FlutterError *error) {
145+ self. mockService . requestAccessStub = ^(AVMediaType mediaType, void (^handler)( BOOL )) {
146+ XCTAssertEqualObjects (mediaType, AVMediaTypeVideo);
147+ handler (NO );
148+ } ;
149+
150+ [ self .permissionManager requestCameraPermissionWithCompletionHandler: ^(FlutterError *error) {
119151 if ([error isEqual: expectedError]) {
120152 [expectation fulfill ];
121153 }
122- }) ;
154+ }] ;
123155
124156 [self waitForExpectationsWithTimeout: 1 handler: nil ];
125157}
@@ -131,17 +163,19 @@ - (void)testRequestAudioPermission_completeWithoutErrorIfPrevoiuslyAuthorized {
131163 [self expectationWithDescription:
132164 @" Must copmlete without error if audio access was previously authorized." ];
133165
134- id mockDevice = OCMClassMock ([AVCaptureDevice class ]);
135- OCMStub ([mockDevice authorizationStatusForMediaType: AVMediaTypeAudio])
136- .andReturn (AVAuthorizationStatusAuthorized);
166+ self.mockService .authorizationStatusStub = ^AVAuthorizationStatus (AVMediaType mediaType) {
167+ XCTAssertEqualObjects (mediaType, AVMediaTypeAudio);
168+ return AVAuthorizationStatusAuthorized;
169+ };
137170
138- FLTRequestAudioPermissionWithCompletionHandler ( ^(FlutterError *error) {
171+ [ self .permissionManager requestAudioPermissionWithCompletionHandler: ^(FlutterError *error) {
139172 if (error == nil ) {
140173 [expectation fulfill ];
141174 }
142- }) ;
175+ }] ;
143176 [self waitForExpectationsWithTimeout: 1 handler: nil ];
144177}
178+
145179- (void )testRequestAudioPermission_completeWithErrorIfPreviouslyDenied {
146180 XCTestExpectation *expectation =
147181 [self expectationWithDescription:
@@ -152,14 +186,16 @@ - (void)testRequestAudioPermission_completeWithErrorIfPreviouslyDenied {
152186 @" Settings to enable audio access."
153187 details: nil ];
154188
155- id mockDevice = OCMClassMock ([AVCaptureDevice class ]);
156- OCMStub ([mockDevice authorizationStatusForMediaType: AVMediaTypeAudio])
157- .andReturn (AVAuthorizationStatusDenied);
158- FLTRequestAudioPermissionWithCompletionHandler (^(FlutterError *error) {
189+ self.mockService .authorizationStatusStub = ^AVAuthorizationStatus (AVMediaType mediaType) {
190+ XCTAssertEqualObjects (mediaType, AVMediaTypeAudio);
191+ return AVAuthorizationStatusDenied;
192+ };
193+
194+ [self .permissionManager requestAudioPermissionWithCompletionHandler: ^(FlutterError *error) {
159195 if ([error isEqual: expectedError]) {
160196 [expectation fulfill ];
161197 }
162- }) ;
198+ }] ;
163199 [self waitForExpectationsWithTimeout: 1 handler: nil ];
164200}
165201
@@ -170,37 +206,39 @@ - (void)testRequestAudioPermission_completeWithErrorIfRestricted {
170206 message: @" Audio access is restricted. "
171207 details: nil ];
172208
173- id mockDevice = OCMClassMock ([AVCaptureDevice class ]);
174- OCMStub ([mockDevice authorizationStatusForMediaType: AVMediaTypeAudio])
175- .andReturn (AVAuthorizationStatusRestricted);
209+ self.mockService .authorizationStatusStub = ^AVAuthorizationStatus (AVMediaType mediaType) {
210+ XCTAssertEqualObjects (mediaType, AVMediaTypeAudio);
211+ return AVAuthorizationStatusRestricted;
212+ };
176213
177- FLTRequestAudioPermissionWithCompletionHandler ( ^(FlutterError *error) {
214+ [ self .permissionManager requestAudioPermissionWithCompletionHandler: ^(FlutterError *error) {
178215 if ([error isEqual: expectedError]) {
179216 [expectation fulfill ];
180217 }
181- }) ;
218+ }] ;
182219 [self waitForExpectationsWithTimeout: 1 handler: nil ];
183220}
184221
185222- (void )testRequestAudioPermission_completeWithoutErrorIfUserGrantAccess {
186223 XCTestExpectation *grantedExpectation = [self
187224 expectationWithDescription: @" Must complete without error if user choose to grant access" ];
188225
189- id mockDevice = OCMClassMock ([AVCaptureDevice class ]);
190- OCMStub ([mockDevice authorizationStatusForMediaType: AVMediaTypeAudio])
191- .andReturn (AVAuthorizationStatusNotDetermined);
226+ self.mockService .authorizationStatusStub = ^AVAuthorizationStatus (AVMediaType mediaType) {
227+ XCTAssertEqualObjects (mediaType, AVMediaTypeAudio);
228+ return AVAuthorizationStatusNotDetermined;
229+ };
230+
192231 // Mimic user choosing "allow" in permission dialog.
193- OCMStub ([mockDevice requestAccessForMediaType: AVMediaTypeAudio
194- completionHandler: [OCMArg checkWithBlock: ^BOOL (void (^block)(BOOL )) {
195- block (YES );
196- return YES ;
197- }]]);
232+ self.mockService .requestAccessStub = ^(AVMediaType mediaType, void (^handler)(BOOL )) {
233+ XCTAssertEqualObjects (mediaType, AVMediaTypeAudio);
234+ handler (YES );
235+ };
198236
199- FLTRequestAudioPermissionWithCompletionHandler ( ^(FlutterError *error) {
237+ [ self .permissionManager requestAudioPermissionWithCompletionHandler: ^(FlutterError *error) {
200238 if (error == nil ) {
201239 [grantedExpectation fulfill ];
202240 }
203- }) ;
241+ }] ;
204242 [self waitForExpectationsWithTimeout: 1 handler: nil ];
205243}
206244
@@ -211,22 +249,22 @@ - (void)testRequestAudioPermission_completeWithErrorIfUserDenyAccess {
211249 message: @" User denied the audio access request."
212250 details: nil ];
213251
214- id mockDevice = OCMClassMock ([AVCaptureDevice class ]);
215- OCMStub ([mockDevice authorizationStatusForMediaType: AVMediaTypeAudio])
216- .andReturn (AVAuthorizationStatusNotDetermined);
252+ self.mockService .authorizationStatusStub = ^AVAuthorizationStatus (AVMediaType mediaType) {
253+ XCTAssertEqualObjects (mediaType, AVMediaTypeAudio);
254+ return AVAuthorizationStatusNotDetermined;
255+ };
217256
218257 // Mimic user choosing "deny" in permission dialog.
219- OCMStub ([mockDevice requestAccessForMediaType: AVMediaTypeAudio
220- completionHandler: [OCMArg checkWithBlock: ^ BOOL ( void (^block)( BOOL )) {
221- block (NO );
222- return YES ;
223- }]]);
224- FLTRequestAudioPermissionWithCompletionHandler ( ^(FlutterError *error) {
258+ self. mockService . requestAccessStub = ^(AVMediaType mediaType, void (^handler)( BOOL )) {
259+ XCTAssertEqualObjects (mediaType, AVMediaTypeAudio);
260+ handler (NO );
261+ } ;
262+
263+ [ self .permissionManager requestAudioPermissionWithCompletionHandler: ^(FlutterError *error) {
225264 if ([error isEqual: expectedError]) {
226265 [expectation fulfill ];
227266 }
228- });
229-
267+ }];
230268 [self waitForExpectationsWithTimeout: 1 handler: nil ];
231269}
232270
0 commit comments