Flutter macOS Embedder
FlutterWindowControllerTest.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 
7 
12 #import "flutter/testing/testing.h"
13 #import "third_party/googletest/googletest/include/gtest/gtest.h"
14 
15 namespace flutter::testing {
16 
18  public:
20 
21  void SetUp() {
23 
24  [GetFlutterEngine() runWithEntrypoint:@"testWindowController"];
25 
26  bool signalled = false;
27 
28  AddNativeCallback("SignalNativeTest", CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) {
30  signalled = true;
31  }));
32 
33  while (!signalled) {
34  CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, false);
35  }
36  }
37 
38  void TearDown() {
39  [GetFlutterEngine().windowController closeAllWindows];
41  }
42 
43  protected:
45  if (isolate_) {
46  return *isolate_;
47  } else {
48  FML_LOG(ERROR) << "Isolate is not set.";
49  FML_UNREACHABLE();
50  }
51  }
52 
53  std::optional<flutter::Isolate> isolate_;
54 };
55 
56 class FlutterWindowControllerRetainTest : public ::testing::Test {};
57 
58 TEST_F(FlutterWindowControllerTest, CreateRegularWindow) {
60  .has_size = true,
61  .size = {.width = 800, .height = 600},
62  .on_close = [] {},
63  .notify_listeners = [] {},
64  };
65 
66  FlutterEngine* engine = GetFlutterEngine();
67  int64_t engineId = reinterpret_cast<int64_t>(engine);
68 
69  {
70  IsolateScope isolate_scope(isolate());
71  int64_t handle = InternalFlutter_WindowController_CreateRegularWindow(engineId, &request);
72  EXPECT_EQ(handle, 1);
73 
74  FlutterViewController* viewController = [engine viewControllerForIdentifier:handle];
75  EXPECT_NE(viewController, nil);
76  CGSize size = viewController.view.frame.size;
77  EXPECT_EQ(size.width, 800);
78  EXPECT_EQ(size.height, 600);
79  }
80 }
81 
82 TEST_F(FlutterWindowControllerRetainTest, WindowControllerDoesNotRetainEngine) {
84  .has_size = true,
85  .size = {.width = 800, .height = 600},
86  .on_close = [] {},
87  .notify_listeners = [] {},
88  };
89 
90  __weak FlutterEngine* weakEngine = nil;
91  @autoreleasepool {
92  NSString* fixtures = @(flutter::testing::GetFixturesPath());
93  NSLog(@"Fixtures path: %@", fixtures);
94  FlutterDartProject* project = [[FlutterDartProject alloc]
95  initWithAssetsPath:fixtures
96  ICUDataPath:[fixtures stringByAppendingString:@"/icudtl.dat"]];
97 
98  static std::optional<flutter::Isolate> isolate;
99  isolate = std::nullopt;
100 
101  project.rootIsolateCreateCallback = [](void*) { isolate = flutter::Isolate::Current(); };
102  FlutterEngine* engine = [[FlutterEngine alloc] initWithName:@"test"
103  project:project
104  allowHeadlessExecution:YES];
105  weakEngine = engine;
106  [engine runWithEntrypoint:@"testWindowControllerRetainCycle"];
107 
108  int64_t engineId = reinterpret_cast<int64_t>(engine);
109 
110  {
111  FML_DCHECK(isolate.has_value());
112  // NOLINTNEXTLINE(bugprone-unchecked-optional-access)
113  IsolateScope isolateScope(*isolate);
114  int64_t handle = InternalFlutter_WindowController_CreateRegularWindow(engineId, &request);
115  EXPECT_EQ(handle, 1);
116  }
117 
118  [engine.windowController closeAllWindows];
119  [engine shutDownEngine];
120  }
121  EXPECT_EQ(weakEngine, nil);
122 }
123 
124 TEST_F(FlutterWindowControllerTest, DestroyRegularWindow) {
126  .has_size = true,
127  .size = {.width = 800, .height = 600},
128  .on_close = [] {},
129  .notify_listeners = [] {},
130  };
131 
132  FlutterEngine* engine = GetFlutterEngine();
133  int64_t engine_id = reinterpret_cast<int64_t>(engine);
134 
135  IsolateScope isolate_scope(isolate());
136  int64_t handle = InternalFlutter_WindowController_CreateRegularWindow(engine_id, &request);
137  FlutterViewController* viewController = [engine viewControllerForIdentifier:handle];
138 
139  InternalFlutter_Window_Destroy(engine_id, (__bridge void*)viewController.view.window);
140  viewController = [engine viewControllerForIdentifier:handle];
141  EXPECT_EQ(viewController, nil);
142 }
143 
146  .has_size = true,
147  .size = {.width = 800, .height = 600},
148  .on_close = [] {},
149  .notify_listeners = [] {},
150  };
151 
152  FlutterEngine* engine = GetFlutterEngine();
153  int64_t engine_id = reinterpret_cast<int64_t>(engine);
154 
155  IsolateScope isolate_scope(isolate());
156  int64_t handle = InternalFlutter_WindowController_CreateRegularWindow(engine_id, &request);
157  FlutterViewController* viewController = [engine viewControllerForIdentifier:handle];
158 
159  void* window_handle = InternalFlutter_Window_GetHandle(engine_id, handle);
160  EXPECT_EQ(window_handle, (__bridge void*)viewController.view.window);
161 }
162 
165  .has_size = true,
166  .size = {.width = 800, .height = 600},
167  .on_close = [] {},
168  .notify_listeners = [] {},
169  };
170 
171  FlutterEngine* engine = GetFlutterEngine();
172  int64_t engine_id = reinterpret_cast<int64_t>(engine);
173 
174  IsolateScope isolate_scope(isolate());
175  int64_t handle = InternalFlutter_WindowController_CreateRegularWindow(engine_id, &request);
176 
177  FlutterViewController* viewController = [engine viewControllerForIdentifier:handle];
178  NSWindow* window = viewController.view.window;
179  void* windowHandle = (__bridge void*)window;
180 
181  EXPECT_EQ(window.zoomed, NO);
182  EXPECT_EQ(window.miniaturized, NO);
183  EXPECT_EQ(window.styleMask & NSWindowStyleMaskFullScreen, 0u);
184 
185  InternalFlutter_Window_SetMaximized(windowHandle, true);
186  CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.5, false);
187  EXPECT_EQ(window.zoomed, YES);
188 
189  InternalFlutter_Window_SetMaximized(windowHandle, false);
190  CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.5, false);
191  EXPECT_EQ(window.zoomed, NO);
192 
193  // FullScreen toggle does not seem to work when the application is not run from a bundle.
194 
195  InternalFlutter_Window_Minimize(windowHandle);
196  CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.5, false);
197  EXPECT_EQ(window.miniaturized, YES);
198 }
199 } // namespace flutter::testing
FLUTTER_DARWIN_EXPORT int64_t InternalFlutter_WindowController_CreateRegularWindow(int64_t engine_id, const FlutterWindowCreationRequest *request)
FLUTTER_DARWIN_EXPORT void InternalFlutter_Window_SetMaximized(void *window, bool maximized)
FLUTTER_DARWIN_EXPORT void InternalFlutter_Window_Destroy(int64_t engine_id, void *window)
FLUTTER_DARWIN_EXPORT void * InternalFlutter_Window_GetHandle(int64_t engine_id, FlutterViewIdentifier view_id)
FLUTTER_DARWIN_EXPORT void InternalFlutter_Window_Minimize(void *window)
static Isolate Current()
Definition: isolate_scope.cc:9
void AddNativeCallback(const char *name, Dart_NativeFunction function)
TEST_F(AccessibilityBridgeMacWindowTest, SendsAccessibilityCreateNotificationFlutterViewWindow)