tests/auto/qaccessibility_mac/tst_qaccessibility_mac.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/auto/qaccessibility_mac/tst_qaccessibility_mac.cpp	Mon Jan 11 14:00:40 2010 +0000
@@ -0,0 +1,1966 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** 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, Nokia gives you certain additional
+** rights.  These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include <QtTest/QtTest>
+
+#if defined(Q_WS_MAC) && !defined (QT_MAC_USE_COCOA)
+
+#include <private/qt_mac_p.h>
+#undef verify // yes, lets reserve the word "verify"
+
+#include <QApplication>
+#include <QDebug>
+#include <QTimer>
+#include <QString>
+#include <QFile>
+#include <QVariant>
+#include <QPushButton>
+#include <QToolBar>
+#include <QSlider>
+#include <QListWidget>
+#include <QTableWidget>
+#include <QScrollArea>
+#include <QLabel>
+#include <QScrollBar>
+#include <QTextEdit>
+#include <QAccessibleInterface>
+#include <QAccessible>
+#include <QPluginLoader>
+#include <private/qaccessible_mac_p.h>
+#include <quiloader.h>
+
+#include <sys/types.h> // for getpid()
+#include <unistd.h>
+
+Q_DECLARE_METATYPE(AXUIElementRef);
+
+typedef QCFType<CFArrayRef> QCFArrayRef;
+
+class tst_qaccessibility_mac : public QObject
+{
+Q_OBJECT
+public slots:
+    void printInfo();
+    void testForm();
+    void testButtons();
+    void testLineEdit();
+    void testLabel();
+    void testGroups();
+    void testTabWidget();
+    void testTabBar();
+    void testComboBox();
+    void testDeleteWidget();
+    void testDeleteWidgets();
+    void testMultipleWindows();
+    void testHiddenWidgets();
+    void testActions();
+    void testChangeState();
+    void testSlider();
+    void testScrollArea();
+    void testListView();
+    void testTableView();
+    void testScrollBar();
+    void testSplitter();
+    void testTextEdit();
+    void testItemViewsWithoutModel();
+private slots:
+    void testQAElement();
+    void testQAInterface();
+
+    // ui tests load an .ui file.
+    void uitests_data();
+    void uitests();
+    
+    void tests_data();
+    void tests();
+private:
+    void runTest(const QString &testSlot);
+};
+
+/*
+    VERIFYs that there is no error and prints an error message if there is.
+*/
+void testError(AXError error, const QString &text)
+{
+    if (error)
+        qDebug() << "Error" << error << text;
+    QVERIFY(error == 0);
+}
+
+/*
+    Prints an CFArray holding CFStrings.
+*/
+void printCFStringArray(CFArrayRef array, const QString &title)
+{
+    const int numElements = CFArrayGetCount(array);
+    qDebug() << "num" << title << " " <<  numElements;
+
+    for (int i = 0; i < numElements; ++i) {
+       CFStringRef str = (CFStringRef)CFArrayGetValueAtIndex(array, i);
+       qDebug() << QCFString::toQString(str);
+    }
+}
+
+QStringList toQStringList(const CFArrayRef array)
+{
+    const int numElements = CFArrayGetCount(array);
+    QStringList qtStrings;
+    
+    for (int i = 0; i < numElements; ++i) {
+        CFStringRef str = (CFStringRef)CFArrayGetValueAtIndex(array, i);
+        qtStrings.append(QCFString::toQString(str));
+    }
+    
+    return qtStrings;
+}
+
+QVariant AXValueToQVariant(AXValueRef value)
+{
+    QVariant var;
+    const AXValueType type = AXValueGetType(value);
+    switch (type) {
+        case kAXValueCGPointType : {
+            CGPoint point;
+            if (AXValueGetValue(value, type, &point))
+                var = QPointF(point.x, point.y);
+        } break;
+        case kAXValueCGSizeType : {
+            CGSize size;
+            if (AXValueGetValue(value, type, &size))
+                var = QSizeF(size.width, size.height);
+        } break;
+        case kAXValueCGRectType :  {
+            CGRect rect;
+            if (AXValueGetValue(value, type, &rect))
+                var = QRectF(rect.origin.x, rect.origin.y, rect.size.width, rect.size.height);
+        } break;
+        case kAXValueCFRangeType :
+#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4)
+        case kAXValueAXErrorType :
+#endif
+        case kAXValueIllegalType :
+        default:
+        qDebug() << "Illegal/Unsuported AXValue:" << type;
+        break;
+    };
+    return var;
+}
+
+/*
+    Converts a CFTypeRef to a QVariant, for certain selected types. Prints
+    an error message and returns QVariant() if the type is not supported.
+*/
+QVariant CFTypeToQVariant(CFTypeRef value)
+{
+    QVariant var;
+    if (value == 0)
+        return var;
+    const uint typeID = CFGetTypeID(value);
+    if (typeID == CFStringGetTypeID()) {
+        var.setValue(QCFString::toQString((CFStringRef)value));
+    } else if (typeID == CFBooleanGetTypeID()) {
+        var.setValue((bool)CFBooleanGetValue((CFBooleanRef)value));
+    } else if (typeID == AXUIElementGetTypeID()) {
+        var.setValue((AXUIElementRef)value);
+    } else if (typeID == AXValueGetTypeID()) {
+        var = AXValueToQVariant((AXValueRef)value);
+    } else if (typeID == CFNumberGetTypeID()) {
+        CFNumberRef number = (CFNumberRef)value;
+        if (CFNumberGetType(number) != kCFNumberSInt32Type)
+            qDebug() << "unsupported number type" << CFNumberGetType(number);
+        int theNumber;
+        CFNumberGetValue(number, kCFNumberSInt32Type, &theNumber);
+        var.setValue(theNumber);
+    } else if (typeID == CFArrayGetTypeID()) {
+        CFArrayRef cfarray = static_cast<CFArrayRef>(value);
+        QVariantList list;
+        CFIndex size = CFArrayGetCount(cfarray);
+        for (CFIndex i = 0; i < size; ++i)
+            list << CFTypeToQVariant(CFArrayGetValueAtIndex(cfarray, i));
+        var.setValue(list);
+    } else {
+        QCFString str = CFCopyTypeIDDescription(typeID);
+        qDebug() << "Unknown CFType: " << typeID << (QString)str;
+    }
+    return var;
+}
+
+/*
+    Tests if a given attribute is supported by an element. Expects either
+    no error or error -25205 (Not supported). Causes a test failure
+    on other error values.
+*/
+bool supportsAttribute(AXUIElementRef element, CFStringRef attribute)
+{
+    CFArrayRef array;
+    AXError err = AXUIElementCopyAttributeNames(element, &array);
+    if (err) {
+        testError(err, QLatin1String("unexpected error when testing for supported attribute") + QCFString::toQString(attribute));
+        return false;
+    }
+    CFRange range;
+    range.location = 0;
+    range.length = CFArrayGetCount(array);
+    return CFArrayContainsValue(array, range, attribute);
+}
+
+/*
+    Returns the accessibility attribute specified with attribute in a QVariant
+*/
+QVariant attribute(AXUIElementRef element, CFStringRef attribute)
+{
+    CFTypeRef value = 0;
+    AXError err = AXUIElementCopyAttributeValue(element, attribute, &value);
+
+    testError(err, QString("Error getting element attribute ") + QCFString::toQString(attribute));
+
+    if (err)
+        return QVariant();
+
+    return CFTypeToQVariant(value);
+}
+
+/*
+    Returns the title for an element.
+*/
+QString title(AXUIElementRef element)
+{
+    return attribute(element, kAXTitleAttribute).toString();
+}
+
+/*
+    Returns the role for an element.
+*/
+QString role(AXUIElementRef element)
+{
+    return attribute(element, kAXRoleAttribute).toString();
+}
+
+/*
+    Returns the subrole for an element.
+*/
+QString subrole(AXUIElementRef element)
+{
+    return attribute(element, kAXSubroleAttribute).toString();
+}
+
+/*
+    Returns the role description for an element.
+*/
+QString roleDescription(AXUIElementRef element)
+{
+    return attribute(element, kAXRoleDescriptionAttribute).toString();
+}
+
+/*
+    Returns the enabled attribute for an element.
+*/
+bool enabled(AXUIElementRef element)
+{
+    return attribute(element, kAXEnabledAttribute).toBool();
+}
+
+/*
+    Returns the value attribute for an element as an QVariant.
+*/
+QVariant value(AXUIElementRef element)
+{
+    return attribute(element, kAXValueAttribute);
+}
+
+QVariant value(QAElement element)
+{
+    return value(element.element());
+}
+
+/*
+    Returns the description attribute for an element as an QVariant.
+*/
+QVariant description(AXUIElementRef element)
+{
+    return attribute(element, kAXDescriptionAttribute);
+}
+
+/*
+    Returns the value attribute for an element as an bool.
+*/
+bool boolValue(AXUIElementRef element)
+{
+    return attribute(element, kAXValueAttribute).toBool();
+}
+
+/*
+    Returns the parent for an element
+*/
+AXUIElementRef parent(AXUIElementRef element)
+{
+    return attribute(element, kAXParentAttribute).value<AXUIElementRef>();
+}
+
+/*
+    Returns the (top-level) window(not a sheet or a drawer) for an element
+*/
+AXUIElementRef window(AXUIElementRef element)
+{
+    return attribute(element, kAXWindowAttribute).value<AXUIElementRef>();
+}
+
+/*
+    Returns the (top-level) UI element(can also be a sheet or drawer) for an element
+*/
+#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4)
+AXUIElementRef topLevelUIElement(AXUIElementRef element)
+{
+    return attribute(element, kAXTopLevelUIElementAttribute).value<AXUIElementRef>();
+}
+#endif
+
+/*
+    Returns thie size of the element.
+*/
+QSizeF size(AXUIElementRef element)
+{
+    return attribute(element, kAXSizeAttribute).value<QSizeF>();
+}
+
+/*
+    Returns the position of the element.
+*/
+QPointF position(AXUIElementRef element)
+{
+    return attribute(element, kAXPositionAttribute).value<QPointF>();
+}
+
+/*
+    Returns the rect of the element.
+*/
+QRectF rect(AXUIElementRef element)
+{
+    return QRectF(position(element), size(element));
+}
+
+bool above(AXUIElementRef a, AXUIElementRef b)
+{
+    return (position(a).y() + size(a).height() <= position(b).y());
+}
+
+bool contains(AXUIElementRef a, AXUIElementRef b)
+{
+    return rect(a).contains(rect(b));
+}
+
+QList<AXUIElementRef> tabs(AXUIElementRef element)
+{
+    CFTypeRef value;
+    AXError err = AXUIElementCopyAttributeValue(element, kAXTabsAttribute, &value);
+    if (err)
+        return QList<AXUIElementRef>();
+        
+    CFArrayRef array = (CFArrayRef)value;
+    QList<AXUIElementRef> elements;
+    const int count = CFArrayGetCount(array);
+    for (int i = 0; i < count; ++i)
+        elements.append((AXUIElementRef)CFArrayGetValueAtIndex(array, i));
+   
+    return elements;
+}
+
+QList<AXUIElementRef> elementListAttribute(AXUIElementRef element, CFStringRef attributeName)
+{
+    QList<AXUIElementRef> elementList;
+    QVariantList variants = attribute(element, attributeName).value<QVariantList>();
+    foreach(QVariant variant, variants)
+        elementList.append(variant.value<AXUIElementRef>());
+    return elementList;
+}
+
+AXUIElementRef elementAttribute(AXUIElementRef element, CFStringRef attributeName)
+{
+    return attribute(element, attributeName).value<AXUIElementRef>();
+}
+
+QString stringAttribute(AXUIElementRef element, CFStringRef attributeName)
+{
+    return attribute(element, attributeName).value<QString>();
+}
+
+
+/*
+    Returns the UIElement at the given position.
+*/
+AXUIElementRef childAtPoint(QPointF position)
+{
+    AXUIElementRef element = 0;
+    const AXError err = AXUIElementCopyElementAtPosition(AXUIElementCreateApplication(getpid()), position.x(), position.y(), &element);
+    if (err) {
+        qDebug() << "Error getting element at " << position;
+        return 0;
+    }
+
+    return element;
+}
+
+/*
+    Returns a QStringList containing the names of the actions the ui element supports
+*/
+QStringList actionNames(AXUIElementRef element)
+{
+    CFArrayRef cfStrings;
+    const AXError err = AXUIElementCopyActionNames(element, &cfStrings);
+    testError(err, "Unable to get action names");
+    return toQStringList(cfStrings);
+}
+
+bool supportsAction(const AXUIElementRef element, const QString &actionName)
+{
+    const QStringList actions = actionNames(element);
+    return actions.contains(actionName);
+}
+
+bool performAction(const AXUIElementRef element, const QString &actionName)
+{
+    const AXError err = AXUIElementPerformAction(element, QCFString(actionName));
+    return (err == 0);
+}
+
+/*
+    Om 10.4 and up, verifyes the AXRoleDescription attribute for an element,
+    on 10.3 and below this test always passes.
+
+    The reason for this is that the HICopyAccessibilityRoleDescription call
+    used to implement this functionality was introduced in 10.4.
+*/
+#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4)
+    #define VERIFY_ROLE_DESCRIPTION(ELEMENT,  TEXT) \
+            QCOMPARE(roleDescription(ELEMENT), QString(TEXT))
+#else
+    #define VERIFY_ROLE_DESCRIPTION(ELEMENT,  TEXT) QVERIFY(true)
+#endif
+
+
+CFArrayRef childrenArray(AXUIElementRef element)
+{
+    CFTypeRef value = 0;
+    AXError err = AXUIElementCopyAttributeValue(element, kAXChildrenAttribute, &value);
+    if (!err && CFGetTypeID(value) == CFArrayGetTypeID()) {
+        return (CFArrayRef)value;
+    }
+   
+    return CFArrayCreate(0,0,0,0);
+}
+
+/*
+    Gest the child count from an element.
+*/
+int numChildren(AXUIElementRef element)
+{
+    return CFArrayGetCount(childrenArray(element));
+}
+
+/*
+    Gets the child with index childIndex from element. Returns 0 if not found.
+*/
+AXUIElementRef child(AXUIElementRef element, int childIndex)
+{
+    CFArrayRef children = childrenArray(element);
+    if (childIndex >= CFArrayGetCount(children))
+        return 0;
+
+    const void *data  = CFArrayGetValueAtIndex(children, childIndex);
+    return (AXUIElementRef)data;
+}
+
+/*
+    Gets the child titled childTitle from element. Returns 0 if not found.
+*/
+AXUIElementRef childByTitle(AXUIElementRef element, const QString &childTitle)
+{
+    CFArrayRef children  = childrenArray(element);
+    const int numChildren = CFArrayGetCount(children);
+    for (int i = 0; i < numChildren; ++i) {
+        const AXUIElementRef childElement = (AXUIElementRef)CFArrayGetValueAtIndex(children, i);
+        // Test for support for title attribute before getting it to avoid test fail.
+        if (supportsAttribute(childElement, kAXTitleAttribute) && title(childElement) == childTitle)
+            return childElement;
+    }
+    return 0;
+}
+
+/*
+    Gets the child with the given value from element. Returns 0 if not found.
+*/
+AXUIElementRef childByValue(AXUIElementRef element, const QVariant &testValue)
+{
+    CFArrayRef children  = childrenArray(element);
+    const int numChildren = CFArrayGetCount(children);
+    for (int i = 0; i < numChildren; ++i) {
+        const AXUIElementRef childElement = (AXUIElementRef)CFArrayGetValueAtIndex(children, i);
+        // Test for support for value attribute before getting it to avoid test fail.
+        if (supportsAttribute(childElement, kAXValueAttribute) && value(childElement) == testValue)
+            return childElement;
+    }
+    return 0;
+}
+
+/*
+    Gets the child by role from element. Returns 0 if not found.
+*/
+AXUIElementRef childByRole(AXUIElementRef element, const QString &macRole)
+{
+    CFArrayRef children  = childrenArray(element);
+    const int numChildren = CFArrayGetCount(children);
+    for (int i = 0; i < numChildren; ++i) {
+        const AXUIElementRef childElement = (AXUIElementRef)CFArrayGetValueAtIndex(children, i);
+        if (role(childElement) == macRole)
+            return childElement;
+    }
+    return 0;
+}
+
+void printTypeForAttribute(AXUIElementRef element, CFStringRef attribute)
+{
+    CFTypeRef value = 0;
+    AXError err = AXUIElementCopyAttributeValue(element, attribute, &value);
+    if (!err) {
+        qDebug() << "type id" << CFGetTypeID(value);
+        QCFString str = CFCopyTypeIDDescription(CFGetTypeID(value));
+        qDebug() << (QString)str;
+    } else {
+        qDebug() << "Attribute Get error" << endl;
+    }
+}
+
+int indent = 0;
+QString space()
+{
+    QString space;
+    for (int i = 0; i < indent; ++i) {
+        space += " ";
+    }
+    return space;
+}
+
+
+/*
+    Recursively prints acccesibility info for currentElement and all its children.
+*/
+void printElementInfo(AXUIElementRef currentElement)
+{
+    if (HIObjectIsAccessibilityIgnored(AXUIElementGetHIObject(currentElement))) {
+        qDebug() << space() << "Ignoring element with role" << role(currentElement);
+        return;
+    }
+    
+    qDebug() << space() <<"Role" << role(currentElement);
+    if (supportsAttribute(currentElement, kAXTitleAttribute))
+        qDebug() << space() << "Title" << title(currentElement);
+    else
+        qDebug() << space() << "Title not supported";
+    
+    if (supportsAttribute(currentElement, kAXValueAttribute))
+        qDebug() << space() << "Value" << attribute(currentElement, kAXValueAttribute);
+    else
+        qDebug() << space() << "Value not supported";
+    
+    qDebug() << space() << "Number of children" << numChildren(currentElement);
+    for (int i = 0; i < numChildren(currentElement); ++i) {
+        AXUIElementRef childElement = child(currentElement, i);
+        // Skip the menu bar.
+        if (role(childElement) != "AXMenuBar") {
+            indent+= 4;
+            printElementInfo(childElement);
+            indent-= 4;
+        }
+    }
+    qDebug() << " ";
+}
+
+/*
+    Recursively prints the child interfaces belonging to interface.
+*/
+
+void printChildren(const QAInterface &interface)
+{
+    if (interface.isValid() == false)
+        return;
+        
+    QList<QAInterface> children = interface.children();
+    if (children.isEmpty())
+        return;
+
+    qDebug() << "## Children for" << interface;
+    foreach (const QAInterface &child, children) {
+        qDebug() << child << "index in parent" << interface.indexOfChild(child);
+    }
+    foreach (const QAInterface &child, children) {
+        printChildren(child);
+    }
+}
+
+bool isIgnored(AXUIElementRef currentElement)
+{
+    return HIObjectIsAccessibilityIgnored(AXUIElementGetHIObject(currentElement));
+}
+
+bool equal(CFTypeRef o1, CFTypeRef o2)
+{
+    if (o1 == 0 || o2 == 0)
+        return false;
+    return CFEqual(o1, o2);
+}
+
+/*
+    Verifies basic element info.
+*/
+#define VERIFY_ELEMENT(element, _parent, _role) \
+    QVERIFY(element != 0); \
+    QVERIFY(role(element) == _role); \
+    QVERIFY(equal(::parent(element), _parent));
+/*
+    Verifies that the application and the main form is there has the right info.
+*/
+void testAppAndForm(AXUIElementRef application)
+{
+    QVERIFY(title(application) == "tst_qaccessibility_mac");
+    QVERIFY(role(application) == "AXApplication");
+
+    AXUIElementRef form = childByTitle(application, "Form");
+    VERIFY_ELEMENT(form, application, "AXWindow");
+}
+
+void tst_qaccessibility_mac::printInfo()
+{
+    AXUIElementRef currentApplication = AXUIElementCreateApplication(getpid());
+    printElementInfo(currentApplication);
+}
+
+/*
+    Tests for form.ui
+*/
+void tst_qaccessibility_mac::testForm()
+{
+    // Get reference to the current application.
+    AXUIElementRef currentApplication = AXUIElementCreateApplication(getpid());
+    testAppAndForm(currentApplication);
+    childByTitle(currentApplication, "Form");
+}
+
+/*
+    Tests for buttons.ui
+*/
+void tst_qaccessibility_mac::testButtons()
+{
+    // Get reference to the current application.
+    AXUIElementRef currentApplication = AXUIElementCreateApplication(getpid());
+    testAppAndForm(currentApplication);
+    AXUIElementRef form = childByTitle(currentApplication, "Form");
+
+    AXUIElementRef ren = childByTitle(form, "Ren");
+    VERIFY_ELEMENT(ren, form, "AXButton");
+    QVERIFY(enabled(ren) == true);
+    VERIFY_ROLE_DESCRIPTION(ren, "button");
+
+    AXUIElementRef stimpy = childByTitle(form, "Stimpy");
+    VERIFY_ELEMENT(stimpy, form, "AXRadioButton");
+    QVERIFY(enabled(stimpy) == true);
+    QVERIFY(value(stimpy).toInt() == 1); // checked;
+    VERIFY_ROLE_DESCRIPTION(stimpy, "radio button");
+
+    AXUIElementRef pinky = childByTitle(form, "Pinky");
+    VERIFY_ELEMENT(pinky, form, "AXCheckBox");
+    QVERIFY(enabled(pinky) == false);
+    QVERIFY(value(pinky).toInt() == 0); // unchecked;
+    VERIFY_ROLE_DESCRIPTION(pinky, "check box");
+
+    AXUIElementRef brain = childByTitle(form, "Brain");
+    VERIFY_ELEMENT(brain, form, "AXButton");
+    VERIFY_ROLE_DESCRIPTION(brain, "button");
+}
+
+void tst_qaccessibility_mac::testLabel()
+{
+    // Get reference to the current application.
+    AXUIElementRef currentApplication = AXUIElementCreateApplication(getpid());
+
+    testAppAndForm(currentApplication);
+    AXUIElementRef form = childByTitle(currentApplication, "Form");
+    AXUIElementRef label = childByValue(form, "This is a Text Label");
+    QVERIFY(label);
+    VERIFY_ELEMENT(label, form, "AXStaticText");
+    VERIFY_ROLE_DESCRIPTION(label, "text");
+    QCOMPARE(supportsAttribute(label, kAXDescriptionAttribute), false);
+}
+
+/*
+    Tests for lineedit.ui
+*/
+void tst_qaccessibility_mac::testLineEdit()
+{
+    // Get reference to the current application.
+    AXUIElementRef currentApplication = AXUIElementCreateApplication(getpid());
+
+    testAppAndForm(currentApplication);
+    AXUIElementRef form = childByTitle(currentApplication, "Form");
+    AXUIElementRef lineEdit = childByValue(form, "Line edit");
+    VERIFY_ELEMENT(lineEdit, form, "AXTextField");
+    VERIFY_ROLE_DESCRIPTION(lineEdit, "text field");
+}
+
+/*
+    Tests for groups.ui
+*/
+void tst_qaccessibility_mac::testGroups()
+{
+    // Get reference to the current application.
+    AXUIElementRef currentApplication = AXUIElementCreateApplication(getpid());
+
+    testAppAndForm(currentApplication);
+    AXUIElementRef form = childByTitle(currentApplication, "Form");
+
+    AXUIElementRef groupA = childByTitle(form, "Group A");
+    VERIFY_ELEMENT(groupA, form, "AXGroup");
+    AXUIElementRef button1 = childByTitle(groupA, "PushButton 1");
+    VERIFY_ELEMENT(button1, groupA, "AXButton");
+    VERIFY_ROLE_DESCRIPTION(groupA, "group");
+
+    AXUIElementRef groupB = childByTitle(form, "Group B");
+    VERIFY_ELEMENT(groupB, form, "AXGroup");
+    AXUIElementRef button3 = childByTitle(groupB, "PushButton 3");
+    VERIFY_ELEMENT(button3, groupB, "AXButton");
+}
+
+/*
+    Tests for tabs.ui
+*/
+void tst_qaccessibility_mac::testTabWidget()
+{
+    {   // Test that the QTabWidget hierarchy is what we expect it to be.
+        QTabWidget tabWidget;
+        tabWidget.show();
+        QAInterface interface = QAccessible::queryAccessibleInterface(&tabWidget);
+        tabWidget.addTab(new QPushButton("Foo"), "FooTab");
+        tabWidget.addTab(new QPushButton("Bar"), "BarTab");
+        QCOMPARE(interface.childCount(), 2);
+        const QList<QAInterface> children = interface.children();
+        QVERIFY(children.at(0).object()->inherits("QStackedWidget"));
+        QVERIFY(children.at(1).object()->inherits("QTabBar"));
+        
+        const QList<QAInterface> tabBarChildren = children.at(1).children();
+        QCOMPARE(tabBarChildren.count(), 4);
+        QCOMPARE(tabBarChildren.at(0).text(QAccessible::Name), QLatin1String("FooTab"));
+        QCOMPARE(tabBarChildren.at(1).text(QAccessible::Name), QLatin1String("BarTab"));
+        QCOMPARE(tabBarChildren.at(0).role(), QAccessible::PageTab);
+        QCOMPARE(tabBarChildren.at(1).role(), QAccessible::PageTab);
+
+        // Check that the hierarchy manager is able to register the tab bar children.
+        QAccessibleHierarchyManager *manager = QAccessibleHierarchyManager::instance();
+        QAInterface tabBarInterface = children.at(1);
+        QAElement tabBarElement = manager->registerInterface(tabBarInterface);
+        QCOMPARE(manager->lookup(tabBarElement).childCount(), 4);
+        manager->registerChildren(tabBarInterface);
+        QAElement tabButtonElement = manager->lookup(tabBarChildren.at(1));
+        QAInterface tabButtonInterface = manager->lookup(tabButtonElement);
+        QCOMPARE(tabButtonInterface.text(QAccessible::Name), QLatin1String("BarTab"));
+        QVERIFY(isItInteresting(tabButtonInterface) == true);
+    }
+
+    // Get reference to the current application.
+    AXUIElementRef currentApplication = AXUIElementCreateApplication(getpid());
+
+    testAppAndForm(currentApplication);
+    const QString formTitle = "Form";
+    AXUIElementRef form = childByTitle(currentApplication, formTitle);
+    QVERIFY(form);
+
+    const QString tabRole = "AXTabGroup";
+    AXUIElementRef tabGroup = childByRole(form, tabRole);
+    QVERIFY(tabGroup);
+
+    // Test that we have three child buttons (the tab buttons + plus the contents of the first tab)
+    const int numChildren = ::numChildren(tabGroup);
+    QCOMPARE(numChildren, 3);
+    
+    const QString tab1Title = "Tab 1";
+    AXUIElementRef tabButton1 = childByTitle(tabGroup, tab1Title);
+    QVERIFY (tabButton1);
+    VERIFY_ELEMENT(tabButton1, tabGroup, "AXRadioButton");
+    QCOMPARE(title(tabButton1), tab1Title);
+
+    const QString tab2Title = "Tab 2";
+    const AXUIElementRef tabButton2 = childByTitle(tabGroup, tab2Title);
+    QVERIFY(tabButton2);
+    VERIFY_ELEMENT(tabButton2, tabGroup, "AXRadioButton");
+    QCOMPARE(title(tabButton2), tab2Title);
+    
+    // Test that the window and top-level-ui-elment is the form.
+    // Window is not reported properly on 10.5
+    if (QSysInfo::MacintoshVersion < QSysInfo::MV_10_5) {
+        QVERIFY(equal(window(tabGroup), form));
+
+    //   ### hangs on 10.4
+#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5)
+    QVERIFY(equal(window(tabButton1), form));
+#endif
+    }
+//   ### hangs on 10.4
+#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5)
+    QVERIFY(equal(topLevelUIElement(tabGroup), form));
+    QVERIFY(equal(topLevelUIElement(tabButton1), form));    
+#endif
+    // Test the bounding rectangles for the tab group and buttons.
+    const QRectF groupRect(position(tabGroup), size(tabGroup));
+    const QRectF tabButton1Rect(position(tabButton1), size(tabButton1));
+    const QRectF tabButton2Rect(position(tabButton2), size(tabButton2));
+    
+    QVERIFY(groupRect.isNull() == false);
+    QVERIFY(tabButton1Rect.isNull() == false);
+    QVERIFY(tabButton1Rect.isNull() == false);
+        
+    QVERIFY(groupRect.contains(tabButton1Rect));
+    QVERIFY(groupRect.contains(tabButton2Rect));
+    QVERIFY(tabButton2Rect.contains(tabButton1Rect) == false);
+    
+    // Test the childAtPoint event.
+    const AXUIElementRef childAtTab1Position = childAtPoint(position(tabButton1) + QPointF(5,5));
+    QVERIFY(equal(childAtTab1Position, tabButton1));
+    const AXUIElementRef childAtOtherPosition = childAtPoint(position(tabButton1) - QPointF(5,5));
+    QVERIFY(equal(childAtOtherPosition, tabButton1) == false);
+
+    // Test AXTabs attribute
+    QVERIFY(supportsAttribute(tabGroup, kAXTabsAttribute));
+    QList<AXUIElementRef> tabElements = tabs(tabGroup);
+    QCOMPARE(tabElements.count(), 2);
+    QVERIFY(equal(tabElements.at(0), tabButton1));
+    QVERIFY(equal(tabElements.at(1), tabButton2));
+    
+    // Perform the press action on each child.
+    for (int i = 0; i < numChildren; ++i) {
+        const AXUIElementRef child = ::child(tabGroup, i);
+        QVERIFY(supportsAction(child, "AXPress"));
+        QVERIFY(performAction(child, "AXPress"));
+    }
+}
+
+void tst_qaccessibility_mac::testTabBar()
+{
+    QTabBar tabBar;
+    tabBar.addTab("Tab A");
+    tabBar.addTab("Tab B");
+    tabBar.show();
+
+    AXUIElementRef currentApplication = AXUIElementCreateApplication(getpid());
+    AXUIElementRef window = childByRole(currentApplication, "AXWindow");
+    QVERIFY(window);
+
+    const QString tabRole = "AXTabGroup";
+    AXUIElementRef tabGroup = childByRole(window, tabRole);
+    QVERIFY(tabGroup);
+
+    const int numChildren = ::numChildren(tabGroup);
+    QCOMPARE(numChildren, 2);
+    
+    const QString tab1Title = "Tab A";
+    AXUIElementRef tabButton1 = childByTitle(tabGroup, tab1Title);
+    QVERIFY (tabButton1);
+    VERIFY_ELEMENT(tabButton1, tabGroup, "AXRadioButton");
+    QCOMPARE(title(tabButton1), tab1Title);
+
+    const QString tab2Title = "Tab B";
+    const AXUIElementRef tabButton2 = childByTitle(tabGroup, tab2Title);
+    QVERIFY(tabButton2);
+    VERIFY_ELEMENT(tabButton2, tabGroup, "AXRadioButton");
+    QCOMPARE(title(tabButton2), tab2Title);
+
+    // Test the childAtPoint event.
+    const AXUIElementRef childAtTab1Position = childAtPoint(position(tabButton1) + QPointF(5,5));
+    QVERIFY(equal(childAtTab1Position, tabButton1));
+    const AXUIElementRef childAtOtherPosition = childAtPoint(position(tabButton1) - QPointF(5,5));
+    QVERIFY(equal(childAtOtherPosition, tabButton1) == false);
+
+    // Test AXTabs attribute
+    QVERIFY(supportsAttribute(tabGroup, kAXTabsAttribute));
+    QList<AXUIElementRef> tabElements = tabs(tabGroup);
+    QCOMPARE(tabElements.count(), 2);
+    QVERIFY(equal(tabElements.at(0), tabButton1));
+    QVERIFY(equal(tabElements.at(1), tabButton2));
+    
+    // Perform the press action on each child.
+    for (int i = 0; i < numChildren; ++i) {
+        const AXUIElementRef child = ::child(tabGroup, i);
+        QVERIFY(supportsAction(child, "AXPress"));
+        QVERIFY(performAction(child, "AXPress"));
+    }
+}
+
+void tst_qaccessibility_mac::testComboBox()
+{
+    // Get reference to the current application.
+    AXUIElementRef currentApplication = AXUIElementCreateApplication(getpid());
+
+    testAppAndForm(currentApplication);
+    const QString formTitle = "Form";
+    AXUIElementRef form = childByTitle(currentApplication, formTitle);
+    
+    const QString comboBoxRole = "AXPopUpButton";
+    AXUIElementRef comboBox = childByRole(form, comboBoxRole);
+    QVERIFY(comboBox != 0);
+    QVERIFY(supportsAction(comboBox, "AXPress"));
+    QVERIFY(performAction(comboBox, "AXPress"));
+}
+
+void tst_qaccessibility_mac::testDeleteWidget()
+{
+    const QString buttonTitle = "Hi there";
+    QWidget *form = new QWidget(0, Qt::Window);
+    form->setWindowTitle("Form");
+    form->show();
+    QPushButton *button = new QPushButton(buttonTitle, form);
+    button->show();
+
+    AXUIElementRef currentApplication = AXUIElementCreateApplication(getpid());
+    testAppAndForm(currentApplication);
+    AXUIElementRef formElement = childByTitle(currentApplication, "Form");
+
+    AXUIElementRef buttonElement = childByTitle(formElement, buttonTitle);
+    QVERIFY(buttonElement);
+
+    button->hide();
+    delete button;
+
+    buttonElement = childByTitle(formElement, buttonTitle);
+    QVERIFY(!buttonElement);
+    delete form;
+}
+
+void tst_qaccessibility_mac::testDeleteWidgets()
+{
+    const QString buttonTitle = "Hi there";
+    const int repeats = 10;
+
+    for (int i = 0; i < repeats; ++i) {
+
+        QWidget *form = new QWidget(0, Qt::Window);
+        form->setWindowTitle("Form");
+        form->show();
+    
+        QPushButton *button = new QPushButton(buttonTitle, form);
+        button->show();
+    
+        AXUIElementRef currentApplication = AXUIElementCreateApplication(getpid());
+        testAppAndForm(currentApplication);
+        AXUIElementRef formElement = childByTitle(currentApplication, "Form");
+        AXUIElementRef buttonElement = childByTitle(formElement, buttonTitle);
+        QVERIFY(buttonElement);
+        delete form;
+
+        {
+            AXUIElementRef currentApplication = AXUIElementCreateApplication(getpid());
+            QVERIFY(currentApplication);
+            AXUIElementRef formElement = childByTitle(currentApplication, "Form");
+            QVERIFY(!formElement);
+        }
+    }
+
+    for (int i = 0; i < repeats; ++i) {
+        QWidget *form = new QWidget(0, Qt::Window);
+        form->setWindowTitle("Form");
+
+    
+        new QScrollBar(form);
+        form->show();
+    
+        AXUIElementRef currentApplication = AXUIElementCreateApplication(getpid());
+        testAppAndForm(currentApplication);
+        AXUIElementRef formElement = childByTitle(currentApplication, "Form");
+        
+        const AXUIElementRef scrollBarElement = childByRole(formElement, "AXScrollBar");
+        QVERIFY(scrollBarElement);
+        delete form;
+
+        {
+            AXUIElementRef currentApplication = AXUIElementCreateApplication(getpid());
+            QVERIFY(currentApplication);
+            AXUIElementRef formElement = childByTitle(currentApplication, "Form");
+            QVERIFY(!formElement);
+        }
+    }
+
+    for (int i = 0; i < repeats; ++i) {
+        QWidget *form = new QWidget(0, Qt::Window);
+        form->setWindowTitle("Form");
+    
+        QListWidget *listWidget = new QListWidget(form);
+        listWidget->addItem("Foo");
+        listWidget->addItem("Bar");
+        form->show();
+    
+        AXUIElementRef currentApplication = AXUIElementCreateApplication(getpid());
+        testAppAndForm(currentApplication);
+        AXUIElementRef formElement = childByTitle(currentApplication, "Form");
+
+        const AXUIElementRef scrollAreaElement = childByRole(formElement, "AXScrollArea");
+        QVERIFY(scrollAreaElement);
+
+        const AXUIElementRef listElement = childByRole(scrollAreaElement, "AXList");
+        QVERIFY(listElement);
+        delete form;
+
+        {
+            AXUIElementRef currentApplication = AXUIElementCreateApplication(getpid());
+            QVERIFY(currentApplication);
+            AXUIElementRef formElement = childByTitle(currentApplication, "Form");
+            QVERIFY(!formElement);
+        }
+    }
+
+}
+
+void tst_qaccessibility_mac::testMultipleWindows()
+{
+    const QString formATitle("FormA");
+    const QString formBTitle("FormB");
+
+    // Create a window
+    QWidget *formA = new QWidget(0, Qt::Window);
+    formA->setWindowTitle(formATitle);
+    formA->show();
+
+    // Test if we can access the window
+    AXUIElementRef currentApplication = AXUIElementCreateApplication(getpid());
+    AXUIElementRef formAElement = childByTitle(currentApplication, formATitle);
+    QVERIFY(formAElement);
+
+    // Create another window
+    QWidget *formB = new QWidget(0, Qt::Window);
+    formB->setWindowTitle(formBTitle);
+    formB->show();
+
+    // Test if we can access both windows
+    formAElement = childByTitle(currentApplication, formATitle);
+    QVERIFY(formAElement);
+
+    AXUIElementRef formBElement = childByTitle(currentApplication, formBTitle);
+    QVERIFY(formBElement);
+    
+    delete formA;
+}
+
+void tst_qaccessibility_mac::testHiddenWidgets()
+{
+    const QString windowTitle ="a widget";
+    QWidget * const window = new QWidget(0);
+    window->setWindowTitle(windowTitle);
+    window->show();
+
+    const AXUIElementRef currentApplication = AXUIElementCreateApplication(getpid());
+    const AXUIElementRef windowElement = childByTitle(currentApplication, windowTitle);
+    QVERIFY(windowElement);
+    QCOMPARE(isIgnored(windowElement), false);
+    
+    const QString buttonTitle = "a button";
+    QPushButton * const button = new QPushButton(window);    
+    button->setText(buttonTitle);
+    button->show();
+    
+    const AXUIElementRef buttonElement = childByTitle(windowElement, buttonTitle);
+    QVERIFY(buttonElement);
+    QCOMPARE(isIgnored(buttonElement), false);
+
+    const QString toolbarTitle = "a toolbar";
+    QToolBar * const toolbar = new QToolBar(toolbarTitle, window);
+    toolbar->show();
+    
+    const AXUIElementRef toolBarElement = childByTitle(windowElement, toolbarTitle);
+    QVERIFY(toolBarElement == 0);
+
+    delete window;
+};
+
+void tst_qaccessibility_mac::testActions()
+{
+    // create a window with a push button
+    const QString windowTitle ="a widget";
+    QWidget * const window = new QWidget();
+    window->setWindowTitle(windowTitle);
+    window->show();
+
+    const AXUIElementRef currentApplication = AXUIElementCreateApplication(getpid());
+    const AXUIElementRef windowElement = childByTitle(currentApplication, windowTitle);
+    QVERIFY(windowElement);
+
+    const QString buttonTitle = "a button";
+    QPushButton * const button = new QPushButton(window);    
+    button->setText(buttonTitle);
+    button->show();
+    
+    const AXUIElementRef buttonElement = childByTitle(windowElement, buttonTitle);
+    QVERIFY(buttonElement);
+
+    // Verify that the button has the Press action.
+    const QStringList actions = actionNames(buttonElement);
+    const QString pressActionName("AXPress");
+    QVERIFY(actions.contains(pressActionName));
+    
+    // Press button and check the pressed signal
+    QSignalSpy pressed(button, SIGNAL(pressed()));
+    QVERIFY(performAction(buttonElement, pressActionName));
+    QCOMPARE(pressed.count(), 1);
+    
+    pressed.clear();
+    QVERIFY(performAction(buttonElement, QString("does not exist")));
+    QCOMPARE(pressed.count(), 0);
+
+    delete window;
+};
+
+void tst_qaccessibility_mac::testChangeState()
+{
+    const QString windowTitle ="a widget";
+    QWidget * const window = new QWidget();
+    window->setWindowTitle(windowTitle);
+    window->show();
+ 
+    const AXUIElementRef applicationElement = AXUIElementCreateApplication(getpid());
+    const AXUIElementRef windowElement = childByTitle(applicationElement, windowTitle);
+    QVERIFY(windowElement);
+    const int otherChildren = numChildren(windowElement);
+    
+    const QString buttonTitle = "Button";
+    QPushButton * const button = new QPushButton(buttonTitle, window);
+    button->setText(buttonTitle);  
+
+    // Test that show/hide adds/removes the button from the hierachy.
+    QVERIFY(childByTitle(windowElement, buttonTitle) == 0);
+    QCOMPARE(numChildren(windowElement), otherChildren);
+    button->show();
+    QVERIFY(childByTitle(windowElement, buttonTitle) != 0);
+    QCOMPARE(numChildren(windowElement), otherChildren + 1);
+    button->hide();
+    QVERIFY(childByTitle(windowElement, buttonTitle) == 0);
+    QCOMPARE(numChildren(windowElement), otherChildren);
+    button->show();
+    QVERIFY(childByTitle(windowElement, buttonTitle) != 0);
+    QCOMPARE(numChildren(windowElement), otherChildren + 1);
+
+    // Test that hiding and showing a widget also removes and adds all its children.
+    {
+        QWidget * const parent = new QWidget(window);
+        const int otherChildren = numChildren(windowElement);
+        
+        QPushButton * const child = new QPushButton(parent);
+        const QString childButtonTitle = "child button";
+        child->setText(childButtonTitle);
+        
+        parent->show();
+        QVERIFY(childByTitle(windowElement, childButtonTitle) != 0);
+        QCOMPARE(numChildren(windowElement), otherChildren + 1);
+
+        parent->hide();
+        QVERIFY(childByTitle(windowElement, childButtonTitle) == 0);
+        QCOMPARE(numChildren(windowElement), otherChildren );
+
+        parent->show();
+        QVERIFY(childByTitle(windowElement, childButtonTitle) != 0);
+        QCOMPARE(numChildren(windowElement), otherChildren + 1);
+        
+        delete parent;
+    }
+
+    // Test that the enabled attribute is updated after a call to setEnabled.
+    const AXUIElementRef buttonElement = childByTitle(windowElement, buttonTitle);
+    QVERIFY(enabled(buttonElement));
+    button->setEnabled(false);
+    QVERIFY(enabled(buttonElement) == false);
+    button->setEnabled(true);
+    QVERIFY(enabled(buttonElement));
+
+    // Test that changing the title updates the accessibility information.
+    const QString buttonTitle2 = "Button 2";    
+    button->setText(buttonTitle2);
+    QVERIFY(childByTitle(windowElement, buttonTitle2) != 0);
+    QVERIFY(childByTitle(windowElement, buttonTitle) == 0);
+
+    delete window;
+}
+
+void tst_qaccessibility_mac::testSlider()
+{
+    const QString windowTitle = "a widget";
+    QWidget * const window = new QWidget();
+    window->setWindowTitle(windowTitle);
+    window->show();
+ 
+    const AXUIElementRef applicationElement = AXUIElementCreateApplication(getpid());
+    QVERIFY(applicationElement);
+    const AXUIElementRef windowElement = childByTitle(applicationElement, windowTitle);
+    QVERIFY(windowElement);
+    const int windowChildren = numChildren(windowElement);
+    
+    QSlider * const slider = new QSlider(window);
+    slider->show();
+    const AXUIElementRef sliderElement = childByRole(windowElement, "AXSlider");
+    QVERIFY(sliderElement);
+
+    // Test that the slider and its children are removed from the hierachy when we call hide().
+    QCOMPARE(numChildren(windowElement), windowChildren + 1);
+    slider->hide();
+    QCOMPARE(numChildren(windowElement), windowChildren);
+    
+    delete slider;
+}
+
+void tst_qaccessibility_mac::testScrollArea()
+{
+    QWidget window;
+    const QString windowTitle = "window";
+    window.setWindowTitle(windowTitle);
+    window.resize(300, 300);
+
+    QScrollArea scrollArea(&window);
+    scrollArea.resize(300, 300);
+    scrollArea.setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
+    scrollArea.setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
+
+    QLabel label;
+    label.setText("Foo"); 
+    scrollArea.setWidget(&label);
+
+    window.show();
+
+    // Verify that the QAinterface returns the correct children
+    QAInterface interface = QAccessible::queryAccessibleInterface(&scrollArea);
+    QCOMPARE(interface.childCount(), 3);
+    
+    QAInterface viewport = interface.navigate(QAccessible::Child, 1);
+    QVERIFY(viewport.isValid());
+
+    QAInterface scrollBarContainer1 = interface.navigate(QAccessible::Child, 2);
+    QVERIFY(scrollBarContainer1.isValid());
+
+    QAInterface scrollBar1 = scrollBarContainer1.navigate(QAccessible::Child, 1);
+
+    QVERIFY(scrollBar1.isValid());
+    QVERIFY(scrollBar1.role() == QAccessible::ScrollBar);
+
+    QAInterface scrollBarContainer2 = interface.navigate(QAccessible::Child, 3);
+    QVERIFY(scrollBarContainer1.isValid());
+
+    QAInterface scrollBar2 = scrollBarContainer2.navigate(QAccessible::Child, 1);
+    QVERIFY(scrollBar2.isValid());
+    QVERIFY(scrollBar2.role() == QAccessible::ScrollBar);    
+
+    // Navigate to the scroll area from the application
+    const AXUIElementRef applicationElement = AXUIElementCreateApplication(getpid());
+    QVERIFY(applicationElement);
+    const AXUIElementRef windowElement = childByTitle(applicationElement, windowTitle);
+    QVERIFY(windowElement);
+    const AXUIElementRef scrollAreaElement = childByRole(windowElement, "AXScrollArea");
+    QVERIFY(scrollAreaElement);
+
+    // Get the scroll bars
+    QVERIFY(supportsAttribute(scrollAreaElement, kAXHorizontalScrollBarAttribute));
+    const AXUIElementRef horizontalScrollBar = elementAttribute(scrollAreaElement, kAXHorizontalScrollBarAttribute);
+    QVERIFY(horizontalScrollBar);
+    QVERIFY(role(horizontalScrollBar) == "AXScrollBar");
+    QVERIFY(stringAttribute(horizontalScrollBar, kAXOrientationAttribute) == "AXHorizontalOrientation");
+
+    QVERIFY(supportsAttribute(scrollAreaElement, kAXVerticalScrollBarAttribute));
+    const AXUIElementRef verticalScrollBar = elementAttribute(scrollAreaElement, kAXVerticalScrollBarAttribute);
+    QVERIFY(verticalScrollBar);
+    QVERIFY(role(verticalScrollBar) == "AXScrollBar");
+    QVERIFY(stringAttribute(verticalScrollBar, kAXOrientationAttribute) == "AXVerticalOrientation");
+
+    // Get the contents and verify that we get the label.
+    QVERIFY(supportsAttribute(scrollAreaElement, kAXContentsAttribute));
+    const QList<AXUIElementRef> contents = elementListAttribute(scrollAreaElement, kAXContentsAttribute);
+    QCOMPARE(contents.count(), 1);
+    AXUIElementRef content = contents.at(0);
+    QVERIFY(role(content) == "AXStaticText");
+    QVERIFY(title(content) == "Foo");
+
+    // Turn scroll bars off
+    {
+    scrollArea.setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+    scrollArea.setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+    QVERIFY(supportsAttribute(scrollAreaElement, kAXHorizontalScrollBarAttribute) == false);
+    QVERIFY(supportsAttribute(scrollAreaElement, kAXVerticalScrollBarAttribute) == false);
+
+    QVERIFY(supportsAttribute(scrollAreaElement, kAXContentsAttribute));
+    const QList<AXUIElementRef> contents = elementListAttribute(scrollAreaElement, kAXContentsAttribute);
+    QCOMPARE(contents.count(), 1);
+    AXUIElementRef content = contents.at(0);
+    
+    QVERIFY(role(content) == "AXStaticText");
+    QVERIFY(title(content) == "Foo");
+    }
+
+    // Turn the horizontal scrollbar on.
+    {
+    scrollArea.setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
+    scrollArea.setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+    QVERIFY(supportsAttribute(scrollAreaElement, kAXHorizontalScrollBarAttribute) == true);
+    QVERIFY(supportsAttribute(scrollAreaElement, kAXVerticalScrollBarAttribute) == false);
+
+    const AXUIElementRef horizontalScrollBar = elementAttribute(scrollAreaElement, kAXHorizontalScrollBarAttribute);
+    QVERIFY(horizontalScrollBar);
+    QVERIFY(role(horizontalScrollBar) == "AXScrollBar");
+    QVERIFY(stringAttribute(horizontalScrollBar, kAXOrientationAttribute) == "AXHorizontalOrientation");
+
+    QVERIFY(supportsAttribute(scrollAreaElement, kAXContentsAttribute));
+    const QList<AXUIElementRef> contents = elementListAttribute(scrollAreaElement, kAXContentsAttribute);
+    QCOMPARE(contents.count(), 1);
+    AXUIElementRef content = contents.at(0);
+    QVERIFY(role(content) == "AXStaticText");
+    QVERIFY(title(content) == "Foo");
+    }
+
+    // Turn the vertical scrollbar on.
+    {
+    scrollArea.setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+    scrollArea.setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
+    QVERIFY(supportsAttribute(scrollAreaElement, kAXHorizontalScrollBarAttribute) == false);
+    QVERIFY(supportsAttribute(scrollAreaElement, kAXVerticalScrollBarAttribute) == true);
+
+    QVERIFY(supportsAttribute(scrollAreaElement, kAXVerticalScrollBarAttribute));
+    const AXUIElementRef verticalScrollBar = elementAttribute(scrollAreaElement, kAXVerticalScrollBarAttribute);
+    QVERIFY(verticalScrollBar);
+    QVERIFY(role(verticalScrollBar) == "AXScrollBar");
+    QVERIFY(stringAttribute(verticalScrollBar, kAXOrientationAttribute) == "AXVerticalOrientation");
+
+    QVERIFY(supportsAttribute(scrollAreaElement, kAXContentsAttribute));
+    const QList<AXUIElementRef> contents = elementListAttribute(scrollAreaElement, kAXContentsAttribute);
+    QCOMPARE(contents.count(), 1);
+    AXUIElementRef content = contents.at(0);
+    QVERIFY(role(content) == "AXStaticText");
+    QVERIFY(title(content) == "Foo");
+    }
+}
+
+void tst_qaccessibility_mac::testListView()
+{
+    QWidget window;
+    const QString windowTitle("window");
+    window.setWindowTitle(windowTitle);
+    window.resize(300, 300);
+
+    QListWidget *listWidget = new QListWidget(&window);
+    listWidget->setObjectName("listwidget");
+    listWidget->addItem("A");
+    listWidget->addItem("B");
+    listWidget->addItem("C");
+    
+    window.show();
+    QTest::qWait(1);
+        
+    {
+        // Verify that QAInterface works as expected for list views
+        QAInterface listWidgetInterface = QAccessible::queryAccessibleInterface(listWidget);
+        QCOMPARE(listWidgetInterface.role(), QAccessible::Client);
+        QCOMPARE(listWidgetInterface.childCount(), 1);
+        QAInterface viewPort = listWidgetInterface.childAt(1);
+        QCOMPARE(viewPort.role(), QAccessible::List);
+        QVERIFY(viewPort.object() != 0);
+        QCOMPARE(viewPort.childCount(), 3);
+        const QList<QAInterface> rows = viewPort.children();
+        QCOMPARE(rows.count(), 3);
+        QVERIFY(rows.at(0).object() == 0);
+        QCOMPARE(rows.at(0).parent().indexOfChild(rows.at(0)), 1);
+        QCOMPARE(rows.at(1).parent().indexOfChild(rows.at(1)), 2);
+        QCOMPARE(rows.at(2).parent().indexOfChild(rows.at(2)), 3);         
+        
+        // test the QAInterface comparison operator
+        QVERIFY(rows.at(0) == rows.at(0));
+        QVERIFY(rows.at(0) != rows.at(1));
+        QVERIFY(rows.at(0) != viewPort);
+        QVERIFY(viewPort == viewPort);
+        QVERIFY(listWidgetInterface != viewPort);
+        QVERIFY(listWidgetInterface == listWidgetInterface);
+        
+        // test QAInterface::isHIView()
+        QVERIFY(viewPort.isHIView());
+        QVERIFY(listWidgetInterface.isHIView());
+        QVERIFY(rows.at(0).isHIView() == false);
+    }
+
+    const AXUIElementRef applicationElement = AXUIElementCreateApplication(getpid());
+    QVERIFY(applicationElement);
+    const AXUIElementRef windowElement = childByTitle(applicationElement, windowTitle);
+    QVERIFY(windowElement);
+    const AXUIElementRef scrollAreaElement = childByRole(windowElement, "AXScrollArea");
+    QVERIFY(scrollAreaElement);
+    const AXUIElementRef listElement = childByRole(scrollAreaElement, "AXList");
+    QVERIFY(listElement);
+    QVERIFY(equal(::parent(listElement), scrollAreaElement));
+    // Window is not reported properly on 10.5
+    if (QSysInfo::MacintoshVersion < QSysInfo::MV_10_5) 
+        QVERIFY(equal(::window(listElement), windowElement));
+    
+    const AXUIElementRef A = childByTitle(listElement, "A");
+    QVERIFY(A);
+    const AXUIElementRef B = childByTitle(listElement, "B");
+    QVERIFY(B);
+    const AXUIElementRef C = childByTitle(listElement, "C");
+    QVERIFY(C);
+
+    QVERIFY(value(A) == "A");
+    QVERIFY(equal(::parent(A), listElement));
+    QVERIFY(enabled(A));
+
+    // Window is not reported properly on 10.5, this test
+    // hangs on 10.4. Disable it for now.
+    //    if (QSysInfo::MacintoshVersion < QSysInfo::MV_10_5) 
+    //        QVERIFY(equal(::window(A), windowElement));
+    
+    QVERIFY(above(A, B));
+    QVERIFY(!above(B, A));
+    QVERIFY(above(B, C));
+    QVERIFY(contains(listElement, A));
+    QVERIFY(!contains(A, listElement));
+    QVERIFY(contains(listElement, B));
+    QVERIFY(contains(listElement, C));
+}
+
+void tst_qaccessibility_mac::testTableView()
+{
+    QWidget window;
+    const QString windowTitle("window");
+    window.setWindowTitle(windowTitle);
+    window.resize(300, 300);
+
+    QTableWidget *tableWidget = new QTableWidget(&window);
+    tableWidget->setObjectName("tablewidget");
+    tableWidget->setRowCount(3);
+    tableWidget->setColumnCount(2);
+
+    tableWidget->setItem(0, 0, new QTableWidgetItem("A1"));
+    tableWidget->setItem(0, 1, new QTableWidgetItem("A2"));
+
+    tableWidget->setItem(1, 0, new QTableWidgetItem("B1"));
+    tableWidget->setItem(1, 1, new QTableWidgetItem("B2"));
+
+    tableWidget->setItem(2, 0, new QTableWidgetItem("C1"));
+    tableWidget->setItem(2, 1, new QTableWidgetItem("C2"));
+
+    window.show();
+    
+    {
+        // Verify that QAInterface works as expected for table view children.
+        QAInterface tableWidgetInterface = QAccessible::queryAccessibleInterface(tableWidget);
+        QCOMPARE(tableWidgetInterface.role(), QAccessible::Client);
+        QCOMPARE(tableWidgetInterface.childCount(), 1);
+        QAInterface viewPort = tableWidgetInterface.childAt(1);
+        QCOMPARE(viewPort.childCount(), 4);
+        QCOMPARE(viewPort.role(), QAccessible::Table);
+        QVERIFY(viewPort.object() != 0);
+        const QList<QAInterface> rows = viewPort.children();
+        QCOMPARE(rows.count(), 4);
+        QVERIFY(rows.at(0).object() == 0);
+        QCOMPARE(rows.at(0).parent().indexOfChild(rows.at(0)), 1);
+        QCOMPARE(rows.at(1).parent().indexOfChild(rows.at(1)), 2);
+        QCOMPARE(rows.at(2).parent().indexOfChild(rows.at(2)), 3);         
+
+        QAInterface Arow = rows.at(1);
+        QCOMPARE(Arow.role(), QAccessible::Row);
+        QAInterface Brow = rows.at(2);
+
+        QVERIFY(Arow.name() == "1");
+        QVERIFY(Brow.name() == "2");
+
+        QVERIFY(Arow == Arow);
+        QVERIFY(Brow != Arow);
+        QVERIFY(Arow.isHIView() == false);
+        QCOMPARE(Arow.childCount(), 3);
+        QList<QAInterface> Achildren = Arow.children();
+        QCOMPARE(Achildren.count(), 3);
+        QAInterface A1 = Achildren.at(1);
+        QAInterface A2 = Achildren.at(2);
+        QCOMPARE(Arow.indexOfChild(A1), 2);
+        QCOMPARE(Arow.indexOfChild(A2), 3);
+        QCOMPARE(A1.role(), QAccessible::Cell);
+
+        QList<QAInterface> Bchildren = Brow.children();
+        QCOMPARE(Bchildren.count(), 3);
+        QAInterface B1 = Bchildren.at(1);
+        QAInterface B2 = Bchildren.at(2);
+        QVERIFY(B1.parent() == Brow);
+        QVERIFY(B1.parent() != Arow);
+        QCOMPARE(Arow.indexOfChild(B1), -1);
+
+        QVERIFY(A1 == A1);
+        QVERIFY(A1 != A2);
+        QVERIFY(B1 != A1);
+        QVERIFY(B1 != A2);
+        QVERIFY(A1 != Arow);
+        QVERIFY(A1 != Brow);
+        QVERIFY(A1 != viewPort);
+        QVERIFY(A1.isHIView() == false);
+
+        QVERIFY(B1.parent() == Brow);
+        QVERIFY(A1.parent() == Arow);
+        B1 = A1;
+        QVERIFY(B1.parent() == Arow);
+    }
+    
+    const AXUIElementRef applicationElement = AXUIElementCreateApplication(getpid());
+    QVERIFY(applicationElement);
+    const AXUIElementRef windowElement = childByTitle(applicationElement, windowTitle);
+    QVERIFY(windowElement);
+    const AXUIElementRef scrollAreaElement = childByRole(windowElement, "AXScrollArea");
+    QVERIFY(scrollAreaElement);
+    const AXUIElementRef tableElement = childByRole(scrollAreaElement, "AXTable");
+    QVERIFY(tableElement);
+   
+    {
+        // Verify that QAccessibleHierarchyManager can look up table view children correctly
+        QAccessibleHierarchyManager *manager = QAccessibleHierarchyManager::instance();
+        QAInterface tableInterface = manager->lookup(tableElement);
+        QVERIFY(tableInterface.isValid());
+        QVERIFY(tableInterface.role() == QAccessible::Table);
+   
+        QAInterface ArowInterface = tableInterface.childAt(2);
+
+        QVERIFY(ArowInterface.name() == "1");
+        QVERIFY(manager->lookup(manager->lookup(ArowInterface)).name() == "1");
+
+        QCOMPARE(ArowInterface.childCount(), 3);
+        QAInterface A1Interface = ArowInterface.childAt(2);
+
+        QCOMPARE(A1Interface.value(), QString("A1"));
+        QVERIFY(value(manager->lookup(A1Interface)).toString() == "A1");
+
+        QAInterface A2Interface = ArowInterface.childAt(3);
+        QAElement A2Element = manager->lookup(A2Interface);
+        QVERIFY(manager->lookup(A2Element).value() == "A2");
+        QVERIFY(value(A2Element).toString() == "A2");
+
+        QAInterface BrowInterface = tableInterface.childAt(3);
+        QVERIFY(BrowInterface.value() == "2");
+        QVERIFY(manager->lookup(manager->lookup(BrowInterface)).value() == "2");
+
+        QCOMPARE(BrowInterface.childCount(), 3);
+        QAInterface B1Interface = BrowInterface.childAt(2);
+        QVERIFY(value(manager->lookup(B1Interface)).toString() == "B1");
+
+        QAInterface B2Interface = BrowInterface.childAt(3);
+        QAElement B2Element = manager->lookup(B2Interface);
+        QVERIFY(manager->lookup(B2Element).value() == "B2");
+        QVERIFY(value(B2Element).toString() == "B2");
+    }
+
+
+
+    const AXUIElementRef Arow = childByTitle(tableElement, "1");
+    QVERIFY(Arow);
+    const AXUIElementRef Brow = childByTitle(tableElement, "2");
+    QVERIFY(Brow);
+    const AXUIElementRef Crow = childByTitle(tableElement, "3");
+    QVERIFY(Crow);
+
+    QCOMPARE(numChildren(Arow), 3);
+    const AXUIElementRef A1cell = childByTitle(Arow, "A1");
+    QVERIFY(A1cell);
+    QVERIFY(role(A1cell) == "AXTextField");
+    const AXUIElementRef A2cell = childByTitle(Arow, "A2");
+    QVERIFY(A2cell);
+    QVERIFY(equal(::parent(A2cell), Arow));
+
+    const AXUIElementRef B2cell = childByTitle(Brow, "B2");
+    QVERIFY(B2cell);
+    QVERIFY(equal(::parent(B2cell), Brow));
+
+    {
+        QVERIFY(supportsAttribute(tableElement, kAXRowsAttribute));
+        const QList<AXUIElementRef> rows = elementListAttribute(tableElement, kAXRowsAttribute);
+        QCOMPARE(rows.count(), 3); // the header is not a row
+        QVERIFY(value(rows.at(1)) == "2");
+        QVERIFY(value(rows.at(2)) == "3");
+    }
+
+    {
+        QVERIFY(supportsAttribute(tableElement, kAXVisibleRowsAttribute));
+        const QList<AXUIElementRef> rows = elementListAttribute(tableElement, kAXVisibleRowsAttribute);
+        QCOMPARE(rows.count(), 3);
+        QVERIFY(value(rows.at(1)) == "2");
+    }
+    {
+        QVERIFY(supportsAttribute(tableElement, kAXSelectedRowsAttribute));
+        const QList<AXUIElementRef> rows = elementListAttribute(tableElement, kAXSelectedRowsAttribute);
+        QCOMPARE(rows.count(), 0);
+    }
+
+    // test row visibility
+    {
+        QTableWidget tableWidget;
+        tableWidget.setObjectName("tablewidget");
+        tableWidget.setRowCount(1000);
+        tableWidget.setColumnCount(1);
+
+        for (int i =0; i < 1000; ++i) {
+            tableWidget.setItem(i, 0, new QTableWidgetItem("item"));
+        }
+        tableWidget.show();
+        
+        QAInterface tableWidgetInterface = QAccessible::queryAccessibleInterface(&tableWidget);
+        QAInterface viewPortInterface = tableWidgetInterface.childAt(1);
+        QCOMPARE(viewPortInterface.childCount(), 1001);
+
+        QVERIFY((viewPortInterface.childAt(2).state() & QAccessible::Invisible) == false);
+        QVERIFY((viewPortInterface.childAt(2).state() & QAccessible::Offscreen) == false);
+        
+        QVERIFY(viewPortInterface.childAt(500).state() & QAccessible::Invisible);
+//        QVERIFY(viewPortInterface.childAt(500).state() & QAccessible::Offscreen);
+        tableWidget.hide();
+    }
+
+//    printElementInfo(tableElement);
+//    QTest::qWait(1000000);
+}
+
+void tst_qaccessibility_mac::testScrollBar()
+{
+    {
+        QScrollBar scrollBar;
+        scrollBar.show();
+
+        QAInterface scrollBarInterface = QAccessible::queryAccessibleInterface(&scrollBar);
+        QVERIFY(scrollBarInterface.isValid());
+        QCOMPARE(scrollBarInterface.childCount(), 5);
+        QCOMPARE(scrollBarInterface.indexOfChild(scrollBarInterface.childAt(1)), 1);
+        QCOMPARE(scrollBarInterface.indexOfChild(scrollBarInterface.childAt(2)), 2);
+        QCOMPARE(scrollBarInterface.indexOfChild(scrollBarInterface.childAt(5)), 5);
+        QCOMPARE(scrollBarInterface.indexOfChild(scrollBarInterface), -1);
+    }
+
+    const AXUIElementRef currentApplication = AXUIElementCreateApplication(getpid());
+    testAppAndForm(currentApplication);
+    const AXUIElementRef form = childByTitle(currentApplication, "Form");
+    QVERIFY(form);
+    const AXUIElementRef scrollBarElement = childByRole(form, "AXScrollBar");
+    QVERIFY(scrollBarElement);
+    QCOMPARE(attribute(scrollBarElement, kAXOrientationAttribute).toString(), QLatin1String("AXVerticalOrientation"));
+
+    {
+        const AXUIElementRef lineUpElement = childByTitle(scrollBarElement, "Line up");
+        QVERIFY(lineUpElement);
+        QCOMPARE (subrole(lineUpElement), QLatin1String("AXDecrementArrow"));
+    }{
+        const AXUIElementRef lineDownElement = childByTitle(scrollBarElement, "Line down");
+        QVERIFY(lineDownElement);
+        QCOMPARE (subrole(lineDownElement), QLatin1String("AXIncrementArrow"));
+    }{
+        const AXUIElementRef pageUpElement = childByTitle(scrollBarElement, "Page up");
+        QVERIFY(pageUpElement);
+        QCOMPARE (subrole(pageUpElement), QLatin1String("AXDecrementPage"));
+    }{
+        const AXUIElementRef pageDownElement = childByTitle(scrollBarElement, "Page down");
+        QVERIFY(pageDownElement);
+        QCOMPARE (subrole(pageDownElement), QLatin1String("AXIncrementPage"));
+    }{
+        const AXUIElementRef valueIndicatorElement = childByTitle(scrollBarElement, "Position");
+        QVERIFY(valueIndicatorElement);
+        QCOMPARE(value(valueIndicatorElement).toInt(), 50);
+    }
+}
+
+void tst_qaccessibility_mac::testSplitter()
+{
+    const AXUIElementRef currentApplication = AXUIElementCreateApplication(getpid());
+    testAppAndForm(currentApplication);
+    const AXUIElementRef form = childByTitle(currentApplication, "Form");
+    QVERIFY(form);
+    
+    const AXUIElementRef splitGroupElement = childByRole(form, "AXSplitGroup");
+    QVERIFY(splitGroupElement);
+
+    for (int i = 0; i < numChildren(splitGroupElement); ++i)
+        QVERIFY(child(splitGroupElement, 3));
+
+    // Visual Order: Foo splitter Bar splitter Baz
+    QList<AXUIElementRef> splitterList = elementListAttribute(splitGroupElement, kAXSplittersAttribute);
+    QCOMPARE(splitterList.count(), 2); 
+    foreach (AXUIElementRef splitter, splitterList) {
+        QCOMPARE(role(splitter), QLatin1String("AXSplitter"));
+        QVERIFY(supportsAttribute(splitter, kAXPreviousContentsAttribute));
+        QVERIFY(supportsAttribute(splitter, kAXNextContentsAttribute));
+        QCOMPARE(attribute(splitter, kAXOrientationAttribute).toString(), QLatin1String("AXVerticalOrientation"));
+        QList<AXUIElementRef> prevList = elementListAttribute(splitter, kAXPreviousContentsAttribute);  
+        QCOMPARE(prevList.count(), 1); 
+        QList<AXUIElementRef> nextList = elementListAttribute(splitter, kAXNextContentsAttribute);  
+        QCOMPARE(nextList.count(), 1);
+        
+        // verify order
+        if (title(prevList.at(0)) == QLatin1String("Foo"))
+            QCOMPARE(title(nextList.at(0)), QLatin1String("Bar"));
+        else if (title(prevList.at(0)) == QLatin1String("Bar"))
+            QCOMPARE(title(nextList.at(0)), QLatin1String("Baz"));
+        else {
+            QFAIL("Splitter contents and handles are out of order"); 
+        }
+    }
+}
+
+void tst_qaccessibility_mac::testTextEdit()
+{
+    QWidget window;
+    const QString windowTitle("window");
+    window.setWindowTitle(windowTitle);
+    window.resize(300, 300);
+
+    QTextEdit *textEdit = new QTextEdit(&window);
+    textEdit->resize(300, 300);
+    const QString textLine("this is a line");
+    textEdit->setText(textLine);
+    
+    window.show();
+
+    const AXUIElementRef applicationElement = AXUIElementCreateApplication(getpid());
+    QVERIFY(applicationElement);
+    const AXUIElementRef windowElement = childByTitle(applicationElement, windowTitle);
+    QVERIFY(windowElement);
+    const AXUIElementRef scrollAreaElement = childByRole(windowElement, "AXScrollArea");
+    QVERIFY(scrollAreaElement);
+    const AXUIElementRef textElement = childByRole(scrollAreaElement, "AXTextField");
+    QVERIFY(textElement);
+    QVERIFY(value(textElement) == textLine);
+}
+
+void testModelLessItemView(QAbstractItemView *itemView, const QByteArray &role)
+{
+    const QString windowTitle("window");
+    itemView->setWindowTitle(windowTitle);
+    itemView->show();
+
+    QTest::qWait(100);
+#if defined(Q_WS_X11)
+    qt_x11_wait_for_window_manager(w);
+#endif
+
+    QAccessibleInterface *acc = QAccessible::queryAccessibleInterface(itemView);
+    QVERIFY(acc->isValid());
+    QCOMPARE(acc->childCount(), 1);
+    acc->role(0);
+    acc->rect(0);
+
+    QAccessibleInterface *accViewport = 0;
+    int entry = acc->navigate(QAccessible::Child, 1, &accViewport);
+    QVERIFY(accViewport);
+    QCOMPARE(entry, 0);
+    QVERIFY(accViewport->isValid());
+    QCOMPARE(accViewport->childCount(), 0);
+    accViewport->role(0);
+    accViewport->rect(0);
+
+    delete acc;
+    delete accViewport;
+        
+    const AXUIElementRef applicationElement = AXUIElementCreateApplication(getpid());
+    QVERIFY(applicationElement);
+    const AXUIElementRef windowElement = childByTitle(applicationElement, windowTitle);
+    QVERIFY(windowElement);
+    const AXUIElementRef scrollAreaElement = childByRole(windowElement, "AXScrollArea");
+    QVERIFY(scrollAreaElement);
+    const AXUIElementRef tableElement = childByRole(scrollAreaElement, role);
+    QVERIFY(tableElement);
+    
+    delete itemView;
+}
+
+void tst_qaccessibility_mac::testItemViewsWithoutModel()
+{
+    testModelLessItemView(new QListView(), "AXList");
+    testModelLessItemView(new QTableView(), "AXTable");
+}
+
+void tst_qaccessibility_mac::testQAElement()
+{
+    {
+        QAElement element;
+        QVERIFY(element.isValid() == false);
+    }
+    
+    {
+        QAElement element(0, 0);
+        QVERIFY(element.isValid() == false);
+    }
+
+    {
+        int argc = 0;
+        char **argv = 0;
+        QApplication app(argc, argv);
+        QWidget w;
+        QAElement element(reinterpret_cast<HIObjectRef>(w.winId()), 0);
+        QVERIFY(element.isValid() == true);
+    }
+
+}
+
+void tst_qaccessibility_mac::testQAInterface()
+{
+    {
+        QAInterface interface;
+        QVERIFY(interface.isValid() == false);
+    }
+    
+    {
+        QAInterface interface(0, 0);
+        QVERIFY(interface.isValid() == false);
+    }
+
+    {
+        int argc = 0;
+        char **argv = 0;
+        QApplication app(argc, argv);
+
+        {
+            QWidget w;
+            QAInterface element(QAccessible::queryAccessibleInterface(&w), 0);
+            QVERIFY(element.isValid() == true);
+        }
+        {
+            QWidget w;
+            QAInterface element(QAccessible::queryAccessibleInterface(&w), 100);
+            QVERIFY(element.isValid() == false);
+        }
+    }
+}
+
+void tst_qaccessibility_mac::uitests_data()
+{
+    QTest::addColumn<QString>("uiFilename");
+    QTest::addColumn<QString>("testSlot");
+
+    QTest::newRow("form") << "form.ui" << SLOT(testForm());
+    QTest::newRow("buttons") << "buttons.ui" << SLOT(testButtons());
+    QTest::newRow("label") << "label.ui" << SLOT(testLabel());
+    QTest::newRow("line edit") << "lineedit.ui" << SLOT(testLineEdit());
+    QTest::newRow("groups") << "groups.ui" << SLOT(testGroups());
+    QTest::newRow("tabs") << "tabs.ui" << SLOT(testTabWidget());
+    QTest::newRow("combobox") << "combobox.ui" << SLOT(testComboBox());
+    QTest::newRow("scrollbar") << "scrollbar.ui" << SLOT(testScrollBar());
+    QTest::newRow("splitters") << "splitters.ui" << SLOT(testSplitter());
+}
+
+void tst_qaccessibility_mac::uitests()
+{
+    QFETCH(QString, uiFilename);
+    QFETCH(QString, testSlot);
+
+    // The Accessibility interface must be enabled to run this test.
+    if (!AXAPIEnabled())
+        QSKIP("Accessibility not enabled. Check \"Enable access for assistive devices\" in the system preferences -> universal access to run this test.", SkipAll);
+
+    int argc = 0;
+    char **argv = 0;
+    QApplication app(argc, argv);
+
+    // Create and display form.
+    QUiLoader loader;
+    QFile file(":" + uiFilename);
+    QVERIFY(file.exists());
+    file.open(QFile::ReadOnly);
+    QWidget *window = loader.load(&file, 0);
+    QVERIFY(window);
+    file.close();
+    window->show();
+
+    QTimer::singleShot(50, this, qPrintable(testSlot));
+    // Quit when returning to the main event loop after running tests.
+    QTimer::singleShot(200, &app, SLOT(quit()));
+    app.exec();
+    delete window;
+}
+
+void tst_qaccessibility_mac::tests_data()
+{
+    QTest::addColumn<QString>("testSlot");
+    QTest::newRow("deleteWidget") << SLOT(testDeleteWidget());
+    QTest::newRow("deleteWidgets") << SLOT(testDeleteWidgets());
+    QTest::newRow("multipleWindows") << SLOT(testMultipleWindows());
+    QTest::newRow("hiddenWidgets") << SLOT(testHiddenWidgets());
+    QTest::newRow("actions") << SLOT(testActions());
+    QTest::newRow("changeState") << SLOT(testChangeState());
+    QTest::newRow("slider") << SLOT(testSlider());
+    QTest::newRow("scrollArea") << SLOT(testScrollArea());
+    QTest::newRow("listView") << SLOT(testListView());
+    QTest::newRow("tableView") << SLOT(testTableView());
+    QTest::newRow("textEdit") << SLOT(testTextEdit());
+    QTest::newRow("ItemViews without model") << SLOT(testItemViewsWithoutModel());
+    QTest::newRow("tabbar") << SLOT(testTabBar());
+}
+
+void tst_qaccessibility_mac::tests()
+{
+    QFETCH(QString, testSlot);
+    runTest(testSlot);
+}
+
+/*
+    Tests show that querying the accessibility interface directly does not work. (I get a
+    kAXErrorAPIDisabled error, indicating that the accessible API is disabled, which it isn't.)
+    To work around this, we run the tests in a callback slot called from the main event loop.
+*/
+void tst_qaccessibility_mac::runTest(const QString &testSlot)
+{
+    // The Accessibility interface must be enabled to run this test.
+    if (!AXAPIEnabled())
+        QSKIP("Accessibility not enabled. Check \"Enable access for assistive devices\" in the system preferences -> universal access to run this test.", SkipAll);
+
+    int argc = 0;
+    char **argv = 0;
+    QApplication app(argc, argv);
+
+    QTimer::singleShot(50, this, qPrintable(testSlot));
+    // Quit when returning to the main event loop after running tests.
+    QTimer::singleShot(200, &app, SLOT(quit()));
+    app.exec();
+
+}
+
+QTEST_APPLESS_MAIN(tst_qaccessibility_mac)
+
+#else // defined(Q_WS_MAC) && !defined (QT_MAC_USE_COCOA)
+
+QTEST_NOOP_MAIN
+
+#endif
+
+#include "tst_qaccessibility_mac.moc"
+
+