5 #import <Foundation/Foundation.h>
6 #import <OCMock/OCMock.h>
7 #import <UIKit/UIKit.h>
8 #import <XCTest/XCTest.h>
9 #include <_types/_uint32_t.h>
11 #include "flutter/fml/platform/darwin/message_loop_darwin.h"
30 typedef BOOL (^BoolGetter)();
41 - (id<FlutterKeyPrimaryResponder>)mockPrimaryResponder:(KeyCallbackSetter)callbackSetter {
42 id<FlutterKeyPrimaryResponder> mock =
44 OCMStub([mock handlePress:[OCMArg any] callback:[OCMArg any]])
45 .andDo((^(NSInvocation* invocation) {
49 [invocation getArgument:&pressUnsafe atIndex:2];
50 [invocation getArgument:&callbackUnsafe atIndex:3];
56 CFRunLoopPerformBlock(CFRunLoopGetCurrent(),
57 fml::MessageLoopDarwin::kMessageLoopCFRunLoopMode, ^() {
58 callbackSetter(press, callback);
64 - (id<FlutterKeySecondaryResponder>)mockSecondaryResponder:(BoolGetter)resultGetter {
65 id<FlutterKeySecondaryResponder> mock =
67 OCMStub([mock handlePress:[OCMArg any]]).andDo((^(NSInvocation* invocation) {
68 BOOL result = resultGetter();
69 [invocation setReturnValue:&result];
74 - (void)testNextResponderShouldThrowOnPressesEnded {
77 UIResponder* nextResponder = OCMStrictClassMock([UIResponder
class]);
78 OCMStub([nextResponder pressesBegan:OCMOCK_ANY withEvent:OCMOCK_ANY]);
85 OCMStub([owner nextResponder]).andReturn(nextResponder);
87 XCTAssertThrowsSpecificNamed([owner.nextResponder pressesEnded:[[NSSet alloc] init]
88 withEvent:[[UIPressesEvent alloc] init]],
89 NSException, NSInternalInconsistencyException);
91 [mockEngine stopMocking];
94 - (void)testSinglePrimaryResponder {
96 __block BOOL primaryResponse = FALSE;
97 __block
int callbackCount = 0;
99 FlutterAsyncKeyCallback callback) {
101 callback(primaryResponse);
103 constexpr UIKeyboardHIDUsage keyId = (UIKeyboardHIDUsage)0x50;
105 __block
bool completeHandled =
true;
106 primaryResponse = TRUE;
109 completeHandled = false;
111 XCTAssertEqual(callbackCount, 1);
112 XCTAssertTrue(completeHandled);
113 completeHandled =
true;
117 primaryResponse = FALSE;
120 completeHandled = false;
122 XCTAssertEqual(callbackCount, 1);
123 XCTAssertFalse(completeHandled);
126 - (void)testDoublePrimaryResponder {
129 __block BOOL callback1Response = FALSE;
130 __block
int callback1Count = 0;
132 FlutterAsyncKeyCallback callback) {
134 callback(callback1Response);
137 __block BOOL callback2Response = FALSE;
138 __block
int callback2Count = 0;
140 FlutterAsyncKeyCallback callback) {
142 callback(callback2Response);
146 __block
bool somethingWasHandled =
true;
147 constexpr UIKeyboardHIDUsage keyId = (UIKeyboardHIDUsage)0x50;
148 callback1Response = TRUE;
149 callback2Response = TRUE;
152 somethingWasHandled = false;
154 XCTAssertEqual(callback1Count, 1);
155 XCTAssertEqual(callback2Count, 1);
156 XCTAssertTrue(somethingWasHandled);
158 somethingWasHandled =
true;
163 callback1Response = TRUE;
164 callback2Response = FALSE;
167 somethingWasHandled = false;
169 XCTAssertEqual(callback1Count, 1);
170 XCTAssertEqual(callback2Count, 1);
171 XCTAssertTrue(somethingWasHandled);
173 somethingWasHandled =
true;
178 callback1Response = FALSE;
179 callback2Response = FALSE;
182 somethingWasHandled = false;
184 XCTAssertEqual(callback1Count, 1);
185 XCTAssertEqual(callback2Count, 1);
186 XCTAssertFalse(somethingWasHandled);
189 - (void)testSingleSecondaryResponder {
192 __block BOOL primaryResponse = FALSE;
193 __block
int callbackCount = 0;
195 FlutterAsyncKeyCallback callback) {
197 callback(primaryResponse);
200 __block BOOL secondaryResponse;
202 return secondaryResponse;
207 constexpr UIKeyboardHIDUsage keyId = (UIKeyboardHIDUsage)0x50;
208 secondaryResponse = FALSE;
209 primaryResponse = TRUE;
210 __block
bool completeHandled =
true;
213 completeHandled = false;
215 XCTAssertEqual(callbackCount, 1);
216 XCTAssertTrue(completeHandled);
217 completeHandled =
true;
222 secondaryResponse = TRUE;
223 primaryResponse = FALSE;
226 completeHandled = false;
228 XCTAssertEqual(callbackCount, 1);
229 XCTAssertTrue(completeHandled);
230 completeHandled =
true;
234 secondaryResponse = FALSE;
235 primaryResponse = FALSE;
238 completeHandled = false;
240 XCTAssertEqual(callbackCount, 1);
241 XCTAssertFalse(completeHandled);
244 - (void)testEventsProcessedSequentially {
245 constexpr UIKeyboardHIDUsage keyId1 = (UIKeyboardHIDUsage)0x50;
246 constexpr UIKeyboardHIDUsage keyId2 = (UIKeyboardHIDUsage)0x51;
251 __block
bool key1Handled =
true;
252 __block
bool key2Handled =
true;
256 FlutterAsyncKeyCallback callback) {
257 if (press == event1) {
258 key1Callback = callback;
259 } else if (press == event2) {
260 key2Callback = callback;
265 CFRunLoopTimerRef timer0 = CFRunLoopTimerCreateWithHandler(
266 kCFAllocatorDefault, CFAbsoluteTimeGetCurrent(), 0, 0, 0, ^(CFRunLoopTimerRef timerRef) {
272 CFRunLoopAddTimer(CFRunLoopGetCurrent(), timer0, kCFRunLoopCommonModes);
273 CFRunLoopTimerRef timer1 = CFRunLoopTimerCreateWithHandler(
274 kCFAllocatorDefault, CFAbsoluteTimeGetCurrent() + 1, 0, 0, 0, ^(CFRunLoopTimerRef timerRef) {
276 XCTAssertFalse(key1Handled);
282 CFRunLoopStop(CFRunLoopGetCurrent());
284 CFRunLoopAddTimer(CFRunLoopGetCurrent(), timer1, kCFRunLoopCommonModes);
288 CFRunLoopTimerRef timer2 = CFRunLoopTimerCreateWithHandler(
289 kCFAllocatorDefault, CFAbsoluteTimeGetCurrent() + 2, 0, 0, 0, ^(CFRunLoopTimerRef timerRef) {
291 XCTAssertTrue(key1Callback != nil);
292 XCTAssertTrue(key2Callback == nil);
295 CFRunLoopAddTimer(CFRunLoopGetCurrent(), timer2,
296 fml::MessageLoopDarwin::kMessageLoopCFRunLoopMode);
297 CFRunLoopTimerRef timer3 = CFRunLoopTimerCreateWithHandler(
298 kCFAllocatorDefault, CFAbsoluteTimeGetCurrent() + 3, 0, 0, 0, ^(CFRunLoopTimerRef timerRef) {
300 XCTAssertTrue(key1Callback != nil);
301 XCTAssertTrue(key2Callback != nil);
304 CFRunLoopAddTimer(CFRunLoopGetCurrent(), timer3,
305 fml::MessageLoopDarwin::kMessageLoopCFRunLoopMode);
309 XCTAssertFalse(key2Handled);
310 XCTAssertFalse(key1Handled);