summaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
authorFrederik Gladhorn <frederik.gladhorn@digia.com>2013-05-30 13:02:45 +0200
committerThe Qt Project <gerrit-noreply@qt-project.org>2013-06-07 14:54:39 +0200
commitcd756e5ed55a7859eca354e898ea5a3039fcb2e6 (patch)
treecaa6c20cddee6ebe0704b91803353a3a292ac2a6 /tests
parenta1c8c581ce590c1c3185fe4bb1d3b4851bdbfd33 (diff)
Cocoa Accessibility: fix ignoring of objects
On Mac it's expected that some elements are filtered out of the a11y hierarchy. We do this with the shouldBeIgnored function. The problem is that we would ignore some objects and then return them in the child attribute function. This is inconsistent and leads to voice over not working. For example having a plain QWidget with other widgets as children would cut off all of these widgets, since the plain QWidget would be ignored. Change-Id: I5f6c26b272e5ca57d59c1ed1ef47e9a2b1181295 Reviewed-by: Gabriel de Dietrich <gabriel.dedietrich@digia.com> Reviewed-by: Jan Arve Sæther <jan-arve.saether@digia.com>
Diffstat (limited to 'tests')
-rw-r--r--tests/auto/other/other.pro4
-rw-r--r--tests/auto/other/qaccessibilitymac/qaccessibilitymac.pro16
-rw-r--r--tests/auto/other/qaccessibilitymac/tst_qaccessibilitymac.cpp136
-rw-r--r--tests/auto/other/qaccessibilitymac/tst_qaccessibilitymac_helpers.h51
-rw-r--r--tests/auto/other/qaccessibilitymac/tst_qaccessibilitymac_helpers.mm213
5 files changed, 419 insertions, 1 deletions
diff --git a/tests/auto/other/other.pro b/tests/auto/other/other.pro
index 1f7582243e..1d57206a73 100644
--- a/tests/auto/other/other.pro
+++ b/tests/auto/other/other.pro
@@ -41,6 +41,7 @@ SUBDIRS=\
windowsmobile \
qaccessibility \
qaccessibilitylinux \
+ qaccessibilitymac \
!qtHaveModule(network): SUBDIRS -= \
baselineexample \
@@ -63,7 +64,8 @@ wince*|!contains(QT_CONFIG, accessibility): SUBDIRS -= qaccessibility
!mac: SUBDIRS -= \
macgui \
macnativeevents \
- macplist
+ macplist \
+ qaccessibilitymac
!embedded|wince*: SUBDIRS -= \
qdirectpainter
diff --git a/tests/auto/other/qaccessibilitymac/qaccessibilitymac.pro b/tests/auto/other/qaccessibilitymac/qaccessibilitymac.pro
new file mode 100644
index 0000000000..5d81567f45
--- /dev/null
+++ b/tests/auto/other/qaccessibilitymac/qaccessibilitymac.pro
@@ -0,0 +1,16 @@
+CONFIG += testcase
+TARGET = tst_qaccessibilitymac
+# LIBS += -framework Carbon
+QT += widgets testlib
+
+HEADERS += tst_qaccessibilitymac_helpers.h
+SOURCES += tst_qaccessibilitymac.cpp
+
+mac {
+ LIBS += -framework Security -framework AppKit -framework ApplicationServices
+ OBJECTIVE_SOURCES += tst_qaccessibilitymac_helpers.mm
+}
+
+
+requires(mac)
+DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0
diff --git a/tests/auto/other/qaccessibilitymac/tst_qaccessibilitymac.cpp b/tests/auto/other/qaccessibilitymac/tst_qaccessibilitymac.cpp
new file mode 100644
index 0000000000..25dd0d39dd
--- /dev/null
+++ b/tests/auto/other/qaccessibilitymac/tst_qaccessibilitymac.cpp
@@ -0,0 +1,136 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QApplication>
+#include <QtWidgets>
+#include <QtTest/QtTest>
+#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();
+ QTest::qWaitForWindowExposed(widget);
+ }
+
+ void clearChildren()
+ {
+ qDeleteAll(children());
+ new QHBoxLayout(this);
+ }
+};
+
+class tst_QAccessibilityMac : public QObject
+{
+Q_OBJECT
+private slots:
+ void init();
+ void cleanup();
+
+ void lineEditTest();
+ void hierarchyTest();
+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);
+
+ QTest::qWaitForWindowExposed(m_window);
+}
+
+void tst_QAccessibilityMac::cleanup()
+{
+ delete m_window;
+}
+
+
+void tst_QAccessibilityMac::lineEditTest()
+{
+ if (!macNativeAccessibilityEnabled())
+ return;
+
+ 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()
+{
+ if (!macNativeAccessibilityEnabled())
+ return;
+
+ QWidget *w = new QWidget(m_window);
+ m_window->addWidget(w);
+ QPushButton *b = new QPushButton(w);
+ w->setLayout(new QVBoxLayout());
+ w->layout()->addWidget(b);
+ b->setText("I am a button");
+
+ QVERIFY(QTest::qWaitForWindowExposed(m_window));
+ QCoreApplication::processEvents();
+ QVERIFY(testHierarchy());
+}
+
+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
new file mode 100644
index 0000000000..ec5beab125
--- /dev/null
+++ b/tests/auto/other/qaccessibilitymac/tst_qaccessibilitymac_helpers.h
@@ -0,0 +1,51 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include <QtCore/QString>
+#include <QtCore/QPair>
+#include <QtWidgets/QWidget>
+
+
+#pragma once // Yeah, it's deprecated in general, but it's standard practice for Mac OS X.
+
+bool macNativeAccessibilityEnabled();
+bool trusted();
+bool testLineEdit();
+bool testHierarchy();
diff --git a/tests/auto/other/qaccessibilitymac/tst_qaccessibilitymac_helpers.mm b/tests/auto/other/qaccessibilitymac/tst_qaccessibilitymac_helpers.mm
new file mode 100644
index 0000000000..8620b7dd2f
--- /dev/null
+++ b/tests/auto/other/qaccessibilitymac/tst_qaccessibilitymac_helpers.mm
@@ -0,0 +1,213 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// some versions of CALayer.h use 'slots' as an identifier
+#define QT_NO_KEYWORDS
+
+#include "tst_qaccessibilitymac_helpers.h"
+#include <QApplication>
+#include <QDebug>
+#include <unistd.h>
+
+#import <Cocoa/Cocoa.h>
+#import <ApplicationServices/ApplicationServices.h>
+
+bool macNativeAccessibilityEnabled()
+{
+ bool enabled = AXAPIEnabled();
+ if (!enabled)
+ qWarning() << "Accessibility is disabled (check System Preferences) skipping test.";
+ return enabled;
+}
+
+bool trusted()
+{
+ return AXIsProcessTrusted();
+}
+
+
+#define EXPECT(cond) \
+ if (!(cond)) { \
+ qWarning("Failure in %s, line: %d", __FILE__ , __LINE__); \
+ return false; \
+ } \
+
+
+@interface TestAXObject : NSObject
+{
+ AXUIElementRef reference;
+}
+ @property (readonly) NSString *role;
+ @property (readonly) NSString *description;
+ @property (readonly) NSString *value;
+ @property (readonly) CGRect rect;
+@end
+
+@implementation TestAXObject
+- (id) initWithAXUIElementRef: (AXUIElementRef) ref {
+ if ( self = [super init] ) {
+ reference = ref;
+ AXUIElementCopyAttributeValue(ref, kAXRoleAttribute, (CFTypeRef*)&_role);
+ AXUIElementCopyAttributeValue(ref, kAXDescriptionAttribute, (CFTypeRef*)&_description);
+ AXUIElementCopyAttributeValue(ref, kAXValueAttribute, (CFTypeRef*)&_value);
+ AXValueRef sizeValue;
+ AXUIElementCopyAttributeValue(ref, kAXSizeAttribute, (CFTypeRef*)&sizeValue);
+ AXValueGetValue(sizeValue, kAXValueCGSizeType, &_rect.size);
+ AXValueRef positionValue;
+ AXUIElementCopyAttributeValue(ref, kAXPositionAttribute, (CFTypeRef*)&positionValue);
+ AXValueGetValue(positionValue, kAXValueCGPointType, &_rect.origin);
+ }
+ return self;
+}
+
+- (AXUIElementRef) ref { return reference; }
+- (void) print {
+ NSLog(@"Accessible Object role: '%@', description: '%@', value: '%@', rect: '%@'", self.role, self.description, self.value, NSStringFromRect(self.rect));
+ NSLog(@" Children: %ld", [self.childList count]);
+}
+
+- (NSArray*) windowList
+{
+ NSArray *list;
+ AXUIElementCopyAttributeValues(
+ reference,
+ kAXWindowsAttribute,
+ 0, 100, /*min, max*/
+ (CFArrayRef *) &list);
+ return list;
+}
+
+- (NSArray*) childList
+{
+ NSArray *list;
+ AXUIElementCopyAttributeValues(
+ reference,
+ kAXChildrenAttribute,
+ 0, 100, /*min, max*/
+ (CFArrayRef *) &list);
+ return list;
+}
+
+- (AXUIElementRef) findDirectChildByRole: (CFStringRef) role
+{
+ AXUIElementRef result = nil;
+ NSArray *childList = [self childList];
+ for (id child in childList) {
+ CFStringRef typeString;
+ AXUIElementCopyAttributeValue((AXUIElementRef)child, kAXRoleAttribute, (CFTypeRef*)&typeString);
+ if (CFStringCompare(typeString, role, 0) == 0) {
+ result = (AXUIElementRef) child;
+ break;
+ }
+ }
+ return result;
+}
+
+- (AXUIElementRef) parent
+{
+ AXUIElementRef p = nil;
+ AXUIElementCopyAttributeValue(reference, kAXParentAttribute, (CFTypeRef*)&p);
+ return p;
+}
+
+@end
+
+
+bool testLineEdit()
+{
+// not sure if this is needed. on my machine the calls succeed.
+// NSString *path = @"/Users/frederik/qt5/qtbase/tests/auto/other/qaccessibilitymac/tst_qaccessibilitymac.app/Contents/MacOS/tst_qaccessibilitymac";
+// NSString *path = @"/Users/frederik/qt5/qtbase/tests/auto/other/qaccessibilitymac/tst_qaccessibilitymac.app";
+// AXError e = AXMakeProcessTrusted((CFStringRef) path);
+// NSLog(@"error: %i", e);
+
+ pid_t pid = getpid();
+ AXUIElementRef app = AXUIElementCreateApplication(pid);
+ EXPECT(app != nil);
+ TestAXObject *appObject = [[TestAXObject alloc] initWithAXUIElementRef: app];
+
+ NSArray *windowList = [appObject windowList];
+ // one window
+ EXPECT([windowList count] == 1);
+ AXUIElementRef windowRef = (AXUIElementRef) [windowList objectAtIndex: 0];
+ EXPECT(windowRef != nil);
+ TestAXObject *window = [[TestAXObject alloc] initWithAXUIElementRef: windowRef];
+
+ EXPECT([window rect].size.width == 400);
+ // height of window includes title bar
+ EXPECT([window rect].size.height >= 400);
+
+ // children of window:
+ AXUIElementRef lineEdit = [window findDirectChildByRole: kAXTextFieldRole];
+ EXPECT(lineEdit != nil);
+
+ TestAXObject *le = [[TestAXObject alloc] initWithAXUIElementRef: lineEdit];
+ EXPECT([[le value] isEqualToString:@"a11y test QLineEdit"]);
+ return true;
+}
+
+bool testHierarchy()
+{
+ pid_t pid = getpid();
+ AXUIElementRef app = AXUIElementCreateApplication(pid);
+ EXPECT(app != nil);
+ TestAXObject *appObject = [[TestAXObject alloc] initWithAXUIElementRef: app];
+
+ NSArray *windowList = [appObject windowList];
+ // one window
+ EXPECT([windowList count] == 1);
+ AXUIElementRef windowRef = (AXUIElementRef) [windowList objectAtIndex: 0];
+ EXPECT(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);
+
+ TestAXObject *buttonObject = [[TestAXObject alloc] initWithAXUIElementRef: buttonRef];
+ TestAXObject *parentObject = [[TestAXObject alloc] initWithAXUIElementRef: [buttonObject parent]];
+
+ // check that the parent is a window
+ EXPECT([[parentObject role] isEqualToString: (NSString *)kAXWindowRole]);
+
+ return true;
+}