diff options
Diffstat (limited to 'tests/auto/quick/qquickaccessible/tst_qquickaccessible.cpp')
-rw-r--r-- | tests/auto/quick/qquickaccessible/tst_qquickaccessible.cpp | 195 |
1 files changed, 129 insertions, 66 deletions
diff --git a/tests/auto/quick/qquickaccessible/tst_qquickaccessible.cpp b/tests/auto/quick/qquickaccessible/tst_qquickaccessible.cpp index 4c192374ee..e164d89217 100644 --- a/tests/auto/quick/qquickaccessible/tst_qquickaccessible.cpp +++ b/tests/auto/quick/qquickaccessible/tst_qquickaccessible.cpp @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtQml module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include <QtTest/QtTest> @@ -44,9 +19,14 @@ #include <QtQuick/private/qquickaccessibleattached_p.h> #include <QtQuick/private/qquicklistview_p.h> #include <QtQuick/private/qquicktext_p.h> +#include <QtQuick/private/qquicktextinput_p.h> -#include "../../shared/util.h" -#include "../shared/visualtestutil.h" +#include <QtQuickTestUtils/private/qmlutils_p.h> +#include <QtQuickTestUtils/private/visualtestutils_p.h> + +#include <QQmlComponent> + +using namespace Qt::StringLiterals; #define EXPECT(cond) \ do { \ @@ -69,7 +49,7 @@ public: public slots: void initTestCase() override; void cleanupTestCase(); - void init(); + void init() override; void cleanup(); private slots: @@ -77,13 +57,16 @@ private slots: void commonTests(); void quickAttachedProperties(); + void attachedWins(); void basicPropertiesTest(); void hitTest(); void checkableTest(); void ignoredTest(); + void passwordTest(); }; tst_QQuickAccessible::tst_QQuickAccessible() + : QQmlDataTest(QT_QMLTEST_DATADIR) { } @@ -110,6 +93,7 @@ void tst_QQuickAccessible::cleanupTestCase() void tst_QQuickAccessible::init() { + QQmlDataTest::init(); QTestAccessibility::clearEvents(); } @@ -117,13 +101,17 @@ void tst_QQuickAccessible::cleanup() { const EventList list = QTestAccessibility::events(); if (!list.isEmpty()) { - qWarning().noquote() << list.count() + qWarning().noquote() << list.size() << "accessibility event(s) were not handled in testfunction '" << QTest::currentTestFunction() << "':"; - for (int i = 0; i < list.count(); ++i) - qWarning().noquote() << " " << (i + 1) << ": Object: " << list.at(i)->object() + for (int i = 0; i < list.size(); ++i) { + auto object = list.at(i)->object(); + QString objectInfo = object ? QDebug::toString(object) + : u"[deleted object]"_s; + qWarning().noquote() << " " << (i + 1) << objectInfo << "Event: '" << qAccessibleEventString(list.at(i)->type()) << "' Child: " << list.at(i)->child(); + } } QTestAccessibility::clearEvents(); } @@ -142,17 +130,17 @@ void tst_QQuickAccessible::commonTests() qDebug() << "testing" << accessibleRoleFileName; - QQuickView *view = new QQuickView(); + auto view = std::make_unique<QQuickView>(); // view->setFixedSize(240,320); view->setSource(testFileUrl(accessibleRoleFileName)); view->show(); // view->setFocus(); QVERIFY(view->rootObject() != nullptr); - QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(view); + QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(view.get()); QVERIFY(iface); - delete view; + view.reset(); QTestAccessibility::clearEvents(); } @@ -163,12 +151,11 @@ void tst_QQuickAccessible::quickAttachedProperties() QQmlComponent component(&engine); component.setData("import QtQuick 2.0\nItem {\n" "}", QUrl()); - QObject *object = component.create(); + auto object = std::unique_ptr<QObject>(component.create()); QVERIFY(object != nullptr); - QObject *attachedObject = QQuickAccessibleAttached::attachedProperties(object); + QObject *attachedObject = QQuickAccessibleAttached::attachedProperties(object.get()); QCOMPARE(attachedObject, static_cast<QObject*>(nullptr)); - delete object; } // Attaching to non-item @@ -197,11 +184,11 @@ void tst_QQuickAccessible::quickAttachedProperties() component.setData("import QtQuick 2.0\nItem {\n" "Accessible.role: Accessible.Button\n" "}", QUrl()); - QObject *object = component.create(); + auto object = std::unique_ptr<QObject>(component.create()); QVERIFY(object != nullptr); const auto attachedObject = qobject_cast<QQuickAccessibleAttached*>( - QQuickAccessibleAttached::attachedProperties(object)); + QQuickAccessibleAttached::attachedProperties(object.get())); QVERIFY(attachedObject); if (attachedObject) { QVariant p = attachedObject->property("role"); @@ -215,7 +202,6 @@ void tst_QQuickAccessible::quickAttachedProperties() QVERIFY2(p.value<QString>().isEmpty(), QTest::toString(p)); QCOMPARE(attachedObject->wasNameExplicitlySet(), false); } - delete object; } // Attached property @@ -227,11 +213,11 @@ void tst_QQuickAccessible::quickAttachedProperties() "Accessible.name: \"Donald\"\n" "Accessible.description: \"Duck\"\n" "}", QUrl()); - QObject *object = component.create(); + auto object = std::unique_ptr<QObject>(component.create()); QVERIFY(object != nullptr); const auto attachedObject = qobject_cast<QQuickAccessibleAttached*>( - QQuickAccessibleAttached::attachedProperties(object)); + QQuickAccessibleAttached::attachedProperties(object.get())); QVERIFY(attachedObject); if (attachedObject) { QVariant p = attachedObject->property("role"); @@ -245,7 +231,6 @@ void tst_QQuickAccessible::quickAttachedProperties() QCOMPARE(p.toString(), QLatin1String("Duck")); QCOMPARE(attachedObject->wasNameExplicitlySet(), true); } - delete object; } // Check overriding of attached role for Text @@ -257,10 +242,10 @@ void tst_QQuickAccessible::quickAttachedProperties() "Accessible.name: \"TextButton\"\n" "Accessible.description: \"Text Button\"\n" "}", QUrl()); - QObject *object = component.create(); + auto object = std::unique_ptr<QObject>(component.create()); QVERIFY(object != nullptr); - QObject *attachedObject = QQuickAccessibleAttached::attachedProperties(object); + QObject *attachedObject = QQuickAccessibleAttached::attachedProperties(object.get()); QVERIFY(attachedObject); if (attachedObject) { QVariant p = attachedObject->property("role"); @@ -273,7 +258,6 @@ void tst_QQuickAccessible::quickAttachedProperties() QCOMPARE(p.isNull(), false); QCOMPARE(p.toString(), QLatin1String("Text Button")); } - delete object; } // Check overriding of attached role for Text { @@ -289,13 +273,13 @@ void tst_QQuickAccessible::quickAttachedProperties() "Accessible.description: \"Text Button\"\n" "}\n" "}", QUrl()); - QObject *object = component.create(); + auto object = std::unique_ptr<QObject>(component.create()); QVERIFY(object != nullptr); - QQuickListView *listview = qobject_cast<QQuickListView *>(object); + QQuickListView *listview = qobject_cast<QQuickListView *>(object.get()); QVERIFY(listview != nullptr); QQuickItem *contentItem = listview->contentItem(); - QQuickText *childItem = QQuickVisualTestUtil::findItem<QQuickText>(contentItem, "acc_text"); + QQuickText *childItem = QQuickVisualTestUtils::findItem<QQuickText>(contentItem, "acc_text"); QVERIFY(childItem != nullptr); QObject *attachedObject = QQuickAccessibleAttached::attachedProperties(childItem); @@ -311,7 +295,6 @@ void tst_QQuickAccessible::quickAttachedProperties() QCOMPARE(p.isNull(), false); QCOMPARE(p.toString(), QLatin1String("Text Button")); } - delete object; } // Check that a name can be implicitly set. { @@ -323,11 +306,11 @@ void tst_QQuickAccessible::quickAttachedProperties() Accessible.role: Accessible.Button Accessible.description: "Text Button" })", QUrl()); - QScopedPointer<QObject> object(component.create()); + auto object = std::unique_ptr<QObject>(component.create()); QVERIFY(object); const auto attachedObject = qobject_cast<QQuickAccessibleAttached*>( - QQuickAccessibleAttached::attachedProperties(object.data())); + QQuickAccessibleAttached::attachedProperties(object.get())); QVERIFY(attachedObject); QVERIFY(!attachedObject->wasNameExplicitlySet()); @@ -342,24 +325,49 @@ void tst_QQuickAccessible::quickAttachedProperties() QTestAccessibility::clearEvents(); } +// Verify that a role can be explicitly set, and that the values from the +// attached object are used even if the item has a default role - QTBUG-110114 +void tst_QQuickAccessible::attachedWins() +{ + QQmlEngine engine; + QQmlComponent component(&engine); + component.setData(R"( + import QtQuick + import QtQuick.Controls + Button { + text: "Button" + objectName: "button" + Accessible.role: Accessible.RadioButton + Accessible.description: "Radio Button" + })", QUrl()); + auto button = std::unique_ptr<QObject>(component.create()); + QVERIFY(button); + + QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(button.get()); + QVERIFY(iface); + + QCOMPARE(iface->role(), QAccessible::RadioButton); + QTestAccessibility::clearEvents(); +} + void tst_QQuickAccessible::basicPropertiesTest() { QAccessibleInterface *app = QAccessible::queryAccessibleInterface(qApp); QCOMPARE(app->childCount(), 0); - QQuickView *window = new QQuickView(); + auto window = std::make_unique<QQuickView>(); window->setSource(testFileUrl("text.qml")); window->show(); QCOMPARE(app->childCount(), 1); - QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(window); + QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(window.get()); QVERIFY(iface); QCOMPARE(iface->childCount(), 1); QAccessibleInterface *item = iface->child(0); QVERIFY(item); - QCOMPARE(item->childCount(), 5); + QCOMPARE(item->childCount(), 6); QCOMPARE(item->rect().size(), QSize(400, 400)); QCOMPARE(item->role(), QAccessible::Client); QCOMPARE(iface->indexOfChild(item), 0); @@ -387,6 +395,7 @@ void tst_QQuickAccessible::basicPropertiesTest() QCOMPARE(item->indexOfChild(text2), 1); QVERIFY(!text2->state().editable); QVERIFY(text2->state().readOnly); + QVERIFY(text2->state().focusable); QCOMPARE(iface->indexOfChild(text2), -1); QCOMPARE(text2->indexOfChild(item), -1); @@ -444,6 +453,31 @@ void tst_QQuickAccessible::basicPropertiesTest() QCOMPARE(text3->role(), QAccessible::StaticText); QVERIFY(text3->state().readOnly); + // Text "Rich text" + QAccessibleInterface *richText = item->child(5); + QVERIFY(text3); + QCOMPARE(richText->childCount(), 2); + QCOMPARE(richText->text(QAccessible::Name), QLatin1String("Rich text with links:\nWebsite or blog")); + QCOMPARE(richText->role(), QAccessible::StaticText); + QCOMPARE(item->indexOfChild(richText), 5); + QVERIFY(!richText->state().editable); + QVERIFY(!richText->state().readOnly); + + // Check for hyperlink child nodes + for (int i = 0; i < richText->childCount(); ++i) { + static const char *linkUrls[2][2] = { + {"Website", "https://qt.io"}, + {"blog", "https://qt.io/blog"} + }; + QAccessibleInterface *link1 = richText->child(i); + QVERIFY(link1); + QCOMPARE(link1->role(), QAccessible::Link); + QAccessibleHyperlinkInterface *link = link1->hyperlinkInterface(); + QVERIFY(link); + QCOMPARE(link->anchor(), QLatin1String(linkUrls[i][0])); + QCOMPARE(link->anchorTarget(), QLatin1String(linkUrls[i][1])); + } + // see if implicit changes back attached->setRole(QAccessible::EditableText); QEXPECT_FAIL("", "EditableText does not implicitly set readOnly to false", Continue); @@ -453,7 +487,7 @@ void tst_QQuickAccessible::basicPropertiesTest() attached->setRole(QAccessible::StaticText); QVERIFY(!text3->state().readOnly); - delete window; + window.reset(); QTestAccessibility::clearEvents(); } @@ -472,14 +506,15 @@ QAccessibleInterface *topLevelChildAt(QAccessibleInterface *iface, int x, int y) void tst_QQuickAccessible::hitTest() { - QQuickView *window = new QQuickView; + auto window = std::make_unique<QQuickView>(); window->setSource(testFileUrl("hittest.qml")); window->show(); - QAccessibleInterface *windowIface = QAccessible::queryAccessibleInterface(window); + QAccessibleInterface *windowIface = QAccessible::queryAccessibleInterface(window.get()); QVERIFY(windowIface); QAccessibleInterface *rootItem = windowIface->child(0); - QRect rootRect = rootItem->rect(); + // on Android the main window is always shown fullscreen + QRect rootRect = QRect(window->x(), window->y(), window->width(), window->height()); // check the root item from app QAccessibleInterface *appIface = QAccessible::queryAccessibleInterface(qApp); @@ -525,13 +560,13 @@ void tst_QQuickAccessible::hitTest() } } - delete window; + window.reset(); QTestAccessibility::clearEvents(); } void tst_QQuickAccessible::checkableTest() { - QScopedPointer<QQuickView> window(new QQuickView()); + auto window = std::make_unique<QQuickView>(); window->setSource(testFileUrl("checkbuttons.qml")); window->show(); @@ -544,7 +579,7 @@ void tst_QQuickAccessible::checkableTest() QAccessible::State activatedChange; activatedChange.active = true; - QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(window.data()); + QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(window.get()); QVERIFY(iface); QAccessibleInterface *root = iface->child(0); @@ -608,7 +643,7 @@ void tst_QQuickAccessible::checkableTest() void tst_QQuickAccessible::ignoredTest() { - QScopedPointer<QQuickView> window(new QQuickView()); + auto window = std::make_unique<QQuickView>(); window->setSource(testFileUrl("ignored.qml")); window->show(); @@ -621,7 +656,7 @@ void tst_QQuickAccessible::ignoredTest() QAccessible::State activatedChange; activatedChange.active = true; - QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(window.data()); + QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(window.get()); QVERIFY(iface); QAccessibleInterface *rectangleA = iface->child(0); @@ -636,6 +671,34 @@ void tst_QQuickAccessible::ignoredTest() QTestAccessibility::clearEvents(); } +void tst_QQuickAccessible::passwordTest() +{ + QQmlEngine engine; + QQmlComponent component(&engine); + component.setData("import QtQuick\nTextInput {\n" + "Accessible.role: Accessible.EditableText\n" + "Accessible.name: \"Password\"\n" + "Accessible.passwordEdit: true\n" + "echoMode: TextInput.Password\n" + "text: \"Green\"\n" + "}", QUrl()); + auto object = std::unique_ptr<QObject>(component.create()); + QVERIFY(object != nullptr); + + QQuickTextInput *textInput = qobject_cast<QQuickTextInput *>(object.get()); + QVERIFY(textInput != nullptr); + + const auto passwordCharacter = textInput->passwordCharacter(); + const auto passwordLength = textInput->text().length(); + const auto password = passwordCharacter.repeated(passwordLength); + + QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(object.get()); + QVERIFY(iface); + QCOMPARE(iface->text(QAccessible::Value), password); + + QTestAccessibility::clearEvents(); +} + QTEST_MAIN(tst_QQuickAccessible) #include "tst_qquickaccessible.moc" |