blob: 57787a968a2d1de2786c7da582fc43e55af7078c [file] [log] [blame]
// 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;
@import camera_avfoundation.Test;
@import XCTest;
@import Flutter;
#import <OCMock/OCMock.h>
@interface StubGlobalEventApi : FCPCameraGlobalEventApi
@property(nonatomic) BOOL called;
@property(nonatomic) FCPPlatformDeviceOrientation lastOrientation;
@end
@implementation StubGlobalEventApi
- (void)deviceOrientationChangedOrientation:(FCPPlatformDeviceOrientation)orientation
completion:(void (^)(FlutterError *_Nullable))completion {
self.called = YES;
self.lastOrientation = orientation;
completion(nil);
}
- (FlutterBinaryMessengerConnection)setMessageHandlerOnChannel:(nonnull NSString *)channel
binaryMessageHandler:
(nullable FlutterBinaryMessageHandler)handler {
return 0;
}
@end
#pragma mark -
@interface CameraOrientationTests : XCTestCase
@end
@implementation CameraOrientationTests
// Ensure that the given queue and then the main queue have both cycled, to wait for any pending
// async events that may have been bounced between them.
- (void)waitForRoundTripWithQueue:(dispatch_queue_t)queue {
XCTestExpectation *expectation = [[XCTestExpectation alloc] initWithDescription:@"Queue flush"];
dispatch_async(queue, ^{
dispatch_async(dispatch_get_main_queue(), ^{
[expectation fulfill];
});
});
[self waitForExpectations:@[ expectation ]];
}
- (void)sendOrientation:(UIDeviceOrientation)orientation toCamera:(CameraPlugin *)cameraPlugin {
[cameraPlugin orientationChanged:[self createMockNotificationForOrientation:orientation]];
[self waitForRoundTripWithQueue:cameraPlugin.captureSessionQueue];
}
- (void)testOrientationNotifications {
StubGlobalEventApi *eventAPI = [[StubGlobalEventApi alloc] init];
CameraPlugin *cameraPlugin = [[CameraPlugin alloc] initWithRegistry:nil
messenger:nil
globalAPI:eventAPI];
[self sendOrientation:UIDeviceOrientationPortraitUpsideDown toCamera:cameraPlugin];
XCTAssertEqual(eventAPI.lastOrientation, FCPPlatformDeviceOrientationPortraitDown);
[self sendOrientation:UIDeviceOrientationPortrait toCamera:cameraPlugin];
XCTAssertEqual(eventAPI.lastOrientation, FCPPlatformDeviceOrientationPortraitUp);
[self sendOrientation:UIDeviceOrientationLandscapeLeft toCamera:cameraPlugin];
XCTAssertEqual(eventAPI.lastOrientation, FCPPlatformDeviceOrientationLandscapeLeft);
[self sendOrientation:UIDeviceOrientationLandscapeRight toCamera:cameraPlugin];
XCTAssertEqual(eventAPI.lastOrientation, FCPPlatformDeviceOrientationLandscapeRight);
}
- (void)testOrientationNotificationsNotCalledForFaceUp {
StubGlobalEventApi *eventAPI = [[StubGlobalEventApi alloc] init];
CameraPlugin *cameraPlugin = [[CameraPlugin alloc] initWithRegistry:nil
messenger:nil
globalAPI:eventAPI];
[self sendOrientation:UIDeviceOrientationFaceUp toCamera:cameraPlugin];
XCTAssertFalse(eventAPI.called);
}
- (void)testOrientationNotificationsNotCalledForFaceDown {
StubGlobalEventApi *eventAPI = [[StubGlobalEventApi alloc] init];
CameraPlugin *cameraPlugin = [[CameraPlugin alloc] initWithRegistry:nil
messenger:nil
globalAPI:eventAPI];
[self sendOrientation:UIDeviceOrientationFaceDown toCamera:cameraPlugin];
XCTAssertFalse(eventAPI.called);
}
- (void)testOrientationUpdateMustBeOnCaptureSessionQueue {
XCTestExpectation *queueExpectation = [self
expectationWithDescription:@"Orientation update must happen on the capture session queue"];
CameraPlugin *camera = [[CameraPlugin alloc] initWithRegistry:nil messenger:nil];
const char *captureSessionQueueSpecific = "capture_session_queue";
dispatch_queue_set_specific(camera.captureSessionQueue, captureSessionQueueSpecific,
(void *)captureSessionQueueSpecific, NULL);
FLTCam *mockCam = OCMClassMock([FLTCam class]);
camera.camera = mockCam;
OCMStub([mockCam setDeviceOrientation:UIDeviceOrientationLandscapeLeft])
.andDo(^(NSInvocation *invocation) {
if (dispatch_get_specific(captureSessionQueueSpecific)) {
[queueExpectation fulfill];
}
});
[camera orientationChanged:
[self createMockNotificationForOrientation:UIDeviceOrientationLandscapeLeft]];
[self waitForExpectationsWithTimeout:1 handler:nil];
}
- (void)testOrientationChanged_noRetainCycle {
dispatch_queue_t captureSessionQueue = dispatch_queue_create("capture_session_queue", NULL);
FLTCam *mockCam = OCMClassMock([FLTCam class]);
StubGlobalEventApi *stubAPI = [[StubGlobalEventApi alloc] init];
__weak CameraPlugin *weakCamera;
@autoreleasepool {
CameraPlugin *camera = [[CameraPlugin alloc] initWithRegistry:nil
messenger:nil
globalAPI:stubAPI];
weakCamera = camera;
camera.captureSessionQueue = captureSessionQueue;
camera.camera = mockCam;
[camera orientationChanged:
[self createMockNotificationForOrientation:UIDeviceOrientationLandscapeLeft]];
}
// Sanity check
XCTAssertNil(weakCamera, @"Camera must have been deallocated.");
// Must check in captureSessionQueue since orientationChanged dispatches to this queue.
XCTestExpectation *expectation =
[self expectationWithDescription:@"Dispatched to capture session queue"];
dispatch_async(captureSessionQueue, ^{
OCMVerify(never(), [mockCam setDeviceOrientation:UIDeviceOrientationLandscapeLeft]);
XCTAssertFalse(stubAPI.called);
[expectation fulfill];
});
[self waitForExpectationsWithTimeout:30 handler:nil];
}
- (NSNotification *)createMockNotificationForOrientation:(UIDeviceOrientation)deviceOrientation {
UIDevice *mockDevice = OCMClassMock([UIDevice class]);
OCMStub([mockDevice orientation]).andReturn(deviceOrientation);
return [NSNotification notificationWithName:@"orientation_test" object:mockDevice];
}
@end