on cd74009 help sign in
unity8/tests/plugins/Utils/WindowInputMonitorTest.cpp
364 lines 9.8 kB history raw
1/*
2 * Copyright (C) 2015-2016 Canonical, Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
17#include "WindowInputMonitor.h"
19#include <QTest>
20#include <QSignalSpy>
23namespace UnityUtil {
24class FakeElapsedTimer : public AbstractElapsedTimer {
25public:
26 static qint64 msecsSinceEpoch;
28 FakeElapsedTimer() { start(); }
30 void start() override { m_msecsSinceReference = msecsSinceEpoch; }
31 qint64 msecsSinceReference() const override { return m_msecsSinceReference; }
32 qint64 elapsed() const override { return msecsSinceEpoch - m_msecsSinceReference; }
34private:
35 qint64 m_msecsSinceReference;
36};
37qint64 FakeElapsedTimer::msecsSinceEpoch = 0;
39class FakeTimer : public AbstractTimer
41 Q_OBJECT
42public:
43 FakeTimer(QObject *parent = nullptr);
45 void update();
46 qint64 nextTimeoutTime() const { return m_nextTimeoutTime; }
48 int interval() const override;
49 void setInterval(int msecs) override;
50 void start() override;
51 bool isSingleShot() const override;
52 void setSingleShot(bool value) override;
53private:
54 int m_interval;
55 bool m_singleShot;
56 qint64 m_nextTimeoutTime;
57};
59class FakeTimerFactory : public AbstractTimerFactory
61public:
62 FakeTimerFactory();
63 virtual ~FakeTimerFactory();
65 void updateTime(qint64 targetTime);
67 AbstractTimer *create(QObject *parent = nullptr) override;
68 QList<QPointer<FakeTimer>> timers;
69};
70} // namespace UnityUtil
72using namespace UnityUtil;
74Q_DECLARE_METATYPE(Qt::Key) // because of QTest::addColumn<Qt::Key>
76class WindowInputMonitorTest : public QObject {
77 Q_OBJECT
78private Q_SLOTS:
79 void init(); // called right before each and every test function is executed
80 void cleanup(); // called right after each and every test function is executed
82 void touchTapTouch_data();
83 void touchTapTouch();
85 void tapWhileTouching();
86 void multipleHomeKeys();
88private:
89 void passTime(qint64 timeSpanMs);
91 FakeTimerFactory *m_fakeTimerFactory;
92};
94void WindowInputMonitorTest::init()
96 m_fakeTimerFactory = new FakeTimerFactory;
99void WindowInputMonitorTest::cleanup()
101 delete m_fakeTimerFactory;
102 m_fakeTimerFactory = nullptr;
106void WindowInputMonitorTest::passTime(qint64 timeSpanMs)
108 qint64 finalTime = FakeElapsedTimer::msecsSinceEpoch + timeSpanMs;
109 m_fakeTimerFactory->updateTime(finalTime);
112void WindowInputMonitorTest::touchTapTouch_data()
114 QTest::addColumn<int>("silenceBeforeTap");
115 QTest::addColumn<int>("tapDuration");
116 QTest::addColumn<int>("silenceAfterTap");
117 QTest::addColumn<int>("expectedActivatedCount");
118 QTest::addColumn<Qt::Key>("key");
120 QTest::newRow("tap followed by touch") << 2000 << 50 << 10 << 0 << Qt::Key_Super_L;
121 QTest::newRow("touch, tap and touch") << 10 << 50 << 10 << 0 << Qt::Key_Super_L;
122 QTest::newRow("touch followed by tap") << 10 << 50 << 2000 << 0 << Qt::Key_Super_L;
123 QTest::newRow("touch followed by long tap") << 10 << 500 << 2000 << 0 << Qt::Key_Super_L;
124 QTest::newRow("isolated tap, Super_L") << 1000 << 50 << 1000 << 1 << Qt::Key_Super_L;
125 QTest::newRow("isolated tap, HomePage") << 1000 << 50 << 1000 << 1 << Qt::Key_HomePage;
126 QTest::newRow("isolated long press") << 1000 << 200 << 1000 << 0 << Qt::Key_Super_L;
129void WindowInputMonitorTest::touchTapTouch()
131 QFETCH(int, silenceBeforeTap);
132 QFETCH(int, tapDuration);
133 QFETCH(int, silenceAfterTap);
134 QFETCH(int, expectedActivatedCount);
135 QFETCH(Qt::Key, key);
136 WindowInputMonitor homeKeyWatcher(m_fakeTimerFactory->create(), new FakeElapsedTimer);
137 QSignalSpy activatedSpy(&homeKeyWatcher, &WindowInputMonitor::homeKeyActivated);
138 QVERIFY(activatedSpy.isValid());
140 {
141 QTouchEvent touchEvent(QEvent::TouchBegin);
142 homeKeyWatcher.update(&touchEvent);
143 }
144 passTime(100);
145 {
146 QTouchEvent touchEvent(QEvent::TouchUpdate);
147 homeKeyWatcher.update(&touchEvent);
148 }
149 passTime(100);
150 {
151 QTouchEvent touchEvent(QEvent::TouchEnd);
152 homeKeyWatcher.update(&touchEvent);
153 }
155 passTime(silenceBeforeTap);
157 {
158 QKeyEvent keyEvent(QEvent::KeyPress, key, Qt::NoModifier);
159 homeKeyWatcher.update(&keyEvent);
160 }
161 int tapTime = 0;
162 while (tapTime < tapDuration) {
163 passTime(10);
164 tapTime += 10;
165 if (tapTime + 10 >= tapDuration) {
166 QKeyEvent keyEvent(QEvent::KeyRelease, key, Qt::NoModifier);
167 homeKeyWatcher.update(&keyEvent);
168 } else {
169 QKeyEvent keyEvent(QEvent::KeyPress, key, Qt::NoModifier, QString(), true /*autorepeat*/);
170 homeKeyWatcher.update(&keyEvent);
171 }
172 }
174 passTime(silenceAfterTap);
176 {
177 QTouchEvent touchEvent(QEvent::TouchBegin);
178 homeKeyWatcher.update(&touchEvent);
179 }
180 passTime(100);
181 {
182 QTouchEvent touchEvent(QEvent::TouchUpdate);
183 homeKeyWatcher.update(&touchEvent);
184 }
185 passTime(100);
186 {
187 QTouchEvent touchEvent(QEvent::TouchEnd);
188 homeKeyWatcher.update(&touchEvent);
189 }
190 passTime(1000);
192 QCOMPARE(activatedSpy.count(), expectedActivatedCount);
195void WindowInputMonitorTest::tapWhileTouching()
197 WindowInputMonitor homeKeyWatcher(m_fakeTimerFactory->create(), new FakeElapsedTimer);
198 QSignalSpy activatedSpy(&homeKeyWatcher, &WindowInputMonitor::homeKeyActivated);
199 QVERIFY(activatedSpy.isValid());
201 {
202 QTouchEvent touchEvent(QEvent::TouchBegin);
203 homeKeyWatcher.update(&touchEvent);
204 }
205 passTime(1000);
206 {
207 QKeyEvent keyEvent(QEvent::KeyPress, Qt::Key_Super_L, Qt::NoModifier);
208 homeKeyWatcher.update(&keyEvent);
209 }
210 passTime(100);
211 {
212 QKeyEvent keyEvent(QEvent::KeyRelease, Qt::Key_Super_L, Qt::NoModifier);
213 homeKeyWatcher.update(&keyEvent);
214 }
215 passTime(1000);
216 {
217 QTouchEvent touchEvent(QEvent::TouchEnd);
218 homeKeyWatcher.update(&touchEvent);
219 }
220 passTime(1000);
223 QCOMPARE(activatedSpy.count(), 0);
226/*
227 Press multiple of the mapped home keys roughly at the same time.
228 The first pressed will be recognized and the other ignored
229 */
230void WindowInputMonitorTest::multipleHomeKeys()
232 WindowInputMonitor homeKeyWatcher(m_fakeTimerFactory->create(), new FakeElapsedTimer);
233 QSignalSpy activatedSpy(&homeKeyWatcher, &WindowInputMonitor::homeKeyActivated);
234 QVERIFY(activatedSpy.isValid());
236 passTime(1000);
237 {
238 QKeyEvent keyEvent(QEvent::KeyPress, Qt::Key_HomePage, Qt::NoModifier);
239 homeKeyWatcher.update(&keyEvent);
240 }
241 passTime(50);
242 {
243 QKeyEvent keyEvent(QEvent::KeyPress, Qt::Key_Super_L, Qt::NoModifier);
244 homeKeyWatcher.update(&keyEvent);
245 }
246 passTime(50);
247 {
248 QKeyEvent keyEvent(QEvent::KeyRelease, Qt::Key_HomePage, Qt::NoModifier);
249 homeKeyWatcher.update(&keyEvent);
250 }
251 passTime(10);
252 {
253 QKeyEvent keyEvent(QEvent::KeyRelease, Qt::Key_Super_L, Qt::NoModifier);
254 homeKeyWatcher.update(&keyEvent);
255 }
256 passTime(1000);
258 QCOMPARE(activatedSpy.count(), 1);
261/////////////////////////////////// FakeTimer //////////////////////////////////
263FakeTimer::FakeTimer(QObject *parent)
264 : UnityUtil::AbstractTimer(parent)
265 , m_interval(0)
266 , m_singleShot(true)
270void FakeTimer::update()
272 if (!isRunning()) {
273 return;
274 }
276 if (m_nextTimeoutTime <= FakeElapsedTimer::msecsSinceEpoch) {
277 if (isSingleShot()) {
278 stop();
279 } else {
280 m_nextTimeoutTime += interval();
281 }
282 Q_EMIT timeout();
283 }
286void FakeTimer::start()
288 AbstractTimer::start();
289 m_nextTimeoutTime = FakeElapsedTimer::msecsSinceEpoch + (qint64)interval();
292int FakeTimer::interval() const
294 return m_interval;
297void FakeTimer::setInterval(int msecs)
299 m_interval = msecs;
302bool FakeTimer::isSingleShot() const
304 return m_singleShot;
307void FakeTimer::setSingleShot(bool value)
309 m_singleShot = value;
312/////////////////////////////////// FakeTimerFactory //////////////////////////////////
314FakeTimerFactory::FakeTimerFactory()
318FakeTimerFactory::~FakeTimerFactory()
320 for (int i = 0; i < timers.count(); ++i) {
321 FakeTimer *timer = timers[i].data();
322 if (timer) {
323 delete timer;
324 }
325 }
328void FakeTimerFactory::updateTime(qint64 targetTime)
330 qint64 minTimeoutTime = targetTime;
332 for (int i = 0; i < timers.count(); ++i) {
333 FakeTimer *timer = timers[i].data();
334 if (timer && timer->isRunning() && timer->nextTimeoutTime() < minTimeoutTime) {
335 minTimeoutTime = timer->nextTimeoutTime();
336 }
337 }
339 FakeElapsedTimer::msecsSinceEpoch = minTimeoutTime;
341 for (int i = 0; i < timers.count(); ++i) {
342 FakeTimer *timer = timers[i].data();
343 if (timer) {
344 timer->update();
345 }
346 }
348 if (FakeElapsedTimer::msecsSinceEpoch < targetTime) {
349 updateTime(targetTime);
350 }
353AbstractTimer *FakeTimerFactory::create(QObject *parent)
355 FakeTimer *fakeTimer = new FakeTimer(parent);
357 timers.append(fakeTimer);
359 return fakeTimer;
362QTEST_GUILESS_MAIN(WindowInputMonitorTest)
364#include "WindowInputMonitorTest.moc"