Flutter Engine
The Flutter Engine
FlutterMenuPluginTest.mm
Go to the documentation of this file.
1// Copyright 2013 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterMenuPlugin.h"
6#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterMenuPlugin_Internal.h"
7
8#import "flutter/shell/platform/common/platform_provided_menu.h"
9#import "flutter/shell/platform/darwin/common/framework/Headers/FlutterChannels.h"
10#import "flutter/shell/platform/darwin/macos/framework/Headers/FlutterPluginMacOS.h"
11#import "flutter/shell/platform/darwin/macos/framework/Headers/FlutterPluginRegistrarMacOS.h"
12#import "flutter/shell/platform/darwin/macos/framework/Headers/FlutterViewController.h"
13#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterDartProject_Internal.h"
14#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterEngine_Internal.h"
15#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterTextInputPlugin.h"
16#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterTextInputSemanticsObject.h"
17#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterViewController_Internal.h"
18#include "flutter/testing/autoreleasepool_test.h"
19#include "flutter/testing/testing.h"
20#include "gtest/gtest.h"
21
23@property(nonatomic, readonly) id<FlutterPlugin> plugin;
24@property(nonatomic, readonly) FlutterMethodChannel* channel;
25@end
26
27@implementation FakePluginRegistrar
28@synthesize messenger;
29@synthesize textures;
30@synthesize view;
31
32- (void)addMethodCallDelegate:(nonnull id<FlutterPlugin>)delegate
33 channel:(nonnull FlutterMethodChannel*)channel {
34 _plugin = delegate;
36 [_channel setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) {
37 [delegate handleMethodCall:call result:result];
38 }];
39}
40
41- (void)addApplicationDelegate:(nonnull NSObject<FlutterAppLifecycleDelegate>*)delegate {
42}
43
44- (void)registerViewFactory:(nonnull NSObject<FlutterPlatformViewFactory>*)factory
45 withId:(nonnull NSString*)factoryId {
46}
47
48- (void)publish:(nonnull NSObject*)value {
49}
50
51- (nonnull NSString*)lookupKeyForAsset:(nonnull NSString*)asset {
52 return @"";
53}
54
55- (nonnull NSString*)lookupKeyForAsset:(nonnull NSString*)asset
56 fromPackage:(nonnull NSString*)package {
57 return @"";
58}
59@end
60
61namespace flutter::testing {
62
63// FlutterMenuPluginTest is an AutoreleasePoolTest that allocates an NSView.
64//
65// This supports the use of NSApplication features that rely on the assumption of a view, such as
66// when modifying the application menu bar, or even accessing the NSApplication.localizedName
67// property.
68//
69// See: https://github.com/flutter/flutter/issues/104748#issuecomment-1159336728
71 public:
74
75 private:
76 NSView* view_;
77};
78
79FlutterMenuPluginTest::FlutterMenuPluginTest() {
80 view_ = [[NSView alloc] initWithFrame:NSZeroRect];
81 view_.wantsLayer = YES;
82}
83
85 // Build a simulation of the default main menu.
86 NSMenu* mainMenu = [[NSMenu alloc] init];
87 NSMenuItem* appNameMenu = [[NSMenuItem alloc] initWithTitle:NSLocalizedString(@"APP_NAME", nil)
88 action:nil
89 keyEquivalent:@""];
90 NSMenu* submenu =
91 [[NSMenu alloc] initWithTitle:NSLocalizedString(@"Prexisting APP_NAME menu", nil)];
92 [submenu addItem:[[NSMenuItem alloc] initWithTitle:NSLocalizedString(@"About APP_NAME", nil)
93 action:nil
94 keyEquivalent:@""]];
95 appNameMenu.submenu = submenu;
96 [mainMenu addItem:appNameMenu];
97 [NSApp setMainMenu:mainMenu];
98
99 FakePluginRegistrar* registrar = [[FakePluginRegistrar alloc] init];
101 FlutterMenuPlugin* plugin = [registrar plugin];
102
103 NSDictionary* testMenus = @{
104 @"0" : @[
105 @{
106 @"id" : [NSNumber numberWithInt:1],
107 @"label" : @"APP_NAME",
108 @"enabled" : @(YES),
109 @"children" : @[
110 @{
111 @"id" : [NSNumber numberWithInt:3],
112 @"platformProvidedMenu" : @(static_cast<int>(flutter::PlatformProvidedMenu::kQuit)),
113 @"enabled" : @(YES),
114 },
115 @{
116 @"id" : [NSNumber numberWithInt:2],
117 @"label" : @"APP_NAME Info",
118 @"enabled" : @(YES),
119 @"shortcutTrigger" : [NSNumber numberWithUnsignedLongLong:0x61],
120 @"shortcutModifiers" : [NSNumber numberWithUnsignedInt:0],
121 },
122 ],
123 },
124 @{
125 @"id" : [NSNumber numberWithInt:4],
126 @"label" : @"Help for APP_NAME",
127 @"enabled" : @(YES),
128 @"children" : @[
129 @{
130 @"id" : [NSNumber numberWithInt:5],
131 @"label" : @"Help me!",
132 @"enabled" : @(YES),
133 },
134 @{
135 @"id" : [NSNumber numberWithInt:6],
136 @"label" : @"",
137 @"enabled" : @(NO),
138 @"isDivider" : @(YES),
139 },
140 @{
141 @"id" : [NSNumber numberWithInt:7],
142 @"label" : @"Search help",
143 @"enabled" : @(NO),
144 },
145 ],
146 },
147 ],
148 };
149
150 __block id available = @NO;
151 [plugin handleMethodCall:[FlutterMethodCall methodCallWithMethodName:@"Menu.isPluginAvailable"
152 arguments:nil]
153 result:^(id _Nullable result) {
154 available = result;
155 }];
156
157 EXPECT_TRUE(available);
158
160 arguments:testMenus]
161 result:^(id _Nullable result){
162 }];
163
164 EXPECT_EQ([NSApp.mainMenu numberOfItems], 2);
165 NSMenuItem* firstMenu = [NSApp.mainMenu itemAtIndex:0];
166 EXPECT_TRUE([[firstMenu title] isEqualToString:@"flutter_desktop_darwin_unittests"]);
167 EXPECT_EQ([firstMenu tag], 1);
168 EXPECT_TRUE([firstMenu isEnabled]);
169 EXPECT_FALSE([firstMenu isHidden]);
170 EXPECT_TRUE([[firstMenu keyEquivalent] isEqualToString:@"\0"]);
171
172 EXPECT_EQ([[firstMenu submenu] numberOfItems], 1);
173 NSMenuItem* firstItem = [[firstMenu submenu] itemAtIndex:0];
174 EXPECT_TRUE([[firstItem title] isEqualToString:@"flutter_desktop_darwin_unittests Info"]);
175 EXPECT_TRUE([[firstItem keyEquivalent] isEqualToString:@"a"]);
176 EXPECT_TRUE([firstItem isEnabled]);
177 EXPECT_FALSE([firstItem isHidden]);
179 [NSStringFromSelector([firstItem action]) isEqualToString:@"flutterMenuItemSelected:"]);
180 EXPECT_EQ([firstItem tag], 2);
181
182 NSMenuItem* secondMenu = [NSApp.mainMenu itemAtIndex:1];
183 EXPECT_TRUE([[secondMenu title] isEqualToString:@"Help for flutter_desktop_darwin_unittests"]);
184 EXPECT_EQ([secondMenu tag], 4);
185 EXPECT_TRUE([secondMenu isEnabled]);
186 EXPECT_FALSE([secondMenu isHidden]);
187
188 EXPECT_EQ([[secondMenu submenu] numberOfItems], 3);
189 NSMenuItem* secondMenuFirst = [[secondMenu submenu] itemAtIndex:0];
190 EXPECT_TRUE([[secondMenuFirst title] isEqualToString:@"Help me!"]);
191 EXPECT_TRUE([secondMenuFirst isEnabled]);
192 EXPECT_FALSE([secondMenuFirst isHidden]);
194 [NSStringFromSelector([secondMenuFirst action]) isEqualToString:@"flutterMenuItemSelected:"]);
195 EXPECT_EQ([secondMenuFirst tag], 5);
196
197 NSMenuItem* secondMenuDivider = [[secondMenu submenu] itemAtIndex:1];
198 EXPECT_TRUE([[secondMenuDivider title] isEqualToString:@""]);
199 EXPECT_TRUE([[secondMenuDivider keyEquivalent] isEqualToString:@""]);
200 EXPECT_FALSE([secondMenuDivider isEnabled]);
201 EXPECT_FALSE([secondMenuDivider isHidden]);
202 EXPECT_EQ([secondMenuDivider action], nil);
203 EXPECT_EQ([secondMenuDivider tag], 0);
204
205 NSMenuItem* secondMenuLast = [[secondMenu submenu] itemAtIndex:2];
206 EXPECT_TRUE([[secondMenuLast title] isEqualToString:@"Search help"]);
207 EXPECT_FALSE([secondMenuLast isEnabled]);
208 EXPECT_FALSE([secondMenuLast isHidden]);
210 [NSStringFromSelector([secondMenuLast action]) isEqualToString:@"flutterMenuItemSelected:"]);
211 EXPECT_EQ([secondMenuLast tag], 7);
212}
213
214} // namespace flutter::testing
FlutterTextInputPlugin * _plugin
FlutterMethodChannel * _channel
HWND(* FlutterPlatformViewFactory)(const FlutterPlatformViewCreationParameters *)
FlutterMethodChannel * channel
id< FlutterPlugin > plugin
void registerWithRegistrar:(nonnull id< FlutterPluginRegistrar > registrar)
void handleMethodCall:result:(FlutterMethodCall *call, [result] FlutterResult result)
instancetype methodCallWithMethodName:arguments:(NSString *method,[arguments] id _Nullable arguments)
TEST_F(FlutterMenuPluginTest, TestSetMenu)
id< FlutterBinaryMessenger > messenger
id< FlutterTextureRegistry > textures
#define EXPECT_TRUE(handle)
Definition: unit_test.h:678