Flutter iOS Embedder
VsyncWaiterIosTest.mm
Go to the documentation of this file.
1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #import <OCMock/OCMock.h>
6 #import <XCTest/XCTest.h>
7 
8 #include "flutter/fml/raster_thread_merger.h"
9 #include "flutter/fml/thread.h"
10 
13 
15 namespace {
16 fml::RefPtr<fml::TaskRunner> CreateNewThread(const std::string& name) {
17  auto thread = std::make_unique<fml::Thread>(name);
18  auto runner = thread->GetTaskRunner();
19  return runner;
20 }
21 } // namespace
22 
23 @interface VSyncClient (Testing)
24 
25 - (CADisplayLink*)getDisplayLink;
26 - (void)onDisplayLink:(CADisplayLink*)link;
27 
28 @end
29 
30 @interface VsyncWaiterIosTest : XCTestCase
31 @end
32 
33 @implementation VsyncWaiterIosTest
34 
35 - (void)testSetAllowPauseAfterVsyncCorrect {
36  auto thread_task_runner = CreateNewThread("VsyncWaiterIosTest");
37  VSyncClient* vsyncClient = [[VSyncClient alloc]
38  initWithTaskRunner:thread_task_runner
39  callback:[](std::unique_ptr<flutter::FrameTimingsRecorder> recorder) {}];
40  CADisplayLink* link = [vsyncClient getDisplayLink];
41  vsyncClient.allowPauseAfterVsync = NO;
42  [vsyncClient await];
43  [vsyncClient onDisplayLink:link];
44  XCTAssertFalse(link.isPaused);
45 
46  vsyncClient.allowPauseAfterVsync = YES;
47  [vsyncClient await];
48  [vsyncClient onDisplayLink:link];
49  XCTAssertTrue(link.isPaused);
50 }
51 
52 - (void)testSetCorrectVariableRefreshRates {
53  auto thread_task_runner = CreateNewThread("VsyncWaiterIosTest");
54  auto callback = [](std::unique_ptr<flutter::FrameTimingsRecorder> recorder) {};
55  id bundleMock = OCMPartialMock([NSBundle mainBundle]);
56  OCMStub([bundleMock objectForInfoDictionaryKey:@"CADisableMinimumFrameDurationOnPhone"])
57  .andReturn(@YES);
58  id mockDisplayLinkManager = [OCMockObject mockForClass:[DisplayLinkManager class]];
59  double maxFrameRate = 120;
60  [[[mockDisplayLinkManager stub] andReturnValue:@(maxFrameRate)] displayRefreshRate];
61 
62  VSyncClient* vsyncClient = [[VSyncClient alloc] initWithTaskRunner:thread_task_runner
63  callback:callback];
64  CADisplayLink* link = [vsyncClient getDisplayLink];
65  if (@available(iOS 15.0, *)) {
66  XCTAssertEqualWithAccuracy(link.preferredFrameRateRange.maximum, maxFrameRate, 0.1);
67  XCTAssertEqualWithAccuracy(link.preferredFrameRateRange.preferred, maxFrameRate, 0.1);
68  XCTAssertEqualWithAccuracy(link.preferredFrameRateRange.minimum, maxFrameRate / 2, 0.1);
69  } else {
70  XCTAssertEqualWithAccuracy(link.preferredFramesPerSecond, maxFrameRate, 0.1);
71  }
72 }
73 
74 - (void)testDoNotSetVariableRefreshRatesIfCADisableMinimumFrameDurationOnPhoneIsNotOn {
75  auto thread_task_runner = CreateNewThread("VsyncWaiterIosTest");
76  auto callback = [](std::unique_ptr<flutter::FrameTimingsRecorder> recorder) {};
77  id bundleMock = OCMPartialMock([NSBundle mainBundle]);
78  OCMStub([bundleMock objectForInfoDictionaryKey:@"CADisableMinimumFrameDurationOnPhone"])
79  .andReturn(@NO);
80  id mockDisplayLinkManager = [OCMockObject mockForClass:[DisplayLinkManager class]];
81  double maxFrameRate = 120;
82  [[[mockDisplayLinkManager stub] andReturnValue:@(maxFrameRate)] displayRefreshRate];
83 
84  VSyncClient* vsyncClient = [[VSyncClient alloc] initWithTaskRunner:thread_task_runner
85  callback:callback];
86  CADisplayLink* link = [vsyncClient getDisplayLink];
87  if (@available(iOS 15.0, *)) {
88  XCTAssertEqualWithAccuracy(link.preferredFrameRateRange.maximum, 0, 0.1);
89  XCTAssertEqualWithAccuracy(link.preferredFrameRateRange.preferred, 0, 0.1);
90  XCTAssertEqualWithAccuracy(link.preferredFrameRateRange.minimum, 0, 0.1);
91  } else {
92  XCTAssertEqualWithAccuracy(link.preferredFramesPerSecond, 0, 0.1);
93  }
94 }
95 
96 - (void)testDoNotSetVariableRefreshRatesIfCADisableMinimumFrameDurationOnPhoneIsNotSet {
97  auto thread_task_runner = CreateNewThread("VsyncWaiterIosTest");
98  auto callback = [](std::unique_ptr<flutter::FrameTimingsRecorder> recorder) {};
99  id mockDisplayLinkManager = [OCMockObject mockForClass:[DisplayLinkManager class]];
100  double maxFrameRate = 120;
101  [[[mockDisplayLinkManager stub] andReturnValue:@(maxFrameRate)] displayRefreshRate];
102  VSyncClient* vsyncClient = [[VSyncClient alloc] initWithTaskRunner:thread_task_runner
103  callback:callback];
104  CADisplayLink* link = [vsyncClient getDisplayLink];
105  if (@available(iOS 15.0, *)) {
106  XCTAssertEqualWithAccuracy(link.preferredFrameRateRange.maximum, 0, 0.1);
107  XCTAssertEqualWithAccuracy(link.preferredFrameRateRange.preferred, 0, 0.1);
108  XCTAssertEqualWithAccuracy(link.preferredFrameRateRange.minimum, 0, 0.1);
109  } else {
110  XCTAssertEqualWithAccuracy(link.preferredFramesPerSecond, 0, 0.1);
111  }
112 }
113 
114 - (void)testAwaitAndPauseWillWorkCorrectly {
115  auto thread_task_runner = CreateNewThread("VsyncWaiterIosTest");
116  VSyncClient* vsyncClient = [[VSyncClient alloc]
117  initWithTaskRunner:thread_task_runner
118  callback:[](std::unique_ptr<flutter::FrameTimingsRecorder> recorder) {}];
119 
120  CADisplayLink* link = [vsyncClient getDisplayLink];
121  XCTAssertTrue(link.isPaused);
122 
123  [vsyncClient await];
124  XCTAssertFalse(link.isPaused);
125 
126  [vsyncClient pause];
127  XCTAssertTrue(link.isPaused);
128 }
129 
130 - (void)testReleasesLinkOnInvalidation {
131  __weak CADisplayLink* weakLink;
132  @autoreleasepool {
133  auto thread_task_runner = CreateNewThread("VsyncWaiterIosTest");
134  VSyncClient* vsyncClient = [[VSyncClient alloc]
135  initWithTaskRunner:thread_task_runner
136  callback:[](std::unique_ptr<flutter::FrameTimingsRecorder> recorder) {}];
137 
138  weakLink = [vsyncClient getDisplayLink];
139  XCTAssertNotNil(weakLink);
140  [vsyncClient invalidate];
141  }
142  // VSyncClient has released the CADisplayLink.
143  XCTAssertNil(weakLink);
144 }
145 
146 @end
-[VSyncClient pause]
void pause()
Definition: vsync_waiter_ios.mm:110
VsyncWaiterIosTest
Definition: VsyncWaiterIosTest.mm:30
-[VSyncClient invalidate]
void invalidate()
Call invalidate before releasing this object to remove from runloops.
Definition: vsync_waiter_ios.mm:137
FLUTTER_ASSERT_ARC::CreateNewThread
fml::RefPtr< fml::TaskRunner > CreateNewThread(const std::string &name)
Definition: VsyncWaiterIosTest.mm:16
-[VSyncClient(Testing) getDisplayLink]
CADisplayLink * getDisplayLink()
-[VSyncClient await]
void await()
Definition: vsync_waiter_ios.mm:106
FlutterMacros.h
VSyncClient::allowPauseAfterVsync
BOOL allowPauseAfterVsync
Default value is YES. Vsync client will pause vsync callback after receiving a vsync signal....
Definition: vsync_waiter_ios.h:46
VSyncClient(Testing)
Definition: FlutterViewControllerTest.mm:184
vsync_waiter_ios.h
FLUTTER_ASSERT_ARC
Definition: FlutterChannelKeyResponder.mm:13
VSyncClient
Definition: vsync_waiter_ios.h:36