@@ -0,0 +1,295 @@
2+ * Copyright (C) 2013 Canonical, Ltd.
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.
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.
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/>.
18+#include <QtTest/QtTest>
19+#include <QtCore/QObject>
20+#include <qpa/qwindowsysteminterface.h>
21+#include <QtQuick/QQuickView>
22+#include <QtQml/QQmlEngine>
24+#include <DirectionalDragArea.h>
26+class FakeTimer : public UbuntuGestures::AbstractTimer
30+ FakeTimer(QObject *parent = 0)
31+ : UbuntuGestures::AbstractTimer(parent)
34+ virtual int interval() const { return m_duration; }
35+ virtual void setInterval(int msecs) { m_duration = msecs; }
40+class FakeTimeSource : public UbuntuGestures::TimeSource
43+ FakeTimeSource() { m_msecsSinceReference = 0; }
44+ virtual qint64 msecsSinceReference() {return m_msecsSinceReference;}
45+ qint64 m_msecsSinceReference;
48+class tst_DragHandle: public QObject
52+ tst_DragHandle() : m_device(0) { }
54+ void initTestCase(); // will be called before the first test function is executed
55+ void cleanupTestCase(); // will be called after the last test function was executed.
57+ void init(); // called right before each and every test function is executed
58+ void cleanup(); // called right after each and every test function is executed
60+ void dragThreshold_horizontal();
61+ void dragThreshold_vertical();
64+ void flickAndHold(DirectionalDragArea *dragHandle, qreal distance);
65+ DirectionalDragArea *fetchAndSetupDragHandle(const char *objectName);
66+ qreal fetchDragThreshold(DirectionalDragArea *dragHandle);
67+ void tryCompare(std::function<qreal ()> actualFunc, qreal expectedValue);
69+ QQuickView *createView();
71+ QTouchDevice *m_device;
72+ FakeTimer *m_fakeTimer;
73+ FakeTimeSource *m_fakeTimeSource;
77+void tst_DragHandle::initTestCase()
80+ m_device = new QTouchDevice;
81+ m_device->setType(QTouchDevice::TouchScreen);
82+ QWindowSystemInterface::registerTouchDevice(m_device);
88+void tst_DragHandle::cleanupTestCase()
92+void tst_DragHandle::init()
94+ m_view = createView();
95+ m_view->setSource(QUrl::fromLocalFile(TEST_DIR"/tst_DragHandle.qml"));
97+ QVERIFY(QTest::qWaitForWindowExposed(m_view));
98+ QVERIFY(m_view->rootObject() != 0);
99+ qApp->processEvents();
101+ m_fakeTimer = new FakeTimer;
102+ m_fakeTimeSource = new FakeTimeSource;
105+void tst_DragHandle::cleanup()
113+ delete m_fakeTimeSource;
114+ m_fakeTimeSource = 0;
117+QQuickView *tst_DragHandle::createView()
119+ QQuickView *window = new QQuickView(0);
120+ window->setResizeMode(QQuickView::SizeRootObjectToView);
121+ window->resize(600, 600);
122+ window->engine()->addImportPath(QLatin1String(UBUNTU_GESTURES_PLUGIN_DIR));
123+ window->engine()->addImportPath(QLatin1String(TEST_DIR));
128+void tst_DragHandle::tryCompare(std::function<qreal ()> actualFunc,
129+ qreal expectedValue)
132+ while (actualFunc() != expectedValue && waitCount < 100) {
136+ QCOMPARE(actualFunc(), expectedValue);
140+QPointF calculateDirectionVector(DirectionalDragArea *edgeDragArea)
143+ switch (edgeDragArea->direction()) {
144+ case Direction::Upwards:
145+ return QPointF(0, -1);
146+ case Direction::Downwards:
147+ return QPointF(0, 1);
148+ case Direction::Leftwards:
149+ return QPointF(-1, 0);
150+ default: // Direction::Rightwards:
151+ return QPointF(1, 0);
156+void tst_DragHandle::flickAndHold(DirectionalDragArea *dragHandle,
159+ QPointF initialTouchPos = dragHandle->mapToScene(
160+ QPointF(dragHandle->width() / 2.0, dragHandle->height() / 2.0));
161+ QPointF touchPoint = initialTouchPos;
163+ qint64 flickTimeMs = 500;
164+ qint64 timeStep = flickTimeMs / numSteps;
166+ QPointF dragDirectionVector = calculateDirectionVector(dragHandle);
167+ QPointF touchMovement = dragDirectionVector * (distance / (qreal)numSteps);
169+ QTest::touchEvent(m_view, m_device).press(0, touchPoint.toPoint());
171+ for (int i = 0; i < numSteps; ++i) {
172+ touchPoint += touchMovement;
173+ m_fakeTimeSource->m_msecsSinceReference += timeStep;
174+ QTest::touchEvent(m_view, m_device).move(0, touchPoint.toPoint());
177+ // Wait for quite a bit before finally releasing to make a very low flick/release
179+ m_fakeTimeSource->m_msecsSinceReference += 5000;
180+ QTest::touchEvent(m_view, m_device).release(0, touchPoint.toPoint());
183+DirectionalDragArea *tst_DragHandle::fetchAndSetupDragHandle(const char *objectName)
185+ DirectionalDragArea *dragHandle =
186+ m_view->rootObject()->findChild<DirectionalDragArea*>(objectName);
187+ Q_ASSERT(dragHandle != 0);
188+ dragHandle->setRecognitionTimer(m_fakeTimer);
189+ dragHandle->setTimeSource(m_fakeTimeSource);
191+ AxisVelocityCalculator *edgeDragEvaluator =
192+ dragHandle->findChild<AxisVelocityCalculator*>("edgeDragEvaluator");
193+ Q_ASSERT(edgeDragEvaluator != 0);
194+ edgeDragEvaluator->setTimeSource(m_fakeTimeSource);
199+qreal tst_DragHandle::fetchDragThreshold(DirectionalDragArea *dragHandle)
201+ AxisVelocityCalculator *edgeDragEvaluator =
202+ dragHandle->findChild<AxisVelocityCalculator*>("edgeDragEvaluator");
203+ Q_ASSERT(edgeDragEvaluator != 0);
205+ return edgeDragEvaluator->property("dragThreshold").toReal();
209+ Checks that ending a low-speed drag before dragThreshold results in the
210+ Showable getting back to its original position, whereas ending after dragThreshold
211+ results in Showable continuing until reaching its new states (shown or hidden)
213+void tst_DragHandle::dragThreshold_horizontal()
215+ DirectionalDragArea *dragHandle = fetchAndSetupDragHandle("rightwardsDragHandle");
217+ qreal dragThreshold = fetchDragThreshold(dragHandle);
219+ // end before the threshold
220+ flickAndHold(dragHandle, dragThreshold * 0.7);
223+ QQuickItem *parentItem = dragHandle->parentItem();
224+ tryCompare([&](){ return parentItem->x(); }, -parentItem->width());
225+ QCOMPARE(parentItem->property("shown").toBool(), false);
227+ // end after the threshold
228+ flickAndHold(dragHandle, dragThreshold * 1.2);
230+ // should keep going until completion
231+ tryCompare([&](){ return parentItem->x(); }, 0);
232+ QCOMPARE(parentItem->property("shown").toBool(), true);
234+ dragHandle = fetchAndSetupDragHandle("leftwardsDragHandle");
236+ dragThreshold = fetchDragThreshold(dragHandle);
238+ // end before the threshold
239+ flickAndHold(dragHandle, dragThreshold * 0.7);
242+ tryCompare([&](){ return parentItem->x(); }, 0);
243+ QCOMPARE(parentItem->property("shown").toBool(), true);
245+ // end after the threshold
246+ flickAndHold(dragHandle, dragThreshold * 1.2);
248+ // should keep going until completion
249+ tryCompare([&](){ return parentItem->x(); }, -parentItem->width());
250+ QCOMPARE(parentItem->property("shown").toBool(), false);
253+void tst_DragHandle::dragThreshold_vertical()
255+ DirectionalDragArea *dragHandle = fetchAndSetupDragHandle("downwardsDragHandle");
257+ qreal dragThreshold = fetchDragThreshold(dragHandle);
259+ // end before the threshold
260+ flickAndHold(dragHandle, dragThreshold * 0.7);
263+ QQuickItem *parentItem = dragHandle->parentItem();
264+ tryCompare([&](){ return parentItem->y(); }, -parentItem->height());
265+ QCOMPARE(parentItem->property("shown").toBool(), false);
267+ // end after the threshold
268+ flickAndHold(dragHandle, dragThreshold * 1.2);
270+ // should keep going until completion
271+ tryCompare([&](){ return parentItem->y(); }, 0);
272+ QCOMPARE(parentItem->property("shown").toBool(), true);
274+ dragHandle = fetchAndSetupDragHandle("upwardsDragHandle");
276+ dragThreshold = fetchDragThreshold(dragHandle);
278+ // end before the threshold
279+ flickAndHold(dragHandle, dragThreshold * 0.7);
282+ tryCompare([&](){ return parentItem->y(); }, 0);
283+ QCOMPARE(parentItem->property("shown").toBool(), true);
285+ // end after the threshold
286+ flickAndHold(dragHandle, dragThreshold * 1.2);
288+ // should keep going until completion
289+ tryCompare([&](){ return parentItem->y(); }, -parentItem->height());
290+ QCOMPARE(parentItem->property("shown").toBool(), false);
293+QTEST_MAIN(tst_DragHandle)
295+#include "tst_DragHandle.moc"