blob: 8ae7310a58efd860853925656859762f62d82f2a [file] [log] [blame]
// Copyright 2022 The Fuchsia 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 <fuchsia/ui/test/conformance/cpp/fidl.h>
#include <fuchsia/ui/test/context/cpp/fidl.h>
#include <fuchsia/ui/test/input/cpp/fidl.h>
#include <lib/fidl/cpp/binding.h>
#include <lib/sys/cpp/component_context.h>
#include <lib/syslog/cpp/macros.h>
#include <memory>
#include <gtest/gtest.h>
#include "src/lib/testing/loop_fixture/real_loop_fixture.h"
namespace ui_conformance_testing {
bool CompareDouble(double f0, double f1, double epsilon) { return std::abs(f0 - f1) <= epsilon; }
class MouseListener : public fuchsia::ui::test::input::MouseInputListener {
public:
MouseListener() : binding_(this) {}
// |fuchsia::ui::test::input::MouseInputListener|
void ReportMouseInput(
fuchsia::ui::test::input::MouseInputListenerReportMouseInputRequest request) override {
events_received_.push_back(std::move(request));
}
// Returns a client end bound to this object.
fidl::InterfaceHandle<fuchsia::ui::test::input::MouseInputListener> NewBinding() {
return binding_.NewBinding();
}
const std::vector<fuchsia::ui::test::input::MouseInputListenerReportMouseInputRequest>&
events_received() const {
return events_received_;
}
private:
fidl::Binding<fuchsia::ui::test::input::MouseInputListener> binding_;
std::vector<fuchsia::ui::test::input::MouseInputListenerReportMouseInputRequest> events_received_;
};
// Holds resources associated with a single puppet instance.
struct MousePuppet {
fuchsia::ui::test::conformance::PuppetSyncPtr puppet_ptr;
MouseListener mouse_listener;
MousePuppet(fuchsia::ui::test::context::Context_Sync* context,
fuchsia::ui::views::ViewCreationToken view_creation_token,
bool is_puppet_under_test = false) {
fuchsia::ui::test::conformance::PuppetCreationArgs puppet_creation_args;
puppet_creation_args.set_server_end(puppet_ptr.NewRequest());
puppet_creation_args.set_view_token(std::move(view_creation_token));
puppet_creation_args.set_mouse_listener(mouse_listener.NewBinding());
if (is_puppet_under_test) {
context->ConnectToPuppetUnderTest(std::move(puppet_creation_args));
} else {
context->ConnectToAuxiliaryPuppet(std::move(puppet_creation_args));
}
}
};
class MouseConformanceTest : public gtest::RealLoopFixture {
public:
~MouseConformanceTest() override = default;
void SetUp() override {
{
auto component_context = sys::ComponentContext::Create();
auto test_context_factory =
component_context->svc()->Connect<fuchsia::ui::test::context::Factory>();
fuchsia::ui::test::context::FactoryCreateRequest request;
request.set_context_server(test_context_.NewRequest());
test_context_factory->Create(std::move(request));
}
// Register fake mouse.
{
FX_LOGS(INFO) << "Connecting to input registry";
fuchsia::ui::test::input::RegistrySyncPtr input_registry;
test_context_->ConnectToInputRegistry(input_registry.NewRequest());
FX_LOGS(INFO) << "Registering fake mouse";
fuchsia::ui::test::input::RegistryRegisterMouseRequest request;
request.set_device(fake_mouse_.NewRequest());
input_registry->RegisterMouse(std::move(request));
}
// Get display dimensions.
{
FX_LOGS(INFO) << "Reading display dimensions";
fuchsia::ui::test::context::ContextGetDisplayDimensionsResponse response;
test_context_->GetDisplayDimensions(&response);
ASSERT_TRUE(response.has_width_in_physical_px());
display_width_ = response.width_in_physical_px();
ASSERT_TRUE(response.has_height_in_physical_px());
display_height_ = response.height_in_physical_px();
FX_LOGS(INFO) << "Received display dimensions (" << display_width_ << ", " << display_height_
<< ")";
}
}
void SimulateMouseEvent(std::vector<fuchsia::ui::test::input::MouseButton> pressed_buttons,
int movement_x, int movement_y) {
FX_LOGS(INFO) << "Requesting mouse event";
fuchsia::ui::test::input::MouseSimulateMouseEventRequest request;
request.set_pressed_buttons(std::move(pressed_buttons));
request.set_movement_x(movement_x);
request.set_movement_y(movement_y);
fake_mouse_->SimulateMouseEvent(std::move(request));
FX_LOGS(INFO) << "Mouse event injected";
}
void WaitForEvent(const MousePuppet& puppet, double expected_x, double expected_y,
std::vector<fuchsia::ui::test::input::MouseButton> expected_buttons) {
RunLoopUntil([&puppet, expected_x, expected_y, &expected_buttons] {
const auto& events_received = puppet.mouse_listener.events_received();
for (const auto& event : events_received) {
const auto dpr = event.device_pixel_ratio();
// Check position of event against expectation.
if (!CompareDouble(event.local_x() * dpr, expected_x, dpr) ||
!CompareDouble(event.local_y() * dpr, expected_y, dpr)) {
continue;
}
// Check the reported buttons against expectations.
//
// For client ergonomics, we accept `buttons` as unset or set to the
// empty vector if no buttons are pressed.
if ((event.has_buttons() && event.buttons() == expected_buttons) ||
(!event.has_buttons() && expected_buttons.empty())) {
return true;
}
}
return false;
});
}
protected:
int32_t display_width_as_int() { return static_cast<int32_t>(display_width_); }
int32_t display_height_as_int() { return static_cast<int32_t>(display_height_); }
fuchsia::ui::test::context::ContextSyncPtr test_context_;
fuchsia::ui::test::input::MouseSyncPtr fake_mouse_;
uint32_t display_width_ = 0;
uint32_t display_height_ = 0;
};
TEST_F(MouseConformanceTest, SimpleClick) {
// Get root view token.
//
// Note that the test context will automatically present the view created
// using this token to the scene.
FX_LOGS(INFO) << "Creating root view token";
fuchsia::ui::views::ViewCreationToken view_creation_token;
test_context_->GetRootViewToken(&view_creation_token);
// Create puppet using root view token.
FX_LOGS(INFO) << "Creating puppet under test";
MousePuppet puppet(test_context_.get(), std::move(view_creation_token),
/* is_puppet_under_test = */ true);
// Inject click with no mouse movement.
// Left button down.
SimulateMouseEvent(/* pressed_buttons = */ {fuchsia::ui::test::input::MouseButton::FIRST},
/* movement_x = */ 0, /* movement_y = */ 0);
FX_LOGS(INFO) << "Waiting for puppet to report DOWN event";
WaitForEvent(puppet, /* expected_x = */ static_cast<double>(display_width_) / 2.f,
/* expected_y = */ static_cast<double>(display_height_) / 2.f,
/* expected_buttons = */ {fuchsia::ui::test::input::MouseButton::FIRST});
// Left button up.
SimulateMouseEvent(/* pressed_buttons = */ {}, /* movement_x = */ 0, /* movement_y = */ 0);
FX_LOGS(INFO) << "Waiting for puppet to report UP";
WaitForEvent(puppet, /* expected_x = */ static_cast<double>(display_width_) / 2.f,
/* expected_y = */ static_cast<double>(display_height_) / 2.f,
/* expected_buttons = */ {});
}
} // namespace ui_conformance_testing