| 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.

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

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

## ◆ testLookupKeyAssetsWithPackage

- (bool) testLookupKeyAssetsWithPackage |  |  |

Definition at line 167 of file FlutterViewControllerTest.mm.

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

## ◆ testModifierKeysAreSynthesizedOnMouseMove:

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

Definition at line 1129 of file FlutterViewControllerTest.mm.

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

1141 :(id)engineMock {
1142 if (@available(macOS 13.3.1, *)) {
1143 // This workaround is disabled for macOS 13.3.1 onwards, since the underlying AppKit bug is
1144 // fixed.
1145 return true;
1146 }
1147
1148 // The root cause of the above bug is NSResponder mouseDown/mouseUp methods that don't correctly
1149 // walk the responder chain calling the appropriate method on the next responder under certain
1150 // conditions. Simulate this by swizzling out the default implementations and replacing them with
1151 // no-ops.
1152 Method mouseDown = class_getInstanceMethod([NSResponder class], @selector(mouseDown:));
1153 Method mouseUp = class_getInstanceMethod([NSResponder class], @selector(mouseUp:));
1154 IMP noopImp = (IMP)SwizzledNoop;
1155 IMP origMouseDown = method_setImplementation(mouseDown, noopImp);
1156 IMP origMouseUp = method_setImplementation(mouseUp, noopImp);
1157
1158 // Verify that mouseDown/mouseUp trigger mouseDown/mouseUp calls on FlutterViewController.
1159 MouseEventFlutterViewController* viewController =
1160 [[MouseEventFlutterViewController alloc] initWithEngine:engineMock nibName:@"" bundle:nil];
1161 FlutterView* view = (FlutterView*)[viewController view];
1162
1163 EXPECT_FALSE(viewController.mouseDownCalled);
1164 EXPECT_FALSE(viewController.mouseUpCalled);
1165
1166 NSEvent* mouseEvent = flutter::testing::CreateMouseEvent(0x00);
1167 [view mouseDown:mouseEvent];
1168 EXPECT_TRUE(viewController.mouseDownCalled);
1169 EXPECT_FALSE(viewController.mouseUpCalled);
1170
1171 viewController.mouseDownCalled = NO;
1172 [view mouseUp:mouseEvent];
1173 EXPECT_FALSE(viewController.mouseDownCalled);
1174 EXPECT_TRUE(viewController.mouseUpCalled);
1175
1176 // Restore the original NSResponder mouseDown/mouseUp implementations.
1177 method_setImplementation(mouseDown, origMouseDown);
1178 method_setImplementation(mouseUp, origMouseUp);
1179
1180 return true;
1181 }
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, static_cast<uint64_t>(kCGEventFlagMaskShift) |
943 static_cast<uint64_t>(flutter::kModifierFlagShiftLeft));
944 CGEventSetIntegerValueField(cgEventDiscreteShift, kCGScrollWheelEventIsContinuous, 0);
945 CGEventSetIntegerValueField(cgEventDiscreteShift, kCGScrollWheelEventDeltaAxis2,
946 0); // scroll_delta_x
947 CGEventSetIntegerValueField(cgEventDiscreteShift, kCGScrollWheelEventDeltaAxis1,
948 2); // scroll_delta_y
949
950 called = false;
951 [viewController scrollWheel:[NSEvent eventWithCGEvent:cgEventDiscreteShift]];
952 EXPECT_TRUE(called);
953 EXPECT_EQ(last_event.signal_kind, kFlutterPointerSignalKindScroll);
954 // pixelsPerLine is 40.0, direction is reversed and axes have been flipped back.
955 EXPECT_FLOAT_EQ(last_event.scroll_delta_x, 0.0 * viewController.flutterView.layer.contentsScale);
956 EXPECT_FLOAT_EQ(last_event.scroll_delta_y,
957 -80.0 * viewController.flutterView.layer.contentsScale);
958
959 // Test for scale events.
960 // Start gesture.
961 called = false;
962 [viewController magnifyWithEvent:flutter::testing::MockGestureEvent(NSEventTypeMagnify,
963 NSEventPhaseBegan, 1, 0)];
964 EXPECT_TRUE(called);
965 EXPECT_EQ(last_event.signal_kind, kFlutterPointerSignalKindNone);
966 EXPECT_EQ(last_event.phase, kPanZoomStart);
967 EXPECT_EQ(last_event.device_kind, kFlutterPointerDeviceKindTrackpad);
968 EXPECT_EQ(last_event.signal_kind, kFlutterPointerSignalKindNone);
969
970 // Update gesture.
971 called = false;
972 [viewController magnifyWithEvent:flutter::testing::MockGestureEvent(NSEventTypeMagnify,
973 NSEventPhaseChanged, 1, 0)];
974 EXPECT_TRUE(called);
975 EXPECT_EQ(last_event.signal_kind, kFlutterPointerSignalKindNone);
976 EXPECT_EQ(last_event.phase, kPanZoomUpdate);
977 EXPECT_EQ(last_event.device_kind, kFlutterPointerDeviceKindTrackpad);
978 EXPECT_EQ(last_event.signal_kind, kFlutterPointerSignalKindNone);
979 EXPECT_EQ(last_event.pan_x, 0);
980 EXPECT_EQ(last_event.pan_y, 0);
981 EXPECT_EQ(last_event.scale, 2); // macOS uses logarithmic scaling values, the linear value for
982 // flutter here should be 2^1 = 2.
983 EXPECT_EQ(last_event.rotation, 0);
984
985 // Make sure the scale values accumulate.
986 called = false;
987 [viewController magnifyWithEvent:flutter::testing::MockGestureEvent(NSEventTypeMagnify,
988 NSEventPhaseChanged, 1, 0)];
989 EXPECT_TRUE(called);
990 EXPECT_EQ(last_event.signal_kind, kFlutterPointerSignalKindNone);
991 EXPECT_EQ(last_event.phase, kPanZoomUpdate);
992 EXPECT_EQ(last_event.device_kind, kFlutterPointerDeviceKindTrackpad);
993 EXPECT_EQ(last_event.signal_kind, kFlutterPointerSignalKindNone);
994 EXPECT_EQ(last_event.pan_x, 0);
995 EXPECT_EQ(last_event.pan_y, 0);
996 EXPECT_EQ(last_event.scale, 4); // macOS uses logarithmic scaling values, the linear value for
997 // flutter here should be 2^(1+1) = 2.
998 EXPECT_EQ(last_event.rotation, 0);
999
1000 // End gesture.
1001 called = false;
1002 [viewController magnifyWithEvent:flutter::testing::MockGestureEvent(NSEventTypeMagnify,
1003 NSEventPhaseEnded, 0, 0)];
1004 EXPECT_TRUE(called);
1005 EXPECT_EQ(last_event.signal_kind, kFlutterPointerSignalKindNone);
1006 EXPECT_EQ(last_event.phase, kPanZoomEnd);
1007 EXPECT_EQ(last_event.device_kind, kFlutterPointerDeviceKindTrackpad);
1008 EXPECT_EQ(last_event.signal_kind, kFlutterPointerSignalKindNone);
1009
1010 // Test for rotation events.
1011 // Start gesture.
1012 called = false;
1013 [viewController rotateWithEvent:flutter::testing::MockGestureEvent(NSEventTypeRotate,
1014 NSEventPhaseBegan, 1, 0)];
1015 EXPECT_TRUE(called);
1016 EXPECT_EQ(last_event.signal_kind, kFlutterPointerSignalKindNone);
1017 EXPECT_EQ(last_event.phase, kPanZoomStart);
1018 EXPECT_EQ(last_event.device_kind, kFlutterPointerDeviceKindTrackpad);
1019 EXPECT_EQ(last_event.signal_kind, kFlutterPointerSignalKindNone);
1020
1021 // Update gesture.
1022 called = false;
1023 [viewController rotateWithEvent:flutter::testing::MockGestureEvent(
1024 NSEventTypeRotate, NSEventPhaseChanged, 0, -180)]; // degrees
1025 EXPECT_TRUE(called);
1026 EXPECT_EQ(last_event.signal_kind, kFlutterPointerSignalKindNone);
1027 EXPECT_EQ(last_event.phase, kPanZoomUpdate);
1028 EXPECT_EQ(last_event.device_kind, kFlutterPointerDeviceKindTrackpad);
1029 EXPECT_EQ(last_event.signal_kind, kFlutterPointerSignalKindNone);
1030 EXPECT_EQ(last_event.pan_x, 0);
1031 EXPECT_EQ(last_event.pan_y, 0);
1032 EXPECT_EQ(last_event.scale, 1);
1033 EXPECT_EQ(last_event.rotation, M_PI); // radians
1034
1035 // Make sure the rotation values accumulate.
1036 called = false;
1037 [viewController rotateWithEvent:flutter::testing::MockGestureEvent(
1038 NSEventTypeRotate, NSEventPhaseChanged, 0, -360)]; // degrees
1039 EXPECT_TRUE(called);
1040 EXPECT_EQ(last_event.signal_kind, kFlutterPointerSignalKindNone);
1041 EXPECT_EQ(last_event.phase, kPanZoomUpdate);
1042 EXPECT_EQ(last_event.device_kind, kFlutterPointerDeviceKindTrackpad);
1043 EXPECT_EQ(last_event.signal_kind, kFlutterPointerSignalKindNone);
1044 EXPECT_EQ(last_event.pan_x, 0);
1045 EXPECT_EQ(last_event.pan_y, 0);
1046 EXPECT_EQ(last_event.scale, 1);
1047 EXPECT_EQ(last_event.rotation, 3 * M_PI); // radians
1048
1049 // End gesture.
1050 called = false;
1051 [viewController rotateWithEvent:flutter::testing::MockGestureEvent(NSEventTypeRotate,
1052 NSEventPhaseEnded, 0, 0)];
1053 EXPECT_TRUE(called);
1054 EXPECT_EQ(last_event.signal_kind, kFlutterPointerSignalKindNone);
1055 EXPECT_EQ(last_event.phase, kPanZoomEnd);
1056 EXPECT_EQ(last_event.device_kind, kFlutterPointerDeviceKindTrackpad);
1057 EXPECT_EQ(last_event.signal_kind, kFlutterPointerSignalKindNone);
1058
1059 // Test that stray NSEventPhaseCancelled event does not crash
1060 called = false;
1061 [viewController rotateWithEvent:flutter::testing::MockGestureEvent(NSEventTypeRotate,
1062 NSEventPhaseCancelled, 0, 0)];
1063 EXPECT_FALSE(called);
1064
1065 return true;
1066 }
kDefaultFlutterPointerEvent
static const FlutterPointerEvent kDefaultFlutterPointerEvent
Definition: FlutterViewControllerTest.mm:26

## ◆ testViewControllerIsReleased

- (bool) testViewControllerIsReleased |  |  |

Definition at line 1129 of file FlutterViewControllerTest.mm.

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

## ◆ testViewWillAppearCalledMultipleTimes:

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

Definition at line 167 of file FlutterViewControllerTest.mm.

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

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

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