blob: 3e5cd111d14ec3aa46f1b0c930426e8bf5a56de8 [file] [log] [blame]
// Copyright 2018 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 <set>
#include <hid/usages.h>
#include "garnet/bin/ui/input_reader/input_reader.h"
#include "garnet/bin/ui/input_reader/tests/mock_device_watcher.h"
#include "garnet/bin/ui/input_reader/tests/mock_hid_decoder.h"
#include "gtest/gtest.h"
#include "lib/gtest/test_loop_fixture.h"
#include "lib/ui/tests/mocks/mock_input_device.h"
#include "lib/ui/tests/mocks/mock_input_device_registry.h"
namespace mozart {
namespace {
using MockInputDevice = mozart::test::MockInputDevice;
using MockInputDeviceRegistry = mozart::test::MockInputDeviceRegistry;
// This fixture sets up a |MockDeviceWatcher| so that tests can add mock
// devices.
class ReaderInterpreterTest : public gtest::TestLoopFixture {
protected:
// Starts an |InputReader| with a |MockDeviceWatcher| and saves it locally so
// that |MockHidDecoder|s can be added to it.
void StartInputReader(InputReader* input_reader) {
auto device_watcher = std::make_unique<MockDeviceWatcher>();
device_watcher_ = device_watcher->GetWeakPtr();
input_reader->Start(std::move(device_watcher));
}
// Creates a |MockHidDecoder| with the supplied |args| and adds it to the
// |MockDeviceWatcher|, returning an |fxl::WeakPtr| to the new
// |MockHidDecoder|.
template <class... Args>
fxl::WeakPtr<MockHidDecoder> AddDevice(Args&&... args) {
auto device = std::make_unique<MockHidDecoder>(std::forward<Args>(args)...);
auto weak_device = device->GetWeakPtr();
device_watcher_->AddDevice(std::move(device));
return weak_device;
}
private:
fxl::WeakPtr<MockDeviceWatcher> device_watcher_;
};
// This fixture sets up a |MockInputDeviceRegistry| and an |InputReader| in
// addition to the |MockDeviceWatcher| provided by |ReaderInterpreterTest| so
// that tests can additionally verify the reports seen by the registry.
class ReaderInterpreterInputTest : public ReaderInterpreterTest {
protected:
ReaderInterpreterInputTest()
: registry_(nullptr,
[this](fuchsia::ui::input::InputReport report) {
++report_count_;
last_report_ = std::move(report);
}),
input_reader_(&registry_) {}
int report_count_ = 0;
fuchsia::ui::input::InputReport last_report_;
private:
void SetUp() override { StartInputReader(&input_reader_); }
MockInputDeviceRegistry registry_;
InputReader input_reader_;
};
} // namespace
TEST_F(ReaderInterpreterTest, RegisterKeyboardTest) {
int registration_count = 0;
MockInputDeviceRegistry registry(
[&](MockInputDevice* client_device) {
EXPECT_EQ(0, registration_count++);
EXPECT_TRUE(client_device->descriptor()->keyboard);
},
nullptr);
InputReader input_reader(&registry);
StartInputReader(&input_reader);
bool did_init = false;
AddDevice([&] {
did_init = true;
return std::make_pair<HidDecoder::Protocol, bool>(
HidDecoder::Protocol::Keyboard, true);
});
EXPECT_TRUE(did_init);
EXPECT_EQ(1, registration_count);
}
TEST_F(ReaderInterpreterTest, DISABLED_RemoveKeyboardTest) {
MockInputDeviceRegistry registry(nullptr, nullptr);
InputReader input_reader(&registry);
StartInputReader(&input_reader);
fxl::WeakPtr<MockHidDecoder> device =
AddDevice(HidDecoder::Protocol::Keyboard);
device->Close();
RunLoopUntilIdle();
EXPECT_FALSE(device);
}
TEST_F(ReaderInterpreterInputTest, KeyboardTest) {
fxl::WeakPtr<MockHidDecoder> device =
AddDevice(HidDecoder::Protocol::Keyboard);
RunLoopUntilIdle();
EXPECT_EQ(0, report_count_);
// A keyboard report is 8 bytes long, with bytes 3-8 containing HID usage
// codes.
device->Send({0, 0, HID_USAGE_KEY_A, 0, 0, 0, 0, 0}, 8);
RunLoopUntilIdle();
EXPECT_EQ(1, report_count_);
ASSERT_TRUE(last_report_.keyboard);
EXPECT_EQ(std::vector<uint32_t>{HID_USAGE_KEY_A},
last_report_.keyboard->pressed_keys);
device->Send({0, 0, HID_USAGE_KEY_A, HID_USAGE_KEY_Z, 0, 0, 0, 0}, 8);
RunLoopUntilIdle();
EXPECT_EQ(2, report_count_);
EXPECT_EQ(std::multiset<uint32_t>({HID_USAGE_KEY_A, HID_USAGE_KEY_Z}),
std::multiset<uint32_t>(last_report_.keyboard->pressed_keys.begin(),
last_report_.keyboard->pressed_keys.end()));
device->Send({0, 0, HID_USAGE_KEY_Z, 0, 0, 0, 0, 0}, 8);
RunLoopUntilIdle();
EXPECT_EQ(std::vector<uint32_t>{HID_USAGE_KEY_Z},
last_report_.keyboard->pressed_keys);
}
TEST_F(ReaderInterpreterInputTest, LightSensorTest) {
fxl::WeakPtr<MockHidDecoder> device =
AddDevice(HidDecoder::Protocol::LightSensor);
RunLoopUntilIdle();
EXPECT_EQ(0, report_count_);
{
HidDecoder::HidAmbientLightSimple light{/* int16_t illuminance */ 42};
device->Send(light);
}
RunLoopUntilIdle();
EXPECT_EQ(1, report_count_);
ASSERT_TRUE(last_report_.sensor);
EXPECT_TRUE(last_report_.sensor->is_scalar());
EXPECT_EQ(42, last_report_.sensor->scalar());
}
TEST_F(ReaderInterpreterInputTest, TouchpadTest) {
fxl::WeakPtr<MockHidDecoder> device =
AddDevice(HidDecoder::Protocol::Touchpad);
RunLoopUntilIdle();
EXPECT_EQ(0, report_count_);
{
// Touchpads use the touchscreen driver behind the scenes, so we
// must send touchscreen reports.
Touchscreen::Report touchpad_rpt{};
touchpad_rpt.contact_count = 1;
touchpad_rpt.contacts[0].id = 1;
touchpad_rpt.contacts[0].x = 10;
touchpad_rpt.contacts[0].y = 20;
device->Send(touchpad_rpt);
RunLoopUntilIdle();
touchpad_rpt.contacts[0].x = 15;
touchpad_rpt.contacts[0].y = 10;
device->Send(touchpad_rpt);
RunLoopUntilIdle();
}
EXPECT_EQ(2, report_count_);
ASSERT_TRUE(last_report_.mouse);
EXPECT_TRUE(last_report_.mouse->rel_x = 5);
EXPECT_TRUE(last_report_.mouse->rel_y = -10);
}
TEST_F(ReaderInterpreterInputTest, TouchscreenTest) {
fxl::WeakPtr<MockHidDecoder> device = AddDevice(HidDecoder::Protocol::Touch);
RunLoopUntilIdle();
EXPECT_EQ(0, report_count_);
{
Touchscreen::Report touchscreen_rpt{};
touchscreen_rpt.contact_count = 1;
touchscreen_rpt.contacts[0].id = 1;
touchscreen_rpt.contacts[0].x = 10;
touchscreen_rpt.contacts[0].y = 20;
device->Send(touchscreen_rpt);
RunLoopUntilIdle();
}
EXPECT_EQ(1, report_count_);
ASSERT_TRUE(last_report_.touchscreen);
fuchsia::ui::input::Touch touch = last_report_.touchscreen->touches.at(0);
EXPECT_TRUE(touch.finger_id = 1);
EXPECT_TRUE(touch.x = 10);
EXPECT_TRUE(touch.y = 20);
}
} // namespace mozart