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  .contentSize = {.has_size = true, .width = 800, .height = 600},
61  .on_close = [] {},
62  .on_size_change = [] {},
63  };
64 
65  FlutterEngine* engine = GetFlutterEngine();
66  int64_t engineId = reinterpret_cast<int64_t>(engine);
67 
68  {
69  IsolateScope isolate_scope(isolate());
70  int64_t handle = InternalFlutter_WindowController_CreateRegularWindow(engineId, &request);
71  EXPECT_EQ(handle, 1);
72 
73  FlutterViewController* viewController = [engine viewControllerForIdentifier:handle];
74  EXPECT_NE(viewController, nil);
75  CGSize size = viewController.view.frame.size;
76  EXPECT_EQ(size.width, 800);
77  EXPECT_EQ(size.height, 600);
78  }
79 }
80 
81 TEST_F(FlutterWindowControllerRetainTest, WindowControllerDoesNotRetainEngine) {
83  .contentSize = {.has_size = true, .width = 800, .height = 600},
84  .on_close = [] {},
85  .on_size_change = [] {},
86  };
87 
88  __weak FlutterEngine* weakEngine = nil;
89  @autoreleasepool {
90  NSString* fixtures = @(flutter::testing::GetFixturesPath());
91  NSLog(@"Fixtures path: %@", fixtures);
92  FlutterDartProject* project = [[FlutterDartProject alloc]
93  initWithAssetsPath:fixtures
94  ICUDataPath:[fixtures stringByAppendingString:@"/icudtl.dat"]];
95 
96  static std::optional<flutter::Isolate> isolate;
97  isolate = std::nullopt;
98 
99  project.rootIsolateCreateCallback = [](void*) { isolate = flutter::Isolate::Current(); };
100  FlutterEngine* engine = [[FlutterEngine alloc] initWithName:@"test"
101  project:project
102  allowHeadlessExecution:YES];
103  weakEngine = engine;
104  [engine runWithEntrypoint:@"testWindowControllerRetainCycle"];
105 
106  int64_t engineId = reinterpret_cast<int64_t>(engine);
107 
108  {
109  FML_DCHECK(isolate.has_value());
110  // NOLINTNEXTLINE(bugprone-unchecked-optional-access)
111  IsolateScope isolateScope(*isolate);
112  int64_t handle = InternalFlutter_WindowController_CreateRegularWindow(engineId, &request);
113  EXPECT_EQ(handle, 1);
114  }
115 
116  [engine.windowController closeAllWindows];
117  [engine shutDownEngine];
118  }
119  EXPECT_EQ(weakEngine, nil);
120 }
121 
122 TEST_F(FlutterWindowControllerTest, DestroyRegularWindow) {
124  .contentSize = {.has_size = true, .width = 800, .height = 600},
125  .on_close = [] {},
126  .on_size_change = [] {},
127  };
128 
129  FlutterEngine* engine = GetFlutterEngine();
130  int64_t engine_id = reinterpret_cast<int64_t>(engine);
131 
132  IsolateScope isolate_scope(isolate());
133  int64_t handle = InternalFlutter_WindowController_CreateRegularWindow(engine_id, &request);
134  FlutterViewController* viewController = [engine viewControllerForIdentifier:handle];
135 
136  InternalFlutter_Window_Destroy(engine_id, (__bridge void*)viewController.view.window);
137  viewController = [engine viewControllerForIdentifier:handle];
138  EXPECT_EQ(viewController, nil);
139 }
140 
143  .contentSize = {.has_size = true, .width = 800, .height = 600},
144  .on_close = [] {},
145  .on_size_change = [] {},
146  };
147 
148  FlutterEngine* engine = GetFlutterEngine();
149  int64_t engine_id = reinterpret_cast<int64_t>(engine);
150 
151  IsolateScope isolate_scope(isolate());
152  int64_t handle = InternalFlutter_WindowController_CreateRegularWindow(engine_id, &request);
153  FlutterViewController* viewController = [engine viewControllerForIdentifier:handle];
154 
155  void* window_handle = InternalFlutter_Window_GetHandle(engine_id, handle);
156  EXPECT_EQ(window_handle, (__bridge void*)viewController.view.window);
157 }
158 
161  .contentSize = {.has_size = true, .width = 800, .height = 600},
162  .on_close = [] {},
163  .on_size_change = [] {},
164  };
165 
166  FlutterEngine* engine = GetFlutterEngine();
167  int64_t engine_id = reinterpret_cast<int64_t>(engine);
168 
169  IsolateScope isolate_scope(isolate());
170  int64_t handle = InternalFlutter_WindowController_CreateRegularWindow(engine_id, &request);
171 
172  FlutterViewController* viewController = [engine viewControllerForIdentifier:handle];
173  NSWindow* window = viewController.view.window;
174  void* windowHandle = (__bridge void*)window;
175 
176  EXPECT_EQ(window.zoomed, NO);
177  EXPECT_EQ(window.miniaturized, NO);
178  EXPECT_EQ(window.styleMask & NSWindowStyleMaskFullScreen, 0u);
179 
180  InternalFlutter_Window_SetMaximized(windowHandle, true);
181  CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.5, false);
182  EXPECT_EQ(window.zoomed, YES);
183 
184  InternalFlutter_Window_SetMaximized(windowHandle, false);
185  CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.5, false);
186  EXPECT_EQ(window.zoomed, NO);
187 
188  // FullScreen toggle does not seem to work when the application is not run from a bundle.
189 
190  InternalFlutter_Window_Minimize(windowHandle);
191  CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.5, false);
192  EXPECT_EQ(window.miniaturized, YES);
193 }
194 } // 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)