From 7302929606ad94c9dd28e7c2cc15bb28085a0d69 Mon Sep 17 00:00:00 2001 From: Alexander Biggs Date: Wed, 7 Sep 2022 11:57:12 -0700 Subject: [PATCH 1/5] [fuchsia] Port text-input-test, part 1. (#35957) Part 1 sets up the test to run but the UI has not been ported yet so the test hangs. This is mostly a straight port from https://cs.opensource.google/fuchsia/fuchsia/+/main:src/ui/tests/integration_input_tests/text-input/ There were some nuances: - Some FIDL APIs are not available in the SDK and have to be referenced by name instead (vulkan.Loader, scheduler.ProfileProvider). - Some subtle differences between the GN rules in fuchsia.git vs. engine (e.g. fuchsia_component doesn't append .cm by default to CFv2 output). - Moved shared logic from embedder test into a utils/ folder to facilitate writing new tests in the future. Part 2 will port over the UI to dart:ui. --- .../flutter/tests/integration/BUILD.gn | 5 +- .../tests/integration/embedder/BUILD.gn | 9 +- .../embedder/child-view/meta/child-view.cml | 3 + .../embedder/flutter-embedder-test.cc | 109 +++---- .../embedder/meta/flutter-embedder-test.cml | 3 + .../embedder/meta/gtest_runner.shard.cml | 3 + .../embedder/parent-view/meta/parent-view.cml | 3 + .../tests/integration/text-input/BUILD.gn | 66 ++++ .../text-input/meta/gtest_runner.shard.cml | 17 + .../text-input/meta/text-input-test.cml | 42 +++ .../integration/text-input/text-input-test.cc | 303 ++++++++++++++++++ .../text-input/text-input-view/BUILD.gn | 46 +++ .../text-input-view/lib/text_input_view.dart | 24 ++ .../meta/text-input-view-realm.cml | 62 ++++ .../text-input-view/meta/text-input-view.cml | 38 +++ .../text-input/text-input-view/pubspec.yaml | 8 + .../flutter/tests/integration/utils/BUILD.gn | 42 +++ .../tests/integration/utils/check_view.cc | 39 +++ .../tests/integration/utils/check_view.h | 30 ++ .../flutter/tests/integration/utils/color.cc | 17 + .../flutter/tests/integration/utils/color.h | 38 +++ .../color.cc => utils/screenshot.cc} | 14 +- .../{embedder/color.h => utils/screenshot.h} | 33 +- testing/fuchsia/test_suites.yaml | 1 - tools/fuchsia/devshell/lib/vars.sh | 9 + .../fuchsia/devshell/run_integration_test.sh | 21 ++ 26 files changed, 879 insertions(+), 106 deletions(-) create mode 100644 shell/platform/fuchsia/flutter/tests/integration/text-input/BUILD.gn create mode 100644 shell/platform/fuchsia/flutter/tests/integration/text-input/meta/gtest_runner.shard.cml create mode 100644 shell/platform/fuchsia/flutter/tests/integration/text-input/meta/text-input-test.cml create mode 100644 shell/platform/fuchsia/flutter/tests/integration/text-input/text-input-test.cc create mode 100644 shell/platform/fuchsia/flutter/tests/integration/text-input/text-input-view/BUILD.gn create mode 100644 shell/platform/fuchsia/flutter/tests/integration/text-input/text-input-view/lib/text_input_view.dart create mode 100644 shell/platform/fuchsia/flutter/tests/integration/text-input/text-input-view/meta/text-input-view-realm.cml create mode 100644 shell/platform/fuchsia/flutter/tests/integration/text-input/text-input-view/meta/text-input-view.cml create mode 100644 shell/platform/fuchsia/flutter/tests/integration/text-input/text-input-view/pubspec.yaml create mode 100644 shell/platform/fuchsia/flutter/tests/integration/utils/BUILD.gn create mode 100644 shell/platform/fuchsia/flutter/tests/integration/utils/check_view.cc create mode 100644 shell/platform/fuchsia/flutter/tests/integration/utils/check_view.h create mode 100644 shell/platform/fuchsia/flutter/tests/integration/utils/color.cc create mode 100644 shell/platform/fuchsia/flutter/tests/integration/utils/color.h rename shell/platform/fuchsia/flutter/tests/integration/{embedder/color.cc => utils/screenshot.cc} (86%) rename shell/platform/fuchsia/flutter/tests/integration/{embedder/color.h => utils/screenshot.h} (68%) diff --git a/shell/platform/fuchsia/flutter/tests/integration/BUILD.gn b/shell/platform/fuchsia/flutter/tests/integration/BUILD.gn index c25f18aaa8b70..7746be62d914b 100644 --- a/shell/platform/fuchsia/flutter/tests/integration/BUILD.gn +++ b/shell/platform/fuchsia/flutter/tests/integration/BUILD.gn @@ -8,5 +8,8 @@ import("//build/fuchsia/sdk.gni") group("integration") { testonly = true - deps = [ "embedder:tests" ] + deps = [ + "embedder:tests", + "text-input:tests", + ] } diff --git a/shell/platform/fuchsia/flutter/tests/integration/embedder/BUILD.gn b/shell/platform/fuchsia/flutter/tests/integration/embedder/BUILD.gn index ce295f31107f7..392a271be85ec 100644 --- a/shell/platform/fuchsia/flutter/tests/integration/embedder/BUILD.gn +++ b/shell/platform/fuchsia/flutter/tests/integration/embedder/BUILD.gn @@ -17,11 +17,7 @@ executable("flutter-embedder-test-bin") { output_name = "flutter-embedder-test" - sources = [ - "color.cc", - "color.h", - "flutter-embedder-test.cc", - ] + sources = [ "flutter-embedder-test.cc" ] # This is needed for //third_party/googletest for linking zircon symbols. libs = [ "$fuchsia_sdk_path/arch/$target_cpu/sysroot/lib/libzircon.so" ] @@ -42,6 +38,9 @@ executable("flutter-embedder-test-bin") { "$fuchsia_sdk_root/pkg:sys_component_cpp_testing", "$fuchsia_sdk_root/pkg:zx", "//flutter/fml", + "//flutter/shell/platform/fuchsia/flutter/tests/integration/utils:check_view", + "//flutter/shell/platform/fuchsia/flutter/tests/integration/utils:color", + "//flutter/shell/platform/fuchsia/flutter/tests/integration/utils:screenshot", "//third_party/googletest:gtest", "//third_party/googletest:gtest_main", ] diff --git a/shell/platform/fuchsia/flutter/tests/integration/embedder/child-view/meta/child-view.cml b/shell/platform/fuchsia/flutter/tests/integration/embedder/child-view/meta/child-view.cml index 9e33d6a3effe9..c1aab3a83d063 100644 --- a/shell/platform/fuchsia/flutter/tests/integration/embedder/child-view/meta/child-view.cml +++ b/shell/platform/fuchsia/flutter/tests/integration/embedder/child-view/meta/child-view.cml @@ -1,3 +1,6 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. { include: [ "syslog/client.shard.cml" ], program: { diff --git a/shell/platform/fuchsia/flutter/tests/integration/embedder/flutter-embedder-test.cc b/shell/platform/fuchsia/flutter/tests/integration/embedder/flutter-embedder-test.cc index 73f36e85ede8c..20200e0725c58 100644 --- a/shell/platform/fuchsia/flutter/tests/integration/embedder/flutter-embedder-test.cc +++ b/shell/platform/fuchsia/flutter/tests/integration/embedder/flutter-embedder-test.cc @@ -26,7 +26,9 @@ #include "flutter/fml/logging.h" #include "gtest/gtest.h" -#include "color.h" +#include "flutter/shell/platform/fuchsia/flutter/tests/integration/utils/check_view.h" +#include "flutter/shell/platform/fuchsia/flutter/tests/integration/utils/color.h" +#include "flutter/shell/platform/fuchsia/flutter/tests/integration/utils/screenshot.h" namespace flutter_embedder_test { namespace { @@ -41,6 +43,8 @@ using component_testing::RealmRoot; using component_testing::Route; using component_testing::StartupMode; +using fuchsia_test_utils::CheckViewExistsInUpdates; + // The FIDL bindings for this service are not exposed in the Fuchsia SDK, so we // must encode the name manually here. constexpr auto kVulkanLoaderServiceName = "fuchsia.vulkan.loader.Loader"; @@ -61,7 +65,7 @@ constexpr char kChildViewUrl[] = "fuchsia-pkg://fuchsia.com/child-view#meta/child-view.cm"; constexpr char kParentViewUrl[] = "fuchsia-pkg://fuchsia.com/parent-view#meta/parent-view.cm"; -static constexpr auto kTestUIStackUrl = +static constexpr auto kTestUiStackUrl = "fuchsia-pkg://fuchsia.com/test-ui-stack#meta/test-ui-stack.cm"; constexpr auto kFlutterRunnerEnvironment = "flutter_runner_env"; @@ -77,31 +81,34 @@ constexpr auto kChildView = "child_view"; constexpr auto kChildViewRef = ChildRef{kChildView}; constexpr auto kParentView = "parent_view"; constexpr auto kParentViewRef = ChildRef{kParentView}; -constexpr auto kTestUIStack = "ui"; -constexpr auto kTestUIStackRef = ChildRef{kTestUIStack}; - -constexpr scenic::Color kParentBackgroundColor = {0x00, 0x00, 0xFF, - 0xFF}; // Blue -constexpr scenic::Color kParentTappedColor = {0x00, 0x00, 0x00, 0xFF}; // Black -constexpr scenic::Color kChildBackgroundColor = {0xFF, 0x00, 0xFF, - 0xFF}; // Pink -constexpr scenic::Color kChildTappedColor = {0xFF, 0xFF, 0x00, 0xFF}; // Yellow +constexpr auto kTestUiStack = "ui"; +constexpr auto kTestUiStackRef = ChildRef{kTestUiStack}; + +constexpr fuchsia_test_utils::Color kParentBackgroundColor = {0x00, 0x00, 0xFF, + 0xFF}; // Blue +constexpr fuchsia_test_utils::Color kParentTappedColor = {0x00, 0x00, 0x00, + 0xFF}; // Black +constexpr fuchsia_test_utils::Color kChildBackgroundColor = {0xFF, 0x00, 0xFF, + 0xFF}; // Pink +constexpr fuchsia_test_utils::Color kChildTappedColor = {0xFF, 0xFF, 0x00, + 0xFF}; // Yellow // TODO(fxb/64201): Remove forced opacity colors when Flatland is enabled. -constexpr scenic::Color kOverlayBackgroundColor1 = { +constexpr fuchsia_test_utils::Color kOverlayBackgroundColor1 = { 0x00, 0xFF, 0x0E, 0xFF}; // Green, blended with blue (FEMU local) -constexpr scenic::Color kOverlayBackgroundColor2 = { +constexpr fuchsia_test_utils::Color kOverlayBackgroundColor2 = { 0x0E, 0xFF, 0x0E, 0xFF}; // Green, blended with pink (FEMU local) -constexpr scenic::Color kOverlayBackgroundColor3 = { +constexpr fuchsia_test_utils::Color kOverlayBackgroundColor3 = { 0x00, 0xFF, 0x0D, 0xFF}; // Green, blended with blue (AEMU infra) -constexpr scenic::Color kOverlayBackgroundColor4 = { +constexpr fuchsia_test_utils::Color kOverlayBackgroundColor4 = { 0x0D, 0xFF, 0x0D, 0xFF}; // Green, blended with pink (AEMU infra) -constexpr scenic::Color kOverlayBackgroundColor5 = { +constexpr fuchsia_test_utils::Color kOverlayBackgroundColor5 = { 0x00, 0xFE, 0x0D, 0xFF}; // Green, blended with blue (NUC) -constexpr scenic::Color kOverlayBackgroundColor6 = { +constexpr fuchsia_test_utils::Color kOverlayBackgroundColor6 = { 0x0D, 0xFF, 0x00, 0xFF}; // Green, blended with pink (NUC) -static size_t OverlayPixelCount(std::map& histogram) { +static size_t OverlayPixelCount( + std::map& histogram) { return histogram[kOverlayBackgroundColor1] + histogram[kOverlayBackgroundColor2] + histogram[kOverlayBackgroundColor3] + @@ -115,34 +122,6 @@ constexpr zx::duration kScreenshotTimeout = zx::sec(10); // Timeout to fail the test if it goes beyond this duration. constexpr zx::duration kTestTimeout = zx::min(1); -bool CheckViewExistsInSnapshot( - const fuchsia::ui::observation::geometry::ViewTreeSnapshot& snapshot, - zx_koid_t view_ref_koid) { - if (!snapshot.has_views()) { - return false; - } - - auto snapshot_count = - std::count_if(snapshot.views().begin(), snapshot.views().end(), - [view_ref_koid](const auto& view) { - return view.view_ref_koid() == view_ref_koid; - }); - - return snapshot_count > 0; -} - -bool CheckViewExistsInUpdates( - const std::vector& - updates, - zx_koid_t view_ref_koid) { - auto update_count = std::count_if( - updates.begin(), updates.end(), [view_ref_koid](auto& snapshot) { - return CheckViewExistsInSnapshot(snapshot, view_ref_koid); - }); - - return update_count > 0; -} - } // namespace class FlutterEmbedderTest : public ::loop_fixture::RealLoop, @@ -173,11 +152,12 @@ class FlutterEmbedderTest : public ::loop_fixture::RealLoop, void LaunchParentViewInRealm( const std::vector& component_args = {}); - scenic::Screenshot TakeScreenshot(); + fuchsia_test_utils::Screenshot TakeScreenshot(); bool TakeScreenshotUntil( - scenic::Color color, - fit::function)> callback = nullptr, + fuchsia_test_utils::Color color, + fit::function)> + callback = nullptr, zx::duration timeout = kTestTimeout); // Simulates a tap at location (x, y). @@ -291,7 +271,7 @@ void FlutterEmbedderTest::SetUpRealmBase() { realm_builder_.ReplaceRealmDecl(std::move(realm_decl)); // Add test UI stack component. - realm_builder_.AddChild(kTestUIStack, kTestUIStackUrl); + realm_builder_.AddChild(kTestUiStack, kTestUiStackUrl); // Add embedded parent and child components. realm_builder_.AddChild(kChildView, kChildViewUrl, @@ -323,13 +303,13 @@ void FlutterEmbedderTest::SetUpRealmBase() { Protocol{fuchsia::tracing::provider::Registry::Name_}, Protocol{kVulkanLoaderServiceName}}, .source = ParentRef{}, - .targets = {kTestUIStackRef}}); + .targets = {kTestUiStackRef}}); // Route UI capabilities from test UI stack to flutter runners. realm_builder_.AddRoute(Route{ .capabilities = {Protocol{fuchsia::ui::composition::Flatland::Name_}, Protocol{fuchsia::ui::scenic::Scenic::Name_}}, - .source = kTestUIStackRef, + .source = kTestUiStackRef, .targets = {kFlutterJitRunnerRef, kFlutterJitProductRunnerRef, kFlutterAotRunnerRef, kFlutterAotProductRunnerRef}}); @@ -338,7 +318,7 @@ void FlutterEmbedderTest::SetUpRealmBase() { .capabilities = {Protocol{fuchsia::ui::test::input::Registry::Name_}, Protocol{fuchsia::ui::test::scene::Controller::Name_}, Protocol{fuchsia::ui::scenic::Scenic::Name_}}, - .source = kTestUIStackRef, + .source = kTestUiStackRef, .targets = {ParentRef{}}}); // Route ViewProvider from child to parent, and parent to test. @@ -428,7 +408,7 @@ void FlutterEmbedderTest::LaunchParentViewInRealm( FML_LOG(INFO) << "Launched parent-view"; } -scenic::Screenshot FlutterEmbedderTest::TakeScreenshot() { +fuchsia_test_utils::Screenshot FlutterEmbedderTest::TakeScreenshot() { FML_LOG(INFO) << "Taking screenshot... "; fuchsia::ui::scenic::ScreenshotData screenshot_out; scenic_->TakeScreenshot( @@ -442,12 +422,12 @@ scenic::Screenshot FlutterEmbedderTest::TakeScreenshot() { << "Timed out waiting for screenshot."; FML_LOG(INFO) << "Screenshot captured."; - return scenic::Screenshot(screenshot_out); + return fuchsia_test_utils::Screenshot(screenshot_out); } bool FlutterEmbedderTest::TakeScreenshotUntil( - scenic::Color color, - fit::function)> callback, + fuchsia_test_utils::Color color, + fit::function)> callback, zx::duration timeout) { return RunLoopWithTimeoutOrUntil( [this, &callback, &color] { @@ -498,7 +478,8 @@ TEST_F(FlutterEmbedderTest, Embedding) { // Take screenshot until we see the child-view's embedded color. ASSERT_TRUE(TakeScreenshotUntil( - kChildBackgroundColor, [](std::map histogram) { + kChildBackgroundColor, + [](std::map histogram) { // Expect parent and child background colors, with parent color > child // color. EXPECT_GT(histogram[kParentBackgroundColor], 0u); @@ -519,7 +500,8 @@ TEST_F(FlutterEmbedderTest, HittestEmbedding) { // Take screenshot until we see the child-view's tapped color. ASSERT_TRUE(TakeScreenshotUntil( - kChildTappedColor, [](std::map histogram) { + kChildTappedColor, + [](std::map histogram) { // Expect parent and child background colors, with parent color > child // color. EXPECT_GT(histogram[kParentBackgroundColor], 0u); @@ -541,7 +523,8 @@ TEST_F(FlutterEmbedderTest, HittestDisabledEmbedding) { // The parent-view should change color. ASSERT_TRUE(TakeScreenshotUntil( - kParentTappedColor, [](std::map histogram) { + kParentTappedColor, + [](std::map histogram) { // Expect parent and child background colors, with parent color > child // color. EXPECT_EQ(histogram[kParentBackgroundColor], 0u); @@ -558,7 +541,8 @@ TEST_F(FlutterEmbedderTest, EmbeddingWithOverlay) { // Take screenshot until we see the child-view's embedded color. ASSERT_TRUE(TakeScreenshotUntil( - kChildBackgroundColor, [](std::map histogram) { + kChildBackgroundColor, + [](std::map histogram) { // Expect parent, overlay and child background colors. // With parent color > child color and overlay color > child color. const size_t overlay_pixel_count = OverlayPixelCount(histogram); @@ -585,7 +569,8 @@ TEST_F(FlutterEmbedderTest, HittestEmbeddingWithOverlay) { // Take screenshot until we see the child-view's tapped color. ASSERT_TRUE(TakeScreenshotUntil( - kChildTappedColor, [](std::map histogram) { + kChildTappedColor, + [](std::map histogram) { // Expect parent, overlay and child background colors. // With parent color > child color and overlay color > child color. const size_t overlay_pixel_count = OverlayPixelCount(histogram); diff --git a/shell/platform/fuchsia/flutter/tests/integration/embedder/meta/flutter-embedder-test.cml b/shell/platform/fuchsia/flutter/tests/integration/embedder/meta/flutter-embedder-test.cml index b053b0a4cc24a..9bf50e3de8166 100644 --- a/shell/platform/fuchsia/flutter/tests/integration/embedder/meta/flutter-embedder-test.cml +++ b/shell/platform/fuchsia/flutter/tests/integration/embedder/meta/flutter-embedder-test.cml @@ -1,3 +1,6 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. { include: [ "gtest_runner.shard.cml", diff --git a/shell/platform/fuchsia/flutter/tests/integration/embedder/meta/gtest_runner.shard.cml b/shell/platform/fuchsia/flutter/tests/integration/embedder/meta/gtest_runner.shard.cml index 4593cf2c66ad3..d9871b70f3022 100644 --- a/shell/platform/fuchsia/flutter/tests/integration/embedder/meta/gtest_runner.shard.cml +++ b/shell/platform/fuchsia/flutter/tests/integration/embedder/meta/gtest_runner.shard.cml @@ -1,3 +1,6 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. { program: { runner: "gtest_runner", diff --git a/shell/platform/fuchsia/flutter/tests/integration/embedder/parent-view/meta/parent-view.cml b/shell/platform/fuchsia/flutter/tests/integration/embedder/parent-view/meta/parent-view.cml index aea9b8bc24dab..3eda9427a29c9 100644 --- a/shell/platform/fuchsia/flutter/tests/integration/embedder/parent-view/meta/parent-view.cml +++ b/shell/platform/fuchsia/flutter/tests/integration/embedder/parent-view/meta/parent-view.cml @@ -1,3 +1,6 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. { include: [ "syslog/client.shard.cml" ], program: { diff --git a/shell/platform/fuchsia/flutter/tests/integration/text-input/BUILD.gn b/shell/platform/fuchsia/flutter/tests/integration/text-input/BUILD.gn new file mode 100644 index 0000000000000..9fb5acaebaecd --- /dev/null +++ b/shell/platform/fuchsia/flutter/tests/integration/text-input/BUILD.gn @@ -0,0 +1,66 @@ +# Copyright 2013 The Flutter Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +assert(is_fuchsia) + +import("//build/fuchsia/sdk.gni") +import("//flutter/tools/fuchsia/fuchsia_archive.gni") +import("//flutter/tools/fuchsia/gn-sdk/package.gni") + +group("tests") { + testonly = true + deps = [ ":text-input-test" ] +} + +executable("text-input-test-bin") { + testonly = true + + output_name = "text-input-test" + + sources = [ "text-input-test.cc" ] + + # This is needed for //third_party/googletest for linking zircon symbols. + libs = [ "$fuchsia_sdk_path/arch/$target_cpu/sysroot/lib/libzircon.so" ] + + deps = [ + "$fuchsia_sdk_root/fidl:fuchsia.feedback", + "$fuchsia_sdk_root/fidl:fuchsia.logger", + "$fuchsia_sdk_root/fidl:fuchsia.sys", + "$fuchsia_sdk_root/fidl:fuchsia.tracing.provider", + "$fuchsia_sdk_root/fidl:fuchsia.ui.app", + "$fuchsia_sdk_root/fidl:fuchsia.ui.composition", + "$fuchsia_sdk_root/fidl:fuchsia.ui.input", + "$fuchsia_sdk_root/fidl:fuchsia.ui.scenic", + "$fuchsia_sdk_root/fidl:fuchsia.ui.test.input", + "$fuchsia_sdk_root/fidl:fuchsia.ui.test.scene", + "$fuchsia_sdk_root/pkg:async", + "$fuchsia_sdk_root/pkg:async-loop-testing", + "$fuchsia_sdk_root/pkg:fidl_cpp", + "$fuchsia_sdk_root/pkg:scenic_cpp", + "$fuchsia_sdk_root/pkg:sys_component_cpp_testing", + "$fuchsia_sdk_root/pkg:zx", + "//flutter/fml", + "//flutter/shell/platform/fuchsia/flutter/tests/integration/utils:check_view", + "//flutter/shell/platform/fuchsia/flutter/tests/integration/utils:color", + "//flutter/shell/platform/fuchsia/flutter/tests/integration/utils:screenshot", + "//third_party/googletest:gtest", + "//third_party/googletest:gtest_main", + ] +} + +fuchsia_test_archive("text-input-test") { + deps = [ + ":text-input-test-bin", + "text-input-view:package", + + # "OOT" copies of the runners used by tests, to avoid conflicting with the + # runners in the base fuchsia image. + # TODO(fxbug.dev/106575): Fix this with subpackages. + "//flutter/shell/platform/fuchsia/flutter:oot_flutter_jit_runner", + ] + + binary = "$target_name" + + cml_file = rebase_path("meta/$target_name.cml") +} diff --git a/shell/platform/fuchsia/flutter/tests/integration/text-input/meta/gtest_runner.shard.cml b/shell/platform/fuchsia/flutter/tests/integration/text-input/meta/gtest_runner.shard.cml new file mode 100644 index 0000000000000..d9871b70f3022 --- /dev/null +++ b/shell/platform/fuchsia/flutter/tests/integration/text-input/meta/gtest_runner.shard.cml @@ -0,0 +1,17 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +{ + program: { + runner: "gtest_runner", + }, + capabilities: [ + { protocol: "fuchsia.test.Suite" }, + ], + expose: [ + { + protocol: "fuchsia.test.Suite", + from: "self", + }, + ], +} diff --git a/shell/platform/fuchsia/flutter/tests/integration/text-input/meta/text-input-test.cml b/shell/platform/fuchsia/flutter/tests/integration/text-input/meta/text-input-test.cml new file mode 100644 index 0000000000000..faab9ced7a451 --- /dev/null +++ b/shell/platform/fuchsia/flutter/tests/integration/text-input/meta/text-input-test.cml @@ -0,0 +1,42 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +{ + include: [ + "gtest_runner.shard.cml", + "sys/component/realm_builder_absolute.shard.cml", + + "syslog/client.shard.cml", + "vulkan/client.shard.cml", + + // This test needs both the vulkan facet and the hermetic-tier-2 facet, + // so we are forced to make it a system test. + "sys/testing/system-test.shard.cml", + + ], + program: { + binary: "bin/app", + }, + use: [ + { protocol: "fuchsia.sys2.EventSource" }, + { + event: "stopped", + from: "framework", + }, + ], + offer: [ + { + protocol: [ + "fuchsia.kernel.RootJobForInspect", + "fuchsia.kernel.Stats", + "fuchsia.logger.LogSink", + "fuchsia.scheduler.ProfileProvider", + "fuchsia.sysmem.Allocator", + "fuchsia.tracing.provider.Registry", + "fuchsia.vulkan.loader.Loader", + ], + from: "parent", + to: "#realm_builder", + }, + ], +} diff --git a/shell/platform/fuchsia/flutter/tests/integration/text-input/text-input-test.cc b/shell/platform/fuchsia/flutter/tests/integration/text-input/text-input-test.cc new file mode 100644 index 0000000000000..5718a9e43c622 --- /dev/null +++ b/shell/platform/fuchsia/flutter/tests/integration/text-input/text-input-test.cc @@ -0,0 +1,303 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "flutter/fml/logging.h" +#include "flutter/shell/platform/fuchsia/flutter/tests/integration/utils/check_view.h" + +namespace { + +// Types imported for the realm_builder library. +using component_testing::ChildRef; +using component_testing::LocalComponent; +using component_testing::LocalComponentHandles; +using component_testing::ParentRef; +using component_testing::Protocol; +using component_testing::RealmBuilder; +using component_testing::RealmRoot; +using component_testing::Route; + +using fuchsia_test_utils::CheckViewExistsInUpdates; + +/// Max timeout in failure cases. +/// Set this as low as you can that still works across all test platforms. +constexpr zx::duration kTimeout = zx::min(5); + +// The FIDL bindings for these services are not exposed in the Fuchsia SDK so we +// must encode the names manually here. +constexpr auto kVulkanLoaderServiceName = "fuchsia.vulkan.loader.Loader"; +constexpr auto kProfileProviderServiceName = "fuchsia.sheduler.ProfileProvider"; + +constexpr auto kResponseListener = "test_text_response_listener"; +constexpr auto kTextInputView = "text-input-view"; +static constexpr auto kTextInputViewUrl = + "fuchsia-pkg://fuchsia.com/view#meta/view-realm.cm"; + +constexpr auto kTestUiStack = "ui"; +constexpr auto kTestUiStackUrl = + "fuchsia-pkg://fuchsia.com/test-ui-stack#meta/test-ui-stack.cm"; + +/// |ResponseListener| is a local test protocol that our test Flutter app uses +/// to let us know what text is being entered into its only text field. +/// +/// The text field contents are reported on almost every change, so if you are +/// entering a long text, you will see calls corresponding to successive +/// additions of characters, not just the end result. +class TestResponseListenerServer + : public fuchsia::ui::test::input::KeyboardInputListener, + public LocalComponent { + public: + explicit TestResponseListenerServer(async_dispatcher_t* dispatcher) + : dispatcher_(dispatcher) {} + + TestResponseListenerServer(const TestResponseListenerServer&) = delete; + TestResponseListenerServer& operator=(const TestResponseListenerServer&) = + delete; + + // |fuchsia::ui::test::input::KeyboardInputListener| + void ReportTextInput( + fuchsia::ui::test::input::KeyboardInputListenerReportTextInputRequest + request) override { + FML_LOG(INFO) << "Flutter app sent: '" << request.text() << "'"; + response_ = request.text(); + } + + /// Starts this server. + void Start(std::unique_ptr handles) override { + handles_ = std::move(handles); + + ASSERT_EQ(ZX_OK, handles_->outgoing()->AddPublicService( + bindings_.GetHandler(this, dispatcher_))); + } + + /// Returns true if the last response received matches `expected`. If a match + /// is found, the match is consumed, so a next call to HasResponse starts from + /// scratch. + bool HasResponse(const std::string& expected) { + bool match = response_.has_value() && response_.value() == expected; + if (match) { + response_ = std::nullopt; + } + return match; + } + + private: + // Not owned. + async_dispatcher_t* dispatcher_ = nullptr; + fidl::BindingSet bindings_; + std::unique_ptr handles_; + std::optional response_; +}; + +class TextInputTest : public ::loop_fixture::RealLoop, public ::testing::Test { + protected: + TextInputTest() + : test_response_listener_( + std::make_unique(dispatcher())) {} + + bool HasViewConnected( + const fuchsia::ui::observation::geometry::ViewTreeWatcherPtr& + view_tree_watcher, + std::optional& + watch_response, + zx_koid_t view_ref_koid) { + std::optional + watch_result; + view_tree_watcher->Watch( + [&watch_result](auto response) { watch_result = std::move(response); }); + FML_LOG(INFO) << "Waiting for view tree watch result"; + RunLoopUntil([&watch_result] { return watch_result.has_value(); }); + FML_LOG(INFO) << "Received for view tree watch result"; + if (CheckViewExistsInUpdates(watch_result->updates(), view_ref_koid)) { + watch_response = std::move(watch_result); + }; + return watch_response.has_value(); + } + + void RegisterKeyboard() { + FML_LOG(INFO) << "Registering fake keyboard"; + input_registry_ = + realm_root_->Connect(); + input_registry_.set_error_handler( + [](auto) { FML_LOG(ERROR) << "Error from input helper"; }); + bool keyboard_registered = false; + fuchsia::ui::test::input::RegistryRegisterKeyboardRequest request; + request.set_device(fake_keyboard_.NewRequest()); + input_registry_->RegisterKeyboard( + std::move(request), + [&keyboard_registered]() { keyboard_registered = true; }); + RunLoopUntil([&keyboard_registered] { return keyboard_registered; }); + FML_LOG(INFO) << "Keyboard registered"; + } + + void InitializeScene() { + // Instruct Scene Manager to present test's View. + std::optional view_ref_koid; + scene_provider_ = + realm_root_->Connect(); + scene_provider_.set_error_handler( + [](auto) { FML_LOG(ERROR) << "Error from test scene provider"; }); + fuchsia::ui::test::scene::ControllerAttachClientViewRequest request; + request.set_view_provider( + realm_root_->Connect()); + scene_provider_->RegisterViewTreeWatcher(view_tree_watcher_.NewRequest(), + []() {}); + scene_provider_->AttachClientView( + std::move(request), [&view_ref_koid](auto client_view_ref_koid) { + view_ref_koid = client_view_ref_koid; + }); + + FML_LOG(INFO) << "Waiting for client view ref koid"; + RunLoopUntil([&view_ref_koid] { return view_ref_koid.has_value(); }); + + // Wait for the client view to get attached to the view tree. + std::optional + watch_response; + FML_LOG(INFO) << "Waiting for client view to render"; + RunLoopUntil([this, &watch_response, &view_ref_koid] { + return HasViewConnected(view_tree_watcher_, watch_response, + *view_ref_koid); + }); + FML_LOG(INFO) << "Client view has rendered"; + } + + void BuildRealm() { + FML_LOG(INFO) << "Building realm"; + realm_builder_.AddChild(kTestUiStack, kTestUiStackUrl); + realm_builder_.AddLocalChild(kResponseListener, + test_response_listener_.get()); + realm_builder_.AddChild(kTextInputView, kTextInputViewUrl); + + // Route base system services to the view and the test UI stack. + realm_builder_.AddRoute(Route{ + .capabilities = {Protocol{fuchsia::logger::LogSink::Name_}, + Protocol{fuchsia::sys::Environment::Name_}, + Protocol{fuchsia::sysmem::Allocator::Name_}, + Protocol{fuchsia::tracing::provider::Registry::Name_}, + Protocol{kVulkanLoaderServiceName}, + Protocol{kProfileProviderServiceName}}, + .source = ParentRef{}, + .targets = {ChildRef{kTestUiStack}, ChildRef{kTextInputView}}}); + + // Expose fuchsia.ui.app.ViewProvider from the flutter app. + realm_builder_.AddRoute( + Route{.capabilities = {Protocol{fuchsia::ui::app::ViewProvider::Name_}}, + .source = ChildRef{kTextInputView}, + .targets = {ParentRef()}}); + + // Route UI capabilities from test-ui-stack to the flutter app. + realm_builder_.AddRoute(Route{ + .capabilities = {Protocol{fuchsia::ui::composition::Flatland::Name_}, + Protocol{fuchsia::ui::composition::Allocator::Name_}, + Protocol{fuchsia::ui::input::ImeService::Name_}, + Protocol{fuchsia::ui::input3::Keyboard::Name_}, + Protocol{fuchsia::ui::scenic::Scenic::Name_}}, + .source = ChildRef{kTestUiStack}, + .targets = {ChildRef{kTextInputView}}}); + + // Route UI helpers to test driver. + realm_builder_.AddRoute(Route{ + .capabilities = {Protocol{fuchsia::ui::test::input::Registry::Name_}, + Protocol{fuchsia::ui::test::scene::Controller::Name_}}, + .source = ChildRef{kTestUiStack}, + .targets = {ParentRef{}}}); + + // Route crash reporter service to flutter app. + realm_builder_.AddRoute( + {.capabilities = + { + Protocol{fuchsia::feedback::CrashReporter::Name_}, + }, + .source = ParentRef(), + .targets = {ChildRef{kTextInputView}}}); + + // Route text listener from the flutter app to the response listener. + realm_builder_.AddRoute(Route{ + .capabilities = + { + Protocol{ + fuchsia::ui::test::input::KeyboardInputListener::Name_}, + }, + .source = ChildRef{kResponseListener}, + .targets = {ChildRef{kTextInputView}}}); + + realm_root_ = std::make_unique(realm_builder_.Build()); + } + + void SetUp() override { + // Post a "just in case" quit task, if the test hangs. + async::PostDelayedTask( + dispatcher(), + [] { + FML_LOG(FATAL) + << "\n\n>> Test did not complete in time, terminating. <<\n\n"; + }, + kTimeout); + + BuildRealm(); + + RegisterKeyboard(); + + InitializeScene(); + } + + std::unique_ptr test_response_listener_; + + fuchsia::ui::test::input::RegistryPtr input_registry_; + fuchsia::ui::test::input::KeyboardPtr fake_keyboard_; + fuchsia::ui::test::scene::ControllerPtr scene_provider_; + fuchsia::ui::observation::geometry::ViewTreeWatcherPtr view_tree_watcher_; + + RealmBuilder realm_builder_ = RealmBuilder::Create(); + std::unique_ptr realm_root_; +}; + +TEST_F(TextInputTest, FlutterTextFieldEntry) { + FML_LOG(INFO) << "Wait for the initial text response"; + RunLoopUntil([&] { return test_response_listener_->HasResponse(""); }); + + FML_LOG(INFO) << "Sending a text message"; + bool done = false; + fuchsia::ui::test::input::KeyboardSimulateUsAsciiTextEntryRequest request; + request.set_text("Hello\nworld!"); + fake_keyboard_->SimulateUsAsciiTextEntry(std::move(request), + [&done]() { done = true; }); + RunLoopUntil([&] { return done; }); + FML_LOG(INFO) << "Message was sent"; + + RunLoopUntil( + [&] { return test_response_listener_->HasResponse("Hello\nworld!"); }); +} + +} // namespace diff --git a/shell/platform/fuchsia/flutter/tests/integration/text-input/text-input-view/BUILD.gn b/shell/platform/fuchsia/flutter/tests/integration/text-input/text-input-view/BUILD.gn new file mode 100644 index 0000000000000..24219ea200dfd --- /dev/null +++ b/shell/platform/fuchsia/flutter/tests/integration/text-input/text-input-view/BUILD.gn @@ -0,0 +1,46 @@ +# Copyright 2013 The Flutter Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import("//build/fuchsia/sdk.gni") +import("//flutter/tools/fuchsia/dart/dart_library.gni") +import("//flutter/tools/fuchsia/flutter/flutter_component.gni") +import("//flutter/tools/fuchsia/gn-sdk/component.gni") +import("//flutter/tools/fuchsia/gn-sdk/package.gni") + +dart_library("lib") { + testonly = true + package_name = "text-input-view" + sources = [ "text_input_view.dart" ] + deps = [ + "//flutter/shell/platform/fuchsia/dart:args", + "//flutter/tools/fuchsia/dart:fuchsia_services", + "//flutter/tools/fuchsia/dart:zircon", + "//flutter/tools/fuchsia/fidl:fuchsia.ui.test.input", + ] +} + +flutter_component("component") { + testonly = true + component_name = "text-input-view" + manifest = rebase_path("meta/text-input-view.cml") + main_package = "text-input-view" + main_dart = "text_input_view.dart" + deps = [ ":lib" ] +} + +fuchsia_component("realm") { + testonly = true + manifest = "meta/text-input-view-realm.cml" + manifest_output_name = "text-input-view-realm.cm" + deps = [ ":component" ] +} + +fuchsia_package("package") { + testonly = true + package_name = "text-input-view" + deps = [ + ":component", + ":realm", + ] +} diff --git a/shell/platform/fuchsia/flutter/tests/integration/text-input/text-input-view/lib/text_input_view.dart b/shell/platform/fuchsia/flutter/tests/integration/text-input/text-input-view/lib/text_input_view.dart new file mode 100644 index 0000000000000..6df6b22f8beb0 --- /dev/null +++ b/shell/platform/fuchsia/flutter/tests/integration/text-input/text-input-view/lib/text_input_view.dart @@ -0,0 +1,24 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// TODO(https://fxbug.dev/84961): Fix null safety and remove this language version. +// @dart=2.9 + +// This is an instrumented test application. It has a single field, is +// able to receive keyboard input from the test fixture, and is able to report +// back the contents of its text field to the test fixture. + +import 'dart:convert'; +import 'dart:typed_data'; +import 'dart:io'; +import 'dart:ui'; + +import 'package:fidl_fuchsia_ui_test_input/fidl_async.dart' as test_text; +import 'package:fuchsia_services/services.dart'; + +int main() { + // TODO(https://fxbug.dev/107917): Port https://cs.opensource.google/fuchsia/fuchsia/+/main:src/ui/tests/integration_input_tests/text-input/text-input-flutter/lib/text-input-flutter.dart + // to dart:ui. + print('text-input-view: starting'); +} diff --git a/shell/platform/fuchsia/flutter/tests/integration/text-input/text-input-view/meta/text-input-view-realm.cml b/shell/platform/fuchsia/flutter/tests/integration/text-input/text-input-view/meta/text-input-view-realm.cml new file mode 100644 index 0000000000000..d95699769dcd0 --- /dev/null +++ b/shell/platform/fuchsia/flutter/tests/integration/text-input/text-input-view/meta/text-input-view-realm.cml @@ -0,0 +1,62 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +{ + children: [ + { + name: "flutter_jit_runner", + url: "fuchsia-pkg://fuchsia.com/flutter_jit_runner#meta/flutter_jit_runner.cm", + }, + { + name: "text_input_view", + url: "#meta/text-input-view.cm", + environment: "#text_input_view_env", + }, + ], + offer: [ + { + protocol: [ + "fuchsia.logger.LogSink", + "fuchsia.memorypressure.Provider", + "fuchsia.posix.socket.Provider", + "fuchsia.sysmem.Allocator", + "fuchsia.tracing.provider.Registry", + "fuchsia.ui.composition.Allocator", + "fuchsia.ui.composition.Flatland", + "fuchsia.ui.input.ImeService", + "fuchsia.ui.input3.Keyboard", + "fuchsia.ui.scenic.Scenic", + "fuchsia.vulkan.loader.Loader", + ], + from: "parent", + to: [ + "#flutter_jit_runner", + "#text_input_view", + ], + }, + { + protocol: [ "fuchsia.ui.test.input.KeyboardInputListener" ], + from: "parent", + to: "#text_input_view", + }, + ], + expose: [ + { + protocol: [ "fuchsia.ui.app.ViewProvider" ], + from: "#text_input_view", + to: "parent", + }, + ], + environments: [ + { + name: "text_input_view_env", + extends: "realm", + runners: [ + { + runner: "flutter_jit_runner", + from: "#flutter_jit_runner", + }, + ], + }, + ], +} diff --git a/shell/platform/fuchsia/flutter/tests/integration/text-input/text-input-view/meta/text-input-view.cml b/shell/platform/fuchsia/flutter/tests/integration/text-input/text-input-view/meta/text-input-view.cml new file mode 100644 index 0000000000000..471f1c1c569b5 --- /dev/null +++ b/shell/platform/fuchsia/flutter/tests/integration/text-input/text-input-view/meta/text-input-view.cml @@ -0,0 +1,38 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +{ + include: [ "syslog/client.shard.cml" ], + program: { + data: "data/text_input_view", + + // Always use the jit runner for now. + // TODO(fxbug.dev/106577): Implement manifest merging build rules for V2 components. + runner: "flutter_jit_runner", + }, + capabilities: [ + { + protocol: [ "fuchsia.ui.app.ViewProvider" ], + }, + ], + use: [ + { + protocol: [ + "fuchsia.logger.LogSink", + "fuchsia.sysmem.Allocator", + "fuchsia.tracing.provider.Registry", + "fuchsia.ui.input.ImeService", + "fuchsia.ui.input3.Keyboard", + "fuchsia.ui.scenic.Scenic", + "fuchsia.ui.test.input.KeyboardInputListener", + "fuchsia.vulkan.loader.Loader", + ], + }, + ], + expose: [ + { + protocol: [ "fuchsia.ui.app.ViewProvider" ], + from: "self", + }, + ], +} diff --git a/shell/platform/fuchsia/flutter/tests/integration/text-input/text-input-view/pubspec.yaml b/shell/platform/fuchsia/flutter/tests/integration/text-input/text-input-view/pubspec.yaml new file mode 100644 index 0000000000000..5031e08688398 --- /dev/null +++ b/shell/platform/fuchsia/flutter/tests/integration/text-input/text-input-view/pubspec.yaml @@ -0,0 +1,8 @@ +# Copyright 2013 The Flutter Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +name: text-input-view + +environment: + sdk: '>=2.12.0 <3.0.0' diff --git a/shell/platform/fuchsia/flutter/tests/integration/utils/BUILD.gn b/shell/platform/fuchsia/flutter/tests/integration/utils/BUILD.gn new file mode 100644 index 0000000000000..78b693d2edc04 --- /dev/null +++ b/shell/platform/fuchsia/flutter/tests/integration/utils/BUILD.gn @@ -0,0 +1,42 @@ +# Copyright 2013 The Flutter Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +assert(is_fuchsia) + +import("//build/fuchsia/sdk.gni") + +source_set("check_view") { + sources = [ + "check_view.cc", + "check_view.h", + ] + + deps = [ + "$fuchsia_sdk_root/fidl:fuchsia.ui.observation.geometry", + "$fuchsia_sdk_root/pkg:zx", + "//flutter/fml", + ] +} + +source_set("color") { + sources = [ + "color.cc", + "color.h", + ] +} + +source_set("screenshot") { + sources = [ + "screenshot.cc", + "screenshot.h", + ] + + deps = [ + ":color", + "$fuchsia_sdk_root/fidl:fuchsia.logger", + "$fuchsia_sdk_root/fidl:fuchsia.ui.scenic", + "$fuchsia_sdk_root/pkg:zx", + "//flutter/fml", + ] +} diff --git a/shell/platform/fuchsia/flutter/tests/integration/utils/check_view.cc b/shell/platform/fuchsia/flutter/tests/integration/utils/check_view.cc new file mode 100644 index 0000000000000..6b35f1e831bd6 --- /dev/null +++ b/shell/platform/fuchsia/flutter/tests/integration/utils/check_view.cc @@ -0,0 +1,39 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "check_view.h" + +#include "flutter/fml/logging.h" + +namespace fuchsia_test_utils { + +bool CheckViewExistsInSnapshot( + const fuchsia::ui::observation::geometry::ViewTreeSnapshot& snapshot, + zx_koid_t view_ref_koid) { + if (!snapshot.has_views()) { + return false; + } + + auto snapshot_count = + std::count_if(snapshot.views().begin(), snapshot.views().end(), + [view_ref_koid](const auto& view) { + return view.view_ref_koid() == view_ref_koid; + }); + + return snapshot_count > 0; +} + +bool CheckViewExistsInUpdates( + const std::vector& + updates, + zx_koid_t view_ref_koid) { + auto update_count = std::count_if( + updates.begin(), updates.end(), [view_ref_koid](auto& snapshot) { + return CheckViewExistsInSnapshot(snapshot, view_ref_koid); + }); + + return update_count > 0; +} + +} // namespace fuchsia_test_utils diff --git a/shell/platform/fuchsia/flutter/tests/integration/utils/check_view.h b/shell/platform/fuchsia/flutter/tests/integration/utils/check_view.h new file mode 100644 index 0000000000000..662de84d59f3c --- /dev/null +++ b/shell/platform/fuchsia/flutter/tests/integration/utils/check_view.h @@ -0,0 +1,30 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_SHELL_PLATFORM_FUCHSIA_FLUTTER_TESTS_INTEGRATION_UTILS_CHECK_VIEW_H_ +#define FLUTTER_SHELL_PLATFORM_FUCHSIA_FLUTTER_TESTS_INTEGRATION_UTILS_CHECK_VIEW_H_ + +#include + +#include +#include + +namespace fuchsia_test_utils { + +/// Returns true if a view with the given |view_ref_koid| exists in a |snapshot| +/// of the view tree, false otherwise. +bool CheckViewExistsInSnapshot( + const fuchsia::ui::observation::geometry::ViewTreeSnapshot& snapshot, + zx_koid_t view_ref_koid); + +/// Returns true if any of the snapshots of the view tree in |updates| contain a +/// view with the given |view_ref_koid|, false otherwise. +bool CheckViewExistsInUpdates( + const std::vector& + updates, + zx_koid_t view_ref_koid); + +} // namespace fuchsia_test_utils + +#endif // FLUTTER_SHELL_PLATFORM_FUCHSIA_FLUTTER_TESTS_INTEGRATION_UTILS_CHECK_VIEW_H_ diff --git a/shell/platform/fuchsia/flutter/tests/integration/utils/color.cc b/shell/platform/fuchsia/flutter/tests/integration/utils/color.cc new file mode 100644 index 0000000000000..818c4c8cc6419 --- /dev/null +++ b/shell/platform/fuchsia/flutter/tests/integration/utils/color.cc @@ -0,0 +1,17 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "color.h" + +namespace fuchsia_test_utils { + +// RGBA hex dump +std::ostream& operator<<(std::ostream& os, const Color& c) { + char rgba[9] = {}; + snprintf(rgba, (sizeof(rgba) / sizeof(char)), "%02X%02X%02X%02X", c.r, c.g, + c.b, c.a); + return os << rgba; +} + +} // namespace fuchsia_test_utils diff --git a/shell/platform/fuchsia/flutter/tests/integration/utils/color.h b/shell/platform/fuchsia/flutter/tests/integration/utils/color.h new file mode 100644 index 0000000000000..4cb1c328fe42e --- /dev/null +++ b/shell/platform/fuchsia/flutter/tests/integration/utils/color.h @@ -0,0 +1,38 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_SHELL_PLATFORM_FUCHSIA_FLUTTER_TESTS_INTEGRATION_UTILS_COLOR_H_ +#define FLUTTER_SHELL_PLATFORM_FUCHSIA_FLUTTER_TESTS_INTEGRATION_UTILS_COLOR_H_ + +#include +#include +#include + +namespace fuchsia_test_utils { + +struct Color { + // Constructor is idiomatic RGBA, but memory layout is native BGRA. + constexpr Color(uint8_t r, uint8_t g, uint8_t b, uint8_t a) + : b(b), g(g), r(r), a(a) {} + + uint8_t b; + uint8_t g; + uint8_t r; + uint8_t a; +}; + +inline bool operator==(const Color& a, const Color& b) { + return a.r == b.r && a.g == b.g && a.b == b.b && a.a == b.a; +} + +inline bool operator<(const Color& a, const Color& b) { + return std::tie(a.r, a.g, a.b, a.a) < std::tie(b.r, b.g, b.b, b.a); +} + +// RGBA hex dump. Note that this differs from the internal BGRA memory layout. +std::ostream& operator<<(std::ostream& os, const Color& c); + +} // namespace fuchsia_test_utils + +#endif // FLUTTER_SHELL_PLATFORM_FUCHSIA_FLUTTER_TESTS_INTEGRATION_UTILS_COLOR_H_ diff --git a/shell/platform/fuchsia/flutter/tests/integration/embedder/color.cc b/shell/platform/fuchsia/flutter/tests/integration/utils/screenshot.cc similarity index 86% rename from shell/platform/fuchsia/flutter/tests/integration/embedder/color.cc rename to shell/platform/fuchsia/flutter/tests/integration/utils/screenshot.cc index 24fd675375247..e3abfb64767e7 100644 --- a/shell/platform/fuchsia/flutter/tests/integration/embedder/color.cc +++ b/shell/platform/fuchsia/flutter/tests/integration/utils/screenshot.cc @@ -2,21 +2,13 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "color.h" +#include "screenshot.h" #include #include "flutter/fml/logging.h" -namespace scenic { - -// RGBA hex dump -std::ostream& operator<<(std::ostream& os, const Color& c) { - char rgba[9] = {}; - snprintf(rgba, (sizeof(rgba) / sizeof(char)), "%02X%02X%02X%02X", c.r, c.g, - c.b, c.a); - return os << rgba; -} +namespace fuchsia_test_utils { Screenshot::Screenshot( const fuchsia::ui::scenic::ScreenshotData& screenshot_data) @@ -75,4 +67,4 @@ std::map Screenshot::Histogram() const { return histogram; } -} // namespace scenic +} // namespace fuchsia_test_utils diff --git a/shell/platform/fuchsia/flutter/tests/integration/embedder/color.h b/shell/platform/fuchsia/flutter/tests/integration/utils/screenshot.h similarity index 68% rename from shell/platform/fuchsia/flutter/tests/integration/embedder/color.h rename to shell/platform/fuchsia/flutter/tests/integration/utils/screenshot.h index a2a297e5d268e..f2090eb7a4e89 100644 --- a/shell/platform/fuchsia/flutter/tests/integration/embedder/color.h +++ b/shell/platform/fuchsia/flutter/tests/integration/utils/screenshot.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef SRC_UI_TESTING_VIEWS_COLOR_H_ -#define SRC_UI_TESTING_VIEWS_COLOR_H_ +#ifndef FLUTTER_SHELL_PLATFORM_FUCHSIA_FLUTTER_TESTS_INTEGRATION_UTILS_SCREENSHOT_H_ +#define FLUTTER_SHELL_PLATFORM_FUCHSIA_FLUTTER_TESTS_INTEGRATION_UTILS_SCREENSHOT_H_ #include @@ -11,30 +11,11 @@ #include #include -namespace scenic { +#include "color.h" -struct Color { - // Constructor is idiomatic RGBA, but memory layout is native BGRA. - constexpr Color(uint8_t r, uint8_t g, uint8_t b, uint8_t a) - : b(b), g(g), r(r), a(a) {} - - uint8_t b; - uint8_t g; - uint8_t r; - uint8_t a; -}; - -inline bool operator==(const Color& a, const Color& b) { - return a.r == b.r && a.g == b.g && a.b == b.b && a.a == b.a; -} - -inline bool operator<(const Color& a, const Color& b) { - return std::tie(a.r, a.g, a.b, a.a) < std::tie(b.r, b.g, b.b, b.a); -} - -// RGBA hex dump. Note that this differs from the internal BGRA memory layout. -std::ostream& operator<<(std::ostream& os, const Color& c); +namespace fuchsia_test_utils { +/// A screenshot that has been taken from a Fuchsia device. class Screenshot { public: Screenshot(const fuchsia::ui::scenic::ScreenshotData& screenshot_data); @@ -72,6 +53,6 @@ class Screenshot { std::vector data_; }; -} // namespace scenic +} // namespace fuchsia_test_utils -#endif // SRC_UI_TESTING_VIEWS_COLOR_H_ +#endif // FLUTTER_SHELL_PLATFORM_FUCHSIA_FLUTTER_TESTS_INTEGRATION_UTILS_SCREENSHOT_H_ diff --git a/testing/fuchsia/test_suites.yaml b/testing/fuchsia/test_suites.yaml index 86630bdb73450..a3701966c50ee 100644 --- a/testing/fuchsia/test_suites.yaml +++ b/testing/fuchsia/test_suites.yaml @@ -1,7 +1,6 @@ # This configuration file specifies several test suites with their package and # test command for femu_test.py. -# v2 components. - test_command: run-test-suite fuchsia-pkg://fuchsia.com/flutter-embedder-test#meta/flutter-embedder-test.cm packages: - flutter-embedder-test-0.far diff --git a/tools/fuchsia/devshell/lib/vars.sh b/tools/fuchsia/devshell/lib/vars.sh index 34fc9233aec0f..9c2f3ffc7b85b 100644 --- a/tools/fuchsia/devshell/lib/vars.sh +++ b/tools/fuchsia/devshell/lib/vars.sh @@ -29,6 +29,15 @@ function engine-is-stderr-tty { [[ -t 2 ]] } +# engine-debug prints a line to stderr with a cyan DEBUG: prefix. +function engine-debug { + if engine-is-stderr-tty; then + echo -e >&2 "\033[1;36mDEBUG:\033[0m $*" + else + echo -e >&2 "DEBUG: $*" + fi +} + # engine-info prints a line to stderr with a green INFO: prefix. function engine-info { if engine-is-stderr-tty; then diff --git a/tools/fuchsia/devshell/run_integration_test.sh b/tools/fuchsia/devshell/run_integration_test.sh index 661702f17dbeb..637fc8b9a1899 100755 --- a/tools/fuchsia/devshell/run_integration_test.sh +++ b/tools/fuchsia/devshell/run_integration_test.sh @@ -45,11 +45,18 @@ test_name=$1 shift # past argument # Ensure we know about the test and look up its packages. +# The first package listed here should be the main package for the test +# (the package that gets passed to `ffx test run`). test_packages= case $test_name in embedder) test_packages=("flutter-embedder-test-0.far" "parent-view.far" "child-view.far") ;; + text-input) + # TODO(https://fxbug.dev/107917): Finish implementing and remove this warning. + engine-warning "This test currently hangs because the Dart view hasn't been implemented yet. https://fxbug.dev/107917" + test_packages=("text-input-test-0.far" "text-input-view.far") + ;; *) engine-error "Unknown test name $test_name. You may need to add it to $0" exit 1 @@ -143,6 +150,20 @@ fuchsia_out_dir="$ENGINE_DIR"/out/"${fuchsia_out_dir_name}" engine-info "Building ${fuchsia_out_dir_name}..." ${ninja_cmd} -C "${fuchsia_out_dir}" flutter/shell/platform/fuchsia/flutter/tests/integration/$test_name:tests +engine-debug "Printing test package contents for debugging..." +far_tool="$ENGINE_DIR"/fuchsia/sdk/linux/tools/x64/far +for test_package in "${test_packages[@]}" +do + far_debug_dir=/tmp/"$test_name"_package_contents + "${far_tool}" extract --archive="$(find $fuchsia_out_dir -name "$test_package")" --output="${far_debug_dir}" + "${far_tool}" extract --archive="${far_debug_dir}"/meta.far --output="${far_debug_dir}" + engine-debug "... $test_package tree:" + tree "${far_debug_dir}" + engine-debug "... $test_package/meta/contents:" + cat "${far_debug_dir}"/meta/contents + rm -r "${far_debug_dir}" +done + engine-info "Registering debug symbols..." "$ENGINE_DIR"/fuchsia/sdk/linux/tools/x64/symbol-index add "${fuchsia_out_dir}"/.build-id "${fuchsia_out_dir}" From 6c4b50df19bec12f5d968d5757036c08dc3b1242 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Wed, 7 Sep 2022 15:05:08 -0400 Subject: [PATCH 2/5] Roll Skia from 3f8e52d43555 to 977dc4d93034 (1 revision) (#35970) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index f9fcd185563e3..99cd7ae7f764c 100644 --- a/DEPS +++ b/DEPS @@ -18,7 +18,7 @@ vars = { 'llvm_git': 'https://llvm.googlesource.com', # OCMock is for testing only so there is no google clone 'ocmock_git': 'https://github.com/erikdoe/ocmock.git', - 'skia_revision': '3f8e52d4355582750c894e236f43a37178b9f683', + 'skia_revision': '977dc4d93034dacee14d1b0a429c7a74f66a382a', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index ab8ba86f8d1a6..37a1082bcf0ce 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: e69881676f2dff9d4423782e3e0dcc7f +Signature: b3de8dec68c4d07a4e0fc81f9d4bf350 UNUSED LICENSES: From b73a6ba1a5f05e7e1a95a9aa6a6d686d1fb732fb Mon Sep 17 00:00:00 2001 From: moko256 Date: Thu, 8 Sep 2022 04:27:12 +0900 Subject: [PATCH 3/5] [Windows] Fix system theme integration. (#35902) The #35019 didn't merge SettingsPluginWin32's constructor and destructor. This PR adds them and fix SettingsPlugin to re-enable it to watch the theme changes. This PR is part of flutter/flutter#110700. No changes in the flutter/tests repo. --- shell/platform/windows/settings_plugin.cc | 17 ++++++++++++++++- shell/platform/windows/settings_plugin.h | 9 ++++++--- .../windows/settings_plugin_unittests.cc | 18 +++++++++++++++--- 3 files changed, 37 insertions(+), 7 deletions(-) diff --git a/shell/platform/windows/settings_plugin.cc b/shell/platform/windows/settings_plugin.cc index 3d293c9134425..2754516e108be 100644 --- a/shell/platform/windows/settings_plugin.cc +++ b/shell/platform/windows/settings_plugin.cc @@ -36,7 +36,9 @@ SettingsPlugin::SettingsPlugin(BinaryMessenger* messenger, &JsonMessageCodec::GetInstance())), task_runner_(task_runner) {} -SettingsPlugin::~SettingsPlugin() = default; +SettingsPlugin::~SettingsPlugin() { + StopWatching(); +} void SettingsPlugin::SendSettings() { rapidjson::Document settings(rapidjson::kObjectType); @@ -55,6 +57,12 @@ void SettingsPlugin::SendSettings() { } void SettingsPlugin::StartWatching() { + RegOpenKeyEx(HKEY_CURRENT_USER, kGetPreferredBrightnessRegKey, + RRF_RT_REG_DWORD, KEY_NOTIFY, &preferred_brightness_reg_hkey_); + RegOpenKeyEx(HKEY_CURRENT_USER, kGetTextScaleFactorRegKey, RRF_RT_REG_DWORD, + KEY_NOTIFY, &text_scale_factor_reg_hkey_); + + // Start watching when the keys exist. if (preferred_brightness_reg_hkey_ != nullptr) { WatchPreferredBrightnessChanged(); } @@ -66,6 +74,13 @@ void SettingsPlugin::StartWatching() { void SettingsPlugin::StopWatching() { preferred_brightness_changed_watcher_ = nullptr; text_scale_factor_changed_watcher_ = nullptr; + + if (preferred_brightness_reg_hkey_ != nullptr) { + RegCloseKey(preferred_brightness_reg_hkey_); + } + if (text_scale_factor_reg_hkey_ != nullptr) { + RegCloseKey(text_scale_factor_reg_hkey_); + } } bool SettingsPlugin::GetAlwaysUse24HourFormat() { diff --git a/shell/platform/windows/settings_plugin.h b/shell/platform/windows/settings_plugin.h index 6491e642ef1f8..2c663fc048212 100644 --- a/shell/platform/windows/settings_plugin.h +++ b/shell/platform/windows/settings_plugin.h @@ -49,12 +49,15 @@ class SettingsPlugin { // Returns the user-preferred brightness. virtual PlatformBrightness GetPreferredBrightness(); + // Starts watching brightness changes. + virtual void WatchPreferredBrightnessChanged(); + + // Starts watching text scale factor changes. + virtual void WatchTextScaleFactorChanged(); + private: std::unique_ptr> channel_; - void WatchPreferredBrightnessChanged(); - void WatchTextScaleFactorChanged(); - HKEY preferred_brightness_reg_hkey_ = nullptr; HKEY text_scale_factor_reg_hkey_ = nullptr; diff --git a/shell/platform/windows/settings_plugin_unittests.cc b/shell/platform/windows/settings_plugin_unittests.cc index 3158e5a41c621..2380f46017014 100644 --- a/shell/platform/windows/settings_plugin_unittests.cc +++ b/shell/platform/windows/settings_plugin_unittests.cc @@ -22,12 +22,12 @@ class MockSettingsPlugin : public SettingsPlugin { virtual ~MockSettingsPlugin() = default; // |SettingsPlugin| - MOCK_METHOD0(StartWatching, void()); - MOCK_METHOD0(StopWatching, void()); - MOCK_METHOD0(GetAlwaysUse24HourFormat, bool()); MOCK_METHOD0(GetTextScaleFactor, float()); MOCK_METHOD0(GetPreferredBrightness, PlatformBrightness()); + + MOCK_METHOD0(WatchPreferredBrightnessChanged, void()); + MOCK_METHOD0(WatchTextScaleFactorChanged, void()); }; } // namespace @@ -58,5 +58,17 @@ TEST(SettingsPluginTest, SendSettingsGetsSettings) { settings_plugin.SendSettings(); } +TEST(SettingsPluginTest, StartWatchingStartsWatchingChanges) { + TestBinaryMessenger messenger([](const std::string& channel, + const uint8_t* message, size_t message_size, + BinaryReply reply) {}); + ::testing::NiceMock settings_plugin(&messenger, nullptr); + + EXPECT_CALL(settings_plugin, WatchPreferredBrightnessChanged).Times(1); + EXPECT_CALL(settings_plugin, WatchTextScaleFactorChanged).Times(1); + + settings_plugin.StartWatching(); +} + } // namespace testing } // namespace flutter From ab8c96ff37a2bfe886928ac4d8e8da5b796a44b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Sharma?= <737941+loic-sharma@users.noreply.github.com> Date: Wed, 7 Sep 2022 14:18:22 -0700 Subject: [PATCH 4/5] Remove noisy log from startup (#35954) --- shell/platform/embedder/embedder.cc | 6 ----- .../windows/flutter_windows_unittests.cc | 26 +++++++++++++++++++ 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/shell/platform/embedder/embedder.cc b/shell/platform/embedder/embedder.cc index ddd368a739995..bceb94e1baaf2 100644 --- a/shell/platform/embedder/embedder.cc +++ b/shell/platform/embedder/embedder.cc @@ -132,12 +132,6 @@ static bool IsOpenGLRendererConfigValid(const FlutterRendererConfig* config) { return false; } - if (!SAFE_EXISTS(open_gl_config, populate_existing_damage)) { - FML_LOG(INFO) << "populate_existing_damage was not defined, disabling " - "partial repaint. If you wish to enable partial repaint, " - "please define this callback."; - } - return true; } diff --git a/shell/platform/windows/flutter_windows_unittests.cc b/shell/platform/windows/flutter_windows_unittests.cc index 40cd9e32a3313..6d32f24313e01 100644 --- a/shell/platform/windows/flutter_windows_unittests.cc +++ b/shell/platform/windows/flutter_windows_unittests.cc @@ -38,6 +38,32 @@ TEST_F(WindowsTest, LaunchMain) { ASSERT_NE(controller, nullptr); } +// Verify there is no unexpected output from launching main. +TEST_F(WindowsTest, LaunchMainHasNoOutput) { + // Replace stdout & stderr stream buffers with our own. + std::stringstream cout_buffer; + std::stringstream cerr_buffer; + std::streambuf* old_cout_buffer = std::cout.rdbuf(); + std::streambuf* old_cerr_buffer = std::cerr.rdbuf(); + std::cout.rdbuf(cout_buffer.rdbuf()); + std::cerr.rdbuf(cerr_buffer.rdbuf()); + + auto& context = GetContext(); + WindowsConfigBuilder builder(context); + ViewControllerPtr controller{builder.Run()}; + ASSERT_NE(controller, nullptr); + + // Restore original stdout & stderr stream buffer. + std::cout.rdbuf(old_cout_buffer); + std::cerr.rdbuf(old_cerr_buffer); + + // Verify stdout & stderr have no output. + std::string cout = cout_buffer.str(); + std::string cerr = cerr_buffer.str(); + EXPECT_TRUE(cout.empty()); + EXPECT_TRUE(cerr.empty()); +} + // Verify we can successfully launch a custom entry point. TEST_F(WindowsTest, LaunchCustomEntrypoint) { auto& context = GetContext(); From cb2234bc0eabd90ce769528a310de30cc33e9083 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Wed, 7 Sep 2022 17:22:06 -0400 Subject: [PATCH 5/5] Roll Skia from 977dc4d93034 to d0b84eceadc6 (3 revisions) (#35971) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 99cd7ae7f764c..b9f875da56551 100644 --- a/DEPS +++ b/DEPS @@ -18,7 +18,7 @@ vars = { 'llvm_git': 'https://llvm.googlesource.com', # OCMock is for testing only so there is no google clone 'ocmock_git': 'https://github.com/erikdoe/ocmock.git', - 'skia_revision': '977dc4d93034dacee14d1b0a429c7a74f66a382a', + 'skia_revision': 'd0b84eceadc6a212c8fdeaec9abd9f33f6be56ca', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 37a1082bcf0ce..e60b435225117 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: b3de8dec68c4d07a4e0fc81f9d4bf350 +Signature: ec08617195c2b6cb203add4cc22e3a9e UNUSED LICENSES: