Fix flaky Windows exit unit test, remove error messages (#40945)

Shutdown is async, so we can not guarantee the order of execution and,
by extension, ignorance of execution used as an auxiliary part of a unit
test. Also, mock the windows view/binding handler for the engine in
order to avoid error messages.

Addresses https://github.com/flutter/flutter/issues/124162

## Pre-launch Checklist

- [x] I read the [Contributor Guide] and followed the process outlined
there for submitting PRs.
- [x] I read the [Tree Hygiene] wiki page, which explains my
responsibilities.
- [x] I read and followed the [Flutter Style Guide] and the [C++,
Objective-C, Java style guides].
- [x] I listed at least one issue that this PR fixes in the description
above.
- [x] I added new tests to check the change I am making or feature I am
adding, or Hixie said the PR is test-exempt. See [testing the engine]
for instructions on writing and running engine tests.
- [x] I updated/added relevant documentation (doc comments with `///`).
- [ ] I signed the [CLA].
- [x] All existing and new tests are passing.

If you need help, consider asking for advice on the #hackers-new channel
on [Discord].

<!-- Links -->
[Contributor Guide]:
https://github.com/flutter/flutter/wiki/Tree-hygiene#overview
[Tree Hygiene]: https://github.com/flutter/flutter/wiki/Tree-hygiene
[Flutter Style Guide]:
https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo
[C++, Objective-C, Java style guides]:
https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style
[testing the engine]:
https://github.com/flutter/flutter/wiki/Testing-the-engine
[CLA]: https://cla.developers.google.com/
[flutter/tests]: https://github.com/flutter/tests
[breaking change policy]:
https://github.com/flutter/flutter/wiki/Tree-hygiene#handling-breaking-changes
[Discord]: https://github.com/flutter/flutter/wiki/Chat
diff --git a/shell/platform/windows/fixtures/main.dart b/shell/platform/windows/fixtures/main.dart
index c9794f6..dd88b7e 100644
--- a/shell/platform/windows/fixtures/main.dart
+++ b/shell/platform/windows/fixtures/main.dart
@@ -97,24 +97,6 @@
     closed.complete(data);
   });
   await closed.future;
-
-  // From here down, nothing should be called, because the application will have already been closed.
-  final Completer<ByteData?> exited = Completer<ByteData?>();
-  final String jsonString = json.encode(<String, dynamic>{
-    'method': 'System.exitApplication',
-    'args': <String, dynamic>{
-      'type': 'required', 'exitCode': 0
-      }
-    });
-  ui.PlatformDispatcher.instance.sendPlatformMessage(
-    'flutter/platform',
-    ByteData.sublistView(
-      Uint8List.fromList(utf8.encode(jsonString))
-    ),
-    (ByteData? reply) {
-      exited.complete(reply);
-    });
-  await exited.future;
 }
 
 @pragma('vm:entry-point')
diff --git a/shell/platform/windows/flutter_windows_engine_unittests.cc b/shell/platform/windows/flutter_windows_engine_unittests.cc
index f21e3aa..161181c 100644
--- a/shell/platform/windows/flutter_windows_engine_unittests.cc
+++ b/shell/platform/windows/flutter_windows_engine_unittests.cc
@@ -639,13 +639,16 @@
   FlutterWindowsEngineBuilder builder{GetContext()};
   builder.SetDartEntrypoint("exitTestExit");
   bool finished = false;
-  bool did_call = false;
 
-  std::unique_ptr<FlutterWindowsEngine> engine = builder.Build();
+  auto window_binding_handler =
+      std::make_unique<::testing::NiceMock<MockWindowBindingHandler>>();
+  MockFlutterWindowsView view(std::move(window_binding_handler));
+  view.SetEngine(builder.Build());
+  FlutterWindowsEngine* engine = view.GetEngine();
 
-  EngineModifier modifier(engine.get());
+  EngineModifier modifier(engine);
   modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; };
-  auto handler = std::make_unique<MockWindowsLifecycleManager>(engine.get());
+  auto handler = std::make_unique<MockWindowsLifecycleManager>(engine);
   ON_CALL(*handler, Quit)
       .WillByDefault(
           [&finished](std::optional<HWND> hwnd, std::optional<WPARAM> wparam,
@@ -655,28 +658,16 @@
   EXPECT_CALL(*handler, Quit).Times(1);
   modifier.SetLifecycleManager(std::move(handler));
 
-  auto binary_messenger =
-      std::make_unique<BinaryMessengerImpl>(engine->messenger());
-  // If this callback is triggered, the test fails. The exit procedure should be
-  // called without checking with the framework.
-  binary_messenger->SetMessageHandler(
-      "flutter/platform", [&did_call](const uint8_t* message,
-                                      size_t message_size, BinaryReply reply) {
-        did_call = true;
-        char response[] = "";
-        reply(reinterpret_cast<uint8_t*>(response), 0);
-      });
-
   engine->Run();
 
   engine->window_proc_delegate_manager()->OnTopLevelWindowProc(0, WM_CLOSE, 0,
                                                                0);
 
+  // The test will only succeed when this while loop exits. Otherwise it will
+  // timeout.
   while (!finished) {
     engine->task_runner()->ProcessTasks();
   }
-
-  EXPECT_FALSE(did_call);
 }
 
 TEST_F(FlutterWindowsEngineTest, TestExitCancel) {
@@ -685,11 +676,15 @@
   bool finished = false;
   bool did_call = false;
 
-  std::unique_ptr<FlutterWindowsEngine> engine = builder.Build();
+  auto window_binding_handler =
+      std::make_unique<::testing::NiceMock<MockWindowBindingHandler>>();
+  MockFlutterWindowsView view(std::move(window_binding_handler));
+  view.SetEngine(builder.Build());
+  FlutterWindowsEngine* engine = view.GetEngine();
 
-  EngineModifier modifier(engine.get());
+  EngineModifier modifier(engine);
   modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; };
-  auto handler = std::make_unique<MockWindowsLifecycleManager>(engine.get());
+  auto handler = std::make_unique<MockWindowsLifecycleManager>(engine);
   ON_CALL(*handler, Quit)
       .WillByDefault([&finished](std::optional<HWND> hwnd,
                                  std::optional<WPARAM> wparam,
@@ -729,22 +724,29 @@
 TEST_F(FlutterWindowsEngineTest, TestExitSecondCloseMessage) {
   FlutterWindowsEngineBuilder builder{GetContext()};
   builder.SetDartEntrypoint("exitTestExit");
-  bool did_call = false;
   bool second_close = false;
 
-  std::unique_ptr<FlutterWindowsEngine> engine = builder.Build();
+  auto window_binding_handler =
+      std::make_unique<::testing::NiceMock<MockWindowBindingHandler>>();
+  MockFlutterWindowsView view(std::move(window_binding_handler));
+  view.SetEngine(builder.Build());
+  FlutterWindowsEngine* engine = view.GetEngine();
 
-  EngineModifier modifier(engine.get());
+  EngineModifier modifier(engine);
   modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; };
-  auto handler = std::make_unique<MockWindowsLifecycleManager>(engine.get());
-  ON_CALL(*handler, IsLastWindowOfProcess).WillByDefault([]() { return true; });
-  ON_CALL(*handler, Quit)
-      .WillByDefault([&handler](std::optional<HWND> hwnd,
-                                std::optional<WPARAM> wparam,
-                                std::optional<LPARAM> lparam, UINT exit_code) {
-        handler->WindowsLifecycleManager::Quit(hwnd, wparam, lparam, exit_code);
-      });
-  ON_CALL(*handler, DispatchMessage)
+  auto handler = std::make_unique<MockWindowsLifecycleManager>(engine);
+  auto& handler_obj = *handler;
+  ON_CALL(handler_obj, IsLastWindowOfProcess).WillByDefault([]() {
+    return true;
+  });
+  ON_CALL(handler_obj, Quit)
+      .WillByDefault(
+          [&handler_obj](std::optional<HWND> hwnd, std::optional<WPARAM> wparam,
+                         std::optional<LPARAM> lparam, UINT exit_code) {
+            handler_obj.WindowsLifecycleManager::Quit(hwnd, wparam, lparam,
+                                                      exit_code);
+          });
+  ON_CALL(handler_obj, DispatchMessage)
       .WillByDefault(
           [&engine](HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
             engine->window_proc_delegate_manager()->OnTopLevelWindowProc(
@@ -752,16 +754,6 @@
           });
   modifier.SetLifecycleManager(std::move(handler));
 
-  auto binary_messenger =
-      std::make_unique<BinaryMessengerImpl>(engine->messenger());
-  binary_messenger->SetMessageHandler(
-      "flutter/platform", [&did_call](const uint8_t* message,
-                                      size_t message_size, BinaryReply reply) {
-        did_call = true;
-        char response[] = "";
-        reply(reinterpret_cast<uint8_t*>(response), 0);
-      });
-
   engine->Run();
 
   // This delegate will be registered after the lifecycle manager, so it will be
@@ -788,21 +780,22 @@
   while (!second_close) {
     engine->task_runner()->ProcessTasks();
   }
-
-  EXPECT_FALSE(did_call);
 }
 
 TEST_F(FlutterWindowsEngineTest, TestExitCloseMultiWindow) {
   FlutterWindowsEngineBuilder builder{GetContext()};
   builder.SetDartEntrypoint("exitTestExit");
   bool finished = false;
-  bool did_call = false;
 
-  std::unique_ptr<FlutterWindowsEngine> engine = builder.Build();
+  auto window_binding_handler =
+      std::make_unique<::testing::NiceMock<MockWindowBindingHandler>>();
+  MockFlutterWindowsView view(std::move(window_binding_handler));
+  view.SetEngine(builder.Build());
+  FlutterWindowsEngine* engine = view.GetEngine();
 
-  EngineModifier modifier(engine.get());
+  EngineModifier modifier(engine);
   modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; };
-  auto handler = std::make_unique<MockWindowsLifecycleManager>(engine.get());
+  auto handler = std::make_unique<MockWindowsLifecycleManager>(engine);
   ON_CALL(*handler, IsLastWindowOfProcess).WillByDefault([&finished]() {
     finished = true;
     return false;
@@ -811,18 +804,6 @@
   EXPECT_CALL(*handler, Quit).Times(0);
   modifier.SetLifecycleManager(std::move(handler));
 
-  auto binary_messenger =
-      std::make_unique<BinaryMessengerImpl>(engine->messenger());
-  // If this callback is triggered, the test fails. The exit procedure should be
-  // called without checking with the framework.
-  binary_messenger->SetMessageHandler(
-      "flutter/platform", [&did_call](const uint8_t* message,
-                                      size_t message_size, BinaryReply reply) {
-        did_call = true;
-        char response[] = "";
-        reply(reinterpret_cast<uint8_t*>(response), 0);
-      });
-
   engine->Run();
 
   engine->window_proc_delegate_manager()->OnTopLevelWindowProc(0, WM_CLOSE, 0,
@@ -831,8 +812,6 @@
   while (!finished) {
     engine->task_runner()->ProcessTasks();
   }
-
-  EXPECT_FALSE(did_call);
 }
 
 }  // namespace testing