diff options
Diffstat (limited to 'tests/auto/other/qaccessibilitymac')
-rw-r--r-- | tests/auto/other/qaccessibilitymac/CMakeLists.txt | 30 | ||||
-rw-r--r-- | tests/auto/other/qaccessibilitymac/tst_qaccessibilitymac.cpp | 150 | ||||
-rw-r--r-- | tests/auto/other/qaccessibilitymac/tst_qaccessibilitymac.mm (renamed from tests/auto/other/qaccessibilitymac/tst_qaccessibilitymac_helpers.mm) | 488 | ||||
-rw-r--r-- | tests/auto/other/qaccessibilitymac/tst_qaccessibilitymac_helpers.h | 41 |
4 files changed, 358 insertions, 351 deletions
diff --git a/tests/auto/other/qaccessibilitymac/CMakeLists.txt b/tests/auto/other/qaccessibilitymac/CMakeLists.txt index 6dd30a6fa1..66896ed384 100644 --- a/tests/auto/other/qaccessibilitymac/CMakeLists.txt +++ b/tests/auto/other/qaccessibilitymac/CMakeLists.txt @@ -1,32 +1,22 @@ -# Generated from qaccessibilitymac.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qaccessibilitymac LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() if(NOT APPLE) return() endif() -##################################################################### -## tst_qaccessibilitymac Test: -##################################################################### - qt_internal_add_test(tst_qaccessibilitymac SOURCES - tst_qaccessibilitymac.cpp - tst_qaccessibilitymac_helpers.h - PUBLIC_LIBRARIES + tst_qaccessibilitymac.mm + LIBRARIES Qt::Gui Qt::Widgets -) - -#### Keys ignored in scope 1:.:.:qaccessibilitymac.pro:<TRUE>: -# _REQUIREMENTS = "mac" - -## Scopes: -##################################################################### - -qt_internal_extend_target(tst_qaccessibilitymac CONDITION APPLE - SOURCES - tst_qaccessibilitymac_helpers.mm - PUBLIC_LIBRARIES ${FWAppKit} ${FWApplicationServices} ${FWSecurity} diff --git a/tests/auto/other/qaccessibilitymac/tst_qaccessibilitymac.cpp b/tests/auto/other/qaccessibilitymac/tst_qaccessibilitymac.cpp deleted file mode 100644 index a766e1e374..0000000000 --- a/tests/auto/other/qaccessibilitymac/tst_qaccessibilitymac.cpp +++ /dev/null @@ -1,150 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite 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$ -** -****************************************************************************/ - -#include <QApplication> -#include <QtWidgets> -#include <QTest> -#include <QtCore/qcoreapplication.h> - -#include "tst_qaccessibilitymac_helpers.h" - -QT_USE_NAMESPACE - - -class AccessibleTestWindow : public QWidget -{ - Q_OBJECT -public: - AccessibleTestWindow() - { - new QHBoxLayout(this); - } - - void addWidget(QWidget* widget) - { - layout()->addWidget(widget); - widget->show(); - QVERIFY(QTest::qWaitForWindowExposed(widget)); - } - - void clearChildren() - { - qDeleteAll(children()); - new QHBoxLayout(this); - } -}; - -class tst_QAccessibilityMac : public QObject -{ -Q_OBJECT -private slots: - void init(); - void cleanup(); - - void singleWidgetTest(); - void lineEditTest(); - void hierarchyTest(); - void notificationsTest(); - void checkBoxTest(); - -private: - AccessibleTestWindow *m_window; -}; - - -void tst_QAccessibilityMac::init() -{ - m_window = new AccessibleTestWindow(); - m_window->setWindowTitle("Test window"); - m_window->show(); - m_window->resize(400, 400); - - QVERIFY(QTest::qWaitForWindowExposed(m_window)); -} - -void tst_QAccessibilityMac::cleanup() -{ - delete m_window; -} - -void tst_QAccessibilityMac::singleWidgetTest() -{ - delete m_window; - m_window = 0; - - QVERIFY(singleWidget()); -} - -void tst_QAccessibilityMac::lineEditTest() -{ - QLineEdit *lineEdit = new QLineEdit(m_window); - lineEdit->setText("a11y test QLineEdit"); - m_window->addWidget(lineEdit); - QVERIFY(QTest::qWaitForWindowExposed(m_window)); - QCoreApplication::processEvents(); - - QVERIFY(testLineEdit()); -} - -void tst_QAccessibilityMac::hierarchyTest() -{ - QWidget *w = new QWidget(m_window); - m_window->addWidget(w); - - w->setLayout(new QVBoxLayout()); - QPushButton *b = new QPushButton(w); - w->layout()->addWidget(b); - b->setText("I am a button"); - - QPushButton *b2 = new QPushButton(w); - w->layout()->addWidget(b2); - b2->setText("Button 2"); - - QVERIFY(QTest::qWaitForWindowExposed(m_window)); - QCoreApplication::processEvents(); - QVERIFY(testHierarchy(w)); -} - -void tst_QAccessibilityMac::notificationsTest() -{ - QVERIFY(notifications(m_window)); -} - -void tst_QAccessibilityMac::checkBoxTest() -{ - QCheckBox *cb = new QCheckBox(m_window); - cb->setText("Great option"); - m_window->addWidget(cb); - QVERIFY(QTest::qWaitForWindowExposed(m_window)); - QCoreApplication::processEvents(); - - QVERIFY(testCheckBox(cb)); -} - -QTEST_MAIN(tst_QAccessibilityMac) -#include "tst_qaccessibilitymac.moc" diff --git a/tests/auto/other/qaccessibilitymac/tst_qaccessibilitymac_helpers.mm b/tests/auto/other/qaccessibilitymac/tst_qaccessibilitymac.mm index 7e89b3a166..4bedd07e15 100644 --- a/tests/auto/other/qaccessibilitymac/tst_qaccessibilitymac_helpers.mm +++ b/tests/auto/other/qaccessibilitymac/tst_qaccessibilitymac.mm @@ -1,35 +1,14 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite 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 <QApplication> +#include <QtWidgets> +#include <QTest> +#include <QtCore/qcoreapplication.h> // some versions of CALayer.h use 'slots' as an identifier #define QT_NO_KEYWORDS -#include "tst_qaccessibilitymac_helpers.h" #include <QtWidgets/qapplication.h> #include <QtWidgets/qlineedit.h> #include <QtWidgets/qpushbutton.h> @@ -80,17 +59,10 @@ QDebug operator<<(QDebug dbg, AXErrorTag err) return dbg; } -#define EXPECT(cond) \ - if (!(cond)) { \ - qWarning("Failure in %s, line: %d", __FILE__ , __LINE__); \ - return false; \ - } \ - -#define TRY_EXPECT(cond) EXPECT(QTest::qWaitFor([&]{ return (cond); })) - @interface TestAXObject : NSObject { AXUIElementRef reference; + bool axError; } @property (readonly) NSString *role; @property (readonly) NSString *title; @@ -106,11 +78,13 @@ QDebug operator<<(QDebug dbg, AXErrorTag err) if ((self = [super init])) { reference = ref; + axError = false; } return self; } - (AXUIElementRef) ref { return reference; } +- (bool)errorOccurred { return axError; } - (void) print { NSLog(@"Accessible Object role: '%@', title: '%@', description: '%@', value: '%@', rect: '%@'", self.role, self.title, self.description, self.value, NSStringFromRect(NSRectFromCGRect(self.rect))); NSLog(@" Children: %ld", [[self childList] count]); @@ -138,6 +112,28 @@ QDebug operator<<(QDebug dbg, AXErrorTag err) return list; } +- (NSArray *)tableRows +{ + NSArray *arr; + AXUIElementCopyAttributeValues( + reference, + kAXRowsAttribute, + 0, 100, /*min, max*/ + (CFArrayRef *) &arr); + return arr; +} + +- (NSArray *)tableColumns +{ + NSArray *arr; + AXUIElementCopyAttributeValues( + reference, + kAXColumnsAttribute, + 0, 100, /*min, max*/ + (CFArrayRef *) &arr); + return arr; +} + - (AXUIElementRef) findDirectChildByRole: (CFStringRef) role { TestAXObject *result = nil; @@ -232,8 +228,8 @@ QDebug operator<<(QDebug dbg, AXErrorTag err) CFTypeRef value = NULL; AXError err; - if (kAXErrorSuccess != (err = AXUIElementCopyAttributeValue(reference, attribute, &value))) - { + if (kAXErrorSuccess != (err = AXUIElementCopyAttributeValue(reference, attribute, &value))) { + axError = true; qDebug() << "AXUIElementCopyAttributeValue(" << QString::fromCFString(attribute) << ") returned error = " << AXErrorTag(err); } return value; @@ -279,8 +275,8 @@ QDebug operator<<(QDebug dbg, AXErrorTag err) CFTypeRef value = NULL; AXError err; - if (kAXErrorSuccess != (err = AXUIElementCopyParameterizedAttributeValue(reference, attribute, parameter, &value))) - { + if (kAXErrorSuccess != (err = AXUIElementCopyParameterizedAttributeValue(reference, attribute, parameter, &value))) { + axError = true; CFStringRef description = CFCopyDescription(parameter); qDebug() << "AXUIElementCopyParameterizedAttributeValue(" << QString::fromCFString(attribute) << ", parameter=" << QString::fromCFString(description) << ") returned error = " << AXErrorTag(err); CFRelease(description); @@ -318,8 +314,8 @@ QDebug operator<<(QDebug dbg, AXErrorTag err) AXError err; CFArrayRef actions; - if (kAXErrorSuccess != (err = AXUIElementCopyActionNames(reference, &actions))) - { + if (kAXErrorSuccess != (err = AXUIElementCopyActionNames(reference, &actions))) { + axError = true; qDebug() << "AXUIElementCopyActionNames(...) returned error = " << AXErrorTag(err); } @@ -330,8 +326,8 @@ QDebug operator<<(QDebug dbg, AXErrorTag err) { AXError err; - if (kAXErrorSuccess != (err = AXUIElementPerformAction(reference, action))) - { + if (kAXErrorSuccess != (err = AXUIElementPerformAction(reference, action))) { + axError = true; qDebug() << "AXUIElementPerformAction(" << QString::fromCFString(action) << ") returned error = " << AXErrorTag(err); } } @@ -366,66 +362,140 @@ QDebug operator<<(QDebug dbg, AXErrorTag err) @end +QVector<int> notificationList; + +void observerCallback(AXObserverRef /*observer*/, AXUIElementRef /*element*/, CFStringRef notification, void *) +{ + if ([(NSString*)notification isEqualToString: NSAccessibilityFocusedUIElementChangedNotification]) + notificationList.append(QAccessible::Focus); + else if ([(NSString*)notification isEqualToString: NSAccessibilityValueChangedNotification]) + notificationList.append(QAccessible::ValueChanged); + else + notificationList.append(-1); +} -bool singleWidget() +class AccessibleTestWindow : public QWidget { + Q_OBJECT +public: + AccessibleTestWindow() + { + new QHBoxLayout(this); + } + + void addWidget(QWidget* widget) + { + layout()->addWidget(widget); + widget->show(); + QVERIFY(QTest::qWaitForWindowExposed(widget)); + } + + void clearChildren() + { + qDeleteAll(children()); + new QHBoxLayout(this); + } +}; + +class tst_QAccessibilityMac : public QObject +{ +Q_OBJECT +private Q_SLOTS: + void init(); + void cleanup(); + + void singleWidgetTest(); + void lineEditTest(); + void hierarchyTest(); + void notificationsTest(); + void checkBoxTest(); + void tableViewTest(); + void treeViewTest(); + +private: + AccessibleTestWindow *m_window; +}; + + +void tst_QAccessibilityMac::init() +{ + m_window = new AccessibleTestWindow(); + m_window->setWindowTitle(QString("Test window - %1").arg(QTest::currentTestFunction())); + m_window->show(); + m_window->resize(400, 400); + + QVERIFY(QTest::qWaitForWindowExposed(m_window)); +} + +void tst_QAccessibilityMac::cleanup() +{ + delete m_window; +} + +void tst_QAccessibilityMac::singleWidgetTest() +{ + delete m_window; + m_window = 0; + QLineEdit *le = new QLineEdit(); le->setText("button"); le->show(); - EXPECT(QTest::qWaitForWindowExposed(le)); + QVERIFY(QTest::qWaitForWindowExposed(le)); QCoreApplication::processEvents(); TestAXObject *appObject = [TestAXObject getApplicationAXObject]; - EXPECT(appObject); + QVERIFY(appObject); - NSArray *windows = [appObject windowList]; - EXPECT([windows count] == 1); + QTRY_VERIFY(appObject.windowList.count == 1); - AXUIElementRef windowRef = (AXUIElementRef) [windows objectAtIndex: 0]; - EXPECT(windowRef != nil); + AXUIElementRef windowRef = (AXUIElementRef) [appObject.windowList objectAtIndex: 0]; + QVERIFY(windowRef != nil); TestAXObject *window = [[TestAXObject alloc] initWithAXUIElementRef: windowRef]; AXUIElementRef lineEditRef = [window findDirectChildByRole: kAXTextFieldRole]; - EXPECT(lineEditRef != nil); + QVERIFY(lineEditRef != nil); TestAXObject *lineEdit = [[TestAXObject alloc] initWithAXUIElementRef: lineEditRef]; - EXPECT([[lineEdit value] isEqualToString:@"button"]); + QVERIFY([[lineEdit value] isEqualToString:@"button"]); // Access invalid reference, should return empty value delete le; QCoreApplication::processEvents(); TestAXObject *lineEditInvalid = [[TestAXObject alloc] initWithAXUIElementRef: lineEditRef]; - EXPECT([[lineEditInvalid value] length] == 0); - - return true; + QVERIFY([[lineEditInvalid value] length] == 0); } -bool testLineEdit() +void tst_QAccessibilityMac::lineEditTest() { + QLineEdit *lineEdit = new QLineEdit(m_window); + lineEdit->setText("a11y test QLineEdit"); + m_window->addWidget(lineEdit); + QVERIFY(QTest::qWaitForWindowExposed(m_window)); + QCoreApplication::processEvents(); + TestAXObject *appObject = [TestAXObject getApplicationAXObject]; - EXPECT(appObject); + QVERIFY(appObject); - NSArray *windowList = [appObject windowList]; // one window - EXPECT([windowList count] == 1); - AXUIElementRef windowRef = (AXUIElementRef) [windowList objectAtIndex: 0]; - EXPECT(windowRef != nil); + QTRY_VERIFY(appObject.windowList.count == 1); + AXUIElementRef windowRef = (AXUIElementRef) [appObject.windowList objectAtIndex: 0]; + QVERIFY(windowRef != nil); TestAXObject *window = [[TestAXObject alloc] initWithAXUIElementRef: windowRef]; - EXPECT([window rect].size.width == 400); + QVERIFY([window rect].size.width == 400); // height of window includes title bar - EXPECT([window rect].size.height >= 400); + QVERIFY([window rect].size.height >= 400); - EXPECT([window.title isEqualToString:@"Test window"]); + QVERIFY([window.title isEqualToString:@"Test window - lineEditTest"]); // children of window: - AXUIElementRef lineEdit = [window findDirectChildByRole: kAXTextFieldRole]; - EXPECT(lineEdit != nil); + AXUIElementRef lineEditElement = [window findDirectChildByRole: kAXTextFieldRole]; + QVERIFY(lineEditElement != nil); - TestAXObject *le = [[TestAXObject alloc] initWithAXUIElementRef: lineEdit]; + TestAXObject *le = [[TestAXObject alloc] initWithAXUIElementRef: lineEditElement]; NSString *value = @"a11y test QLineEdit"; - EXPECT([le.value isEqualToString:value]); - EXPECT(value.length <= NSIntegerMax); - EXPECT(le.numberOfCharacters == static_cast<NSInteger>(value.length)); + QVERIFY([le.value isEqualToString:value]); + QVERIFY(value.length <= NSIntegerMax); + QVERIFY(le.numberOfCharacters == static_cast<NSInteger>(value.length)); const NSRange ranges[] = { { 0, 0}, { 0, 1}, @@ -440,82 +510,81 @@ bool testLineEdit() NSString *expectedSubstring = [value substringWithRange:range]; NSString *actualSubstring = [le stringForRange:range]; NSString *actualAttributedSubstring = [le attributedStringForRange:range].string; - EXPECT([actualSubstring isEqualTo:expectedSubstring]); - EXPECT([actualAttributedSubstring isEqualTo:expectedSubstring]); + QVERIFY([actualSubstring isEqualTo:expectedSubstring]); + QVERIFY([actualAttributedSubstring isEqualTo:expectedSubstring]); } - return true; } -bool testHierarchy(QWidget *w) +void tst_QAccessibilityMac::hierarchyTest() { + QWidget *w = new QWidget(m_window); + m_window->addWidget(w); + + w->setLayout(new QVBoxLayout()); + QPushButton *b = new QPushButton(w); + w->layout()->addWidget(b); + b->setText("I am a button"); + + QPushButton *b2 = new QPushButton(w); + w->layout()->addWidget(b2); + b2->setText("Button 2"); + + QVERIFY(QTest::qWaitForWindowExposed(m_window)); + QCoreApplication::processEvents(); + TestAXObject *appObject = [TestAXObject getApplicationAXObject]; - EXPECT(appObject); + QVERIFY(appObject); - NSArray *windowList = [appObject windowList]; // one window - EXPECT([windowList count] == 1); - AXUIElementRef windowRef = (AXUIElementRef) [windowList objectAtIndex: 0]; - EXPECT(windowRef != nil); + QTRY_VERIFY(appObject.windowList.count == 1); + AXUIElementRef windowRef = (AXUIElementRef) [appObject.windowList objectAtIndex: 0]; + QVERIFY(windowRef != nil); TestAXObject *window = [[TestAXObject alloc] initWithAXUIElementRef: windowRef]; // Because the plain widget is filtered out of the hierarchy, we expect the button // to be a direct child of the window AXUIElementRef buttonRef = [window findDirectChildByRole: kAXButtonRole]; - EXPECT(buttonRef != nil); + QVERIFY(buttonRef != nil); TestAXObject *buttonObject = [[TestAXObject alloc] initWithAXUIElementRef: buttonRef]; TestAXObject *parentObject = [[TestAXObject alloc] initWithAXUIElementRef: [buttonObject parent]]; // check that the parent is a window - EXPECT([[parentObject role] isEqualToString: NSAccessibilityWindowRole]); + QVERIFY([[parentObject role] isEqualToString: NSAccessibilityWindowRole]); // test the focus // child 0 is the layout, then button1 and 2 QPushButton *button1 = qobject_cast<QPushButton*>(w->children().at(1)); - EXPECT(button1); + QVERIFY(button1); QPushButton *button2 = qobject_cast<QPushButton*>(w->children().at(2)); - EXPECT(button2); + QVERIFY(button2); button2->setFocus(); AXUIElementRef systemWideElement = AXUIElementCreateSystemWide(); AXUIElementRef focussedElement = NULL; AXError error = AXUIElementCopyAttributeValue(systemWideElement, (CFStringRef)NSAccessibilityFocusedUIElementAttribute, (CFTypeRef*)&focussedElement); - EXPECT(!error); - EXPECT(focussedElement); + QVERIFY(!error); + QVERIFY(focussedElement); TestAXObject *focusButton2 = [[TestAXObject alloc] initWithAXUIElementRef: focussedElement]; - EXPECT([[focusButton2 role] isEqualToString: NSAccessibilityButtonRole]); - EXPECT([[focusButton2 title] isEqualToString: @"Button 2"]); + QVERIFY([[focusButton2 role] isEqualToString: NSAccessibilityButtonRole]); + QVERIFY([[focusButton2 title] isEqualToString: @"Button 2"]); button1->setFocus(); error = AXUIElementCopyAttributeValue(systemWideElement, (CFStringRef)NSAccessibilityFocusedUIElementAttribute, (CFTypeRef*)&focussedElement); - EXPECT(!error); - EXPECT(focussedElement); + QVERIFY(!error); + QVERIFY(focussedElement); TestAXObject *focusButton1 = [[TestAXObject alloc] initWithAXUIElementRef: focussedElement]; - EXPECT([[focusButton1 role] isEqualToString: NSAccessibilityButtonRole]); - EXPECT([[focusButton1 title] isEqualToString: @"I am a button"]); - - return true; + QVERIFY([[focusButton1 role] isEqualToString: NSAccessibilityButtonRole]); + QVERIFY([[focusButton1 title] isEqualToString: @"I am a button"]); } -QVector<int> notificationList; - -void observerCallback(AXObserverRef /*observer*/, AXUIElementRef /*element*/, CFStringRef notification, void *) -{ - if ([(NSString*)notification isEqualToString: NSAccessibilityFocusedUIElementChangedNotification]) - notificationList.append(QAccessible::Focus); - else if ([(NSString*)notification isEqualToString: NSAccessibilityValueChangedNotification]) - notificationList.append(QAccessible::ValueChanged); - else - notificationList.append(-1); -} - - -bool notifications(QWidget *w) +void tst_QAccessibilityMac::notificationsTest() { + auto *w = m_window; QLineEdit *le1 = new QLineEdit(w); QLineEdit *le2 = new QLineEdit(w); w->layout()->addWidget(le1); @@ -525,76 +594,215 @@ bool notifications(QWidget *w) QTest::qWait(100); TestAXObject *appObject = [TestAXObject getApplicationAXObject]; - EXPECT(appObject); + QVERIFY(appObject); - NSArray *windowList = [appObject windowList]; // one window - EXPECT([windowList count] == 1); - AXUIElementRef windowRef = (AXUIElementRef) [windowList objectAtIndex: 0]; - EXPECT(windowRef != nil); + QTRY_VERIFY(appObject.windowList.count == 1); + AXUIElementRef windowRef = (AXUIElementRef) [appObject.windowList objectAtIndex: 0]; + QVERIFY(windowRef != nil); TestAXObject *window = [[TestAXObject alloc] initWithAXUIElementRef: windowRef]; AXUIElementRef lineEdit1 = [window findDirectChildByRole: kAXTextFieldRole]; - EXPECT(lineEdit1 != nil); + QVERIFY(lineEdit1 != nil); AXObserverRef observer = 0; AXError err = AXObserverCreate(getpid(), observerCallback, &observer); - EXPECT(!err); + QVERIFY(!err); AXObserverAddNotification(observer, appObject.ref, kAXFocusedUIElementChangedNotification, 0); AXObserverAddNotification(observer, lineEdit1, kAXValueChangedNotification, 0); CFRunLoopAddSource( [[NSRunLoop currentRunLoop] getCFRunLoop], AXObserverGetRunLoopSource(observer), kCFRunLoopDefaultMode); - EXPECT(notificationList.length() == 0); + QVERIFY(notificationList.length() == 0); le2->setFocus(); - TRY_EXPECT(notificationList.length() == 1); - TRY_EXPECT(notificationList.at(0) == QAccessible::Focus); + QTRY_VERIFY(notificationList.length() == 1); + QTRY_VERIFY(notificationList.at(0) == QAccessible::Focus); le1->setFocus(); - TRY_EXPECT(notificationList.length() == 2); - TRY_EXPECT(notificationList.at(1) == QAccessible::Focus); + QTRY_VERIFY(notificationList.length() == 2); + QTRY_VERIFY(notificationList.at(1) == QAccessible::Focus); le1->setText("hello"); - TRY_EXPECT(notificationList.length() == 3); - TRY_EXPECT(notificationList.at(2) == QAccessible::ValueChanged); + QTRY_VERIFY(notificationList.length() == 3); + QTRY_VERIFY(notificationList.at(2) == QAccessible::ValueChanged); le1->setText("foo"); - TRY_EXPECT(notificationList.length() == 4); - TRY_EXPECT(notificationList.at(3) == QAccessible::ValueChanged); - - return true; + QTRY_VERIFY(notificationList.length() == 4); + QTRY_VERIFY(notificationList.at(3) == QAccessible::ValueChanged); } -bool testCheckBox(QCheckBox *ckBox) +void tst_QAccessibilityMac::checkBoxTest() { + QCheckBox *ckBox = new QCheckBox(m_window); + ckBox->setText("Great option"); + m_window->addWidget(ckBox); + QVERIFY(QTest::qWaitForWindowExposed(m_window)); + QCoreApplication::processEvents(); + TestAXObject *appObject = [TestAXObject getApplicationAXObject]; - EXPECT(appObject); + QVERIFY(appObject); - NSArray *windowList = [appObject windowList]; // one window - EXPECT([windowList count] == 1); - AXUIElementRef windowRef = (AXUIElementRef) [windowList objectAtIndex: 0]; - EXPECT(windowRef != nil); + QTRY_VERIFY(appObject.windowList.count == 1); + AXUIElementRef windowRef = (AXUIElementRef) [appObject.windowList objectAtIndex: 0]; + QVERIFY(windowRef != nil); TestAXObject *window = [[TestAXObject alloc] initWithAXUIElementRef: windowRef]; // children of window: AXUIElementRef checkBox = [window findDirectChildByRole: kAXCheckBoxRole]; - EXPECT(checkBox != nil); + QVERIFY(checkBox != nil); TestAXObject *cb = [[TestAXObject alloc] initWithAXUIElementRef: checkBox]; // here start actual checkbox tests - EXPECT([cb valueNumber] == 0); - EXPECT([cb.title isEqualToString:@"Great option"]); + QVERIFY([cb valueNumber] == 0); + QVERIFY([cb.title isEqualToString:@"Great option"]); // EXPECT(cb.description == nil); // currently returns "" instead of nil - EXPECT([cb.actions containsObject:(NSString*)kAXPressAction]); + QVERIFY([cb.actions containsObject:(NSString*)kAXPressAction]); [cb performAction:kAXPressAction]; - EXPECT([cb valueNumber] == 1); + QVERIFY([cb valueNumber] == 1); [cb performAction:kAXPressAction]; - EXPECT([cb valueNumber] == 0); + QVERIFY([cb valueNumber] == 0); ckBox->setCheckState(Qt::PartiallyChecked); - EXPECT([cb valueNumber] == 2); + QVERIFY([cb valueNumber] == 2); +} + +void tst_QAccessibilityMac::tableViewTest() +{ + QTableWidget *tw = new QTableWidget(3, 2, m_window); + struct Person + { + const char *name; + const char *address; + }; + const Person contents[] = { { "Socrates", "Greece" }, + { "Confucius", "China" }, + { "Kant", "Preussia" } + }; + for (int i = 0; i < int(sizeof(contents) / sizeof(Person)); ++i) { + Person p = contents[i]; + QTableWidgetItem *name = new QTableWidgetItem(QString::fromLatin1(p.name)); + tw->setItem(i, 0, name); + QTableWidgetItem *address = new QTableWidgetItem(QString::fromLatin1(p.address)); + tw->setItem(i, 1, address); + } + m_window->addWidget(tw); + QVERIFY(QTest::qWaitForWindowExposed(m_window)); + QCoreApplication::processEvents(); + + TestAXObject *appObject = [TestAXObject getApplicationAXObject]; + QVERIFY(appObject); - return true; + NSArray *windowList = [appObject windowList]; + // one window + QVERIFY([windowList count] == 1); + AXUIElementRef windowRef = (AXUIElementRef)[windowList objectAtIndex:0]; + QVERIFY(windowRef != nil); + TestAXObject *window = [[TestAXObject alloc] initWithAXUIElementRef:windowRef]; + + // children of window: + AXUIElementRef tableView = [window findDirectChildByRole:kAXTableRole]; + QVERIFY(tableView != nil); + + TestAXObject *tv = [[TestAXObject alloc] initWithAXUIElementRef:tableView]; + + // here start actual tableview tests + // Should have 2 columns + const unsigned int columnCount = 2; + NSArray *columnArray = [tv tableColumns]; + QCOMPARE([columnArray count], columnCount); + + // should have 3 rows + const unsigned int rowCount = 3; + NSArray *rowArray = [tv tableRows]; + QCOMPARE([rowArray count], rowCount); + + // The individual cells are children of the rows + TestAXObject *row = [[TestAXObject alloc] initWithAXUIElementRef:(AXUIElementRef)rowArray[0]]; + TestAXObject *cell = [[TestAXObject alloc] initWithAXUIElementRef:(AXUIElementRef)[row childList][0]]; + QVERIFY([cell.title isEqualToString:@"Socrates"]); + row = [[TestAXObject alloc] initWithAXUIElementRef:(AXUIElementRef)rowArray[2]]; + cell = [[TestAXObject alloc] initWithAXUIElementRef:(AXUIElementRef)[row childList][1]]; + QVERIFY([cell.title isEqualToString:@"Preussia"]); + + // both rows and columns are direct children of the table + NSArray *childList = [tv childList]; + QCOMPARE([childList count], columnCount + rowCount); + for (id child in childList) { + TestAXObject *childObject = [[TestAXObject alloc] initWithAXUIElementRef:(AXUIElementRef)child]; + QVERIFY([childObject.role isEqualToString:NSAccessibilityRowRole] || + [childObject.role isEqualToString:NSAccessibilityColumnRole]); + } } + +void tst_QAccessibilityMac::treeViewTest() +{ + QTreeWidget *tw = new QTreeWidget; + tw->setColumnCount(2); + QTreeWidgetItem *root = new QTreeWidgetItem(tw, {"/", "0"}); + root->setExpanded(false); + QTreeWidgetItem *users = new QTreeWidgetItem(root,{ "Users", "1"}); + (void)new QTreeWidgetItem(root, {"Applications", "2"}); + QTreeWidgetItem *lastChild = new QTreeWidgetItem(root, {"Libraries", "3"}); + + m_window->addWidget(tw); + QVERIFY(QTest::qWaitForWindowExposed(m_window)); + QCoreApplication::processEvents(); + + TestAXObject *appObject = [TestAXObject getApplicationAXObject]; + QVERIFY(appObject); + + NSArray *windowList = [appObject windowList]; + // one window + QVERIFY([windowList count] == 1); + AXUIElementRef windowRef = (AXUIElementRef)[windowList objectAtIndex:0]; + QVERIFY(windowRef != nil); + TestAXObject *window = [[TestAXObject alloc] initWithAXUIElementRef:windowRef]; + + // children of window + AXUIElementRef treeView = [window findDirectChildByRole:kAXOutlineRole]; + QVERIFY(treeView != nil); + + TestAXObject *tv = [[TestAXObject alloc] initWithAXUIElementRef:treeView]; + + // here start actual treeview tests. NSAccessibilityOutline is a specialization + // of NSAccessibilityTable, and we represent trees as tables. + // Should have 2 columns + const unsigned int columnCount = 2; + NSArray *columnArray = [tv tableColumns]; + QCOMPARE([columnArray count], columnCount); + + // should have 1 row for now - as long as the root item is not expanded + NSArray *rowArray = [tv tableRows]; + QCOMPARE(int([rowArray count]), 1); + + root->setExpanded(true); + rowArray = [tv tableRows]; + QCOMPARE(int([rowArray count]), root->childCount() + 1); + + // this should not trigger any assert + tw->setCurrentItem(lastChild); + + bool errorOccurred = false; + + const auto cellText = [rowArray, &errorOccurred](int rowIndex, int columnIndex) -> QString { + TestAXObject *row = [[TestAXObject alloc] initWithAXUIElementRef:(AXUIElementRef)rowArray[rowIndex]]; + Q_ASSERT(row); + TestAXObject *cell = [[TestAXObject alloc] initWithAXUIElementRef:(AXUIElementRef)[row childList][columnIndex]]; + Q_ASSERT(cell); + const QString result = QString::fromNSString(cell.title); + errorOccurred = cell.errorOccurred; + return result; + }; + + QString text = cellText(0, 0); + if (errorOccurred) + QSKIP("Cocoa Accessibility API error, aborting"); + QCOMPARE(text, root->text(0)); + QCOMPARE(cellText(1, 0), users->text(0)); + QCOMPARE(cellText(1, 1), users->text(1)); +} + +QTEST_MAIN(tst_QAccessibilityMac) +#include "tst_qaccessibilitymac.moc" diff --git a/tests/auto/other/qaccessibilitymac/tst_qaccessibilitymac_helpers.h b/tests/auto/other/qaccessibilitymac/tst_qaccessibilitymac_helpers.h deleted file mode 100644 index 58ea2d02b0..0000000000 --- a/tests/auto/other/qaccessibilitymac/tst_qaccessibilitymac_helpers.h +++ /dev/null @@ -1,41 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite 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$ -** -****************************************************************************/ -#include <QtCore/QString> -#include <QtCore/QPair> -#include <QtWidgets/QWidget> -#include <QtWidgets/QCheckBox> - -#pragma once // Yeah, it's deprecated in general, but it's standard practice for Mac OS X. - -QT_USE_NAMESPACE - -bool testLineEdit(); -bool testHierarchy(QWidget *w); -bool singleWidget(); -bool notifications(QWidget *w); -bool testCheckBox(QCheckBox *ckBox); |