VirtualTouchpad_test.cpp revision 43b5b06c8be24e465bd6a7b22a8d341db1ad50a2
1#include <android/input.h>
2#include <cstdio>
3#include <cstdlib>
4#include <cstring>
5#include <gtest/gtest.h>
6#include <linux/input.h>
7
8#include "EvdevInjector.h"
9#include "VirtualTouchpad.h"
10
11namespace android {
12namespace dvr {
13
14namespace {
15
16class UInputForTesting : public EvdevInjector::UInput {
17 public:
18  void WriteInputEvent(uint16_t type, uint16_t code, int32_t value) {
19    struct input_event event;
20    memset(&event, 0, sizeof(event));
21    event.type = type;
22    event.code = code;
23    event.value = value;
24    Write(&event, sizeof (event));
25  }
26};
27
28// Recording test implementation of UInput.
29//
30class UInputRecorder : public UInputForTesting {
31 public:
32  UInputRecorder() {}
33  virtual ~UInputRecorder() {}
34
35  const std::string& GetString() const { return s_; }
36  void Reset() { s_.clear(); }
37
38  // UInput overrides:
39
40  int Open() override {
41    s_ += "o;";
42    return 0;
43  }
44
45  int Close() override {
46    s_ += "c;";
47    return 0;
48  }
49
50  int Write(const void* buf, size_t count) override {
51    s_ += "w(";
52    s_ += Encode(&count, sizeof(count));
53    s_ += ",";
54    s_ += Encode(buf, count);
55    s_ += ");";
56    return 0;
57  }
58
59  int IoctlVoid(int request) override {
60    s_ += "i(";
61    s_ += Encode(&request, sizeof(request));
62    s_ += ");";
63    return 0;
64  }
65
66  int IoctlSetInt(int request, int value) override {
67    s_ += "i(";
68    s_ += Encode(&request, sizeof(request));
69    s_ += ",";
70    s_ += Encode(&value, sizeof(value));
71    s_ += ");";
72    return 0;
73  }
74
75 private:
76  std::string s_;
77
78  std::string Encode(const void* buf, size_t count) {
79    const char* in = static_cast<const char*>(buf);
80    char out[2 * count + 1];
81    for (size_t i = 0; i < count; ++i) {
82      snprintf(&out[2 * i], 3, "%02X", in[i]);
83    }
84    return out;
85  }
86};
87
88class EvdevInjectorForTesting : public EvdevInjector {
89 public:
90  EvdevInjectorForTesting(UInput& uinput) {
91    SetUInputForTesting(&uinput);
92  }
93  const uinput_user_dev* GetUiDev() const { return GetUiDevForTesting(); }
94};
95
96class VirtualTouchpadForTesting : public VirtualTouchpad {
97 public:
98  VirtualTouchpadForTesting(EvdevInjector& injector) {
99    SetEvdevInjectorForTesting(&injector);
100  }
101};
102
103void DumpDifference(const char* expect, const char* actual) {
104  printf("  common: ");
105  while (*expect && *expect == *actual) {
106    putchar(*expect);
107    ++expect;
108    ++actual;
109  }
110  printf("\n  expect: %s\n", expect);
111  printf("  actual: %s\n", actual);
112}
113
114}  // anonymous namespace
115
116class VirtualTouchpadTest : public testing::Test {
117};
118
119TEST_F(VirtualTouchpadTest, Goodness) {
120  UInputRecorder expect;
121  UInputRecorder record;
122  EvdevInjectorForTesting injector(record);
123  VirtualTouchpadForTesting touchpad(injector);
124
125  const int initialization_status = touchpad.Initialize();
126  EXPECT_EQ(0, initialization_status);
127
128  // Check some aspects of uinput_user_dev.
129  const uinput_user_dev* uidev = injector.GetUiDev();
130  for (int i = 0; i < ABS_CNT; ++i) {
131    EXPECT_EQ(0, uidev->absmin[i]);
132    EXPECT_EQ(0, uidev->absfuzz[i]);
133    EXPECT_EQ(0, uidev->absflat[i]);
134    if (i != ABS_MT_POSITION_X && i != ABS_MT_POSITION_Y && i != ABS_MT_SLOT) {
135      EXPECT_EQ(0, uidev->absmax[i]);
136    }
137  }
138  const int32_t width = 1 + uidev->absmax[ABS_MT_POSITION_X];
139  const int32_t height = 1 + uidev->absmax[ABS_MT_POSITION_Y];
140  const int32_t slots = uidev->absmax[ABS_MT_SLOT];
141
142  // Check the system calls performed by initialization.
143  // From ConfigureBegin():
144  expect.Open();
145  // From ConfigureInputProperty(INPUT_PROP_DIRECT):
146  expect.IoctlSetInt(UI_SET_PROPBIT, INPUT_PROP_DIRECT);
147  // From ConfigureMultiTouchXY(0, 0, kWidth - 1, kHeight - 1):
148  expect.IoctlSetInt(UI_SET_EVBIT, EV_ABS);
149  expect.IoctlSetInt(UI_SET_ABSBIT, ABS_MT_POSITION_X);
150  expect.IoctlSetInt(UI_SET_ABSBIT, ABS_MT_POSITION_Y);
151  // From ConfigureAbsSlots(kSlots):
152  expect.IoctlSetInt(UI_SET_ABSBIT, ABS_MT_SLOT);
153  // From ConfigureKey(BTN_TOUCH):
154  expect.IoctlSetInt(UI_SET_EVBIT, EV_KEY);
155  expect.IoctlSetInt(UI_SET_KEYBIT, BTN_TOUCH);
156  // From ConfigureEnd():
157  expect.Write(uidev, sizeof (uinput_user_dev));
158  expect.IoctlVoid(UI_DEV_CREATE);
159  EXPECT_EQ(expect.GetString(), record.GetString());
160
161  expect.Reset();
162  record.Reset();
163  int touch_status = touchpad.Touch(0, 0, 0);
164  EXPECT_EQ(0, touch_status);
165  expect.WriteInputEvent(EV_ABS, ABS_MT_SLOT, 0);
166  expect.WriteInputEvent(EV_ABS, ABS_MT_TRACKING_ID, 0);
167  expect.WriteInputEvent(EV_ABS, ABS_MT_POSITION_X, 0);
168  expect.WriteInputEvent(EV_ABS, ABS_MT_POSITION_Y, 0);
169  expect.WriteInputEvent(EV_SYN, SYN_REPORT, 0);
170  EXPECT_EQ(expect.GetString(), record.GetString());
171
172  expect.Reset();
173  record.Reset();
174  touch_status = touchpad.Touch(0.25f, 0.75f, 0.5f);
175  EXPECT_EQ(0, touch_status);
176  expect.WriteInputEvent(EV_ABS, ABS_MT_TRACKING_ID, 0);
177  expect.WriteInputEvent(EV_ABS, ABS_MT_POSITION_X, 0.25f * width);
178  expect.WriteInputEvent(EV_ABS, ABS_MT_POSITION_Y, 0.75f * height);
179  expect.WriteInputEvent(EV_KEY, BTN_TOUCH, EvdevInjector::KEY_PRESS);
180  expect.WriteInputEvent(EV_SYN, SYN_REPORT, 0);
181  EXPECT_EQ(expect.GetString(), record.GetString());
182
183  expect.Reset();
184  record.Reset();
185  touch_status = touchpad.Touch(1.0f, 1.0f, 1.0f);
186  EXPECT_EQ(0, touch_status);
187  expect.WriteInputEvent(EV_ABS, ABS_MT_TRACKING_ID, 0);
188  expect.WriteInputEvent(EV_ABS, ABS_MT_POSITION_X, width);
189  expect.WriteInputEvent(EV_ABS, ABS_MT_POSITION_Y, height);
190  expect.WriteInputEvent(EV_SYN, SYN_REPORT, 0);
191  EXPECT_EQ(expect.GetString(), record.GetString());
192
193  expect.Reset();
194  record.Reset();
195  touch_status = touchpad.Touch(0.25f, 0.75f, -0.01f);
196  EXPECT_EQ(0, touch_status);
197  expect.WriteInputEvent(EV_KEY, BTN_TOUCH, EvdevInjector::KEY_RELEASE);
198  expect.WriteInputEvent(EV_ABS, ABS_MT_TRACKING_ID, -1);
199  expect.WriteInputEvent(EV_SYN, SYN_REPORT, 0);
200  EXPECT_EQ(expect.GetString(), record.GetString());
201
202  expect.Reset();
203  record.Reset();
204  touch_status = touchpad.ButtonState(AMOTION_EVENT_BUTTON_BACK);
205  EXPECT_EQ(0, touch_status);
206  expect.WriteInputEvent(EV_KEY, BTN_BACK, EvdevInjector::KEY_PRESS);
207  expect.WriteInputEvent(EV_SYN, SYN_REPORT, 0);
208  EXPECT_EQ(expect.GetString(), record.GetString());
209
210  expect.Reset();
211  record.Reset();
212  touch_status = touchpad.ButtonState(AMOTION_EVENT_BUTTON_BACK);
213  EXPECT_EQ(0, touch_status);
214  EXPECT_EQ(expect.GetString(), record.GetString());
215
216  expect.Reset();
217  record.Reset();
218  touch_status = touchpad.ButtonState(0);
219  EXPECT_EQ(0, touch_status);
220  expect.WriteInputEvent(EV_KEY, BTN_BACK, EvdevInjector::KEY_RELEASE);
221  expect.WriteInputEvent(EV_SYN, SYN_REPORT, 0);
222  EXPECT_EQ(expect.GetString(), record.GetString());
223
224  expect.Reset();
225  record.Reset();
226}
227
228TEST_F(VirtualTouchpadTest, Badness) {
229  UInputRecorder expect;
230  UInputRecorder record;
231  EvdevInjectorForTesting injector(record);
232  VirtualTouchpadForTesting touchpad(injector);
233
234  // Touch before initialization should return an error,
235  // and should not result in any system calls.
236  expect.Reset();
237  record.Reset();
238  int touch_status = touchpad.Touch(0.25f, 0.75f, -0.01f);
239  EXPECT_NE(0, touch_status);
240  EXPECT_EQ(expect.GetString(), record.GetString());
241
242  // Button change before initialization should return an error,
243  // and should not result in any system calls.
244  expect.Reset();
245  record.Reset();
246  touch_status = touchpad.ButtonState(AMOTION_EVENT_BUTTON_BACK);
247  EXPECT_NE(0, touch_status);
248  EXPECT_EQ(expect.GetString(), record.GetString());
249
250  expect.Reset();
251  record.Reset();
252  touchpad.Initialize();
253
254  // Repeated initialization should return an error,
255  // and should not result in any system calls.
256  expect.Reset();
257  record.Reset();
258  const int initialization_status = touchpad.Initialize();
259  EXPECT_NE(0, initialization_status);
260  EXPECT_EQ(expect.GetString(), record.GetString());
261
262  // Touch off-screen should return an error,
263  // and should not result in any system calls.
264  expect.Reset();
265  record.Reset();
266  touch_status = touchpad.Touch(-0.25f, 0.75f, 1.0f);
267  EXPECT_NE(0, touch_status);
268  touch_status = touchpad.Touch(0.25f, -0.75f, 1.0f);
269  EXPECT_NE(0, touch_status);
270  touch_status = touchpad.Touch(1.25f, 0.75f, 1.0f);
271  EXPECT_NE(0, touch_status);
272  touch_status = touchpad.Touch(0.25f, 1.75f, 1.0f);
273  EXPECT_NE(0, touch_status);
274  EXPECT_EQ(expect.GetString(), record.GetString());
275
276  // Unsupported button should return an error,
277  // and should not result in any system calls.
278  expect.Reset();
279  record.Reset();
280  touch_status = touchpad.ButtonState(AMOTION_EVENT_BUTTON_FORWARD);
281  EXPECT_NE(0, touch_status);
282  EXPECT_EQ(expect.GetString(), record.GetString());
283}
284
285}  // namespace dvr
286}  // namespace android
287