| Flutter macOS Embedder |

Instance Methods | Class Methods | List of all members
FlutterViewControllerTestObjC Class Reference
Inheritance diagram for FlutterViewControllerTestObjC:

## Instance Methods
(bool) | - testKeyEventsAreSentToFramework:
(bool) | - testKeyEventsArePropagatedIfNotHandled:
(bool) | - testKeyEventsAreNotPropagatedIfHandled:
(bool) | - testCtrlTabKeyEventIsPropagated:
(bool) | - testKeyEquivalentIsPassedToTextInputPlugin:
(bool) | - testFlagsChangedEventsArePropagatedIfNotHandled:
(bool) | - testKeyboardIsRestartedOnEngineRestart:
(bool) | - testTrackpadGesturesAreSentToFramework:
(bool) | - mouseAndGestureEventsAreHandledSeparately:
(bool) | - testMouseDownUpEventsSentToNextResponder:
(bool) | - testModifierKeysAreSynthesizedOnMouseMove:
(bool) | - testViewWillAppearCalledMultipleTimes:
(bool) | - testFlutterViewIsConfigured:
(bool) | - testLookupKeyAssets
(bool) | - testLookupKeyAssetsWithPackage
(bool) | - testViewControllerIsReleased

## Class Methods
(void) | + respondFalseForSendEvent:callback:userData:

## Detailed Description

Definition at line 100 of file FlutterViewControllerTest.mm.

## Method Documentation

## ◆ mouseAndGestureEventsAreHandledSeparately:

- (bool) mouseAndGestureEventsAreHandledSeparately: |  | (id) | engineMock |

Definition at line 167 of file FlutterViewControllerTest.mm.

1068 :(id)engineMock {
1069 FlutterViewController* viewController = [[FlutterViewController alloc] initWithEngine:engineMock
1070 nibName:@""
1071 bundle:nil];
1072 [viewController loadView];
1073
1074 // Test for pan events.
1075 // Start gesture.
1076 fml::CFRef<CGEventRef> cgEventStart(
1077 CGEventCreateScrollWheelEvent(NULL, kCGScrollEventUnitPixel, 1, 0));
1078 CGEventSetType(cgEventStart, kCGEventScrollWheel);
1079 CGEventSetIntegerValueField(cgEventStart, kCGScrollWheelEventScrollPhase, kCGScrollPhaseBegan);
1080 CGEventSetIntegerValueField(cgEventStart, kCGScrollWheelEventIsContinuous, 1);
1081 [viewController scrollWheel:[NSEvent eventWithCGEvent:cgEventStart]];
1082
1083 fml::CFRef<CGEventRef> cgEventUpdate(CGEventCreateCopy(cgEventStart));
1084 CGEventSetIntegerValueField(cgEventUpdate, kCGScrollWheelEventScrollPhase, kCGScrollPhaseChanged);
1085 CGEventSetIntegerValueField(cgEventUpdate, kCGScrollWheelEventDeltaAxis2, 1); // pan_x
1086 CGEventSetIntegerValueField(cgEventUpdate, kCGScrollWheelEventDeltaAxis1, 2); // pan_y
1087 [viewController scrollWheel:[NSEvent eventWithCGEvent:cgEventUpdate]];
1088
1089 NSEvent* mouseEvent = flutter::testing::CreateMouseEvent(0x00);
1090 [viewController mouseEntered:mouseEvent];
1091 [viewController mouseExited:mouseEvent];
1092
1093 // End gesture.
1094 fml::CFRef<CGEventRef> cgEventEnd(CGEventCreateCopy(cgEventStart));
1095 CGEventSetIntegerValueField(cgEventEnd, kCGScrollWheelEventScrollPhase, kCGScrollPhaseEnded);
1096 [viewController scrollWheel:[NSEvent eventWithCGEvent:cgEventEnd]];
1097
1098 return true;
1099 }
FlutterViewController
Definition: FlutterViewController.h:73

## ◆ respondFalseForSendEvent:callback:userData:

+ (void) respondFalseForSendEvent: |  | (const FlutterKeyEvent&) | event
callback: |  | (nullable FlutterKeyEventCallback) | callback
userData: |  | (nullable void*) | userData

Definition at line 167 of file FlutterViewControllerTest.mm.

758 :(const FlutterKeyEvent&)event
759 callback:(nullable FlutterKeyEventCallback)callback
760 userData:(nullable void*)userData {
761 if (callback != nullptr) {
762 callback(false, userData);
763 }
764 }

## ◆ testCtrlTabKeyEventIsPropagated:

- (bool) testCtrlTabKeyEventIsPropagated: |  | (id) | mockEngine |

Definition at line 167 of file FlutterViewControllerTest.mm.

396 :(id)engineMock {
397 __block bool called = false;
398 __block FlutterKeyEvent last_event;
399 OCMStub([[engineMock ignoringNonObjectArgs] sendKeyEvent:kDefaultFlutterKeyEvent
400 callback:nil
401 userData:nil])
402 .andDo((^(NSInvocation* invocation) {
403 FlutterKeyEvent* event;
404 [invocation getArgument:&event atIndex:2];
405 called = true;
406 last_event = *event;
407 }));
408 FlutterKeyboardManager* keyboardManager =
409 [[FlutterKeyboardManager alloc] initWithDelegate:engineMock];
410 OCMStub([engineMock keyboardManager]).andReturn(keyboardManager);
411
412 FlutterViewController* viewController = [[FlutterViewController alloc] initWithEngine:engineMock
413 nibName:@""
414 bundle:nil];
415 // Ctrl+tab
416 NSEvent* event = [NSEvent keyEventWithType:NSEventTypeKeyDown
417 location:NSZeroPoint
418 modifierFlags:0x40101
419 timestamp:0
420 windowNumber:0
421 context:nil
422 characters:@""
423 charactersIgnoringModifiers:@""
424 isARepeat:NO
425 keyCode:48];
426 const uint64_t kPhysicalKeyTab = 0x7002b;
427
428 [viewController viewWillAppear]; // Initializes the event channel.
429 // Creates a NSWindow so that FlutterView view can be first responder.
430 NSWindow* window = [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, 800, 600)
431 styleMask:NSBorderlessWindowMask
432 backing:NSBackingStoreBuffered
433 defer:NO];
434 window.contentView = viewController.view;
435 [window makeFirstResponder:viewController.flutterView];
436 [viewController.view performKeyEquivalent:event];
437
438 EXPECT_TRUE(called);
439 EXPECT_EQ(last_event.type, kFlutterKeyEventTypeDown);
440 EXPECT_EQ(last_event.physical, kPhysicalKeyTab);
441 return true;
442 }
kDefaultFlutterKeyEvent
static const FlutterKeyEvent kDefaultFlutterKeyEvent
Definition: FlutterViewControllerTest.mm:27
FlutterKeyboardManager
Definition: FlutterKeyboardManager.h:79

## ◆ testFlagsChangedEventsArePropagatedIfNotHandled:

- (bool) testFlagsChangedEventsArePropagatedIfNotHandled: |  | (id) | mockEngine |

Definition at line 167 of file FlutterViewControllerTest.mm.

584 :(id)engineMock {
585 id binaryMessengerMock = OCMProtocolMock(@protocol(FlutterBinaryMessenger));
586 OCMStub( // NOLINT(google-objc-avoid-throwing-exception)
587 [engineMock binaryMessenger])
588 .andReturn(binaryMessengerMock);
589 FlutterKeyboardManager* keyboardManager =
590 [[FlutterKeyboardManager alloc] initWithDelegate:engineMock];
591 OCMStub([engineMock keyboardManager]).andReturn(keyboardManager);
592 OCMStub([[engineMock ignoringNonObjectArgs] sendKeyEvent:kDefaultFlutterKeyEvent
593 callback:nil
594 userData:nil])
595 .andCall([FlutterViewControllerTestObjC class],
596 @selector(respondFalseForSendEvent:callback:userData:));
597 FlutterViewController* viewController = [[FlutterViewController alloc] initWithEngine:engineMock
598 nibName:@""
599 bundle:nil];
600 id responderMock = flutter::testing::mockResponder();
601 id responderWrapper = [[FlutterResponderWrapper alloc] initWithResponder:responderMock];
602 viewController.nextResponder = responderWrapper;
603 NSDictionary* expectedEvent = @{
604 @"keymap" : @"macos",
605 @"type" : @"keydown",
606 @"keyCode" : @(56), // SHIFT key
607 @"modifiers" : @(537001986),
608 };
609 NSData* encodedKeyEvent = [[FlutterJSONMessageCodec sharedInstance] encode:expectedEvent];
610 CGEventRef cgEvent = CGEventCreateKeyboardEvent(NULL, 56, TRUE); // SHIFT key
611 CGEventSetType(cgEvent, kCGEventFlagsChanged);
612 NSEvent* event = [NSEvent eventWithCGEvent:cgEvent];
613 OCMExpect( // NOLINT(google-objc-avoid-throwing-exception)
614 [binaryMessengerMock sendOnChannel:@"flutter/keyevent"
615 message:encodedKeyEvent
616 binaryReply:[OCMArg any]])
617 .andDo((^(NSInvocation* invocation) {
618 FlutterBinaryReply handler;
619 [invocation getArgument:&handler atIndex:4];
620 NSDictionary* reply = @{
621 @"handled" : @(false),
622 };
623 NSData* encodedReply = [[FlutterJSONMessageCodec sharedInstance] encode:reply];
624 handler(encodedReply);
625 }));
626 [viewController viewWillAppear]; // Initializes the event channel.
627 [viewController flagsChanged:event];
628 @try {
629 OCMVerify( // NOLINT(google-objc-avoid-throwing-exception)
630 [binaryMessengerMock sendOnChannel:@"flutter/keyevent"
631 message:encodedKeyEvent
632 binaryReply:[OCMArg any]]);
633 } @catch (NSException* e) {
634 NSLog(@"%@", e.reason);
635 return false;
636 }
637 return true;
638 }
FlutterBinaryReply
NS_ASSUME_NONNULL_BEGIN typedef void(^ FlutterBinaryReply)(NSData *_Nullable reply)
FlutterJSONMessageCodec
Definition: FlutterCodecs.h:81
FlutterResponderWrapper
Definition: FlutterViewControllerTest.mm:51
FlutterViewControllerTestObjC
Definition: FlutterViewControllerTest.mm:101
FlutterBinaryMessenger-p
Definition: FlutterBinaryMessenger.h:49
+[FlutterMessageCodec-p sharedInstance]
instancetype sharedInstance()

## ◆ testFlutterViewIsConfigured:

- (bool) testFlutterViewIsConfigured: |  | (id) | mockEngine |

Definition at line 167 of file FlutterViewControllerTest.mm.

565 :(id)engineMock {
566 FlutterRenderer* renderer_ = [[FlutterRenderer alloc] initWithFlutterEngine:engineMock];
567 OCMStub([engineMock renderer]).andReturn(renderer_);
568
569 FlutterViewController* viewController = [[FlutterViewController alloc] initWithEngine:engineMock
570 nibName:@""
571 bundle:nil];
572 [viewController loadView];
573
574 @try {
575 // Make sure "renderer" was called during "loadView", which means "flutterView" is created
576 OCMVerify([engineMock renderer]);
577 } @catch (...) {
578 return false;
579 }
580
581 return true;
582 }
FlutterRenderer
Definition: FlutterRenderer.h:19

## ◆ testKeyboardIsRestartedOnEngineRestart:

- (bool) testKeyboardIsRestartedOnEngineRestart: |  | (id) | mockEngine |

Definition at line 167 of file FlutterViewControllerTest.mm.

698 :(id)engineMock {
699 id binaryMessengerMock = OCMProtocolMock(@protocol(FlutterBinaryMessenger));
700 OCMStub( // NOLINT(google-objc-avoid-throwing-exception)
701 [engineMock binaryMessenger])
702 .andReturn(binaryMessengerMock);
703 __block bool called = false;
704 __block FlutterKeyEvent last_event;
705 __block FlutterKeyboardManager* keyboardManager =
706 [[FlutterKeyboardManager alloc] initWithDelegate:engineMock];
707
708 OCMStub([engineMock keyboardManager]).andDo(^(NSInvocation* invocation) {
709 [invocation setReturnValue:&keyboardManager];
710 });
711
712 OCMStub([[engineMock ignoringNonObjectArgs] sendKeyEvent:kDefaultFlutterKeyEvent
713 callback:nil
714 userData:nil])
715 .andDo((^(NSInvocation* invocation) {
716 FlutterKeyEvent* event;
717 [invocation getArgument:&event atIndex:2];
718 called = true;
719 last_event = *event;
720 }));
721
722 FlutterViewController* viewController = [[FlutterViewController alloc] initWithEngine:engineMock
723 nibName:@""
724 bundle:nil];
725 [viewController viewWillAppear];
726 NSEvent* keyADown = [NSEvent keyEventWithType:NSEventTypeKeyDown
727 location:NSZeroPoint
728 modifierFlags:0x100
729 timestamp:0
730 windowNumber:0
731 context:nil
732 characters:@"a"
733 charactersIgnoringModifiers:@"a"
734 isARepeat:FALSE
735 keyCode:0];
736 const uint64_t kPhysicalKeyA = 0x70004;
737
738 // Send KeyA key down event twice. Without restarting the keyboard during
739 // onPreEngineRestart, the second event received will be an empty event with
740 // physical key 0x0 because duplicate key down events are ignored.
741
742 called = false;
743 [viewController keyDown:keyADown];
744 EXPECT_TRUE(called);
745 EXPECT_EQ(last_event.type, kFlutterKeyEventTypeDown);
746 EXPECT_EQ(last_event.physical, kPhysicalKeyA);
747
748 keyboardManager = [[FlutterKeyboardManager alloc] initWithDelegate:engineMock];
749
750 called = false;
751 [viewController keyDown:keyADown];
752 EXPECT_TRUE(called);
753 EXPECT_EQ(last_event.type, kFlutterKeyEventTypeDown);
754 EXPECT_EQ(last_event.physical, kPhysicalKeyA);
755 return true;
756 }

## ◆ testKeyEquivalentIsPassedToTextInputPlugin:

- (bool) testKeyEquivalentIsPassedToTextInputPlugin: |  | (id) | mockEngine |

Definition at line 167 of file FlutterViewControllerTest.mm.

444 :(id)engineMock {
445 __block bool called = false;
446 __block FlutterKeyEvent last_event;
447 OCMStub([[engineMock ignoringNonObjectArgs] sendKeyEvent:kDefaultFlutterKeyEvent
448 callback:nil
449 userData:nil])
450 .andDo((^(NSInvocation* invocation) {
451 FlutterKeyEvent* event;
452 [invocation getArgument:&event atIndex:2];
453 called = true;
454 last_event = *event;
455 }));
456 FlutterViewController* viewController = [[FlutterViewController alloc] initWithEngine:engineMock
457 nibName:@""
458 bundle:nil];
459 // Ctrl+tab
460 NSEvent* event = [NSEvent keyEventWithType:NSEventTypeKeyDown
461 location:NSZeroPoint
462 modifierFlags:0x40101
463 timestamp:0
464 windowNumber:0
465 context:nil
466 characters:@""
467 charactersIgnoringModifiers:@""
468 isARepeat:NO
469 keyCode:48];
470 const uint64_t kPhysicalKeyTab = 0x7002b;
471
472 [viewController viewWillAppear]; // Initializes the event channel.
473
474 NSWindow* window = [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, 800, 600)
475 styleMask:NSBorderlessWindowMask
476 backing:NSBackingStoreBuffered
477 defer:NO];
478 window.contentView = viewController.view;
479
480 NSDictionary* setClientConfig = @{
481 @"viewId" : @(flutter::kFlutterImplicitViewId),
482 };
483 FlutterMethodCall* methodCall =
484 [FlutterMethodCall methodCallWithMethodName:@"TextInput.setClient"
485 arguments:@[ @(1), setClientConfig ]];
486 FlutterResult result = ^(id result) {
487 };
488 [viewController.engine.textInputPlugin handleMethodCall:methodCall result:result];
489
490 [viewController.engine.textInputPlugin
491 handleMethodCall:[FlutterMethodCall methodCallWithMethodName:@"TextInput.show" arguments:@[]]
492 result:^(id){
493 }];
494
495 // Make the textInputPlugin first responder. This should still result in
496 // view controller reporting the key event.
497 [window makeFirstResponder:viewController.engine.textInputPlugin];
498
499 [viewController.view performKeyEquivalent:event];
500
501 EXPECT_TRUE(called);
502 EXPECT_EQ(last_event.type, kFlutterKeyEventTypeDown);
503 EXPECT_EQ(last_event.physical, kPhysicalKeyTab);
504 return true;
505 }
FlutterResult
void(^ FlutterResult)(id _Nullable result)
Definition: FlutterChannels.h:194
FlutterMethodCall
Definition: FlutterCodecs.h:221
+[FlutterMethodCall methodCallWithMethodName:arguments:]
instancetype methodCallWithMethodName:arguments:(NSString *method,[arguments] id _Nullable arguments)

## ◆ testKeyEventsAreNotPropagatedIfHandled:

- (bool) testKeyEventsAreNotPropagatedIfHandled: |  | (id) | mockEngine |

Definition at line 167 of file FlutterViewControllerTest.mm.

640 :(id)engineMock {
641 id binaryMessengerMock = OCMProtocolMock(@protocol(FlutterBinaryMessenger));
642 OCMStub( // NOLINT(google-objc-avoid-throwing-exception)
643 [engineMock binaryMessenger])
644 .andReturn(binaryMessengerMock);
645 FlutterKeyboardManager* keyboardManager =
646 [[FlutterKeyboardManager alloc] initWithDelegate:engineMock];
647 OCMStub([engineMock keyboardManager]).andReturn(keyboardManager);
648 OCMStub([[engineMock ignoringNonObjectArgs] sendKeyEvent:kDefaultFlutterKeyEvent
649 callback:nil
650 userData:nil])
651 .andCall([FlutterViewControllerTestObjC class],
652 @selector(respondFalseForSendEvent:callback:userData:));
653 FlutterViewController* viewController = [[FlutterViewController alloc] initWithEngine:engineMock
654 nibName:@""
655 bundle:nil];
656 id responderMock = flutter::testing::mockResponder();
657 id responderWrapper = [[FlutterResponderWrapper alloc] initWithResponder:responderMock];
658 viewController.nextResponder = responderWrapper;
659 NSDictionary* expectedEvent = @{
660 @"keymap" : @"macos",
661 @"type" : @"keydown",
662 @"keyCode" : @(65),
663 @"modifiers" : @(538968064),
664 @"characters" : @".",
665 @"charactersIgnoringModifiers" : @".",
666 };
667 NSData* encodedKeyEvent = [[FlutterJSONMessageCodec sharedInstance] encode:expectedEvent];
668 CGEventRef cgEvent = CGEventCreateKeyboardEvent(NULL, 65, TRUE);
669 NSEvent* event = [NSEvent eventWithCGEvent:cgEvent];
670 OCMExpect( // NOLINT(google-objc-avoid-throwing-exception)
671 [binaryMessengerMock sendOnChannel:@"flutter/keyevent"
672 message:encodedKeyEvent
673 binaryReply:[OCMArg any]])
674 .andDo((^(NSInvocation* invocation) {
675 FlutterBinaryReply handler;
676 [invocation getArgument:&handler atIndex:4];
677 NSDictionary* reply = @{
678 @"handled" : @(true),
679 };
680 NSData* encodedReply = [[FlutterJSONMessageCodec sharedInstance] encode:reply];
681 handler(encodedReply);
682 }));
683 [viewController viewWillAppear]; // Initializes the event channel.
684 [viewController keyDown:event];
685 @try {
686 OCMVerify( // NOLINT(google-objc-avoid-throwing-exception)
687 never(), [responderMock keyDown:[OCMArg any]]);
688 OCMVerify( // NOLINT(google-objc-avoid-throwing-exception)
689 [binaryMessengerMock sendOnChannel:@"flutter/keyevent"
690 message:encodedKeyEvent
691 binaryReply:[OCMArg any]]);
692 } @catch (...) {
693 return false;
694 }
695 return true;
696 }

## ◆ testKeyEventsArePropagatedIfNotHandled:

- (bool) testKeyEventsArePropagatedIfNotHandled: |  | (id) | mockEngine |

Definition at line 167 of file FlutterViewControllerTest.mm.

507 :(id)engineMock {
508 id binaryMessengerMock = OCMProtocolMock(@protocol(FlutterBinaryMessenger));
509 OCMStub( // NOLINT(google-objc-avoid-throwing-exception)
510 [engineMock binaryMessenger])
511 .andReturn(binaryMessengerMock);
512 FlutterKeyboardManager* keyboardManager =
513 [[FlutterKeyboardManager alloc] initWithDelegate:engineMock];
514 OCMStub([engineMock keyboardManager]).andReturn(keyboardManager);
515 OCMStub([[engineMock ignoringNonObjectArgs] sendKeyEvent:kDefaultFlutterKeyEvent
516 callback:nil
517 userData:nil])
518 .andCall([FlutterViewControllerTestObjC class],
519 @selector(respondFalseForSendEvent:callback:userData:));
520 FlutterViewController* viewController = [[FlutterViewController alloc] initWithEngine:engineMock
521 nibName:@""
522 bundle:nil];
523 id responderMock = flutter::testing::mockResponder();
524 id responderWrapper = [[FlutterResponderWrapper alloc] initWithResponder:responderMock];
525 viewController.nextResponder = responderWrapper;
526 NSDictionary* expectedEvent = @{
527 @"keymap" : @"macos",
528 @"type" : @"keydown",
529 @"keyCode" : @(65),
530 @"modifiers" : @(538968064),
531 @"characters" : @".",
532 @"charactersIgnoringModifiers" : @".",
533 };
534 NSData* encodedKeyEvent = [[FlutterJSONMessageCodec sharedInstance] encode:expectedEvent];
535 CGEventRef cgEvent = CGEventCreateKeyboardEvent(NULL, 65, TRUE);
536 NSEvent* event = [NSEvent eventWithCGEvent:cgEvent];
537 OCMExpect( // NOLINT(google-objc-avoid-throwing-exception)
538 [binaryMessengerMock sendOnChannel:@"flutter/keyevent"
539 message:encodedKeyEvent
540 binaryReply:[OCMArg any]])
541 .andDo((^(NSInvocation* invocation) {
542 FlutterBinaryReply handler;
543 [invocation getArgument:&handler atIndex:4];
544 NSDictionary* reply = @{
545 @"handled" : @(false),
546 };
547 NSData* encodedReply = [[FlutterJSONMessageCodec sharedInstance] encode:reply];
548 handler(encodedReply);
549 }));
550 [viewController viewWillAppear]; // Initializes the event channel.
551 [viewController keyDown:event];
552 @try {
553 OCMVerify( // NOLINT(google-objc-avoid-throwing-exception)
554 [responderMock keyDown:[OCMArg any]]);
555 OCMVerify( // NOLINT(google-objc-avoid-throwing-exception)
556 [binaryMessengerMock sendOnChannel:@"flutter/keyevent"
557 message:encodedKeyEvent
558 binaryReply:[OCMArg any]]);
559 } @catch (...) {
560 return false;
561 }
562 return true;
563 }

## ◆ testKeyEventsAreSentToFramework:

- (bool) testKeyEventsAreSentToFramework: |  | (id) | mockEngine |

Definition at line 167 of file FlutterViewControllerTest.mm.

354 :(id)engineMock {
355 id binaryMessengerMock = OCMProtocolMock(@protocol(FlutterBinaryMessenger));
356 OCMStub( // NOLINT(google-objc-avoid-throwing-exception)
357 [engineMock binaryMessenger])
358 .andReturn(binaryMessengerMock);
359 FlutterKeyboardManager* keyboardManager =
360 [[FlutterKeyboardManager alloc] initWithDelegate:engineMock];
361 OCMStub([engineMock keyboardManager]).andReturn(keyboardManager);
362
363 OCMStub([[engineMock ignoringNonObjectArgs] sendKeyEvent:kDefaultFlutterKeyEvent
364 callback:nil
365 userData:nil])
366 .andCall([FlutterViewControllerTestObjC class],
367 @selector(respondFalseForSendEvent:callback:userData:));
368 FlutterViewController* viewController = [[FlutterViewController alloc] initWithEngine:engineMock
369 nibName:@""
370 bundle:nil];
371 NSDictionary* expectedEvent = @{
372 @"keymap" : @"macos",
373 @"type" : @"keydown",
374 @"keyCode" : @(65),
375 @"modifiers" : @(538968064),
376 @"characters" : @".",
377 @"charactersIgnoringModifiers" : @".",
378 };
379 NSData* encodedKeyEvent = [[FlutterJSONMessageCodec sharedInstance] encode:expectedEvent];
380 CGEventRef cgEvent = CGEventCreateKeyboardEvent(NULL, 65, TRUE);
381 NSEvent* event = [NSEvent eventWithCGEvent:cgEvent];
382 [viewController viewWillAppear]; // Initializes the event channel.
383 [viewController keyDown:event];
384 @try {
385 OCMVerify( // NOLINT(google-objc-avoid-throwing-exception)
386 [binaryMessengerMock sendOnChannel:@"flutter/keyevent"
387 message:encodedKeyEvent
388 binaryReply:[OCMArg any]]);
389 } @catch (...) {
390 return false;
391 }
392 return true;
393 }

## ◆ testLookupKeyAssets

- (bool) testLookupKeyAssets |  |  |

Definition at line 167 of file FlutterViewControllerTest.mm.

1110 {
1111 FlutterViewController* viewController = [[FlutterViewController alloc] initWithProject:nil];
1112 NSString* key = [viewController lookupKeyForAsset:@"test.png"];
1113 EXPECT_TRUE(
1114 [key isEqualToString:@"Contents/Frameworks/App.framework/Resources/flutter_assets/test.png"]);
1115 return true;
1116 }
-[FlutterViewController lookupKeyForAsset:]
nonnull NSString * lookupKeyForAsset:(nonnull NSString *asset)

## ◆ testLookupKeyAssetsWithPackage

- (bool) testLookupKeyAssetsWithPackage |  |  |

Definition at line 167 of file FlutterViewControllerTest.mm.

1118 {
1119 FlutterViewController* viewController = [[FlutterViewController alloc] initWithProject:nil];
1120
1121 NSString* packageKey = [viewController lookupKeyForAsset:@"test.png" fromPackage:@"test"];
1122 EXPECT_TRUE([packageKey
1123 isEqualToString:
1124 @"Contents/Frameworks/App.framework/Resources/flutter_assets/packages/test/test.png"]);
1125 return true;
1126 }
-[FlutterViewController lookupKeyForAsset:fromPackage:]
nonnull NSString * lookupKeyForAsset:fromPackage:(nonnull NSString *asset,[fromPackage] nonnull NSString *package)

## ◆ testModifierKeysAreSynthesizedOnMouseMove:

- (bool) testModifierKeysAreSynthesizedOnMouseMove: |  | (id) | mockEngine |

Definition at line 1128 of file FlutterViewControllerTest.mm.

1182 :(id)engineMock {
1183 id binaryMessengerMock = OCMProtocolMock(@protocol(FlutterBinaryMessenger));
1184 OCMStub( // NOLINT(google-objc-avoid-throwing-exception)
1185 [engineMock binaryMessenger])
1186 .andReturn(binaryMessengerMock);
1187
1188 // Need to return a real renderer to allow view controller to load.
1189 FlutterRenderer* renderer_ = [[FlutterRenderer alloc] initWithFlutterEngine:engineMock];
1190 OCMStub([engineMock renderer]).andReturn(renderer_);
1191
1192 FlutterKeyboardManager* keyboardManager =
1193 [[FlutterKeyboardManager alloc] initWithDelegate:engineMock];
1194 OCMStub([engineMock keyboardManager]).andReturn(keyboardManager);
1195
1196 // Capture calls to sendKeyEvent
1197 __block NSMutableArray<KeyEventWrapper*>* events = [NSMutableArray array];
1198 OCMStub([[engineMock ignoringNonObjectArgs] sendKeyEvent:kDefaultFlutterKeyEvent
1199 callback:nil
1200 userData:nil])
1201 .andDo((^(NSInvocation* invocation) {
1202 FlutterKeyEvent* event;
1203 [invocation getArgument:&event atIndex:2];
1204 [events addObject:[[KeyEventWrapper alloc] initWithEvent:event]];
1205 }));
1206
1207 __block NSMutableArray<NSDictionary*>* channelEvents = [NSMutableArray array];
1208 OCMStub([binaryMessengerMock sendOnChannel:@"flutter/keyevent"
1209 message:[OCMArg any]
1210 binaryReply:[OCMArg any]])
1211 .andDo((^(NSInvocation* invocation) {
1212 NSData* data;
1213 [invocation getArgument:&data atIndex:3];
1214 id event = [[FlutterJSONMessageCodec sharedInstance] decode:data];
1215 [channelEvents addObject:event];
1216 }));
1217
1218 FlutterViewController* viewController = [[FlutterViewController alloc] initWithEngine:engineMock
1219 nibName:@""
1220 bundle:nil];
1221 [viewController loadView];
1222 [viewController viewWillAppear];
1223
1224 // Zeroed modifier flag should not synthesize events.
1225 NSEvent* mouseEvent = flutter::testing::CreateMouseEvent(0x00);
1226 [viewController mouseMoved:mouseEvent];
1227 EXPECT_EQ([events count], 0u);
1228
1229 // For each modifier key, check that key events are synthesized.
1230 for (NSNumber* keyCode in flutter::keyCodeToModifierFlag) {
1231 FlutterKeyEvent* event;
1232 NSDictionary* channelEvent;
1233 NSNumber* logicalKey;
1234 NSNumber* physicalKey;
1235 NSEventModifierFlags flag = [flutter::keyCodeToModifierFlag[keyCode] unsignedLongValue];
1236
1237 // Cocoa event always contain combined flags.
1238 if (flag & (flutter::kModifierFlagShiftLeft | flutter::kModifierFlagShiftRight)) {
1239 flag |= NSEventModifierFlagShift;
1240 }
1241 if (flag & (flutter::kModifierFlagControlLeft | flutter::kModifierFlagControlRight)) {
1242 flag |= NSEventModifierFlagControl;
1243 }
1244 if (flag & (flutter::kModifierFlagAltLeft | flutter::kModifierFlagAltRight)) {
1245 flag |= NSEventModifierFlagOption;
1246 }
1247 if (flag & (flutter::kModifierFlagMetaLeft | flutter::kModifierFlagMetaRight)) {
1248 flag |= NSEventModifierFlagCommand;
1249 }
1250
1251 // Should synthesize down event.
1252 NSEvent* mouseEvent = flutter::testing::CreateMouseEvent(flag);
1253 [viewController mouseMoved:mouseEvent];
1254 EXPECT_EQ([events count], 1u);
1255 event = events[0].data;
1256 logicalKey = [flutter::keyCodeToLogicalKey objectForKey:keyCode];
1257 physicalKey = [flutter::keyCodeToPhysicalKey objectForKey:keyCode];
1258 EXPECT_EQ(event->type, kFlutterKeyEventTypeDown);
1259 EXPECT_EQ(event->logical, logicalKey.unsignedLongLongValue);
1260 EXPECT_EQ(event->physical, physicalKey.unsignedLongLongValue);
1261 EXPECT_EQ(event->synthesized, true);
1262
1263 channelEvent = channelEvents[0];
1264 EXPECT_TRUE([channelEvent[@"type"] isEqual:@"keydown"]);
1265 EXPECT_TRUE([channelEvent[@"keyCode"] isEqual:keyCode]);
1266 EXPECT_TRUE([channelEvent[@"modifiers"] isEqual:@(flag)]);
1267
1268 // Should synthesize up event.
1269 mouseEvent = flutter::testing::CreateMouseEvent(0x00);
1270 [viewController mouseMoved:mouseEvent];
1271 EXPECT_EQ([events count], 2u);
1272 event = events[1].data;
1273 logicalKey = [flutter::keyCodeToLogicalKey objectForKey:keyCode];
1274 physicalKey = [flutter::keyCodeToPhysicalKey objectForKey:keyCode];
1275 EXPECT_EQ(event->type, kFlutterKeyEventTypeUp);
1276 EXPECT_EQ(event->logical, logicalKey.unsignedLongLongValue);
1277 EXPECT_EQ(event->physical, physicalKey.unsignedLongLongValue);
1278 EXPECT_EQ(event->synthesized, true);
1279
1280 channelEvent = channelEvents[1];
1281 EXPECT_TRUE([channelEvent[@"type"] isEqual:@"keyup"]);
1282 EXPECT_TRUE([channelEvent[@"keyCode"] isEqual:keyCode]);
1283 EXPECT_TRUE([channelEvent[@"modifiers"] isEqual:@(0)]);
1284
1285 [events removeAllObjects];
1286 [channelEvents removeAllObjects];
1287 };
1288
1289 return true;
1290 }
KeyEventWrapper
Definition: FlutterViewControllerTest.mm:31
flutter::keyCodeToModifierFlag
const NSDictionary * keyCodeToModifierFlag
Definition: KeyCodeMap.g.mm:223
flutter::kModifierFlagShiftLeft
@ kModifierFlagShiftLeft
Definition: KeyCodeMap_Internal.h:81
flutter::kModifierFlagAltLeft
@ kModifierFlagAltLeft
Definition: KeyCodeMap_Internal.h:85
flutter::kModifierFlagMetaRight
@ kModifierFlagMetaRight
Definition: KeyCodeMap_Internal.h:84
flutter::kModifierFlagMetaLeft
@ kModifierFlagMetaLeft
Definition: KeyCodeMap_Internal.h:83
flutter::kModifierFlagControlLeft
@ kModifierFlagControlLeft
Definition: KeyCodeMap_Internal.h:80
flutter::kModifierFlagAltRight
@ kModifierFlagAltRight
Definition: KeyCodeMap_Internal.h:86
flutter::kModifierFlagControlRight
@ kModifierFlagControlRight
Definition: KeyCodeMap_Internal.h:87
flutter::kModifierFlagShiftRight
@ kModifierFlagShiftRight
Definition: KeyCodeMap_Internal.h:82

## ◆ testMouseDownUpEventsSentToNextResponder:

- (bool) testMouseDownUpEventsSentToNextResponder: |  | (id) | mockEngine |

Definition at line 1128 of file FlutterViewControllerTest.mm.

1140 :(id)engineMock {
1141 if (@available(macOS 13.3.1, *)) {
1142 // This workaround is disabled for macOS 13.3.1 onwards, since the underlying AppKit bug is
1143 // fixed.
1144 return true;
1145 }
1146
1147 // The root cause of the above bug is NSResponder mouseDown/mouseUp methods that don't correctly
1148 // walk the responder chain calling the appropriate method on the next responder under certain
1149 // conditions. Simulate this by swizzling out the default implementations and replacing them with
1150 // no-ops.
1151 Method mouseDown = class_getInstanceMethod([NSResponder class], @selector(mouseDown:));
1152 Method mouseUp = class_getInstanceMethod([NSResponder class], @selector(mouseUp:));
1153 IMP noopImp = (IMP)SwizzledNoop;
1154 IMP origMouseDown = method_setImplementation(mouseDown, noopImp);
1155 IMP origMouseUp = method_setImplementation(mouseUp, noopImp);
1156
1157 // Verify that mouseDown/mouseUp trigger mouseDown/mouseUp calls on FlutterViewController.
1158 MouseEventFlutterViewController* viewController =
1159 [[MouseEventFlutterViewController alloc] initWithEngine:engineMock nibName:@"" bundle:nil];
1160 FlutterView* view = (FlutterView*)[viewController view];
1161
1162 EXPECT_FALSE(viewController.mouseDownCalled);
1163 EXPECT_FALSE(viewController.mouseUpCalled);
1164
1165 NSEvent* mouseEvent = flutter::testing::CreateMouseEvent(0x00);
1166 [view mouseDown:mouseEvent];
1167 EXPECT_TRUE(viewController.mouseDownCalled);
1168 EXPECT_FALSE(viewController.mouseUpCalled);
1169
1170 viewController.mouseDownCalled = NO;
1171 [view mouseUp:mouseEvent];
1172 EXPECT_FALSE(viewController.mouseDownCalled);
1173 EXPECT_TRUE(viewController.mouseUpCalled);
1174
1175 // Restore the original NSResponder mouseDown/mouseUp implementations.
1176 method_setImplementation(mouseDown, origMouseDown);
1177 method_setImplementation(mouseUp, origMouseUp);
1178
1179 return true;
1180 }
FlutterView
Definition: FlutterView.h:36
MouseEventFlutterViewController
Definition: FlutterViewControllerTest.mm:86
MouseEventFlutterViewController::mouseUpCalled
BOOL mouseUpCalled
Definition: FlutterViewControllerTest.mm:87
MouseEventFlutterViewController::mouseDownCalled
BOOL mouseDownCalled
Definition: FlutterViewControllerTest.mm:86

## ◆ testTrackpadGesturesAreSentToFramework:

- (bool) testTrackpadGesturesAreSentToFramework: |  | (id) | mockEngine |

Definition at line 167 of file FlutterViewControllerTest.mm.

766 :(id)engineMock {
767 // Need to return a real renderer to allow view controller to load.
768 FlutterRenderer* renderer_ = [[FlutterRenderer alloc] initWithFlutterEngine:engineMock];
769 OCMStub([engineMock renderer]).andReturn(renderer_);
770 __block bool called = false;
771 __block FlutterPointerEvent last_event;
772 OCMStub([[engineMock ignoringNonObjectArgs] sendPointerEvent:kDefaultFlutterPointerEvent])
773 .andDo((^(NSInvocation* invocation) {
774 FlutterPointerEvent* event;
775 [invocation getArgument:&event atIndex:2];
776 called = true;
777 last_event = *event;
778 }));
779
780 FlutterViewController* viewController = [[FlutterViewController alloc] initWithEngine:engineMock
781 nibName:@""
782 bundle:nil];
783 [viewController loadView];
784
785 // Test for pan events.
786 // Start gesture.
787 CGEventRef cgEventStart = CGEventCreateScrollWheelEvent(NULL, kCGScrollEventUnitPixel, 1, 0);
788 CGEventSetType(cgEventStart, kCGEventScrollWheel);
789 CGEventSetIntegerValueField(cgEventStart, kCGScrollWheelEventScrollPhase, kCGScrollPhaseBegan);
790 CGEventSetIntegerValueField(cgEventStart, kCGScrollWheelEventIsContinuous, 1);
791
792 called = false;
793 [viewController scrollWheel:[NSEvent eventWithCGEvent:cgEventStart]];
794 EXPECT_TRUE(called);
795 EXPECT_EQ(last_event.signal_kind, kFlutterPointerSignalKindNone);
796 EXPECT_EQ(last_event.phase, kPanZoomStart);
797 EXPECT_EQ(last_event.device_kind, kFlutterPointerDeviceKindTrackpad);
798 EXPECT_EQ(last_event.signal_kind, kFlutterPointerSignalKindNone);
799
800 // Update gesture.
801 CGEventRef cgEventUpdate = CGEventCreateCopy(cgEventStart);
802 CGEventSetIntegerValueField(cgEventUpdate, kCGScrollWheelEventScrollPhase, kCGScrollPhaseChanged);
803 CGEventSetIntegerValueField(cgEventUpdate, kCGScrollWheelEventDeltaAxis2, 1); // pan_x
804 CGEventSetIntegerValueField(cgEventUpdate, kCGScrollWheelEventDeltaAxis1, 2); // pan_y
805
806 called = false;
807 [viewController scrollWheel:[NSEvent eventWithCGEvent:cgEventUpdate]];
808 EXPECT_TRUE(called);
809 EXPECT_EQ(last_event.signal_kind, kFlutterPointerSignalKindNone);
810 EXPECT_EQ(last_event.phase, kPanZoomUpdate);
811 EXPECT_EQ(last_event.device_kind, kFlutterPointerDeviceKindTrackpad);
812 EXPECT_EQ(last_event.signal_kind, kFlutterPointerSignalKindNone);
813 EXPECT_EQ(last_event.pan_x, 8 * viewController.flutterView.layer.contentsScale);
814 EXPECT_EQ(last_event.pan_y, 16 * viewController.flutterView.layer.contentsScale);
815
816 // Make sure the pan values accumulate.
817 called = false;
818 [viewController scrollWheel:[NSEvent eventWithCGEvent:cgEventUpdate]];
819 EXPECT_TRUE(called);
820 EXPECT_EQ(last_event.signal_kind, kFlutterPointerSignalKindNone);
821 EXPECT_EQ(last_event.phase, kPanZoomUpdate);
822 EXPECT_EQ(last_event.device_kind, kFlutterPointerDeviceKindTrackpad);
823 EXPECT_EQ(last_event.signal_kind, kFlutterPointerSignalKindNone);
824 EXPECT_EQ(last_event.pan_x, 16 * viewController.flutterView.layer.contentsScale);
825 EXPECT_EQ(last_event.pan_y, 32 * viewController.flutterView.layer.contentsScale);
826
827 // End gesture.
828 CGEventRef cgEventEnd = CGEventCreateCopy(cgEventStart);
829 CGEventSetIntegerValueField(cgEventEnd, kCGScrollWheelEventScrollPhase, kCGScrollPhaseEnded);
830
831 called = false;
832 [viewController scrollWheel:[NSEvent eventWithCGEvent:cgEventEnd]];
833 EXPECT_TRUE(called);
834 EXPECT_EQ(last_event.signal_kind, kFlutterPointerSignalKindNone);
835 EXPECT_EQ(last_event.phase, kPanZoomEnd);
836 EXPECT_EQ(last_event.device_kind, kFlutterPointerDeviceKindTrackpad);
837 EXPECT_EQ(last_event.signal_kind, kFlutterPointerSignalKindNone);
838
839 // Start system momentum.
840 CGEventRef cgEventMomentumStart = CGEventCreateCopy(cgEventStart);
841 CGEventSetIntegerValueField(cgEventMomentumStart, kCGScrollWheelEventScrollPhase, 0);
842 CGEventSetIntegerValueField(cgEventMomentumStart, kCGScrollWheelEventMomentumPhase,
843 kCGMomentumScrollPhaseBegin);
844
845 called = false;
846 [viewController scrollWheel:[NSEvent eventWithCGEvent:cgEventMomentumStart]];
847 EXPECT_FALSE(called);
848
849 // Advance system momentum.
850 CGEventRef cgEventMomentumUpdate = CGEventCreateCopy(cgEventStart);
851 CGEventSetIntegerValueField(cgEventMomentumUpdate, kCGScrollWheelEventScrollPhase, 0);
852 CGEventSetIntegerValueField(cgEventMomentumUpdate, kCGScrollWheelEventMomentumPhase,
853 kCGMomentumScrollPhaseContinue);
854
855 called = false;
856 [viewController scrollWheel:[NSEvent eventWithCGEvent:cgEventMomentumUpdate]];
857 EXPECT_FALSE(called);
858
859 // Mock a touch on the trackpad.
860 id touchMock = OCMClassMock([NSTouch class]);
861 NSSet* touchSet = [NSSet setWithObject:touchMock];
862 id touchEventMock1 = OCMClassMock([NSEvent class]);
863 OCMStub([touchEventMock1 allTouches]).andReturn(touchSet);
864 CGPoint touchLocation = {0, 0};
865 OCMStub([touchEventMock1 locationInWindow]).andReturn(touchLocation);
866 OCMStub([(NSEvent*)touchEventMock1 timestamp]).andReturn(0.150); // 150 milliseconds.
867
868 // Scroll inertia cancel event should not be issued (timestamp too far in the future).
869 called = false;
870 [viewController touchesBeganWithEvent:touchEventMock1];
871 EXPECT_FALSE(called);
872
873 // Mock another touch on the trackpad.
874 id touchEventMock2 = OCMClassMock([NSEvent class]);
875 OCMStub([touchEventMock2 allTouches]).andReturn(touchSet);
876 OCMStub([touchEventMock2 locationInWindow]).andReturn(touchLocation);
877 OCMStub([(NSEvent*)touchEventMock2 timestamp]).andReturn(0.005); // 5 milliseconds.
878
879 // Scroll inertia cancel event should be issued.
880 called = false;
881 [viewController touchesBeganWithEvent:touchEventMock2];
882 EXPECT_TRUE(called);
883 EXPECT_EQ(last_event.signal_kind, kFlutterPointerSignalKindScrollInertiaCancel);
884 EXPECT_EQ(last_event.device_kind, kFlutterPointerDeviceKindTrackpad);
885
886 // End system momentum.
887 CGEventRef cgEventMomentumEnd = CGEventCreateCopy(cgEventStart);
888 CGEventSetIntegerValueField(cgEventMomentumEnd, kCGScrollWheelEventScrollPhase, 0);
889 CGEventSetIntegerValueField(cgEventMomentumEnd, kCGScrollWheelEventMomentumPhase,
890 kCGMomentumScrollPhaseEnd);
891
892 called = false;
893 [viewController scrollWheel:[NSEvent eventWithCGEvent:cgEventMomentumEnd]];
894 EXPECT_FALSE(called);
895
896 // May-begin and cancel are used while macOS determines which type of gesture to choose.
897 CGEventRef cgEventMayBegin = CGEventCreateCopy(cgEventStart);
898 CGEventSetIntegerValueField(cgEventMayBegin, kCGScrollWheelEventScrollPhase,
899 kCGScrollPhaseMayBegin);
900
901 called = false;
902 [viewController scrollWheel:[NSEvent eventWithCGEvent:cgEventMayBegin]];
903 EXPECT_TRUE(called);
904 EXPECT_EQ(last_event.signal_kind, kFlutterPointerSignalKindNone);
905 EXPECT_EQ(last_event.phase, kPanZoomStart);
906 EXPECT_EQ(last_event.device_kind, kFlutterPointerDeviceKindTrackpad);
907 EXPECT_EQ(last_event.signal_kind, kFlutterPointerSignalKindNone);
908
909 // Cancel gesture.
910 CGEventRef cgEventCancel = CGEventCreateCopy(cgEventStart);
911 CGEventSetIntegerValueField(cgEventCancel, kCGScrollWheelEventScrollPhase,
912 kCGScrollPhaseCancelled);
913
914 called = false;
915 [viewController scrollWheel:[NSEvent eventWithCGEvent:cgEventCancel]];
916 EXPECT_TRUE(called);
917 EXPECT_EQ(last_event.signal_kind, kFlutterPointerSignalKindNone);
918 EXPECT_EQ(last_event.phase, kPanZoomEnd);
919 EXPECT_EQ(last_event.device_kind, kFlutterPointerDeviceKindTrackpad);
920 EXPECT_EQ(last_event.signal_kind, kFlutterPointerSignalKindNone);
921
922 // A discrete scroll event should use the PointerSignal system.
923 CGEventRef cgEventDiscrete = CGEventCreateScrollWheelEvent(NULL, kCGScrollEventUnitPixel, 1, 0);
924 CGEventSetType(cgEventDiscrete, kCGEventScrollWheel);
925 CGEventSetIntegerValueField(cgEventDiscrete, kCGScrollWheelEventIsContinuous, 0);
926 CGEventSetIntegerValueField(cgEventDiscrete, kCGScrollWheelEventDeltaAxis2, 1); // scroll_delta_x
927 CGEventSetIntegerValueField(cgEventDiscrete, kCGScrollWheelEventDeltaAxis1, 2); // scroll_delta_y
928
929 called = false;
930 [viewController scrollWheel:[NSEvent eventWithCGEvent:cgEventDiscrete]];
931 EXPECT_TRUE(called);
932 EXPECT_EQ(last_event.signal_kind, kFlutterPointerSignalKindScroll);
933 // pixelsPerLine is 40.0 and direction is reversed.
934 EXPECT_EQ(last_event.scroll_delta_x, -40 * viewController.flutterView.layer.contentsScale);
935 EXPECT_EQ(last_event.scroll_delta_y, -80 * viewController.flutterView.layer.contentsScale);
936
937 // A discrete scroll event should use the PointerSignal system, and flip the
938 // direction when shift is pressed.
939 CGEventRef cgEventDiscreteShift =
940 CGEventCreateScrollWheelEvent(NULL, kCGScrollEventUnitPixel, 1, 0);
941 CGEventSetType(cgEventDiscreteShift, kCGEventScrollWheel);
942 CGEventSetFlags(cgEventDiscreteShift, kCGEventFlagMaskShift | flutter::kModifierFlagShiftLeft);
943 CGEventSetIntegerValueField(cgEventDiscreteShift, kCGScrollWheelEventIsContinuous, 0);
944 CGEventSetIntegerValueField(cgEventDiscreteShift, kCGScrollWheelEventDeltaAxis2,
945 0); // scroll_delta_x
946 CGEventSetIntegerValueField(cgEventDiscreteShift, kCGScrollWheelEventDeltaAxis1,
947 2); // scroll_delta_y
948
949 called = false;
950 [viewController scrollWheel:[NSEvent eventWithCGEvent:cgEventDiscreteShift]];
951 EXPECT_TRUE(called);
952 EXPECT_EQ(last_event.signal_kind, kFlutterPointerSignalKindScroll);
953 // pixelsPerLine is 40.0, direction is reversed and axes have been flipped back.
954 EXPECT_FLOAT_EQ(last_event.scroll_delta_x, 0.0 * viewController.flutterView.layer.contentsScale);
955 EXPECT_FLOAT_EQ(last_event.scroll_delta_y,
956 -80.0 * viewController.flutterView.layer.contentsScale);
957
958 // Test for scale events.
959 // Start gesture.
960 called = false;
961 [viewController magnifyWithEvent:flutter::testing::MockGestureEvent(NSEventTypeMagnify,
962 NSEventPhaseBegan, 1, 0)];
963 EXPECT_TRUE(called);
964 EXPECT_EQ(last_event.signal_kind, kFlutterPointerSignalKindNone);
965 EXPECT_EQ(last_event.phase, kPanZoomStart);
966 EXPECT_EQ(last_event.device_kind, kFlutterPointerDeviceKindTrackpad);
967 EXPECT_EQ(last_event.signal_kind, kFlutterPointerSignalKindNone);
968
969 // Update gesture.
970 called = false;
971 [viewController magnifyWithEvent:flutter::testing::MockGestureEvent(NSEventTypeMagnify,
972 NSEventPhaseChanged, 1, 0)];
973 EXPECT_TRUE(called);
974 EXPECT_EQ(last_event.signal_kind, kFlutterPointerSignalKindNone);
975 EXPECT_EQ(last_event.phase, kPanZoomUpdate);
976 EXPECT_EQ(last_event.device_kind, kFlutterPointerDeviceKindTrackpad);
977 EXPECT_EQ(last_event.signal_kind, kFlutterPointerSignalKindNone);
978 EXPECT_EQ(last_event.pan_x, 0);
979 EXPECT_EQ(last_event.pan_y, 0);
980 EXPECT_EQ(last_event.scale, 2); // macOS uses logarithmic scaling values, the linear value for
981 // flutter here should be 2^1 = 2.
982 EXPECT_EQ(last_event.rotation, 0);
983
984 // Make sure the scale values accumulate.
985 called = false;
986 [viewController magnifyWithEvent:flutter::testing::MockGestureEvent(NSEventTypeMagnify,
987 NSEventPhaseChanged, 1, 0)];
988 EXPECT_TRUE(called);
989 EXPECT_EQ(last_event.signal_kind, kFlutterPointerSignalKindNone);
990 EXPECT_EQ(last_event.phase, kPanZoomUpdate);
991 EXPECT_EQ(last_event.device_kind, kFlutterPointerDeviceKindTrackpad);
992 EXPECT_EQ(last_event.signal_kind, kFlutterPointerSignalKindNone);
993 EXPECT_EQ(last_event.pan_x, 0);
994 EXPECT_EQ(last_event.pan_y, 0);
995 EXPECT_EQ(last_event.scale, 4); // macOS uses logarithmic scaling values, the linear value for
996 // flutter here should be 2^(1+1) = 2.
997 EXPECT_EQ(last_event.rotation, 0);
998
999 // End gesture.
1000 called = false;
1001 [viewController magnifyWithEvent:flutter::testing::MockGestureEvent(NSEventTypeMagnify,
1002 NSEventPhaseEnded, 0, 0)];
1003 EXPECT_TRUE(called);
1004 EXPECT_EQ(last_event.signal_kind, kFlutterPointerSignalKindNone);
1005 EXPECT_EQ(last_event.phase, kPanZoomEnd);
1006 EXPECT_EQ(last_event.device_kind, kFlutterPointerDeviceKindTrackpad);
1007 EXPECT_EQ(last_event.signal_kind, kFlutterPointerSignalKindNone);
1008
1009 // Test for rotation events.
1010 // Start gesture.
1011 called = false;
1012 [viewController rotateWithEvent:flutter::testing::MockGestureEvent(NSEventTypeRotate,
1013 NSEventPhaseBegan, 1, 0)];
1014 EXPECT_TRUE(called);
1015 EXPECT_EQ(last_event.signal_kind, kFlutterPointerSignalKindNone);
1016 EXPECT_EQ(last_event.phase, kPanZoomStart);
1017 EXPECT_EQ(last_event.device_kind, kFlutterPointerDeviceKindTrackpad);
1018 EXPECT_EQ(last_event.signal_kind, kFlutterPointerSignalKindNone);
1019
1020 // Update gesture.
1021 called = false;
1022 [viewController rotateWithEvent:flutter::testing::MockGestureEvent(
1023 NSEventTypeRotate, NSEventPhaseChanged, 0, -180)]; // degrees
1024 EXPECT_TRUE(called);
1025 EXPECT_EQ(last_event.signal_kind, kFlutterPointerSignalKindNone);
1026 EXPECT_EQ(last_event.phase, kPanZoomUpdate);
1027 EXPECT_EQ(last_event.device_kind, kFlutterPointerDeviceKindTrackpad);
1028 EXPECT_EQ(last_event.signal_kind, kFlutterPointerSignalKindNone);
1029 EXPECT_EQ(last_event.pan_x, 0);
1030 EXPECT_EQ(last_event.pan_y, 0);
1031 EXPECT_EQ(last_event.scale, 1);
1032 EXPECT_EQ(last_event.rotation, M_PI); // radians
1033
1034 // Make sure the rotation values accumulate.
1035 called = false;
1036 [viewController rotateWithEvent:flutter::testing::MockGestureEvent(
1037 NSEventTypeRotate, NSEventPhaseChanged, 0, -360)]; // degrees
1038 EXPECT_TRUE(called);
1039 EXPECT_EQ(last_event.signal_kind, kFlutterPointerSignalKindNone);
1040 EXPECT_EQ(last_event.phase, kPanZoomUpdate);
1041 EXPECT_EQ(last_event.device_kind, kFlutterPointerDeviceKindTrackpad);
1042 EXPECT_EQ(last_event.signal_kind, kFlutterPointerSignalKindNone);
1043 EXPECT_EQ(last_event.pan_x, 0);
1044 EXPECT_EQ(last_event.pan_y, 0);
1045 EXPECT_EQ(last_event.scale, 1);
1046 EXPECT_EQ(last_event.rotation, 3 * M_PI); // radians
1047
1048 // End gesture.
1049 called = false;
1050 [viewController rotateWithEvent:flutter::testing::MockGestureEvent(NSEventTypeRotate,
1051 NSEventPhaseEnded, 0, 0)];
1052 EXPECT_TRUE(called);
1053 EXPECT_EQ(last_event.signal_kind, kFlutterPointerSignalKindNone);
1054 EXPECT_EQ(last_event.phase, kPanZoomEnd);
1055 EXPECT_EQ(last_event.device_kind, kFlutterPointerDeviceKindTrackpad);
1056 EXPECT_EQ(last_event.signal_kind, kFlutterPointerSignalKindNone);
1057
1058 // Test that stray NSEventPhaseCancelled event does not crash
1059 called = false;
1060 [viewController rotateWithEvent:flutter::testing::MockGestureEvent(NSEventTypeRotate,
1061 NSEventPhaseCancelled, 0, 0)];
1062 EXPECT_FALSE(called);
1063
1064 return true;
1065 }
kDefaultFlutterPointerEvent
static const FlutterPointerEvent kDefaultFlutterPointerEvent
Definition: FlutterViewControllerTest.mm:26

## ◆ testViewControllerIsReleased

- (bool) testViewControllerIsReleased |  |  |

Definition at line 1128 of file FlutterViewControllerTest.mm.

1292 {
1293 __weak FlutterViewController* weakController;
1294 @autoreleasepool {
1295 id engineMock = flutter::testing::CreateMockFlutterEngine(@"");
1296
1297 FlutterRenderer* renderer_ = [[FlutterRenderer alloc] initWithFlutterEngine:engineMock];
1298 OCMStub([engineMock renderer]).andReturn(renderer_);
1299
1300 FlutterViewController* viewController = [[FlutterViewController alloc] initWithEngine:engineMock
1301 nibName:@""
1302 bundle:nil];
1303 [viewController loadView];
1304 weakController = viewController;
1305
1306 [engineMock shutDownEngine];
1307 }
1308
1309 EXPECT_EQ(weakController, nil);
1310 return true;
1311 }
flutter::testing::CreateMockFlutterEngine
id CreateMockFlutterEngine(NSString *pasteboardString)
Definition: FlutterEngineTestUtils.mm:76

## ◆ testViewWillAppearCalledMultipleTimes:

- (bool) testViewWillAppearCalledMultipleTimes: |  | (id) | mockEngine |

Definition at line 167 of file FlutterViewControllerTest.mm.

1101 :(id)engineMock {
1102 FlutterViewController* viewController = [[FlutterViewController alloc] initWithEngine:engineMock
1103 nibName:@""
1104 bundle:nil];
1105 [viewController viewWillAppear];
1106 [viewController viewWillAppear];
1107 return true;
1108 }

The documentation for this class was generated from the following file:

- shell/platform/darwin/macos/framework/Source/FlutterViewControllerTest.mm