Index: webrtc/sdk/objc/Framework/UnitTests/avformatmappertests.mm |
diff --git a/webrtc/sdk/objc/Framework/UnitTests/avformatmappertests.mm b/webrtc/sdk/objc/Framework/UnitTests/avformatmappertests.mm |
new file mode 100644 |
index 0000000000000000000000000000000000000000..6e3295005ccd4f79d50829cd9ec9a360c4184eea |
--- /dev/null |
+++ b/webrtc/sdk/objc/Framework/UnitTests/avformatmappertests.mm |
@@ -0,0 +1,317 @@ |
+/* |
+ * Copyright 2016 The WebRTC project authors. All Rights Reserved. |
+ * |
+ * Use of this source code is governed by a BSD-style license |
+ * that can be found in the LICENSE file in the root of the source |
+ * tree. An additional intellectual property rights grant can be found |
+ * in the file PATENTS. All contributing project authors may |
+ * be found in the AUTHORS file in the root of the source tree. |
+ */ |
+ |
+#import <Foundation/Foundation.h> |
+#import <OCMock/OCMock.h> |
+#include "avfoundationformatmapper.h" |
+#include "webrtc/base/gunit.h" |
+ |
+static NSString * const kMediaSubtypeKey = @"subtype"; |
+static NSString * const kMinFrameRateKey = @"min_framerate"; |
+static NSString * const kMaxFrameRateKey = @"max_framerate"; |
+ |
+// Widht and height don't play any role so lets use predefined values troughout |
magjed_webrtc
2016/11/24 13:42:59
nit: Spelling: Width and throughout
daniela-webrtc
2016/11/25 08:58:15
Done.
|
+// the tests. |
+static const int kFormatWidth = 789; |
+static const int kFormatHeight = 987; |
+ |
+// Hardcoded framrate to be used troughout the tests. |
magjed_webrtc
2016/11/24 13:42:59
nit: spelling: throughout
daniela-webrtc
2016/11/25 08:58:15
Done.
|
+static const int kFramerate = 30; |
+ |
+namespace webrtc { |
+NSArray<AVCaptureDeviceFormat*>* GetEligibleDeviceFormats( |
magjed_webrtc
2016/11/24 13:42:59
Are you testing some implementation helper functio
daniela-webrtc
2016/11/25 08:58:15
Yes it's an implementation helper function. I want
magjed_webrtc
2016/11/28 12:21:23
I see. I'm sorry, but you have to stick to testing
|
+ const AVCaptureDevice* device, |
+ int supportedFps); |
+AVCaptureDeviceFormat* GetDeviceFormatForVideoFormat( |
+ const AVCaptureDevice* device, |
+ const cricket::VideoFormat& videoFormat); |
+} |
+ |
+// Mock class for AVCaptureDeviceFormat. |
+// Custom implementation needed because OCMock cannot handle the |
+// CMVideoDescriptionRef mocking. |
+@interface AVCaptureDeviceFormatMock : NSObject { |
+ CMVideoFormatDescriptionRef _format; |
+ OCMockObject *_rangeMock; |
+} |
+ |
+// The dictionaries are in the following format. |
+// @{@"subtype":@(kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange), |
+// @"min_framerate":@0, |
+// @"max_framerate":@30} |
+ |
+- (instancetype)initWithDictionary:(NSDictionary *)mockDataDictionary; |
+@end |
+ |
+@implementation AVCaptureDeviceFormatMock |
+ |
+- (instancetype)initWithDictionary:(NSDictionary *)mockDataDictionary { |
+ if (self = [super init]) { |
+ NSNumber *subtype = [mockDataDictionary objectForKey:kMediaSubtypeKey]; |
+ NSNumber *minFramerate = [mockDataDictionary objectForKey:kMinFrameRateKey]; |
+ NSNumber *maxFramerate = [mockDataDictionary objectForKey:kMaxFrameRateKey]; |
+ |
+ |
+ CMVideoFormatDescriptionCreate(nil, subtype.intValue, kFormatWidth, |
+ kFormatHeight, nil, &_format); |
+ // We can use OCMock for the range. |
+ _rangeMock = [OCMockObject mockForClass:[AVFrameRateRange class]]; |
+ [[[_rangeMock stub] andReturnValue:@(minFramerate.floatValue)] minFrameRate]; |
+ [[[_rangeMock stub] andReturnValue:@(maxFramerate.floatValue)] maxFrameRate]; |
+ } |
+ |
+ return self; |
+} |
+ |
+- (void)dealloc { |
+ if (_rangeMock != nil) { |
+ [_rangeMock dealloc]; |
+ _rangeMock = nil; |
+ } |
+ if (_format != nil) { |
+ CFRelease(_format); |
+ _format = nil; |
+ } |
+ [super dealloc]; |
+} |
+ |
+// Redefinition of AVCaptureDevice methods we want to mock. |
+- (CMVideoFormatDescriptionRef)formatDescription { |
+ return _format; |
+} |
+ |
+- (NSArray *)videoSupportedFrameRateRanges { |
+ return @[_rangeMock]; |
+} |
+ |
+@end |
+ |
+class AVFormatMapperTest : public ::testing::Test { |
+ protected: |
+ void testEligibleWithValidFormats() { |
+ // given |
+ id mockDevice = [OCMockObject mockForClass:[AVCaptureDevice class]]; |
+ |
+ // Valid media subtype, valid framerate |
+ AVCaptureDeviceFormatMock* mockOne = |
+ [[AVCaptureDeviceFormatMock alloc] initWithDictionary:@{ |
+ kMediaSubtypeKey : @(kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange), |
+ kMinFrameRateKey : @(0), |
+ kMaxFrameRateKey : @(20) |
+ }]; |
+ // Valid media subtype, valid framerate |
+ AVCaptureDeviceFormatMock* mockTwo = |
+ [[AVCaptureDeviceFormatMock alloc] initWithDictionary:@{ |
+ kMediaSubtypeKey : @(kCVPixelFormatType_420YpCbCr8PlanarFullRange), |
+ kMinFrameRateKey : @(0), |
+ kMaxFrameRateKey : @(20) |
+ }]; |
+ [[[mockDevice stub] andReturn:@[ mockOne, mockTwo ]] formats]; |
+ |
+ // when |
+ NSArray* result = webrtc::GetEligibleDeviceFormats(mockDevice, kFramerate); |
+ |
+ // then |
+ EXPECT_TRUE(result.count == 2); |
+ } |
+ |
+ void testEligibleWithInvalidFramerateFormats() { |
+ // given |
+ id mockDevice = [OCMockObject mockForClass:[AVCaptureDevice class]]; |
+ |
+ // Valid media subtype, invalid framerate |
+ AVCaptureDeviceFormatMock* mockOne = |
+ [[AVCaptureDeviceFormatMock alloc] initWithDictionary:@{ |
+ kMediaSubtypeKey : @(kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange), |
+ kMinFrameRateKey : @(0), |
+ kMaxFrameRateKey : @(35) |
+ }]; |
+ |
+ // Valid media subtype, valid framerate |
+ AVCaptureDeviceFormatMock* mockTwo = |
+ [[AVCaptureDeviceFormatMock alloc] initWithDictionary:@{ |
+ kMediaSubtypeKey : @(kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange), |
+ kMinFrameRateKey : @(0), |
+ kMaxFrameRateKey : @(30) |
+ }]; |
+ |
+ [[[mockDevice stub] andReturn:@[ mockOne, mockTwo ]] formats]; |
+ |
+ // when |
+ NSArray* result = webrtc::GetEligibleDeviceFormats(mockDevice, kFramerate); |
+ |
+ // then |
+ EXPECT_TRUE(result.count == 1); |
+ EXPECT_TRUE([result[0] isEqual:mockTwo]); |
+ } |
+ |
+ void testEligibleWithInvalidFormats() { |
+ // given |
+ id mockDevice = [OCMockObject mockForClass:[AVCaptureDevice class]]; |
+ |
+ // Invalid media subtype, valid framerate |
+ AVCaptureDeviceFormatMock* mockOne = |
+ [[AVCaptureDeviceFormatMock alloc] initWithDictionary:@{ |
+ kMediaSubtypeKey : @(kCVPixelFormatType_420YpCbCr8Planar), |
+ kMinFrameRateKey : @(0), |
+ kMaxFrameRateKey : @(20) |
+ }]; |
+ |
+ // Valid media subtype, valid framerate |
+ AVCaptureDeviceFormatMock* mockTwo = |
+ [[AVCaptureDeviceFormatMock alloc] initWithDictionary:@{ |
+ kMediaSubtypeKey : @(kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange), |
+ kMinFrameRateKey : @(0), |
+ kMaxFrameRateKey : @(20) |
+ }]; |
+ |
+ [[[mockDevice stub] andReturn:@[ mockOne, mockTwo ]] formats]; |
+ |
+ // when |
+ NSArray* result = webrtc::GetEligibleDeviceFormats(mockDevice, kFramerate); |
+ |
+ // then |
+ EXPECT_TRUE(result.count == 1); |
+ EXPECT_TRUE([result[0] isEqual:mockTwo]); |
+ } |
+ |
+ void testSuportedCricketFormats() { |
+ // given |
+ id mockDevice = [OCMockObject mockForClass:[AVCaptureDevice class]]; |
+ |
+ // valid media subtype, valid framerate |
+ AVCaptureDeviceFormatMock* mockOne = |
+ [[AVCaptureDeviceFormatMock alloc] initWithDictionary:@{ |
+ kMediaSubtypeKey : @(kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange), |
+ kMinFrameRateKey : @(0), |
+ kMaxFrameRateKey : @(20) |
+ }]; |
+ |
+ [[[mockDevice stub] andReturn:@[ mockOne ]] formats]; |
+ |
+ cricket::VideoFormat expectedFormat = cricket::VideoFormat( |
+ kFormatWidth, kFormatHeight, |
+ cricket::VideoFormat::FpsToInterval(kFramerate), cricket::FOURCC_NV12); |
+ |
+ // when |
+ std::set<cricket::VideoFormat> result = |
+ webrtc::GetSupportedVideoFormatsForDevice(mockDevice); |
+ |
+ // then |
+ EXPECT_EQ(result.size(), 1); |
+ |
+ // make sure the set has the expected format |
+ auto it = result.find(expectedFormat); |
+ EXPECT_TRUE(it != result.end()); |
+ } |
+ |
+ void testAVFormatForCricketFormat() { |
+ // given |
+ id mockDevice = [OCMockObject mockForClass:[AVCaptureDevice class]]; |
+ |
+ // valid media subtype, valid framerate |
+ AVCaptureDeviceFormatMock* mockOne = |
+ [[AVCaptureDeviceFormatMock alloc] initWithDictionary:@{ |
+ kMediaSubtypeKey : @(kCVPixelFormatType_420YpCbCr8PlanarFullRange), |
+ kMinFrameRateKey : @(0), |
+ kMaxFrameRateKey : @(20) |
+ }]; |
+ |
+ // valid media subtype, valid framerate. |
+ // This media subtype should be the preffered one. |
+ AVCaptureDeviceFormatMock* mockTwo = |
+ [[AVCaptureDeviceFormatMock alloc] initWithDictionary:@{ |
+ kMediaSubtypeKey : @(kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange), |
+ kMinFrameRateKey : @(0), |
+ kMaxFrameRateKey : @(20) |
+ }]; |
+ |
+ [[[mockDevice stub] andReturn:@[ mockOne, mockTwo ]] formats]; |
+ |
+ cricket::VideoFormat inputFormat = cricket::VideoFormat( |
+ kFormatWidth, kFormatHeight, |
+ cricket::VideoFormat::FpsToInterval(kFramerate), cricket::FOURCC_NV12); |
+ |
+ // when |
+ id resultFormat = |
+ webrtc::GetDeviceFormatForVideoFormat(mockDevice, inputFormat); |
+ |
+ // then |
+ EXPECT_TRUE([resultFormat isEqual:mockTwo]); |
+ } |
+ |
+ void testSetFormatWhenDeviceCannotLock() { |
+ // given |
+ id mockDevice = [OCMockObject mockForClass:[AVCaptureDevice class]]; |
+ [[[mockDevice stub] andReturnValue:@(NO)] |
+ lockForConfiguration:[OCMArg setTo:nil]]; |
+ |
+ [[[mockDevice stub] andReturn:@[]] formats]; |
+ |
+ // when |
+ bool resultFormat = webrtc::SetFormatForCaptureDevice( |
+ mockDevice, nil, cricket::VideoFormat()); |
+ |
+ // then |
+ EXPECT_FALSE(resultFormat); |
+ } |
+ |
+ void testSetFormatWhenFormatIsIncompatible() { |
+ // given |
+ id mockDevice = [OCMockObject mockForClass:[AVCaptureDevice class]]; |
+ [[[mockDevice stub] andReturn:@[]] formats]; |
+ [[[mockDevice stub] andReturnValue:@(YES)] |
+ lockForConfiguration:[OCMArg setTo:nil]]; |
+ |
+ NSException* exception = |
+ [NSException exceptionWithName:@"Test exception" |
+ reason:@"Raised from unit tests" |
+ userInfo:nil]; |
+ [[[mockDevice stub] andThrow:exception] setActiveFormat:[OCMArg any]]; |
+ [[mockDevice expect] unlockForConfiguration]; |
+ |
+ // when |
+ bool resultFormat = webrtc::SetFormatForCaptureDevice( |
+ mockDevice, nil, cricket::VideoFormat()); |
+ |
+ // then |
+ EXPECT_FALSE(resultFormat); |
+ [mockDevice verify]; |
+ } |
+}; |
+ |
+TEST_F(AVFormatMapperTest, EligibleFormatsPerDeviceWithValidFormats) { |
+ testEligibleWithValidFormats(); |
+} |
+ |
+TEST_F(AVFormatMapperTest, |
+ EligibleFormatsPerDeviceWithInvalidFramerateFormats) { |
+ testEligibleWithInvalidFramerateFormats(); |
+} |
+ |
+TEST_F(AVFormatMapperTest, EligibleFormatsPerDeviceWithInvalidFormats) { |
+ testEligibleWithInvalidFormats(); |
+} |
+ |
+TEST_F(AVFormatMapperTest, SuportedCricketFormats) { |
+ testSuportedCricketFormats(); |
+} |
+ |
+TEST_F(AVFormatMapperTest, AVFormatForCricketFormat) { |
+ testAVFormatForCricketFormat(); |
+} |
+ |
+TEST_F(AVFormatMapperTest, SetFormatWhenDeviceCannotLock) { |
+ testSetFormatWhenDeviceCannotLock(); |
+} |
+ |
+TEST_F(AVFormatMapperTest, SetFormatWhenFormatIsIncompatible) { |
+ testSetFormatWhenFormatIsIncompatible(); |
+} |