diff options
Diffstat (limited to 'third_party/libwebrtc/sdk/objc/unittests/RTCMTLVideoView_xctest.m')
-rw-r--r-- | third_party/libwebrtc/sdk/objc/unittests/RTCMTLVideoView_xctest.m | 298 |
1 files changed, 298 insertions, 0 deletions
diff --git a/third_party/libwebrtc/sdk/objc/unittests/RTCMTLVideoView_xctest.m b/third_party/libwebrtc/sdk/objc/unittests/RTCMTLVideoView_xctest.m new file mode 100644 index 0000000000..f152eeec91 --- /dev/null +++ b/third_party/libwebrtc/sdk/objc/unittests/RTCMTLVideoView_xctest.m @@ -0,0 +1,298 @@ +/* + * Copyright 2017 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 <XCTest/XCTest.h> + +#import <Foundation/Foundation.h> +#import <MetalKit/MetalKit.h> +#import <OCMock/OCMock.h> + +#import "components/renderer/metal/RTCMTLVideoView.h" + +#import "api/video_frame_buffer/RTCNativeI420Buffer.h" +#import "base/RTCVideoFrameBuffer.h" +#import "components/renderer/metal/RTCMTLNV12Renderer.h" +#import "components/video_frame_buffer/RTCCVPixelBuffer.h" + +static size_t kBufferWidth = 200; +static size_t kBufferHeight = 200; + +// Extension of RTC_OBJC_TYPE(RTCMTLVideoView) for testing purposes. +@interface RTC_OBJC_TYPE (RTCMTLVideoView) +(Testing) + + @property(nonatomic, readonly) MTKView *metalView; + ++ (BOOL)isMetalAvailable; ++ (UIView *)createMetalView:(CGRect)frame; ++ (id<RTCMTLRenderer>)createNV12Renderer; ++ (id<RTCMTLRenderer>)createI420Renderer; +- (void)drawInMTKView:(id)view; +@end + +@interface RTCMTLVideoViewTests : XCTestCase +@property(nonatomic, strong) id classMock; +@property(nonatomic, strong) id rendererNV12Mock; +@property(nonatomic, strong) id rendererI420Mock; +@property(nonatomic, strong) id frameMock; +@end + +@implementation RTCMTLVideoViewTests + +@synthesize classMock = _classMock; +@synthesize rendererNV12Mock = _rendererNV12Mock; +@synthesize rendererI420Mock = _rendererI420Mock; +@synthesize frameMock = _frameMock; + +- (void)setUp { + self.classMock = OCMClassMock([RTC_OBJC_TYPE(RTCMTLVideoView) class]); + [self startMockingNilView]; +} + +- (void)tearDown { + [self.classMock stopMocking]; + [self.rendererI420Mock stopMocking]; + [self.rendererNV12Mock stopMocking]; + [self.frameMock stopMocking]; + self.classMock = nil; + self.rendererI420Mock = nil; + self.rendererNV12Mock = nil; + self.frameMock = nil; +} + +- (id)frameMockWithCVPixelBuffer:(BOOL)hasCVPixelBuffer { + id frameMock = OCMClassMock([RTC_OBJC_TYPE(RTCVideoFrame) class]); + if (hasCVPixelBuffer) { + CVPixelBufferRef pixelBufferRef; + CVPixelBufferCreate(kCFAllocatorDefault, + kBufferWidth, + kBufferHeight, + kCVPixelFormatType_420YpCbCr8Planar, + nil, + &pixelBufferRef); + OCMStub([frameMock buffer]) + .andReturn([[RTC_OBJC_TYPE(RTCCVPixelBuffer) alloc] initWithPixelBuffer:pixelBufferRef]); + } else { + OCMStub([frameMock buffer]) + .andReturn([[RTC_OBJC_TYPE(RTCI420Buffer) alloc] initWithWidth:kBufferWidth + height:kBufferHeight]); + } + OCMStub([((RTC_OBJC_TYPE(RTCVideoFrame) *)frameMock) width]).andReturn(kBufferWidth); + OCMStub([((RTC_OBJC_TYPE(RTCVideoFrame) *)frameMock) height]).andReturn(kBufferHeight); + OCMStub([frameMock timeStampNs]).andReturn(arc4random_uniform(INT_MAX)); + return frameMock; +} + +- (id)rendererMockWithSuccessfulSetup:(BOOL)success { + id rendererMock = OCMClassMock([RTCMTLRenderer class]); + OCMStub([rendererMock addRenderingDestination:[OCMArg any]]).andReturn(success); + return rendererMock; +} + +- (void)startMockingNilView { + // Use OCMock 2 syntax here until OCMock is upgraded to 3.4 + [[[self.classMock stub] andReturn:nil] createMetalView:CGRectZero]; +} + +#pragma mark - Test cases + +- (void)testInitAssertsIfMetalUnavailabe { + // given + OCMStub([self.classMock isMetalAvailable]).andReturn(NO); + + // when + BOOL asserts = NO; + @try { + RTC_OBJC_TYPE(RTCMTLVideoView) *realView = + [[RTC_OBJC_TYPE(RTCMTLVideoView) alloc] initWithFrame:CGRectZero]; + (void)realView; + } @catch (NSException *ex) { + asserts = YES; + } + + XCTAssertTrue(asserts); +} + +- (void)testRTCVideoRenderNilFrameCallback { + // given + OCMStub([self.classMock isMetalAvailable]).andReturn(YES); + + RTC_OBJC_TYPE(RTCMTLVideoView) *realView = + [[RTC_OBJC_TYPE(RTCMTLVideoView) alloc] initWithFrame:CGRectMake(0, 0, 640, 480)]; + self.frameMock = OCMClassMock([RTC_OBJC_TYPE(RTCVideoFrame) class]); + + [[self.frameMock reject] buffer]; + [[self.classMock reject] createNV12Renderer]; + [[self.classMock reject] createI420Renderer]; + + // when + [realView renderFrame:nil]; + [realView drawInMTKView:realView.metalView]; + + // then + [self.frameMock verify]; + [self.classMock verify]; +} + +- (void)testRTCVideoRenderFrameCallbackI420 { + // given + OCMStub([self.classMock isMetalAvailable]).andReturn(YES); + self.rendererI420Mock = [self rendererMockWithSuccessfulSetup:YES]; + self.frameMock = [self frameMockWithCVPixelBuffer:NO]; + + OCMExpect([self.rendererI420Mock drawFrame:self.frameMock]); + OCMExpect([self.classMock createI420Renderer]).andReturn(self.rendererI420Mock); + [[self.classMock reject] createNV12Renderer]; + + RTC_OBJC_TYPE(RTCMTLVideoView) *realView = + [[RTC_OBJC_TYPE(RTCMTLVideoView) alloc] initWithFrame:CGRectMake(0, 0, 640, 480)]; + + // when + [realView renderFrame:self.frameMock]; + [realView drawInMTKView:realView.metalView]; + + // then + [self.rendererI420Mock verify]; + [self.classMock verify]; +} + +- (void)testRTCVideoRenderFrameCallbackNV12 { + // given + OCMStub([self.classMock isMetalAvailable]).andReturn(YES); + self.rendererNV12Mock = [self rendererMockWithSuccessfulSetup:YES]; + self.frameMock = [self frameMockWithCVPixelBuffer:YES]; + + OCMExpect([self.rendererNV12Mock drawFrame:self.frameMock]); + OCMExpect([self.classMock createNV12Renderer]).andReturn(self.rendererNV12Mock); + [[self.classMock reject] createI420Renderer]; + + RTC_OBJC_TYPE(RTCMTLVideoView) *realView = + [[RTC_OBJC_TYPE(RTCMTLVideoView) alloc] initWithFrame:CGRectMake(0, 0, 640, 480)]; + + // when + [realView renderFrame:self.frameMock]; + [realView drawInMTKView:realView.metalView]; + + // then + [self.rendererNV12Mock verify]; + [self.classMock verify]; +} + +- (void)testRTCVideoRenderWorksAfterReconstruction { + OCMStub([self.classMock isMetalAvailable]).andReturn(YES); + self.rendererNV12Mock = [self rendererMockWithSuccessfulSetup:YES]; + self.frameMock = [self frameMockWithCVPixelBuffer:YES]; + + OCMExpect([self.rendererNV12Mock drawFrame:self.frameMock]); + OCMExpect([self.classMock createNV12Renderer]).andReturn(self.rendererNV12Mock); + [[self.classMock reject] createI420Renderer]; + + RTC_OBJC_TYPE(RTCMTLVideoView) *realView = + [[RTC_OBJC_TYPE(RTCMTLVideoView) alloc] initWithFrame:CGRectMake(0, 0, 640, 480)]; + + [realView renderFrame:self.frameMock]; + [realView drawInMTKView:realView.metalView]; + [self.rendererNV12Mock verify]; + [self.classMock verify]; + + // Recreate view. + realView = [[RTC_OBJC_TYPE(RTCMTLVideoView) alloc] initWithFrame:CGRectMake(0, 0, 640, 480)]; + OCMExpect([self.rendererNV12Mock drawFrame:self.frameMock]); + // View hould reinit renderer. + OCMExpect([self.classMock createNV12Renderer]).andReturn(self.rendererNV12Mock); + + [realView renderFrame:self.frameMock]; + [realView drawInMTKView:realView.metalView]; + [self.rendererNV12Mock verify]; + [self.classMock verify]; +} + +- (void)testDontRedrawOldFrame { + OCMStub([self.classMock isMetalAvailable]).andReturn(YES); + self.rendererNV12Mock = [self rendererMockWithSuccessfulSetup:YES]; + self.frameMock = [self frameMockWithCVPixelBuffer:YES]; + + OCMExpect([self.rendererNV12Mock drawFrame:self.frameMock]); + OCMExpect([self.classMock createNV12Renderer]).andReturn(self.rendererNV12Mock); + [[self.classMock reject] createI420Renderer]; + + RTC_OBJC_TYPE(RTCMTLVideoView) *realView = + [[RTC_OBJC_TYPE(RTCMTLVideoView) alloc] initWithFrame:CGRectMake(0, 0, 640, 480)]; + [realView renderFrame:self.frameMock]; + [realView drawInMTKView:realView.metalView]; + + [self.rendererNV12Mock verify]; + [self.classMock verify]; + + [[self.rendererNV12Mock reject] drawFrame:[OCMArg any]]; + + [realView renderFrame:self.frameMock]; + [realView drawInMTKView:realView.metalView]; + + [self.rendererNV12Mock verify]; +} + +- (void)testDoDrawNewFrame { + OCMStub([self.classMock isMetalAvailable]).andReturn(YES); + self.rendererNV12Mock = [self rendererMockWithSuccessfulSetup:YES]; + self.frameMock = [self frameMockWithCVPixelBuffer:YES]; + + OCMExpect([self.rendererNV12Mock drawFrame:self.frameMock]); + OCMExpect([self.classMock createNV12Renderer]).andReturn(self.rendererNV12Mock); + [[self.classMock reject] createI420Renderer]; + + RTC_OBJC_TYPE(RTCMTLVideoView) *realView = + [[RTC_OBJC_TYPE(RTCMTLVideoView) alloc] initWithFrame:CGRectMake(0, 0, 640, 480)]; + [realView renderFrame:self.frameMock]; + [realView drawInMTKView:realView.metalView]; + + [self.rendererNV12Mock verify]; + [self.classMock verify]; + + // Get new frame. + self.frameMock = [self frameMockWithCVPixelBuffer:YES]; + OCMExpect([self.rendererNV12Mock drawFrame:self.frameMock]); + + [realView renderFrame:self.frameMock]; + [realView drawInMTKView:realView.metalView]; + + [self.rendererNV12Mock verify]; +} + +- (void)testReportsSizeChangesToDelegate { + OCMStub([self.classMock isMetalAvailable]).andReturn(YES); + + id delegateMock = OCMProtocolMock(@protocol(RTC_OBJC_TYPE(RTCVideoViewDelegate))); + CGSize size = CGSizeMake(640, 480); + OCMExpect([delegateMock videoView:[OCMArg any] didChangeVideoSize:size]); + + RTC_OBJC_TYPE(RTCMTLVideoView) *realView = + [[RTC_OBJC_TYPE(RTCMTLVideoView) alloc] initWithFrame:CGRectMake(0, 0, 640, 480)]; + realView.delegate = delegateMock; + [realView setSize:size]; + + // Delegate method is invoked with a dispatch_async. + OCMVerifyAllWithDelay(delegateMock, 1); +} + +- (void)testSetContentMode { + OCMStub([self.classMock isMetalAvailable]).andReturn(YES); + id metalKitView = OCMClassMock([MTKView class]); + [[[[self.classMock stub] ignoringNonObjectArgs] andReturn:metalKitView] + createMetalView:CGRectZero]; + OCMExpect([metalKitView setContentMode:UIViewContentModeScaleAspectFill]); + + RTC_OBJC_TYPE(RTCMTLVideoView) *realView = [[RTC_OBJC_TYPE(RTCMTLVideoView) alloc] init]; + [realView setVideoContentMode:UIViewContentModeScaleAspectFill]; + + OCMVerify(metalKitView); +} + +@end |