9064d247b0d029487b21134b83f4a6556812bde1
[profile/ivi/qtdeclarative.git] / tests / auto / declarative / qdeclarativeaccessibility / tst_qdeclarativeaccessibility.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 **
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 **
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
29 **
30 ** Other Usage
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42
43 #include <QtTest/QtTest>
44 #include "QtTest/qtestaccessible.h"
45
46 #include <QtGui/qaccessible.h>
47
48 #include <QtQuick1/qdeclarativeview.h>
49 #include <QtQuick/qquickview.h>
50 #include <QtQuick/qquickitem.h>
51
52 #include <QtDeclarative/qdeclarativeengine.h>
53 #include <QtDeclarative/qdeclarativeproperty.h>
54 #include <private/qdeclarativeaccessibleattached_p.h>
55
56 #include "../../shared/util.h"
57
58
59 typedef QSharedPointer<QAccessibleInterface> QAI;
60
61
62 static inline bool verifyChild(QWidget *child, QAccessibleInterface *iface,
63                                int index, const QRect &domain)
64 {
65     if (!child) {
66         qWarning("tst_QAccessibility::verifyChild: null pointer to child.");
67         return false;
68     }
69
70     if (!iface) {
71         qWarning("tst_QAccessibility::verifyChild: null pointer to interface.");
72         return false;
73     }
74
75     // Verify that we get a valid QAccessibleInterface for the child.
76     QAccessibleInterface *childInterface = QAccessible::queryAccessibleInterface(child);
77     if (!childInterface) {
78         qWarning("tst_QAccessibility::verifyChild: Failed to retrieve interface for child.");
79         return false;
80     }
81
82     // QAccessibleInterface::indexOfChild():
83     // Verify that indexOfChild() returns an index equal to the index passed in
84     int indexFromIndexOfChild = iface->indexOfChild(childInterface);
85     delete childInterface;
86     if (indexFromIndexOfChild != index) {
87         qWarning("tst_QAccessibility::verifyChild (indexOfChild()):");
88         qWarning() << "Expected:" << index;
89         qWarning() << "Actual:  " << indexFromIndexOfChild;
90         return false;
91     }
92
93     // Navigate to child, compare its object and role with the interface from queryAccessibleInterface(child).
94     QAccessibleInterface *navigatedChildInterface = iface->child(index - 1);
95     if (navigatedChildInterface == 0)
96         return false;
97
98     const QRect rectFromInterface = navigatedChildInterface->rect();
99     delete navigatedChildInterface;
100
101     // QAccessibleInterface::childAt():
102     // Calculate global child position and check that the interface
103     // returns the correct index for that position.
104     QPoint globalChildPos = child->mapToGlobal(QPoint(0, 0));
105     QAccessibleInterface *childAtInterface = iface->childAt(globalChildPos.x(), globalChildPos.y());
106     if (!childAtInterface) {
107         qWarning("tst_QAccessibility::verifyChild (childAt()):");
108         qWarning() << "Expected:" << childInterface;
109         qWarning() << "Actual:  no child";
110         return false;
111     }
112     if (childAtInterface->object() != childInterface->object()) {
113         qWarning("tst_QAccessibility::verifyChild (childAt()):");
114         qWarning() << "Expected:" << childInterface;
115         qWarning() << "Actual:  " << childAtInterface;
116         return false;
117     }
118     delete childInterface;
119     delete childAtInterface;
120
121     // Verify that the child is within its domain.
122     if (!domain.contains(rectFromInterface)) {
123         qWarning("tst_QAccessibility::verifyChild: Child is not within its domain.");
124         return false;
125     }
126
127     return true;
128 }
129
130 static inline int indexOfChild(QAccessibleInterface *parentInterface, QWidget *childWidget)
131 {
132     if (!parentInterface || !childWidget)
133         return -1;
134     QAccessibleInterface *childInterface = QAccessible::queryAccessibleInterface(childWidget);
135     if (!childInterface)
136         return -1;
137     int index = parentInterface->indexOfChild(childInterface);
138     delete childInterface;
139     return index;
140 }
141
142 #define EXPECT(cond) \
143     do { \
144         if (!errorAt && !(cond)) { \
145             errorAt = __LINE__; \
146             qWarning("level: %d, middle: %d, role: %d (%s)", treelevel, middle, iface->role(), #cond); \
147         } \
148     } while (0)
149
150 static int verifyHierarchy(QAccessibleInterface *iface)
151 {
152     int errorAt = 0;
153     static int treelevel = 0;   // for error diagnostics
154     QAccessibleInterface *middleChild, *if2;
155     middleChild = 0;
156     ++treelevel;
157     int middle = iface->childCount()/2 + 1;
158     if (iface->childCount() >= 2) {
159         middleChild = iface->child(middle - 1);
160     }
161     for (int i = 0; i < iface->childCount() && !errorAt; ++i) {
162         if2 = iface->child(i);
163         EXPECT(if2 != 0);
164         // navigate Ancestor...
165         QAccessibleInterface *parent = if2->parent();
166         EXPECT(iface->object() == parent->object());
167         delete parent;
168
169             // navigate Sibling...
170 //            if (middleChild) {
171 //                entry = if2->navigate(QAccessible::Sibling, middle, &if3);
172 //                EXPECT(entry == 0 && if3->object() == middleChild->object());
173 //                if (entry == 0)
174 //                    delete if3;
175 //                EXPECT(iface->indexOfChild(middleChild) == middle);
176 //            }
177
178         // verify children...
179         if (!errorAt)
180             errorAt = verifyHierarchy(if2);
181         delete if2;
182     }
183     delete middleChild;
184
185     --treelevel;
186     return errorAt;
187 }
188
189
190 //TESTED_FILES=
191
192 class tst_QDeclarativeAccessibility : public QDeclarativeDataTest
193 {
194     Q_OBJECT
195 public:
196     tst_QDeclarativeAccessibility();
197     virtual ~tst_QDeclarativeAccessibility();
198
199 private slots:
200     void commonTests_data();
201     void commonTests();
202
203     void declarativeAttachedProperties();
204     void basicPropertiesTest();
205     void hitTest();
206 };
207
208 tst_QDeclarativeAccessibility::tst_QDeclarativeAccessibility()
209 {
210
211 }
212
213 tst_QDeclarativeAccessibility::~tst_QDeclarativeAccessibility()
214 {
215
216 }
217
218 void tst_QDeclarativeAccessibility::commonTests_data()
219 {
220     QTest::addColumn<QString>("accessibleRoleFileName");
221
222     QTest::newRow("StaticText") << SRCDIR "/data/statictext.qml";
223     QTest::newRow("PushButton") << SRCDIR "/data/pushbutton.qml";
224 }
225
226 void tst_QDeclarativeAccessibility::commonTests()
227 {
228     QFETCH(QString, accessibleRoleFileName);
229
230     qDebug() << "testing" << accessibleRoleFileName;
231
232     QQuickView *view = new QQuickView();
233 //    view->setFixedSize(240,320);
234     view->setSource(QUrl::fromLocalFile(accessibleRoleFileName));
235     view->show();
236 //    view->setFocus();
237     QVERIFY(view->rootObject() != 0);
238
239     QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(view);
240     QVERIFY(iface);
241
242     delete iface;
243     delete view;
244 }
245
246
247
248 QString eventName(const int ev)
249 {
250     switch (ev) {
251     case 0x0001: return "SoundPlayed";
252     case 0x0002: return "Alert";
253     case 0x0003: return "ForegroundChanged";
254     case 0x0004: return "MenuStart";
255     case 0x0005: return "MenuEnd";
256     case 0x0006: return "PopupMenuStart";
257     case 0x0007: return "PopupMenuEnd";
258     case 0x000C: return "ContextHelpStart";
259     case 0x000D: return "ContextHelpEnd";
260     case 0x000E: return "DragDropStart";
261     case 0x000F: return "DragDropEnd";
262     case 0x0010: return "DialogStart";
263     case 0x0011: return "DialogEnd";
264     case 0x0012: return "ScrollingStart";
265     case 0x0013: return "ScrollingEnd";
266     case 0x0018: return "MenuCommand";
267     case 0x8000: return "ObjectCreated";
268     case 0x8001: return "ObjectDestroyed";
269     case 0x8002: return "ObjectShow";
270     case 0x8003: return "ObjectHide";
271     case 0x8004: return "ObjectReorder";
272     case 0x8005: return "Focus";
273     case 0x8006: return "Selection";
274     case 0x8007: return "SelectionAdd";
275     case 0x8008: return "SelectionRemove";
276     case 0x8009: return "SelectionWithin";
277     case 0x800A: return "StateChanged";
278     case 0x800B: return "LocationChanged";
279     case 0x800C: return "NameChanged";
280     case 0x800D: return "DescriptionChanged";
281     case 0x800E: return "ValueChanged";
282     case 0x800F: return "ParentChanged";
283     case 0x80A0: return "HelpChanged";
284     case 0x80B0: return "DefaultActionChanged";
285     case 0x80C0: return "AcceleratorChanged";
286     default: return "Unknown Event";
287     }
288 }
289
290 static QString stateNames(int state)
291 {
292     QString stateString;
293     if (state == 0x00000000) stateString += " Normal";
294     if (state & 0x00000001) stateString += " Unavailable";
295     if (state & 0x00000002) stateString += " Selected";
296     if (state & 0x00000004) stateString += " Focused";
297     if (state & 0x00000008) stateString += " Pressed";
298     if (state & 0x00000010) stateString += " Checked";
299     if (state & 0x00000020) stateString += " Mixed";
300     if (state & 0x00000040) stateString += " ReadOnly";
301     if (state & 0x00000080) stateString += " HotTracked";
302     if (state & 0x00000100) stateString += " DefaultButton";
303     if (state & 0x00000200) stateString += " Expanded";
304     if (state & 0x00000400) stateString += " Collapsed";
305     if (state & 0x00000800) stateString += " Busy";
306     if (state & 0x00001000) stateString += " Floating";
307     if (state & 0x00002000) stateString += " Marqueed";
308     if (state & 0x00004000) stateString += " Animated";
309     if (state & 0x00008000) stateString += " Invisible";
310     if (state & 0x00010000) stateString += " Offscreen";
311     if (state & 0x00020000) stateString += " Sizeable";
312     if (state & 0x00040000) stateString += " Moveable";
313     if (state & 0x00080000) stateString += " SelfVoicing";
314     if (state & 0x00100000) stateString += " Focusable";
315     if (state & 0x00200000) stateString += " Selectable";
316     if (state & 0x00400000) stateString += " Linked";
317     if (state & 0x00800000) stateString += " Traversed";
318     if (state & 0x01000000) stateString += " MultiSelectable";
319     if (state & 0x02000000) stateString += " ExtSelectable";
320     if (state & 0x04000000) stateString += " AlertLow";
321     if (state & 0x08000000) stateString += " AlertMedium";
322     if (state & 0x10000000) stateString += " AlertHigh";
323     if (state & 0x20000000) stateString += " Protected";
324     if (state & 0x3fffffff) stateString += " Valid";
325
326     if (stateString.isEmpty())
327         stateString = "Unknown state " + QString::number(state);
328
329     return stateString;
330 }
331
332 void tst_QDeclarativeAccessibility::declarativeAttachedProperties()
333 {
334     {
335         QDeclarativeEngine engine;
336         QDeclarativeComponent component(&engine);
337         component.setData("import QtQuick 1.1\nItem {\n"
338                                 "}", QUrl());
339         QObject *object = component.create();
340         QVERIFY(object != 0);
341
342         QObject *attachedObject = QDeclarativeAccessibleAttached::attachedProperties(object);
343         QCOMPARE(attachedObject, static_cast<QObject*>(0));
344         delete object;
345     }
346
347     // Attached property
348     {
349         QObject parent;
350         QDeclarativeAccessibleAttached *attachedObj = new QDeclarativeAccessibleAttached(&parent);
351
352         attachedObj->name();
353
354         QVariant pp = attachedObj->property("name");
355         QDeclarativeEngine engine;
356         QDeclarativeComponent component(&engine);
357         component.setData("import QtQuick 1.1\nItem {\n"
358                                 "Accessible.role: Accessible.Button\n"
359                                 "}", QUrl());
360         QObject *object = component.create();
361         QVERIFY(object != 0);
362
363         QObject *attachedObject = QDeclarativeAccessibleAttached::attachedProperties(object);
364         QVERIFY(attachedObject);
365         if (attachedObject) {
366             QVariant p = attachedObject->property("role");
367             QCOMPARE(p.isNull(), false);
368             QCOMPARE(p.toInt(), int(QAccessible::PushButton));
369             p = attachedObject->property("name");
370             QCOMPARE(p.isNull(), true);
371             p = attachedObject->property("description");
372             QCOMPARE(p.isNull(), true);
373         }
374         delete object;
375     }
376
377     // Attached property
378     {
379         QDeclarativeEngine engine;
380         QDeclarativeComponent component(&engine);
381         component.setData("import QtQuick 1.1\nItem {\n"
382                                 "Accessible.role: Accessible.Button\n"
383                                 "Accessible.name: \"Donald\"\n"
384                                 "Accessible.description: \"Duck\"\n"
385                                 "}", QUrl());
386         QObject *object = component.create();
387         QVERIFY(object != 0);
388
389         QObject *attachedObject = QDeclarativeAccessibleAttached::attachedProperties(object);
390         QVERIFY(attachedObject);
391         if (attachedObject) {
392             QVariant p = attachedObject->property("role");
393             QCOMPARE(p.isNull(), false);
394             QCOMPARE(p.toInt(), int(QAccessible::PushButton));
395             p = attachedObject->property("name");
396             QCOMPARE(p.isNull(), false);
397             QCOMPARE(p.toString(), QLatin1String("Donald"));
398             p = attachedObject->property("description");
399             QCOMPARE(p.isNull(), false);
400             QCOMPARE(p.toString(), QLatin1String("Duck"));
401         }
402         delete object;
403     }
404 }
405
406
407 void tst_QDeclarativeAccessibility::basicPropertiesTest()
408 {
409     QAI app = QAI(QAccessible::queryAccessibleInterface(qApp));
410     QCOMPARE(app->childCount(), 0);
411
412     QQuickView *canvas = new QQuickView();
413     canvas->setSource(testFileUrl("statictext.qml"));
414     canvas->show();
415     QCOMPARE(app->childCount(), 1);
416
417     QAI iface = QAI(QAccessible::queryAccessibleInterface(canvas));
418     QVERIFY(iface.data());
419     QCOMPARE(iface->childCount(), 1);
420
421     QAI item = QAI(iface->child(0));
422     QVERIFY(item.data());
423     QCOMPARE(item->childCount(), 2);
424     QCOMPARE(item->rect().size(), QSize(400, 400));
425     QCOMPARE(item->role(), QAccessible::Pane);
426
427     QAI text = QAI(item->child(0));
428     QVERIFY(text.data());
429     QCOMPARE(text->childCount(), 0);
430
431     QCOMPARE(text->text(QAccessible::Name), QLatin1String("Hello Accessibility"));
432     QCOMPARE(text->rect().size(), QSize(200, 50));
433     QCOMPARE(text->rect().x(), item->rect().x() + 100);
434     QCOMPARE(text->rect().y(), item->rect().y() + 20);
435     QCOMPARE(text->role(), QAccessible::StaticText);
436
437     QAI text2 = QAI(item->child(1));
438     QVERIFY(text2.data());
439     QCOMPARE(text2->childCount(), 0);
440
441     QCOMPARE(text2->text(QAccessible::Name), QLatin1String("The Hello 2 accessible text"));
442     QCOMPARE(text2->rect().size(), QSize(100, 40));
443     QCOMPARE(text2->rect().x(), item->rect().x() + 100);
444     QCOMPARE(text2->rect().y(), item->rect().y() + 40);
445     QCOMPARE(text2->role(), QAccessible::StaticText);
446
447     delete canvas;
448 }
449
450 QAI topLevelChildAt(QAccessibleInterface *iface, int x, int y)
451 {
452     QAI child = QAI(iface->childAt(x, y));
453     if (!child)
454         return QAI();
455
456     QAI childOfChild;
457     while (childOfChild = QAI(child->childAt(x, y))) {
458         child = childOfChild;
459     }
460     return child;
461 }
462
463 void tst_QDeclarativeAccessibility::hitTest()
464 {
465     QQuickView *canvas = new QQuickView();
466     canvas->setSource(testFileUrl("statictext.qml"));
467     canvas->show();
468
469     QAI iface = QAI(QAccessible::queryAccessibleInterface(canvas));
470     QVERIFY(iface.data());
471     QAI item = QAI(iface->child(0));
472     QRect itemRect = item->rect();
473
474     // hit the root item
475     QAI itemHit = QAI(iface->childAt(itemRect.x() + 5, itemRect.y() + 5));
476     QVERIFY(itemHit);
477     QCOMPARE(itemRect, itemHit->rect());
478
479     // hit a text element
480     QAI textChild = QAI(item->child(0));
481     QAI textChildHit = topLevelChildAt(iface.data(), itemRect.x() + 105, itemRect.y() + 25);
482     QVERIFY(textChildHit);
483     QCOMPARE(textChild->rect(), textChildHit->rect());
484     QCOMPARE(textChildHit->text(QAccessible::Name), QLatin1String("Hello Accessibility"));
485
486     // should also work from top level (app)
487     QAI app = QAI(QAccessible::queryAccessibleInterface(qApp));
488     QAI textChildHit2 = topLevelChildAt(app.data(), itemRect.x() + 105, itemRect.y() + 25);
489     QVERIFY(textChildHit2);
490     QCOMPARE(textChild->rect(), textChildHit2->rect());
491     QCOMPARE(textChildHit2->text(QAccessible::Name), QLatin1String("Hello Accessibility"));
492
493     delete canvas;
494 }
495 QTEST_MAIN(tst_QDeclarativeAccessibility)
496
497 #include "tst_qdeclarativeaccessibility.moc"