Skip to content

Commit

Permalink
[macOS] Fix tests failing on Sonoma (#46461)
Browse files Browse the repository at this point in the history
1. Using arbitrary struct passed as const reference  to `OCMStub` now fails in OCMock. Down the line this will result with `object_getClass` being called in [`OCMArg.m`](https://github.com/erikdoe/ocmock/blob/master/Source/OCMock/OCMArg.m#L129-L133) with the address of the reference, which is not a valid class instance. This seems to have worked pre-sonoma, but it seems like a weird thing to rely on.

2. `NSResponder` mock can not be set to view controller anymore. The controller will try to access an ivar of the `NSResponder`, but mocked responder does not have the ivar of original objects which will result on invalid selector being called on a `NSMutableArray` one of the ivar of mock objects. Solution for this is to inherit from `NSResponder` and forward calls to mocked object.

3. Adding `flutter::kModifierFlagShiftLeft` to a modifier flag containing `kCGEventFlagMaskShift`. The assertion was introduced in #46230 but i missed the test failure because of the problems above.

[C++, Objective-C, Java style guides]: https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style
  • Loading branch information
knopp authored and harryterkelsen committed Oct 23, 2023
1 parent c0df034 commit 64ec710
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,9 @@ - (nonnull instancetype)init {
OCMStub([viewDelegateMock onTextInputKeyEvent:[OCMArg any]])
.andCall(self, @selector(handleTextInputKeyEvent:));
OCMStub([viewDelegateMock getBinaryMessenger]).andReturn(_messengerMock);
OCMStub([viewDelegateMock sendKeyEvent:FlutterKeyEvent {} callback:nil userData:nil])
OCMStub([viewDelegateMock sendKeyEvent:*(const FlutterKeyEvent*)[OCMArg anyPointer]
callback:nil
userData:nil])
.ignoringNonObjectArgs()
.andCall(self, @selector(handleEmbedderEvent:callback:userData:));
OCMStub([viewDelegateMock subscribeToKeyboardLayoutChange:[OCMArg any]])
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,42 @@ - (void)dealloc {
}
@end

/// Responder wrapper that forwards key events to another responder. This is a necessary middle step
/// for mocking responder because when setting the responder to controller AppKit will access ivars
/// of the objects, which means it must extend NSResponder instead of just implementing the
/// selectors.
@interface FlutterResponderWrapper : NSResponder {
NSResponder* _responder;
}
@end

@implementation FlutterResponderWrapper

- (instancetype)initWithResponder:(NSResponder*)responder {
if (self = [super init]) {
_responder = responder;
}
return self;
}

- (void)keyDown:(NSEvent*)event {
[_responder keyDown:event];
}

- (void)keyUp:(NSEvent*)event {
[_responder keyUp:event];
}

- (BOOL)performKeyEquivalent:(NSEvent*)event {
return [_responder performKeyEquivalent:event];
}

- (void)flagsChanged:(NSEvent*)event {
[_responder flagsChanged:event];
}

@end

// A FlutterViewController subclass for testing that mouseDown/mouseUp get called when
// mouse events are sent to the associated view.
@interface MouseEventFlutterViewController : FlutterViewController
Expand Down Expand Up @@ -417,7 +453,8 @@ - (bool)testKeyEventsArePropagatedIfNotHandled {
nibName:@""
bundle:nil];
id responderMock = flutter::testing::mockResponder();
viewController.nextResponder = responderMock;
id responderWrapper = [[FlutterResponderWrapper alloc] initWithResponder:responderMock];
viewController.nextResponder = responderWrapper;
NSDictionary* expectedEvent = @{
@"keymap" : @"macos",
@"type" : @"keydown",
Expand Down Expand Up @@ -493,7 +530,8 @@ - (bool)testFlagsChangedEventsArePropagatedIfNotHandled {
nibName:@""
bundle:nil];
id responderMock = flutter::testing::mockResponder();
viewController.nextResponder = responderMock;
id responderWrapper = [[FlutterResponderWrapper alloc] initWithResponder:responderMock];
viewController.nextResponder = responderWrapper;
NSDictionary* expectedEvent = @{
@"keymap" : @"macos",
@"type" : @"keydown",
Expand Down Expand Up @@ -546,7 +584,8 @@ - (bool)testKeyEventsAreNotPropagatedIfHandled {
nibName:@""
bundle:nil];
id responderMock = flutter::testing::mockResponder();
viewController.nextResponder = responderMock;
id responderWrapper = [[FlutterResponderWrapper alloc] initWithResponder:responderMock];
viewController.nextResponder = responderWrapper;
NSDictionary* expectedEvent = @{
@"keymap" : @"macos",
@"type" : @"keydown",
Expand Down Expand Up @@ -825,7 +864,7 @@ - (bool)testTrackpadGesturesAreSentToFramework {
CGEventRef cgEventDiscreteShift =
CGEventCreateScrollWheelEvent(NULL, kCGScrollEventUnitPixel, 1, 0);
CGEventSetType(cgEventDiscreteShift, kCGEventScrollWheel);
CGEventSetFlags(cgEventDiscreteShift, kCGEventFlagMaskShift);
CGEventSetFlags(cgEventDiscreteShift, kCGEventFlagMaskShift | flutter::kModifierFlagShiftLeft);
CGEventSetIntegerValueField(cgEventDiscreteShift, kCGScrollWheelEventIsContinuous, 0);
CGEventSetIntegerValueField(cgEventDiscreteShift, kCGScrollWheelEventDeltaAxis2,
0); // scroll_delta_x
Expand Down

0 comments on commit 64ec710

Please sign in to comment.