Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Added integration test for platform channels on windows. #36853

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 17 additions & 5 deletions shell/platform/windows/fixtures/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// found in the LICENSE file.

import 'dart:io' as io;
import 'dart:typed_data' show ByteData;
import 'dart:ui' as ui;

// Signals a waiting latch in the native test.
Expand All @@ -20,13 +21,24 @@ bool signalBoolReturn() native 'SignalBoolReturn';
// Notify the native test that the first frame has been scheduled.
void notifyFirstFrameScheduled() native 'NotifyFirstFrameScheduled';

void main() {
}
void main() {}

@pragma('vm:entry-point')
void customEntrypoint() {
void hiPlatformChannels() {
ui.channelBuffers.setListener('hi',
(ByteData? data, ui.PlatformMessageResponseCallback callback) async {
ui.PlatformDispatcher.instance.sendPlatformMessage('hi', data,
(ByteData? reply) {
ui.PlatformDispatcher.instance
.sendPlatformMessage('hi', reply, (ByteData? reply) {});
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this supposed to be bye instead of hi? The test seems to be checking for a message starting with b too.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yea, it's a bit confusing. I'm not sure how to make it more clear, "hi" is the name of the channel, not the payload. Dart just echos the payloads that it gets from the c++ side.

});
callback(null);
});
}

@pragma('vm:entry-point')
void customEntrypoint() {}

@pragma('vm:entry-point')
void verifyNativeFunction() {
signal();
Expand All @@ -51,8 +63,8 @@ void readPlatformExecutable() {
@pragma('vm:entry-point')
void drawHelloWorld() {
ui.PlatformDispatcher.instance.onBeginFrame = (Duration duration) {
final ui.ParagraphBuilder paragraphBuilder = ui.ParagraphBuilder(ui.ParagraphStyle())
..addText('Hello world');
final ui.ParagraphBuilder paragraphBuilder =
ui.ParagraphBuilder(ui.ParagraphStyle())..addText('Hello world');
final ui.Paragraph paragraph = paragraphBuilder.build();

paragraph.layout(const ui.ParagraphConstraints(width: 800.0));
Expand Down
79 changes: 66 additions & 13 deletions shell/platform/windows/flutter_windows_engine_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
#include "flutter/shell/platform/embedder/test_utils/proc_table_replacement.h"
#include "flutter/shell/platform/windows/testing/engine_modifier.h"
#include "flutter/shell/platform/windows/testing/test_keyboard.h"
#include "flutter/shell/platform/windows/testing/windows_test.h"
#include "fml/synchronization/waitable_event.h"
#include "gtest/gtest.h"

// winbase.h defines GetCurrentTime as a macro.
Expand Down Expand Up @@ -40,7 +42,9 @@ std::unique_ptr<FlutterWindowsEngine> GetTestEngine() {
}
} // namespace

TEST(FlutterWindowsEngine, RunDoesExpectedInitialization) {
class FlutterWindowsEngineTest : public WindowsTest {};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just curious for my own knowledge, what are the benefits of this?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The WindowsTest class has access to the dart code that is compiled into the test runner. This tripped me up for a long time but you can't send and receive messages on windows unless you have a running engine, and you can't have a running engine without a dart kernel to execute. (On iOS and Android that isn't the case.) That's why I had to make this test suit a subclass of WindowsTest.


TEST_F(FlutterWindowsEngineTest, RunDoesExpectedInitialization) {
std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
EngineModifier modifier(engine.get());

Expand Down Expand Up @@ -148,7 +152,7 @@ TEST(FlutterWindowsEngine, RunDoesExpectedInitialization) {
modifier.ReleaseSurfaceManager();
}

TEST(FlutterWindowsEngine, ConfiguresFrameVsync) {
TEST_F(FlutterWindowsEngineTest, ConfiguresFrameVsync) {
std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
EngineModifier modifier(engine.get());
bool on_vsync_called = false;
Expand All @@ -174,7 +178,7 @@ TEST(FlutterWindowsEngine, ConfiguresFrameVsync) {
EXPECT_TRUE(on_vsync_called);
}

TEST(FlutterWindowsEngine, RunWithoutANGLEUsesSoftware) {
TEST_F(FlutterWindowsEngineTest, RunWithoutANGLEUsesSoftware) {
std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
EngineModifier modifier(engine.get());

Expand Down Expand Up @@ -226,7 +230,7 @@ TEST(FlutterWindowsEngine, RunWithoutANGLEUsesSoftware) {
modifier.embedder_api().Shutdown = [](auto engine) { return kSuccess; };
}

TEST(FlutterWindowsEngine, SendPlatformMessageWithoutResponse) {
TEST_F(FlutterWindowsEngineTest, SendPlatformMessageWithoutResponse) {
std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
EngineModifier modifier(engine.get());

Expand All @@ -252,7 +256,56 @@ TEST(FlutterWindowsEngine, SendPlatformMessageWithoutResponse) {
EXPECT_TRUE(called);
}

TEST(FlutterWindowsEngine, SendPlatformMessageWithResponse) {
TEST_F(FlutterWindowsEngineTest, PlatformMessageRoundTrip) {
FlutterDesktopEngineProperties properties = {};
properties.assets_path = GetContext().GetAssetsPath().c_str();
properties.icu_data_path = GetContext().GetIcuDataPath().c_str();
properties.dart_entrypoint = "hiPlatformChannels";

FlutterProjectBundle project(properties);
auto engine = std::make_unique<FlutterWindowsEngine>(project);

EngineModifier modifier(engine.get());
modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; };

auto binary_messenger =
std::make_unique<BinaryMessengerImpl>(engine->messenger());

engine->Run();
bool did_call_callback = false;
bool did_call_reply = false;
bool did_call_dart_reply = false;
std::string channel = "hi";
binary_messenger->SetMessageHandler(
channel,
[&did_call_callback, &did_call_dart_reply](
const uint8_t* message, size_t message_size, BinaryReply reply) {
if (message_size == 5) {
EXPECT_EQ(message[0], static_cast<uint8_t>('h'));
char response[] = {'b', 'y', 'e'};
reply(reinterpret_cast<uint8_t*>(response), 3);
did_call_callback = true;
} else {
EXPECT_EQ(message_size, 3);
EXPECT_EQ(message[0], static_cast<uint8_t>('b'));
did_call_dart_reply = true;
}
});
char payload[] = {'h', 'e', 'l', 'l', 'o'};
binary_messenger->Send(
channel, reinterpret_cast<uint8_t*>(payload), 5,
[&did_call_reply](const uint8_t* reply, size_t reply_size) {
EXPECT_EQ(reply_size, 3);
EXPECT_EQ(reply[0], static_cast<uint8_t>('b'));
did_call_reply = true;
});
// Rely on timeout mechanism in CI.
while (!did_call_callback && !did_call_reply && !did_call_dart_reply) {
engine->task_runner()->ProcessTasks();
}
}

TEST_F(FlutterWindowsEngineTest, SendPlatformMessageWithResponse) {
std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
EngineModifier modifier(engine.get());

Expand Down Expand Up @@ -310,7 +363,7 @@ TEST(FlutterWindowsEngine, SendPlatformMessageWithResponse) {
EXPECT_TRUE(send_message_called);
}

TEST(FlutterWindowsEngine, DispatchSemanticsAction) {
TEST_F(FlutterWindowsEngineTest, DispatchSemanticsAction) {
std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
EngineModifier modifier(engine.get());

Expand All @@ -334,7 +387,7 @@ TEST(FlutterWindowsEngine, DispatchSemanticsAction) {
EXPECT_TRUE(called);
}

TEST(FlutterWindowsEngine, SetsThreadPriority) {
TEST_F(FlutterWindowsEngineTest, SetsThreadPriority) {
WindowsPlatformThreadPrioritySetter(FlutterThreadPriority::kBackground);
EXPECT_EQ(GetThreadPriority(GetCurrentThread()),
THREAD_PRIORITY_BELOW_NORMAL);
Expand All @@ -355,7 +408,7 @@ TEST(FlutterWindowsEngine, SetsThreadPriority) {
EXPECT_EQ(GetThreadPriority(GetCurrentThread()), THREAD_PRIORITY_NORMAL);
}

TEST(FlutterWindowsEngine, AddPluginRegistrarDestructionCallback) {
TEST_F(FlutterWindowsEngineTest, AddPluginRegistrarDestructionCallback) {
std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
EngineModifier modifier(engine.get());

Expand Down Expand Up @@ -385,7 +438,7 @@ TEST(FlutterWindowsEngine, AddPluginRegistrarDestructionCallback) {
EXPECT_EQ(result2, 2);
}

TEST(FlutterWindowsEngine, ScheduleFrame) {
TEST_F(FlutterWindowsEngineTest, ScheduleFrame) {
std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
EngineModifier modifier(engine.get());

Expand All @@ -400,7 +453,7 @@ TEST(FlutterWindowsEngine, ScheduleFrame) {
EXPECT_TRUE(called);
}

TEST(FlutterWindowsEngine, SetNextFrameCallback) {
TEST_F(FlutterWindowsEngineTest, SetNextFrameCallback) {
std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
EngineModifier modifier(engine.get());

Expand All @@ -415,14 +468,14 @@ TEST(FlutterWindowsEngine, SetNextFrameCallback) {
EXPECT_TRUE(called);
}

TEST(FlutterWindowsEngine, GetExecutableName) {
TEST_F(FlutterWindowsEngineTest, GetExecutableName) {
std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
EXPECT_EQ(engine->GetExecutableName(), "flutter_windows_unittests.exe");
}

// Ensure that after setting or resetting the high contrast feature,
// the corresponding status flag can be retrieved from the engine.
TEST(FlutterWindowsEngine, UpdateHighContrastFeature) {
TEST_F(FlutterWindowsEngineTest, UpdateHighContrastFeature) {
std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
EngineModifier modifier(engine.get());

Expand All @@ -447,7 +500,7 @@ TEST(FlutterWindowsEngine, UpdateHighContrastFeature) {
EXPECT_FALSE(engine->high_contrast_enabled());
}

TEST(FlutterWindowsEngine, PostRasterThreadTask) {
TEST_F(FlutterWindowsEngineTest, PostRasterThreadTask) {
std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
EngineModifier modifier(engine.get());

Expand Down