blob: bacd90ef4e263bfb02865deae161dc059a8ca2e8 [file] [log] [blame]
// Copyright 2016 The Chromium OS 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 <errno.h>
#include <gtest/gtest.h>
#include "touch_keyboard/syscallhandler_mock.h"
#include "touch_keyboard/uinputdevice.h"
namespace touch_keyboard {
constexpr char kTestDeviceName[] = "test device name";
constexpr int kTestValidFD = 4;
constexpr int kTestX = 22;
constexpr int kTestY = 22;
using ::testing::_;
using ::testing::Matcher;
using ::testing::Return;
using ::testing::StrEq;
class UinputDeviceTest : public ::testing::Test {};
TEST_F(UinputDeviceTest, UinputControlOpeningTest) {
// This tests confirms that when you try to open a new uinput control file
// descriptor it behaives correctly.
MockSyscallHandler mock_syscall_handler;
// Open() should be called once with these arguments only. To simulate
// success it is configured to return a valid file descriptor.
EXPECT_CALL(mock_syscall_handler,
open(StrEq(kUinputControlFilename), O_WRONLY | O_NONBLOCK))
.WillOnce(Return(kTestValidFD));
// The UI_DEV_DESTROY ioctl will be called in the device's destructor.
EXPECT_CALL(mock_syscall_handler,
ioctl(kTestValidFD, UI_DEV_DESTROY)).WillOnce(Return(0));
// Given that open() succeeds, this function should return true to indicate to
// us that everything went as expected.
UinputDevice dev(&mock_syscall_handler);
EXPECT_TRUE(dev.CreateUinputFD());
// Finally, check that the class stored the file descriptor correctly.
EXPECT_EQ(dev.uinput_fd_, kTestValidFD);
}
TEST_F(UinputDeviceTest, UinputControlOpeningFailureTest) {
// This tests confirms that when you try to open a new uinput control file
// descriptor it correctly identifies failures.
MockSyscallHandler mock_syscall_handler;
// Open() should be called once with these arguments only. To simulate failure
// we set it to return an error.
EXPECT_CALL(mock_syscall_handler,
open(StrEq(kUinputControlFilename), O_WRONLY | O_NONBLOCK))
.WillOnce(Return(-ENOENT));
// Given that we've set up open to fail, this function should return false
// to indicate to us that something went awry.
UinputDevice dev(&mock_syscall_handler);
EXPECT_FALSE(dev.CreateUinputFD());
}
TEST_F(UinputDeviceTest, EnableEventTypeTest) {
// This tests the ability to enable event types for the UinputDevice. To do
// so, we simulate enabling several types that both succeed and fail.
int ev_types[] = {EV_ABS, EV_KEY, EV_SYN};
int num_ev_types = sizeof(ev_types) / sizeof(*ev_types);
MockSyscallHandler mock_syscall_handler;
EXPECT_CALL(mock_syscall_handler, open(_, _)).WillOnce(Return(kTestValidFD));
EXPECT_CALL(mock_syscall_handler,
ioctl(kTestValidFD, UI_DEV_DESTROY)).WillOnce(Return(0));
// Ioctl()s are used to enable an event type, so we expect this input and set
// up all but the last one to succeed.
EXPECT_CALL(mock_syscall_handler,
ioctl(kTestValidFD, UI_SET_EVBIT, Matcher<uint64_t>(_)))
.WillOnce(Return(-EPERM));
EXPECT_CALL(mock_syscall_handler,
ioctl(kTestValidFD, UI_SET_EVBIT, Matcher<uint64_t>(_)))
.Times(num_ev_types - 1).WillRepeatedly(Return(0)).RetiresOnSaturation();
UinputDevice dev(&mock_syscall_handler);
dev.CreateUinputFD();
// Going through and enabling several event types should all work until the
// last one, which should fail.
for (int i = 0; i < num_ev_types - 1; i++) {
EXPECT_TRUE(dev.EnableEventType(ev_types[i]));
}
EXPECT_FALSE(dev.EnableEventType(ev_types[num_ev_types - 1]));
}
TEST_F(UinputDeviceTest, EnableKeyEventTest) {
// This tests the ability to enable key events for the UinputDevice. To do
// so, we simulate enabling events for several keys that succeed and fail.
int key_codes[] = {KEY_ESC, KEY_BACKSPACE, BTN_TOUCH, BTN_TOOL_FINGER};
int num_key_codes = sizeof(key_codes) / sizeof(*key_codes);
MockSyscallHandler mock_syscall_handler;
EXPECT_CALL(mock_syscall_handler, open(_, _)).WillOnce(Return(kTestValidFD));
EXPECT_CALL(mock_syscall_handler,
ioctl(kTestValidFD, UI_DEV_DESTROY)).WillOnce(Return(0));
// Ioctl()s are used to enable a key event, so we expect this input. Setting
// up the first (num_key_codes - 1) attempts to succeed and the last one
// will fail.
EXPECT_CALL(mock_syscall_handler,
ioctl(kTestValidFD, UI_SET_KEYBIT, Matcher<uint64_t>(_)))
.WillRepeatedly(Return(-EPERM));
EXPECT_CALL(mock_syscall_handler,
ioctl(kTestValidFD, UI_SET_KEYBIT, Matcher<uint64_t>(_)))
.Times(num_key_codes - 1).WillRepeatedly(Return(0)).RetiresOnSaturation();
UinputDevice dev(&mock_syscall_handler);
dev.CreateUinputFD();
// Going through and enabling several key events should work until the last
// one, which should fail.
for (int i = 0; i < num_key_codes - 1; i++) {
EXPECT_TRUE(dev.EnableKeyEvent(key_codes[i]));
}
EXPECT_FALSE(dev.EnableKeyEvent(key_codes[num_key_codes - 1]));
}
TEST_F(UinputDeviceTest, EnableAbsEventTest) {
// This tests the ability to enable abs events (like those used by touchpads
// and touchscreens) for the UinputDevice. To do so, we simulate enabling
// everal kinds of abs events that both succeed and fail.
int abs_codes[] = {ABS_PRESSURE, ABS_MT_TOUCH_MAJOR,
ABS_MT_POSITION_X, ABS_X};
int num_abs_codes = sizeof(abs_codes) / sizeof(*abs_codes);
MockSyscallHandler mock_syscall_handler;
EXPECT_CALL(mock_syscall_handler, open(_, _)).WillOnce(Return(kTestValidFD));
EXPECT_CALL(mock_syscall_handler,
ioctl(kTestValidFD, UI_DEV_DESTROY)).WillOnce(Return(0));
// Ioctls are used to enable an abs event, so we expect this input -- setting
// up the first (num_abs_codes - 1) attempts to succeed and the last one
// will fail.
EXPECT_CALL(mock_syscall_handler,
ioctl(kTestValidFD, UI_SET_ABSBIT, Matcher<uint64_t>(_)))
.WillRepeatedly(Return(-EPERM));
EXPECT_CALL(mock_syscall_handler,
ioctl(kTestValidFD, UI_SET_ABSBIT, Matcher<uint64_t>(_)))
.Times(num_abs_codes - 1).WillRepeatedly(Return(0)).RetiresOnSaturation();
UinputDevice dev(&mock_syscall_handler);
dev.CreateUinputFD();
// Going through and enabling several key events should work until the last
// one, which should fail.
for (int i = 0; i < num_abs_codes - 1; i++) {
EXPECT_TRUE(dev.EnableAbsEvent(abs_codes[i]));
}
EXPECT_FALSE(dev.EnableAbsEvent(abs_codes[num_abs_codes - 1]));
}
TEST_F(UinputDeviceTest, FinalizeUinputCreationSuccessTest) {
// This tests how the class finalized the creation of a uinput device. This
// would normally be the last setup step when making a uinput device and it
// tells the kernel to actually create the device on disk.
MockSyscallHandler mock_syscall_handler;
// Since the order of the ioctls is essential, configure this test to only
// accept them in the order I specify below.
::testing::InSequence seq;
EXPECT_CALL(mock_syscall_handler, open(_, _)).WillOnce(Return(kTestValidFD));
EXPECT_CALL(mock_syscall_handler, ioctl(kTestValidFD, UI_DEV_SETUP,
Matcher<struct uinput_setup*>(_)))
.WillOnce(Return(0));
EXPECT_CALL(mock_syscall_handler, ioctl(kTestValidFD, UI_DEV_CREATE))
.WillOnce(Return(0));
EXPECT_CALL(mock_syscall_handler,
ioctl(kTestValidFD, UI_DEV_DESTROY)).WillOnce(Return(0));
UinputDevice dev(&mock_syscall_handler);
dev.CreateUinputFD();
EXPECT_TRUE(dev.FinalizeUinputCreation(kTestDeviceName));
}
TEST_F(UinputDeviceTest, FinalizeUinputCreationDEV_SETUPFailTest) {
// This tests how FinalizeUinputCreation handles a failure while trying to
// setup the device details with the UI_DEV_SETUP ioctl().
MockSyscallHandler mock_syscall_handler;
// Since the order of the ioctls is essential, configure this test to only
// accept them in the order specified below.
::testing::InSequence seq;
EXPECT_CALL(mock_syscall_handler, open(_, _)).WillOnce(Return(kTestValidFD));
EXPECT_CALL(mock_syscall_handler, ioctl(kTestValidFD, UI_DEV_SETUP,
Matcher<struct uinput_setup*>(_)))
.WillOnce(Return(-EPERM));
EXPECT_CALL(mock_syscall_handler,
ioctl(kTestValidFD, UI_DEV_DESTROY)).WillOnce(Return(0));
UinputDevice dev(&mock_syscall_handler);
dev.CreateUinputFD();
EXPECT_FALSE(dev.FinalizeUinputCreation(kTestDeviceName));
}
TEST_F(UinputDeviceTest, FinalizeUinputCreationDEV_CREATEFailTest) {
// This tests how FinalizeUinputCreation handles a failure while trying to
// tell the kernel to the create device details with the UI_DEV_CREATE ioctl
MockSyscallHandler mock_syscall_handler;
// Since the order of the ioctls is essential, configure this test to only
// accept them in the order I specify below.
::testing::InSequence seq;
EXPECT_CALL(mock_syscall_handler, open(_, _)).WillOnce(Return(kTestValidFD));
EXPECT_CALL(mock_syscall_handler, ioctl(kTestValidFD, UI_DEV_SETUP,
Matcher<struct uinput_setup*>(_)))
.WillOnce(Return(0));
EXPECT_CALL(mock_syscall_handler, ioctl(kTestValidFD, UI_DEV_CREATE))
.WillOnce(Return(-EPERM));
EXPECT_CALL(mock_syscall_handler,
ioctl(kTestValidFD, UI_DEV_DESTROY)).WillOnce(Return(0));
UinputDevice dev(&mock_syscall_handler);
dev.CreateUinputFD();
EXPECT_FALSE(dev.FinalizeUinputCreation(kTestDeviceName));
}
TEST_F(UinputDeviceTest, SendEventTest) {
// This test makes sure that sending events works as expected. They should
// be send using the write() command, so this tests how the class handles
// success and failure of that write.
MockSyscallHandler mock_syscall_handler;
// Set up open() to work as normal so the class can set itself up.
EXPECT_CALL(mock_syscall_handler, open(_, _)).WillOnce(Return(kTestValidFD));
EXPECT_CALL(mock_syscall_handler,
ioctl(kTestValidFD, UI_DEV_DESTROY)).WillOnce(Return(0));
// The first call to write an event to the file descriptor should succeed by
// returning the full size of the struct, but after that it is configured to
// return an error on subsequent calls.
EXPECT_CALL(mock_syscall_handler,
write(kTestValidFD, _, sizeof(struct input_event)))
.WillRepeatedly(Return(-EPERM));
EXPECT_CALL(mock_syscall_handler,
write(kTestValidFD, _, sizeof(struct input_event)))
.WillOnce(Return(sizeof(struct input_event))).RetiresOnSaturation();
UinputDevice dev(&mock_syscall_handler);
dev.CreateUinputFD();
// Given how write was configured for this test, only the first event should
// send correctly.
EXPECT_TRUE(dev.SendEvent(EV_ABS, ABS_MT_POSITION_X, kTestX));
EXPECT_FALSE(dev.SendEvent(EV_ABS, ABS_MT_POSITION_X, kTestX));
EXPECT_FALSE(dev.SendEvent(EV_ABS, ABS_MT_POSITION_Y, kTestY));
}
} // namespace touch_keyboard