Merge Objective-C++ parts of tst_QAccessibilityMac into main source file
There's no need to split it, we can use the -x compiler flag to build the .cpp file as Objective-C++, or, as done here, just rename the file. This allows us to use QVERIFY and friends, giving more precise failure reporting. Change-Id: I6fb1c4454335082c8a39010c5b75c59e6ec6561b Reviewed-by: Alexandru Croitor <alexandru.croitor@qt.io> Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io> Reviewed-by: Jan Arve Sæther <jan-arve.saether@qt.io> (cherry picked from commit 16b9f9a9aaf7455fe3134d4517511c280aad3ee9) Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@qt.io>
This commit is contained in:
parent
a120999765
commit
9e31cca206
@ -1,32 +1,14 @@
|
|||||||
# Generated from qaccessibilitymac.pro.
|
|
||||||
|
|
||||||
if(NOT APPLE)
|
if(NOT APPLE)
|
||||||
return()
|
return()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
#####################################################################
|
|
||||||
## tst_qaccessibilitymac Test:
|
|
||||||
#####################################################################
|
|
||||||
|
|
||||||
qt_internal_add_test(tst_qaccessibilitymac
|
qt_internal_add_test(tst_qaccessibilitymac
|
||||||
SOURCES
|
SOURCES
|
||||||
tst_qaccessibilitymac.cpp
|
tst_qaccessibilitymac.mm
|
||||||
tst_qaccessibilitymac_helpers.h
|
|
||||||
PUBLIC_LIBRARIES
|
PUBLIC_LIBRARIES
|
||||||
Qt::Gui
|
Qt::Gui
|
||||||
Qt::Widgets
|
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}
|
${FWAppKit}
|
||||||
${FWApplicationServices}
|
${FWApplicationServices}
|
||||||
${FWSecurity}
|
${FWSecurity}
|
||||||
|
@ -1,125 +0,0 @@
|
|||||||
// Copyright (C) 2016 The Qt Company Ltd.
|
|
||||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
|
||||||
|
|
||||||
#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"
|
|
@ -1,10 +1,14 @@
|
|||||||
// Copyright (C) 2016 The Qt Company Ltd.
|
// Copyright (C) 2016 The Qt Company Ltd.
|
||||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||||
|
|
||||||
|
#include <QApplication>
|
||||||
|
#include <QtWidgets>
|
||||||
|
#include <QTest>
|
||||||
|
#include <QtCore/qcoreapplication.h>
|
||||||
|
|
||||||
// some versions of CALayer.h use 'slots' as an identifier
|
// some versions of CALayer.h use 'slots' as an identifier
|
||||||
#define QT_NO_KEYWORDS
|
#define QT_NO_KEYWORDS
|
||||||
|
|
||||||
#include "tst_qaccessibilitymac_helpers.h"
|
|
||||||
#include <QtWidgets/qapplication.h>
|
#include <QtWidgets/qapplication.h>
|
||||||
#include <QtWidgets/qlineedit.h>
|
#include <QtWidgets/qlineedit.h>
|
||||||
#include <QtWidgets/qpushbutton.h>
|
#include <QtWidgets/qpushbutton.h>
|
||||||
@ -55,14 +59,6 @@ QDebug operator<<(QDebug dbg, AXErrorTag err)
|
|||||||
return dbg;
|
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
|
@interface TestAXObject : NSObject
|
||||||
{
|
{
|
||||||
AXUIElementRef reference;
|
AXUIElementRef reference;
|
||||||
@ -341,66 +337,140 @@ QDebug operator<<(QDebug dbg, AXErrorTag err)
|
|||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
QVector<int> notificationList;
|
||||||
|
|
||||||
bool singleWidget()
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
QLineEdit *le = new QLineEdit();
|
QLineEdit *le = new QLineEdit();
|
||||||
le->setText("button");
|
le->setText("button");
|
||||||
le->show();
|
le->show();
|
||||||
EXPECT(QTest::qWaitForWindowExposed(le));
|
QVERIFY(QTest::qWaitForWindowExposed(le));
|
||||||
QCoreApplication::processEvents();
|
QCoreApplication::processEvents();
|
||||||
|
|
||||||
TestAXObject *appObject = [TestAXObject getApplicationAXObject];
|
TestAXObject *appObject = [TestAXObject getApplicationAXObject];
|
||||||
EXPECT(appObject);
|
QVERIFY(appObject);
|
||||||
|
|
||||||
NSArray *windows = [appObject windowList];
|
NSArray *windows = [appObject windowList];
|
||||||
EXPECT([windows count] == 1);
|
QVERIFY([windows count] == 1);
|
||||||
|
|
||||||
AXUIElementRef windowRef = (AXUIElementRef) [windows objectAtIndex: 0];
|
AXUIElementRef windowRef = (AXUIElementRef) [windows objectAtIndex: 0];
|
||||||
EXPECT(windowRef != nil);
|
QVERIFY(windowRef != nil);
|
||||||
TestAXObject *window = [[TestAXObject alloc] initWithAXUIElementRef: windowRef];
|
TestAXObject *window = [[TestAXObject alloc] initWithAXUIElementRef: windowRef];
|
||||||
|
|
||||||
AXUIElementRef lineEditRef = [window findDirectChildByRole: kAXTextFieldRole];
|
AXUIElementRef lineEditRef = [window findDirectChildByRole: kAXTextFieldRole];
|
||||||
EXPECT(lineEditRef != nil);
|
QVERIFY(lineEditRef != nil);
|
||||||
TestAXObject *lineEdit = [[TestAXObject alloc] initWithAXUIElementRef: lineEditRef];
|
TestAXObject *lineEdit = [[TestAXObject alloc] initWithAXUIElementRef: lineEditRef];
|
||||||
EXPECT([[lineEdit value] isEqualToString:@"button"]);
|
QVERIFY([[lineEdit value] isEqualToString:@"button"]);
|
||||||
|
|
||||||
// Access invalid reference, should return empty value
|
// Access invalid reference, should return empty value
|
||||||
delete le;
|
delete le;
|
||||||
QCoreApplication::processEvents();
|
QCoreApplication::processEvents();
|
||||||
TestAXObject *lineEditInvalid = [[TestAXObject alloc] initWithAXUIElementRef: lineEditRef];
|
TestAXObject *lineEditInvalid = [[TestAXObject alloc] initWithAXUIElementRef: lineEditRef];
|
||||||
EXPECT([[lineEditInvalid value] length] == 0);
|
QVERIFY([[lineEditInvalid value] length] == 0);
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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];
|
TestAXObject *appObject = [TestAXObject getApplicationAXObject];
|
||||||
EXPECT(appObject);
|
QVERIFY(appObject);
|
||||||
|
|
||||||
NSArray *windowList = [appObject windowList];
|
NSArray *windowList = [appObject windowList];
|
||||||
// one window
|
// one window
|
||||||
EXPECT([windowList count] == 1);
|
QVERIFY([windowList count] == 1);
|
||||||
AXUIElementRef windowRef = (AXUIElementRef) [windowList objectAtIndex: 0];
|
AXUIElementRef windowRef = (AXUIElementRef) [windowList objectAtIndex: 0];
|
||||||
EXPECT(windowRef != nil);
|
QVERIFY(windowRef != nil);
|
||||||
TestAXObject *window = [[TestAXObject alloc] initWithAXUIElementRef: windowRef];
|
TestAXObject *window = [[TestAXObject alloc] initWithAXUIElementRef: windowRef];
|
||||||
|
|
||||||
EXPECT([window rect].size.width == 400);
|
QVERIFY([window rect].size.width == 400);
|
||||||
// height of window includes title bar
|
// 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"]);
|
||||||
|
|
||||||
// children of window:
|
// children of window:
|
||||||
AXUIElementRef lineEdit = [window findDirectChildByRole: kAXTextFieldRole];
|
AXUIElementRef lineEditElement = [window findDirectChildByRole: kAXTextFieldRole];
|
||||||
EXPECT(lineEdit != nil);
|
QVERIFY(lineEditElement != nil);
|
||||||
|
|
||||||
TestAXObject *le = [[TestAXObject alloc] initWithAXUIElementRef: lineEdit];
|
TestAXObject *le = [[TestAXObject alloc] initWithAXUIElementRef: lineEditElement];
|
||||||
NSString *value = @"a11y test QLineEdit";
|
NSString *value = @"a11y test QLineEdit";
|
||||||
EXPECT([le.value isEqualToString:value]);
|
QVERIFY([le.value isEqualToString:value]);
|
||||||
EXPECT(value.length <= NSIntegerMax);
|
QVERIFY(value.length <= NSIntegerMax);
|
||||||
EXPECT(le.numberOfCharacters == static_cast<NSInteger>(value.length));
|
QVERIFY(le.numberOfCharacters == static_cast<NSInteger>(value.length));
|
||||||
const NSRange ranges[] = {
|
const NSRange ranges[] = {
|
||||||
{ 0, 0},
|
{ 0, 0},
|
||||||
{ 0, 1},
|
{ 0, 1},
|
||||||
@ -415,82 +485,82 @@ bool testLineEdit()
|
|||||||
NSString *expectedSubstring = [value substringWithRange:range];
|
NSString *expectedSubstring = [value substringWithRange:range];
|
||||||
NSString *actualSubstring = [le stringForRange:range];
|
NSString *actualSubstring = [le stringForRange:range];
|
||||||
NSString *actualAttributedSubstring = [le attributedStringForRange:range].string;
|
NSString *actualAttributedSubstring = [le attributedStringForRange:range].string;
|
||||||
EXPECT([actualSubstring isEqualTo:expectedSubstring]);
|
QVERIFY([actualSubstring isEqualTo:expectedSubstring]);
|
||||||
EXPECT([actualAttributedSubstring 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];
|
TestAXObject *appObject = [TestAXObject getApplicationAXObject];
|
||||||
EXPECT(appObject);
|
QVERIFY(appObject);
|
||||||
|
|
||||||
NSArray *windowList = [appObject windowList];
|
NSArray *windowList = [appObject windowList];
|
||||||
// one window
|
// one window
|
||||||
EXPECT([windowList count] == 1);
|
QVERIFY([windowList count] == 1);
|
||||||
AXUIElementRef windowRef = (AXUIElementRef) [windowList objectAtIndex: 0];
|
AXUIElementRef windowRef = (AXUIElementRef) [windowList objectAtIndex: 0];
|
||||||
EXPECT(windowRef != nil);
|
QVERIFY(windowRef != nil);
|
||||||
TestAXObject *window = [[TestAXObject alloc] initWithAXUIElementRef: windowRef];
|
TestAXObject *window = [[TestAXObject alloc] initWithAXUIElementRef: windowRef];
|
||||||
|
|
||||||
// Because the plain widget is filtered out of the hierarchy, we expect the button
|
// Because the plain widget is filtered out of the hierarchy, we expect the button
|
||||||
// to be a direct child of the window
|
// to be a direct child of the window
|
||||||
AXUIElementRef buttonRef = [window findDirectChildByRole: kAXButtonRole];
|
AXUIElementRef buttonRef = [window findDirectChildByRole: kAXButtonRole];
|
||||||
EXPECT(buttonRef != nil);
|
QVERIFY(buttonRef != nil);
|
||||||
|
|
||||||
TestAXObject *buttonObject = [[TestAXObject alloc] initWithAXUIElementRef: buttonRef];
|
TestAXObject *buttonObject = [[TestAXObject alloc] initWithAXUIElementRef: buttonRef];
|
||||||
TestAXObject *parentObject = [[TestAXObject alloc] initWithAXUIElementRef: [buttonObject parent]];
|
TestAXObject *parentObject = [[TestAXObject alloc] initWithAXUIElementRef: [buttonObject parent]];
|
||||||
|
|
||||||
// check that the parent is a window
|
// check that the parent is a window
|
||||||
EXPECT([[parentObject role] isEqualToString: NSAccessibilityWindowRole]);
|
QVERIFY([[parentObject role] isEqualToString: NSAccessibilityWindowRole]);
|
||||||
|
|
||||||
// test the focus
|
// test the focus
|
||||||
// child 0 is the layout, then button1 and 2
|
// child 0 is the layout, then button1 and 2
|
||||||
QPushButton *button1 = qobject_cast<QPushButton*>(w->children().at(1));
|
QPushButton *button1 = qobject_cast<QPushButton*>(w->children().at(1));
|
||||||
EXPECT(button1);
|
QVERIFY(button1);
|
||||||
QPushButton *button2 = qobject_cast<QPushButton*>(w->children().at(2));
|
QPushButton *button2 = qobject_cast<QPushButton*>(w->children().at(2));
|
||||||
EXPECT(button2);
|
QVERIFY(button2);
|
||||||
button2->setFocus();
|
button2->setFocus();
|
||||||
|
|
||||||
AXUIElementRef systemWideElement = AXUIElementCreateSystemWide();
|
AXUIElementRef systemWideElement = AXUIElementCreateSystemWide();
|
||||||
AXUIElementRef focussedElement = NULL;
|
AXUIElementRef focussedElement = NULL;
|
||||||
AXError error = AXUIElementCopyAttributeValue(systemWideElement,
|
AXError error = AXUIElementCopyAttributeValue(systemWideElement,
|
||||||
(CFStringRef)NSAccessibilityFocusedUIElementAttribute, (CFTypeRef*)&focussedElement);
|
(CFStringRef)NSAccessibilityFocusedUIElementAttribute, (CFTypeRef*)&focussedElement);
|
||||||
EXPECT(!error);
|
QVERIFY(!error);
|
||||||
EXPECT(focussedElement);
|
QVERIFY(focussedElement);
|
||||||
TestAXObject *focusButton2 = [[TestAXObject alloc] initWithAXUIElementRef: focussedElement];
|
TestAXObject *focusButton2 = [[TestAXObject alloc] initWithAXUIElementRef: focussedElement];
|
||||||
|
|
||||||
EXPECT([[focusButton2 role] isEqualToString: NSAccessibilityButtonRole]);
|
QVERIFY([[focusButton2 role] isEqualToString: NSAccessibilityButtonRole]);
|
||||||
EXPECT([[focusButton2 title] isEqualToString: @"Button 2"]);
|
QVERIFY([[focusButton2 title] isEqualToString: @"Button 2"]);
|
||||||
|
|
||||||
|
|
||||||
button1->setFocus();
|
button1->setFocus();
|
||||||
error = AXUIElementCopyAttributeValue(systemWideElement,
|
error = AXUIElementCopyAttributeValue(systemWideElement,
|
||||||
(CFStringRef)NSAccessibilityFocusedUIElementAttribute, (CFTypeRef*)&focussedElement);
|
(CFStringRef)NSAccessibilityFocusedUIElementAttribute, (CFTypeRef*)&focussedElement);
|
||||||
EXPECT(!error);
|
QVERIFY(!error);
|
||||||
EXPECT(focussedElement);
|
QVERIFY(focussedElement);
|
||||||
TestAXObject *focusButton1 = [[TestAXObject alloc] initWithAXUIElementRef: focussedElement];
|
TestAXObject *focusButton1 = [[TestAXObject alloc] initWithAXUIElementRef: focussedElement];
|
||||||
EXPECT([[focusButton1 role] isEqualToString: NSAccessibilityButtonRole]);
|
QVERIFY([[focusButton1 role] isEqualToString: NSAccessibilityButtonRole]);
|
||||||
EXPECT([[focusButton1 title] isEqualToString: @"I am a button"]);
|
QVERIFY([[focusButton1 title] isEqualToString: @"I am a button"]);
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QVector<int> notificationList;
|
void tst_QAccessibilityMac::notificationsTest()
|
||||||
|
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
|
auto *w = m_window;
|
||||||
QLineEdit *le1 = new QLineEdit(w);
|
QLineEdit *le1 = new QLineEdit(w);
|
||||||
QLineEdit *le2 = new QLineEdit(w);
|
QLineEdit *le2 = new QLineEdit(w);
|
||||||
w->layout()->addWidget(le1);
|
w->layout()->addWidget(le1);
|
||||||
@ -500,76 +570,81 @@ bool notifications(QWidget *w)
|
|||||||
QTest::qWait(100);
|
QTest::qWait(100);
|
||||||
|
|
||||||
TestAXObject *appObject = [TestAXObject getApplicationAXObject];
|
TestAXObject *appObject = [TestAXObject getApplicationAXObject];
|
||||||
EXPECT(appObject);
|
QVERIFY(appObject);
|
||||||
|
|
||||||
NSArray *windowList = [appObject windowList];
|
NSArray *windowList = [appObject windowList];
|
||||||
// one window
|
// one window
|
||||||
EXPECT([windowList count] == 1);
|
QVERIFY([windowList count] == 1);
|
||||||
AXUIElementRef windowRef = (AXUIElementRef) [windowList objectAtIndex: 0];
|
AXUIElementRef windowRef = (AXUIElementRef) [windowList objectAtIndex: 0];
|
||||||
EXPECT(windowRef != nil);
|
QVERIFY(windowRef != nil);
|
||||||
TestAXObject *window = [[TestAXObject alloc] initWithAXUIElementRef: windowRef];
|
TestAXObject *window = [[TestAXObject alloc] initWithAXUIElementRef: windowRef];
|
||||||
|
|
||||||
AXUIElementRef lineEdit1 = [window findDirectChildByRole: kAXTextFieldRole];
|
AXUIElementRef lineEdit1 = [window findDirectChildByRole: kAXTextFieldRole];
|
||||||
EXPECT(lineEdit1 != nil);
|
QVERIFY(lineEdit1 != nil);
|
||||||
|
|
||||||
AXObserverRef observer = 0;
|
AXObserverRef observer = 0;
|
||||||
AXError err = AXObserverCreate(getpid(), observerCallback, &observer);
|
AXError err = AXObserverCreate(getpid(), observerCallback, &observer);
|
||||||
EXPECT(!err);
|
QVERIFY(!err);
|
||||||
AXObserverAddNotification(observer, appObject.ref, kAXFocusedUIElementChangedNotification, 0);
|
AXObserverAddNotification(observer, appObject.ref, kAXFocusedUIElementChangedNotification, 0);
|
||||||
AXObserverAddNotification(observer, lineEdit1, kAXValueChangedNotification, 0);
|
AXObserverAddNotification(observer, lineEdit1, kAXValueChangedNotification, 0);
|
||||||
|
|
||||||
CFRunLoopAddSource( [[NSRunLoop currentRunLoop] getCFRunLoop], AXObserverGetRunLoopSource(observer), kCFRunLoopDefaultMode);
|
CFRunLoopAddSource( [[NSRunLoop currentRunLoop] getCFRunLoop], AXObserverGetRunLoopSource(observer), kCFRunLoopDefaultMode);
|
||||||
|
|
||||||
EXPECT(notificationList.length() == 0);
|
QVERIFY(notificationList.length() == 0);
|
||||||
le2->setFocus();
|
le2->setFocus();
|
||||||
TRY_EXPECT(notificationList.length() == 1);
|
QTRY_VERIFY(notificationList.length() == 1);
|
||||||
TRY_EXPECT(notificationList.at(0) == QAccessible::Focus);
|
QTRY_VERIFY(notificationList.at(0) == QAccessible::Focus);
|
||||||
le1->setFocus();
|
le1->setFocus();
|
||||||
TRY_EXPECT(notificationList.length() == 2);
|
QTRY_VERIFY(notificationList.length() == 2);
|
||||||
TRY_EXPECT(notificationList.at(1) == QAccessible::Focus);
|
QTRY_VERIFY(notificationList.at(1) == QAccessible::Focus);
|
||||||
le1->setText("hello");
|
le1->setText("hello");
|
||||||
TRY_EXPECT(notificationList.length() == 3);
|
QTRY_VERIFY(notificationList.length() == 3);
|
||||||
TRY_EXPECT(notificationList.at(2) == QAccessible::ValueChanged);
|
QTRY_VERIFY(notificationList.at(2) == QAccessible::ValueChanged);
|
||||||
le1->setText("foo");
|
le1->setText("foo");
|
||||||
TRY_EXPECT(notificationList.length() == 4);
|
QTRY_VERIFY(notificationList.length() == 4);
|
||||||
TRY_EXPECT(notificationList.at(3) == QAccessible::ValueChanged);
|
QTRY_VERIFY(notificationList.at(3) == QAccessible::ValueChanged);
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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];
|
TestAXObject *appObject = [TestAXObject getApplicationAXObject];
|
||||||
EXPECT(appObject);
|
QVERIFY(appObject);
|
||||||
|
|
||||||
NSArray *windowList = [appObject windowList];
|
NSArray *windowList = [appObject windowList];
|
||||||
// one window
|
// one window
|
||||||
EXPECT([windowList count] == 1);
|
QVERIFY([windowList count] == 1);
|
||||||
AXUIElementRef windowRef = (AXUIElementRef) [windowList objectAtIndex: 0];
|
AXUIElementRef windowRef = (AXUIElementRef) [windowList objectAtIndex: 0];
|
||||||
EXPECT(windowRef != nil);
|
QVERIFY(windowRef != nil);
|
||||||
TestAXObject *window = [[TestAXObject alloc] initWithAXUIElementRef: windowRef];
|
TestAXObject *window = [[TestAXObject alloc] initWithAXUIElementRef: windowRef];
|
||||||
|
|
||||||
// children of window:
|
// children of window:
|
||||||
AXUIElementRef checkBox = [window findDirectChildByRole: kAXCheckBoxRole];
|
AXUIElementRef checkBox = [window findDirectChildByRole: kAXCheckBoxRole];
|
||||||
EXPECT(checkBox != nil);
|
QVERIFY(checkBox != nil);
|
||||||
|
|
||||||
TestAXObject *cb = [[TestAXObject alloc] initWithAXUIElementRef: checkBox];
|
TestAXObject *cb = [[TestAXObject alloc] initWithAXUIElementRef: checkBox];
|
||||||
|
|
||||||
// here start actual checkbox tests
|
// here start actual checkbox tests
|
||||||
EXPECT([cb valueNumber] == 0);
|
QVERIFY([cb valueNumber] == 0);
|
||||||
EXPECT([cb.title isEqualToString:@"Great option"]);
|
QVERIFY([cb.title isEqualToString:@"Great option"]);
|
||||||
// EXPECT(cb.description == nil); // currently returns "" instead of nil
|
// EXPECT(cb.description == nil); // currently returns "" instead of nil
|
||||||
|
|
||||||
EXPECT([cb.actions containsObject:(NSString*)kAXPressAction]);
|
QVERIFY([cb.actions containsObject:(NSString*)kAXPressAction]);
|
||||||
|
|
||||||
[cb performAction:kAXPressAction];
|
[cb performAction:kAXPressAction];
|
||||||
EXPECT([cb valueNumber] == 1);
|
QVERIFY([cb valueNumber] == 1);
|
||||||
|
|
||||||
[cb performAction:kAXPressAction];
|
[cb performAction:kAXPressAction];
|
||||||
EXPECT([cb valueNumber] == 0);
|
QVERIFY([cb valueNumber] == 0);
|
||||||
|
|
||||||
ckBox->setCheckState(Qt::PartiallyChecked);
|
ckBox->setCheckState(Qt::PartiallyChecked);
|
||||||
EXPECT([cb valueNumber] == 2);
|
QVERIFY([cb valueNumber] == 2);
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QTEST_MAIN(tst_QAccessibilityMac)
|
||||||
|
#include "tst_qaccessibilitymac.moc"
|
@ -1,16 +0,0 @@
|
|||||||
// Copyright (C) 2016 The Qt Company Ltd.
|
|
||||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
|
||||||
#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);
|
|
Loading…
x
Reference in New Issue
Block a user