Integrate QtQuickTest into Qt
authorCharles Yin <charles.yin@nokia.com>
Fri, 20 May 2011 01:57:29 +0000 (11:57 +1000)
committerCharles Yin <charles.yin@nokia.com>
Fri, 20 May 2011 02:07:23 +0000 (12:07 +1000)
Change-Id: I558821c0dec9166ea1d0d2e1e2f889553c436316
Task-number:QTBUG-16082

51 files changed:
doc/src/declarative/qmltest.qdoc [new file with mode: 0644]
examples/examples.pro
examples/qmltest/qmltest.pro [new file with mode: 0644]
examples/qmltest/tst_basic.qml [new file with mode: 0644]
examples/qmltest/tst_item.qml [new file with mode: 0644]
examples/qmltest/tst_qmltest.cpp [new file with mode: 0644]
modules/qt_qmltest.pri [new file with mode: 0644]
src/imports/imports.pro
src/imports/testlib/SignalSpy.qml [new file with mode: 0644]
src/imports/testlib/TestCase.qml [new file with mode: 0644]
src/imports/testlib/main.cpp [new file with mode: 0644]
src/imports/testlib/qmldir [new file with mode: 0644]
src/imports/testlib/signalspy.h [new file with mode: 0644]
src/imports/testlib/signalspy.qdoc [new file with mode: 0644]
src/imports/testlib/testcase.h [new file with mode: 0644]
src/imports/testlib/testcase.qdoc [new file with mode: 0644]
src/imports/testlib/testlib.pro [new file with mode: 0644]
src/imports/testlib/testlogger.js [new file with mode: 0644]
src/qmltest/features/qmltestcase.prf [new file with mode: 0644]
src/qmltest/qmltest.pro [new file with mode: 0644]
src/qmltest/qtestoptions_p.h [new file with mode: 0644]
src/qmltest/quicktest.cpp [new file with mode: 0644]
src/qmltest/quicktest.h [new file with mode: 0644]
src/qmltest/quicktestevent.cpp [new file with mode: 0644]
src/qmltest/quicktestevent_p.h [new file with mode: 0644]
src/qmltest/quicktestglobal.h [new file with mode: 0644]
src/qmltest/quicktestresult.cpp [new file with mode: 0644]
src/qmltest/quicktestresult_p.h [new file with mode: 0644]
src/src.pro
sync.profile
tests/auto/auto.pro
tests/auto/qmltest/buttonclick/Button.qml [new file with mode: 0644]
tests/auto/qmltest/buttonclick/tst_buttonclick.qml [new file with mode: 0644]
tests/auto/qmltest/createbenchmark/item.qml [new file with mode: 0644]
tests/auto/qmltest/createbenchmark/tst_createbenchmark.qml [new file with mode: 0644]
tests/auto/qmltest/events/tst_events.qml [new file with mode: 0644]
tests/auto/qmltest/qdecarativebinding/tst_binding.qml [new file with mode: 0644]
tests/auto/qmltest/qdecarativebinding/tst_binding2.qml [new file with mode: 0644]
tests/auto/qmltest/qdecarativeborderimage/InvalidSciFile.qml [new file with mode: 0644]
tests/auto/qmltest/qdecarativeborderimage/colors-round.sci [new file with mode: 0644]
tests/auto/qmltest/qdecarativeborderimage/colors.png [new file with mode: 0644]
tests/auto/qmltest/qdecarativeborderimage/invalid.sci [new file with mode: 0644]
tests/auto/qmltest/qdecarativeborderimage/tst_borderimage.qml [new file with mode: 0644]
tests/auto/qmltest/qmltest.pro [new file with mode: 0644]
tests/auto/qmltest/selftests/tst_compare.qml [new file with mode: 0644]
tests/auto/qmltest/selftests/tst_compare_quickobjects.qml [new file with mode: 0644]
tests/auto/qmltest/selftests/tst_selftests.qml [new file with mode: 0644]
tests/auto/qmltest/tst_qmltest.cpp [new file with mode: 0644]
tools/qmltestrunner/main.cpp [new file with mode: 0644]
tools/qmltestrunner/qmltestrunner.pro [new file with mode: 0644]
tools/tools.pro

diff --git a/doc/src/declarative/qmltest.qdoc b/doc/src/declarative/qmltest.qdoc
new file mode 100644 (file)
index 0000000..fdecf21
--- /dev/null
@@ -0,0 +1,123 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** 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 Free Documentation License
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of this
+** file.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+    \page qmltest.html
+    \title QtQuickTest Reference Documentation
+    \keyword QtQuickTest Reference Documentation
+
+    \section1 Introduction
+
+    QtQuickTest is a unit test framework for Qt Quick (QML) applications.
+    Test cases are written as JavaScript functions within a TestCase
+    element:
+
+    \code
+    import QtQuick 2.0
+    import QtTest 1.0
+
+    TestCase {
+        name: "MathTests"
+
+        function test_math() {
+            compare(2 + 2, 4, "2 + 2 = 4")
+        }
+
+        function test_fail() {
+            compare(2 + 2, 5, "2 + 2 = 5")
+        }
+    }
+    \endcode
+
+    Functions whose names start with \c{test_} are treated as test cases
+    to be executed.  See the documentation for the \l TestCase and
+    \l SignalSpy elements for more information on writing test cases.
+
+    \section1 Running tests
+
+    Test cases are launched by a C++ harness that consists of
+    the following code:
+
+    \code
+    #include <QtQuickTest/quicktest.h>
+    QUICK_TEST_MAIN(example)
+    \endcode
+
+    Where "example" is an identifier to use to uniquely identify
+    this set of tests.  You should add \c{CONFIG += qmltestcase}.
+    for example:
+
+    \code
+    TEMPLATE = app
+    TARGET = tst_example
+    CONFIG += warn_on qmltestcase
+    SOURCES += tst_example.cpp
+    \endcode
+
+    The test harness scans the specified source directory recursively
+    for "tst_*.qml" files.  If \c{QUICK_TEST_SOURCE_DIR} is not defined,
+    then the current directory will be scanned when the harness is run.
+    Other *.qml files may appear for auxillary QML components that are
+    used by the test.
+
+    The \c{-input} command-line option can be set at runtime to run
+    test cases from a different directory.  This may be needed to run
+    tests on a target device where the compiled-in directory name refers
+    to a host.  For example:
+
+    \code
+    tst_example -input /mnt/SDCard/qmltests
+    \endcode
+
+    See \c{tests/qmlauto} in the source tree for an example of creating a
+    test harness that uses the \c{QUICK_TEST_SOURCE_DIR} macro.
+
+    If your test case needs QML imports, then you can add them as
+    \c{-import} options to the the test program command-line by adding
+    the following line to your .pro file:
+
+    \code
+    IMPORTPATH += $$PWD/../imports/my_module1 $$PWD/../imports/my_module2
+    \endcode
+
+    \section1 Running tests with QtQuick 1
+
+    The \c{-qtquick1} option can be passed to a test binary to run
+    the tests using QDeclarativeView (QtQuick 1) rather than QSGView (QtQuick 2):
+
+    \code
+    tst_example -qtquick1
+    \endcode
+
+    To run tests with either QtQuick 1 or QtQuick 2, use
+    "import QtQuick 1.0" in your unit tests and then specify
+    compatibility mode to the QtQuick2 engine:
+
+    \code
+    QMLSCENE_IMPORT_NAME=quick1 tst_example
+    \endcode
+*/
index 09881f1..2ee93a9 100644 (file)
@@ -1,2 +1,3 @@
 TEMPLATE = subdirs
 SUBDIRS += declarative 
+contains(QT_CONFIG, qmltest): SUBDIRS += qmltest
diff --git a/examples/qmltest/qmltest.pro b/examples/qmltest/qmltest.pro
new file mode 100644 (file)
index 0000000..40d964c
--- /dev/null
@@ -0,0 +1,4 @@
+TEMPLATE=app
+TARGET=tst_qmltestexample
+CONFIG += qmltestcase
+SOURCES += tst_qmltest.cpp
diff --git a/examples/qmltest/tst_basic.qml b/examples/qmltest/tst_basic.qml
new file mode 100644 (file)
index 0000000..48aac14
--- /dev/null
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 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$
+**
+****************************************************************************/
+
+import QtQuick 2.0 
+import QtTest 1.0
+
+TestCase {
+    name: "BasicTests"
+
+    function test_pass() {
+        compare(2 + 2, 4, "2 + 2")
+    }
+
+    function test_fail() {
+        compare(2 + 2, 5, "2 + 2")
+    }
+
+    function test_skip() {
+        skip("skipping")
+    }
+
+    function test_expecting() {
+        expectFail("", "this is the fail we wanted")
+        verify(false)
+    }
+
+    function test_table_data() {
+        return [
+            {tag: "2 + 2 = 4", a: 2, b: 2, answer: 4 },
+            {tag: "2 + 6 = 8", a: 2, b: 6, answer: 8 },
+            {tag: "2 + 2 = 5", a: 2, b: 2, answer: 5 }, // fail
+        ]
+    }
+
+    function test_table(data) {
+        compare(data.a + data.b, data.answer)
+    }
+}
diff --git a/examples/qmltest/tst_item.qml b/examples/qmltest/tst_item.qml
new file mode 100644 (file)
index 0000000..4247834
--- /dev/null
@@ -0,0 +1,58 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 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$
+**
+****************************************************************************/
+
+import QtQuick 2.0
+import QtTest 1.0
+
+Rectangle {
+    id: foo
+    width: 640; height: 480
+    color: "cyan"
+
+    TestCase {
+        name: "ItemTests"
+        id: test1
+
+        function test_color() {
+            compare(foo.color, "#00ffff")
+        }
+    }
+}
diff --git a/examples/qmltest/tst_qmltest.cpp b/examples/qmltest/tst_qmltest.cpp
new file mode 100644 (file)
index 0000000..4f6eb4d
--- /dev/null
@@ -0,0 +1,43 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 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 <QtQuickTest/quicktest.h>
+QUICK_TEST_MAIN(qmltest)
diff --git a/modules/qt_qmltest.pri b/modules/qt_qmltest.pri
new file mode 100644 (file)
index 0000000..9cc2977
--- /dev/null
@@ -0,0 +1,17 @@
+QT.qmltest.VERSION = 5.0.0
+QT.qmltest.MAJOR_VERSION = 5
+QT.qmltest.MINOR_VERSION = 0
+QT.qmltest.PATCH_VERSION = 0
+
+QT.qmltest.name = QtQuickTest
+QT.qmltest.bins = $$QT_MODULE_BIN_BASE
+QT.qmltest.includes = $$QT_MODULE_INCLUDE_BASE $$QT_MODULE_INCLUDE_BASE/QtQuickTest
+QT.qmltest.private_includes = $$QT_MODULE_INCLUDE_BASE/QtQuickTest/$$QT.qmltest.VERSION
+QT.qmltest.sources = $$QT_MODULE_BASE/src/qmltest
+QT.qmltest.libs = $$QT_MODULE_LIB_BASE
+QT.qmltest.plugins = $$QT_MODULE_PLUGIN_BASE
+QT.qmltest.imports = $$QT_MODULE_IMPORT_BASE
+QT.qmltest.depends = declarative testlib
+QT.qmltest.DEFINES = QT_DECLARATIVE_LIB
+
+QT_CONFIG += qmltest
index 6704b3a..e81c4bf 100644 (file)
@@ -1,4 +1,5 @@
 TEMPLATE = subdirs
 
 SUBDIRS += folderlistmodel particles gestures inputcontext etcprovider
+contains(QT_CONFIG, qmltest): SUBDIRS += testlib
 
diff --git a/src/imports/testlib/SignalSpy.qml b/src/imports/testlib/SignalSpy.qml
new file mode 100644 (file)
index 0000000..6764129
--- /dev/null
@@ -0,0 +1,109 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 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$
+**
+****************************************************************************/
+
+import QtQuick 2.0
+
+Item {
+    id: spy
+    visible: false
+
+    // Public API.
+
+    property variant target: null
+    property string signalName: ""
+    property int count: 0
+
+    function clear() {
+        count = 0
+        qtest_expectedCount = 0
+    }
+
+    function wait(timeout) {
+        if (timeout === undefined)
+            timeout = 5000
+        var expected = ++qtest_expectedCount
+        var i = 0
+        while (i < timeout && count < expected) {
+            qtest_results.wait(50)
+            i += 50
+        }
+        var success = (count >= expected)
+        if (!qtest_results.verify(success, "wait for signal " + signalName, Qt.qtest_caller_file(), Qt.qtest_caller_line()))
+            throw new Error("QtQuickTest::fail")
+    }
+
+    // Internal implementation detail follows.
+
+    TestResult { id: qtest_results }
+
+    onTargetChanged: {
+        qtest_update()
+    }
+    onSignalNameChanged: {
+        qtest_update()
+    }
+
+    property variant qtest_prevTarget: null
+    property string qtest_prevSignalName: ""
+    property int qtest_expectedCount: 0
+
+    function qtest_update() {
+        if (qtest_prevTarget != null) {
+            qtest_prevTarget[qtest_prevSignalName].disconnect(spy, "qtest_activated")
+            qtest_prevTarget = null
+            qtest_prevSignalName = ""
+        }
+        if (target != null && signalName != "") {
+            var func = target[signalName]
+            if (func === undefined) {
+                console.log("Signal '" + signalName + "' not found")
+            } else {
+                qtest_prevTarget = target
+                qtest_prevSignalName = signalName
+                func.connect(spy.qtest_activated)
+            }
+        }
+    }
+
+    function qtest_activated() {
+        ++count
+    }
+}
diff --git a/src/imports/testlib/TestCase.qml b/src/imports/testlib/TestCase.qml
new file mode 100644 (file)
index 0000000..3659c60
--- /dev/null
@@ -0,0 +1,692 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 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$
+**
+****************************************************************************/
+
+import QtQuick 2.0
+import QtTest 1.0
+import "testlogger.js" as TestLogger
+
+Item {
+    id: testCase
+    visible: false
+
+    // Name of the test case to prefix the function name in messages.
+    property string name
+
+    // Set to true to start the test running.
+    property bool when: true
+
+    // Set to true once the test has completed.
+    property bool completed: false
+
+    // Set to true when the test is running but not yet complete.
+    property bool running: false
+
+    // Set to true if the test doesn't have to run (because some
+    // other test failed which this one depends on).
+    property bool optional: false
+
+    // Property that is set to true when the main window is shown.
+    // We need to set the property value in an odd way to handle
+    // both qmlviewer and the QtQuickTest module test wrapper.
+    property bool windowShown: Qt.qtest_wrapper ? qtest.windowShown : false
+
+    // Internal private state.  Identifiers prefixed with qtest are reserved.
+    property bool qtest_prevWhen: true
+    property int qtest_testId: -1
+    property variant qtest_testCaseResult
+    property variant qtest_results: qtest_results_normal
+    TestResult { id: qtest_results_normal }
+    property variant qtest_events: qtest_events_normal
+    TestEvent { id: qtest_events_normal }
+
+    function fail(msg) {
+        if (msg === undefined)
+            msg = "";
+        qtest_results.fail(msg, Qt.qtest_caller_file(), Qt.qtest_caller_line())
+        throw new Error("QtQuickTest::fail")
+    }
+
+    function qtest_fail(msg, frame) {
+        if (msg === undefined)
+            msg = "";
+        qtest_results.fail(msg, Qt.qtest_caller_file(frame), Qt.qtest_caller_line(frame))
+        throw new Error("QtQuickTest::fail")
+    }
+
+    function verify(cond, msg) {
+        if (msg === undefined)
+            msg = "";
+        if (!qtest_results.verify(cond, msg, Qt.qtest_caller_file(), Qt.qtest_caller_line()))
+            throw new Error("QtQuickTest::fail")
+    }
+
+    // Determine what is o.
+    // Discussions and reference: http://philrathe.com/articles/equiv
+    // Test suites: http://philrathe.com/tests/equiv
+    // Author: Philippe Rathé <prathe@gmail.com>
+    function qtest_typeof(o) {
+        if (typeof o === "undefined") {
+            return "undefined";
+
+        // consider: typeof null === object
+        } else if (o === null) {
+            return "null";
+
+        } else if (o.constructor === String) {
+            return "string";
+
+        } else if (o.constructor === Boolean) {
+            return "boolean";
+
+        } else if (o.constructor === Number) {
+
+            if (isNaN(o)) {
+                return "nan";
+            } else {
+                return "number";
+            }
+        // consider: typeof [] === object
+        } else if (o instanceof Array) {
+            return "array";
+
+        // consider: typeof new Date() === object
+        } else if (o instanceof Date) {
+            return "date";
+
+        // consider: /./ instanceof Object;
+        //           /./ instanceof RegExp;
+        //          typeof /./ === "function"; // => false in IE and Opera,
+        //                                          true in FF and Safari
+        } else if (o instanceof RegExp) {
+            return "regexp";
+
+        } else if (typeof o === "object") {
+            if ("mapFromItem" in o && "mapToItem" in o) {
+                return "declarativeitem";  // @todo improve detection of declarative items
+            } else if ("x" in o && "y" in o && "z" in o) {
+                return "vector3d"; // Qt3D vector
+            }
+            return "object";
+        } else if (o instanceof Function) {
+            return "function";
+        } else {
+            return undefined;
+        }
+    }
+
+    // Test for equality
+    // Large parts contain sources from QUnit or http://philrathe.com
+    // Discussions and reference: http://philrathe.com/articles/equiv
+    // Test suites: http://philrathe.com/tests/equiv
+    // Author: Philippe Rathé <prathe@gmail.com>
+    function qtest_compareInternal(act, exp) {
+        var success = false;
+
+        if (act === exp) {
+            success = true; // catch the most you can
+        } else if (act === null || exp === null || typeof act === "undefined" || typeof exp === "undefined") {
+            success = false; // don't lose time with error prone cases
+        } else {
+            var typeExp = qtest_typeof(exp), typeAct = qtest_typeof(act)
+
+            if (typeExp !== typeAct) {
+                // allow object vs string comparison (e.g. for colors)
+                // else break on different types
+                if ((typeExp === "string" && typeAct === "object") || (typeExp === "object" && typeAct === "string")) {
+                    success = (act == exp)
+                }
+            } else if (typeExp === "string" || typeExp === "boolean" || typeExp === "number" ||
+                       typeExp === "null" || typeExp === "undefined") {
+                if (exp instanceof act.constructor || act instanceof exp.constructor) {
+                    // to catch short annotaion VS 'new' annotation of act declaration
+                    // e.g. var i = 1;
+                    //      var j = new Number(1);
+                    success = (act == exp)
+                } else {
+                    success = (act === exp)
+                }
+            } else if (typeExp === "nan") {
+                success = isNaN(act);
+            } else if (typeExp == "number") {
+                // Use act fuzzy compare if the two values are floats
+                if (Math.abs(act - exp) <= 0.00001) {
+                    success = true
+                }
+            } else if (typeExp === "array") {
+                success = qtest_compareInternalArrays(act, exp)
+            } else if (typeExp === "object") {
+                success = qtest_compareInternalObjects(act, exp)
+            } else if (typeExp === "declarativeitem") {
+                success = qtest_compareInternalObjects(act, exp) // @todo improve comparison of declarative items
+            } else if (typeExp === "vector3d") {
+                success = (Math.abs(act.x - exp.x) <= 0.00001 &&
+                           Math.abs(act.y - exp.y) <= 0.00001 &&
+                           Math.abs(act.z - exp.z) <= 0.00001)
+            } else if (typeExp === "date") {
+                success = (act.valueOf() === exp.valueOf())
+            } else if (typeExp === "regexp") {
+                success = (act.source === exp.source && // the regex itself
+                           act.global === exp.global && // and its modifers (gmi) ...
+                           act.ignoreCase === exp.ignoreCase &&
+                           act.multiline === exp.multiline)
+            }
+        }
+        return success
+    }
+
+    function qtest_compareInternalObjects(act, exp) {
+        var i;
+        var eq = true; // unless we can proove it
+        var aProperties = [], bProperties = []; // collection of strings
+
+        // comparing constructors is more strict than using instanceof
+        if (act.constructor !== exp.constructor) {
+            return false;
+        }
+
+        for (i in act) { // be strict: don't ensures hasOwnProperty and go deep
+            aProperties.push(i); // collect act's properties
+
+            if (!qtest_compareInternal(act[i], exp[i])) {
+                eq = false;
+                break;
+            }
+        }
+
+        for (i in exp) {
+            bProperties.push(i); // collect exp's properties
+        }
+
+        // Ensures identical properties name
+        return eq && qtest_compareInternal(aProperties.sort(), bProperties.sort());
+
+    }
+
+    function qtest_compareInternalArrays(actual, expected) {
+        if (actual.length != expected.length) {
+            return false
+        }
+
+        for (var i = 0, len = actual.length; i < len; i++) {
+            if (!qtest_compareInternal(actual[i], expected[i])) {
+                return false
+            }
+        }
+
+        return true
+    }
+
+    function qtest_formatValue(value) {
+        if (typeof value == "object") {
+            if ("x" in value && "y" in value && "z" in value) {
+                return "Qt.vector3d(" + value.x + ", " +
+                       value.y + ", " + value.z + ")"
+            }
+            try {
+                return JSON.stringify(value)
+            } catch (ex) {
+                // stringify might fail (e.g. due to circular references)
+            }
+        }
+        return value
+    }
+
+    function compare(actual, expected, msg) {
+        var act = qtest_formatValue(actual)
+        var exp = qtest_formatValue(expected)
+        var success = qtest_compareInternal(actual, expected)
+        if (msg === undefined) {
+            if (success)
+                msg = "COMPARE()"
+            else
+                msg = "Compared values are not the same"
+        }
+        if (!qtest_results.compare(success, msg, act, exp, Qt.qtest_caller_file(), Qt.qtest_caller_line()))
+            throw new Error("QtQuickTest::fail")
+    }
+
+    function tryCompare(obj, prop, value, timeout) {
+        if (!timeout)
+            timeout = 5000
+        if (!qtest_compareInternal(obj[prop], value))
+            wait(0)
+        var i = 0
+        while (i < timeout && !qtest_compareInternal(obj[prop], value)) {
+            wait(50)
+            i += 50
+        }
+        var actual = obj[prop]
+        var act = qtest_formatValue(actual)
+        var exp = qtest_formatValue(value)
+        var success = qtest_compareInternal(actual, value)
+        if (!qtest_results.compare(success, "property " + prop, act, exp, Qt.qtest_caller_file(), Qt.qtest_caller_line()))
+            throw new Error("QtQuickTest::fail")
+    }
+
+    function skip(msg) {
+        if (msg === undefined)
+            msg = ""
+        qtest_results.skipSingle(msg, Qt.qtest_caller_file(), Qt.qtest_caller_line())
+        throw new Error("QtQuickTest::skip")
+    }
+
+    function skipAll(msg) {
+        if (msg === undefined)
+            msg = ""
+        qtest_results.skipAll(msg, Qt.qtest_caller_file(), Qt.qtest_caller_line())
+        throw new Error("QtQuickTest::skip")
+    }
+
+    function expectFail(tag, msg) {
+        if (tag === undefined) {
+            warn("tag argument missing from expectFail()")
+            tag = ""
+        }
+        if (msg === undefined) {
+            warn("message argument missing from expectFail()")
+            msg = ""
+        }
+        if (!qtest_results.expectFail(tag, msg, Qt.qtest_caller_file(), Qt.qtest_caller_line()))
+            throw new Error("QtQuickTest::expectFail")
+    }
+
+    function expectFailContinue(tag, msg) {
+        if (tag === undefined) {
+            warn("tag argument missing from expectFailContinue()")
+            tag = ""
+        }
+        if (msg === undefined) {
+            warn("message argument missing from expectFailContinue()")
+            msg = ""
+        }
+        if (!qtest_results.expectFailContinue(tag, msg, Qt.qtest_caller_file(), Qt.qtest_caller_line()))
+            throw new Error("QtQuickTest::expectFail")
+    }
+
+    function warn(msg) {
+        if (msg === undefined)
+            msg = ""
+        qtest_results.warn(msg);
+    }
+
+    function ignoreWarning(msg) {
+        if (msg === undefined)
+            msg = ""
+        qtest_results.ignoreWarning(msg)
+    }
+
+    function wait(ms) {
+        qtest_results.wait(ms)
+    }
+
+    function sleep(ms) {
+        qtest_results.sleep(ms)
+    }
+
+    function keyPress(key, modifiers, delay) {
+        if (modifiers === undefined)
+            modifiers = Qt.NoModifier
+        if (delay == undefined)
+            delay = -1
+        if (!qtest_events.keyPress(key, modifiers, delay))
+            qtest_fail("window not shown", 2)
+    }
+
+    function keyRelease(key, modifiers, delay) {
+        if (modifiers === undefined)
+            modifiers = Qt.NoModifier
+        if (delay == undefined)
+            delay = -1
+        if (!qtest_events.keyRelease(key, modifiers, delay))
+            qtest_fail("window not shown", 2)
+    }
+
+    function keyClick(key, modifiers, delay) {
+        if (modifiers === undefined)
+            modifiers = Qt.NoModifier
+        if (delay == undefined)
+            delay = -1
+        if (!qtest_events.keyClick(key, modifiers, delay))
+            qtest_fail("window not shown", 2)
+    }
+
+    function mousePress(item, x, y, button, modifiers, delay) {
+        if (button === undefined)
+            button = Qt.LeftButton
+        if (modifiers === undefined)
+            modifiers = Qt.NoModifier
+        if (delay == undefined)
+            delay = -1
+        if (!qtest_events.mousePress(item, x, y, button, modifiers, delay))
+            qtest_fail("window not shown", 2)
+    }
+
+    function mouseRelease(item, x, y, button, modifiers, delay) {
+        if (button === undefined)
+            button = Qt.LeftButton
+        if (modifiers === undefined)
+            modifiers = Qt.NoModifier
+        if (delay == undefined)
+            delay = -1
+        if (!qtest_events.mouseRelease(item, x, y, button, modifiers, delay))
+            qtest_fail("window not shown", 2)
+    }
+
+    function mouseClick(item, x, y, button, modifiers, delay) {
+        if (button === undefined)
+            button = Qt.LeftButton
+        if (modifiers === undefined)
+            modifiers = Qt.NoModifier
+        if (delay == undefined)
+            delay = -1
+        if (!qtest_events.mouseClick(item, x, y, button, modifiers, delay))
+            qtest_fail("window not shown", 2)
+    }
+
+    function mouseDoubleClick(item, x, y, button, modifiers, delay) {
+        if (button === undefined)
+            button = Qt.LeftButton
+        if (modifiers === undefined)
+            modifiers = Qt.NoModifier
+        if (delay == undefined)
+            delay = -1
+        if (!qtest_events.mouseDoubleClick(item, x, y, button, modifiers, delay))
+            qtest_fail("window not shown", 2)
+    }
+
+    function mouseMove(item, x, y, delay) {
+        if (delay == undefined)
+            delay = -1
+        if (!qtest_events.mouseMove(item, x, y, delay))
+            qtest_fail("window not shown", 2)
+    }
+
+    // Functions that can be overridden in subclasses for init/cleanup duties.
+    function initTestCase() {}
+    function cleanupTestCase() {}
+    function init() {}
+    function cleanup() {}
+
+    function qtest_runInternal(prop, arg) {
+        try {
+            qtest_testCaseResult = testCase[prop](arg)
+        } catch (e) {
+            qtest_testCaseResult = []
+            if (e.message.indexOf("QtQuickTest::") != 0) {
+                // Test threw an unrecognized exception - fail.
+                qtest_results.fail("Uncaught exception: " + e.message,
+                             e.fileName, e.lineNumber)
+            }
+        }
+        return !qtest_results.dataFailed
+    }
+
+    function qtest_runFunction(prop, arg) {
+        qtest_results.functionType = TestResult.InitFunc
+        qtest_runInternal("init")
+        if (!qtest_results.skipped) {
+            qtest_results.functionType = TestResult.Func
+            qtest_runInternal(prop, arg)
+            qtest_results.functionType = TestResult.CleanupFunc
+            qtest_runInternal("cleanup")
+        }
+        qtest_results.functionType = TestResult.NoWhere
+    }
+
+    function qtest_runBenchmarkFunction(prop, arg) {
+        qtest_results.startMeasurement()
+        do {
+            qtest_results.beginDataRun()
+            do {
+                // Run the initialization function.
+                qtest_results.functionType = TestResult.InitFunc
+                qtest_runInternal("init")
+                if (qtest_results.skipped)
+                    break
+
+                // Execute the benchmark function.
+                qtest_results.functionType = TestResult.Func
+                if (prop.indexOf("benchmark_once_") != 0)
+                    qtest_results.startBenchmark(TestResult.RepeatUntilValidMeasurement, qtest_results.dataTag)
+                else
+                    qtest_results.startBenchmark(TestResult.RunOnce, qtest_results.dataTag)
+                while (!qtest_results.isBenchmarkDone()) {
+                    if (!qtest_runInternal(prop, arg))
+                        break
+                    qtest_results.nextBenchmark()
+                }
+                qtest_results.stopBenchmark()
+
+                // Run the cleanup function.
+                qtest_results.functionType = TestResult.CleanupFunc
+                qtest_runInternal("cleanup")
+                qtest_results.functionType = TestResult.NoWhere
+            } while (!qtest_results.measurementAccepted())
+            qtest_results.endDataRun()
+        } while (qtest_results.needsMoreMeasurements())
+    }
+
+    function qtest_run() {
+        if (Qt.qtest_printAvailableFunctions) {
+            completed = true
+            return
+        }
+
+        if (TestLogger.log_start_test()) {
+            qtest_results.reset()
+            qtest_results.testCaseName = name
+            qtest_results.startLogging()
+        } else {
+            qtest_results.testCaseName = name
+        }
+        running = true
+
+        // Check the run list to see if this class is mentioned.
+        var functionsToRun = qtest_results.functionsToRun
+        if (functionsToRun.length > 0) {
+            var found = false
+            var list = []
+            if (name.length > 0) {
+                var prefix = name + "::"
+                for (var index in functionsToRun) {
+                    if (functionsToRun[index].indexOf(prefix) == 0) {
+                        list.push(functionsToRun[index])
+                        found = true
+                    }
+                }
+            }
+            if (!found) {
+                completed = true
+                if (!TestLogger.log_complete_test(qtest_testId)) {
+                    qtest_results.stopLogging()
+                    Qt.quit()
+                }
+                qtest_results.testCaseName = ""
+                return
+            }
+            functionsToRun = list
+        }
+
+        // Run the initTestCase function.
+        qtest_results.functionName = "initTestCase"
+        qtest_results.functionType = TestResult.InitFunc
+        var runTests = true
+        if (!qtest_runInternal("initTestCase"))
+            runTests = false
+        qtest_results.finishTestFunction()
+
+        // Run the test methods.
+        var testList = []
+        if (runTests) {
+            for (var prop in testCase) {
+                if (prop.indexOf("test_") != 0 && prop.indexOf("benchmark_") != 0)
+                    continue
+                var tail = prop.lastIndexOf("_data");
+                if (tail != -1 && tail == (prop.length - 5))
+                    continue
+                testList.push(prop)
+            }
+            testList.sort()
+        }
+        var checkNames = (functionsToRun.length > 0)
+        for (var index in testList) {
+            var prop = testList[index]
+            var datafunc = prop + "_data"
+            var isBenchmark = (prop.indexOf("benchmark_") == 0)
+            if (checkNames) {
+                var index = functionsToRun.indexOf(name + "::" + prop)
+                if (index < 0)
+                    continue
+                functionsToRun.splice(index, 1)
+            }
+            qtest_results.functionName = prop
+            if (datafunc in testCase) {
+                qtest_results.functionType = TestResult.DataFunc
+                if (qtest_runInternal(datafunc)) {
+                    var table = qtest_testCaseResult
+                    var haveData = false
+                    qtest_results.initTestTable()
+                    for (var index in table) {
+                        haveData = true
+                        var row = table[index]
+                        if (!row.tag)
+                            row.tag = "row " + index    // Must have something
+                        qtest_results.dataTag = row.tag
+                        if (isBenchmark)
+                            qtest_runBenchmarkFunction(prop, row)
+                        else
+                            qtest_runFunction(prop, row)
+                        qtest_results.dataTag = ""
+                    }
+                    if (!haveData)
+                        qtest_results.warn("no data supplied for " + prop + "() by " + datafunc + "()")
+                    qtest_results.clearTestTable()
+                }
+            } else if (isBenchmark) {
+                qtest_runBenchmarkFunction(prop, null, isBenchmark)
+            } else {
+                qtest_runFunction(prop, null, isBenchmark)
+            }
+            qtest_results.finishTestFunction()
+            qtest_results.skipped = false
+        }
+
+        // Run the cleanupTestCase function.
+        qtest_results.skipped = false
+        qtest_results.functionName = "cleanupTestCase"
+        qtest_results.functionType = TestResult.CleanupFunc
+        qtest_runInternal("cleanupTestCase")
+
+        // Complain about missing functions that we were supposed to run.
+        if (functionsToRun.length > 0)
+            qtest_results.fail("Could not find functions: " + functionsToRun, "", 0)
+
+        // Clean up and exit.
+        running = false
+        completed = true
+        qtest_results.finishTestFunction()
+        qtest_results.functionName = ""
+
+        // Stop if there are no more tests to be run.
+        if (!TestLogger.log_complete_test(qtest_testId)) {
+            qtest_results.stopLogging()
+            Qt.quit()
+        }
+        qtest_results.testCaseName = ""
+    }
+
+    onWhenChanged: {
+        if (when != qtest_prevWhen) {
+            qtest_prevWhen = when
+            if (when && !completed && !running)
+                qtest_run()
+        }
+    }
+
+    onOptionalChanged: {
+        if (!completed) {
+            if (optional)
+                TestLogger.log_optional_test(qtest_testId)
+            else
+                TestLogger.log_mandatory_test(qtest_testId)
+        }
+    }
+
+    // The test framework will set qtest.windowShown when the
+    // window is actually shown.  If we are running with qmlviewer,
+    // then this won't happen.  So we use a timer instead.
+    Timer {
+        id: qtest_windowShowTimer
+        interval: 100
+        repeat: false
+        onTriggered: { windowShown = true }
+    }
+
+    Component.onCompleted: {
+        if (Qt.qtest_printAvailableFunctions) {
+            var testList = []
+            for (var prop in testCase) {
+                if (prop.indexOf("test_") != 0 && prop.indexOf("benchmark_") != 0)
+                    continue
+                var tail = prop.lastIndexOf("_data");
+                if (tail != -1 && tail == (prop.length - 5))
+                    continue
+                // Note: cannot run functions in TestCase elements
+                // that lack a name.
+                if (name.length > 0)
+                    testList.push(name + "::" + prop + "()")
+            }
+            testList.sort()
+            for (var index in testList)
+                console.log(testList[index])
+            return
+        }
+        qtest_testId = TestLogger.log_register_test(name)
+        if (optional)
+            TestLogger.log_optional_test(qtest_testId)
+        qtest_prevWhen = when
+        var isQmlViewer = Qt.qtest_wrapper ? false : true
+        if (isQmlViewer)
+            qtest_windowShowTimer.running = true
+        if (when && !completed && !running)
+            qtest_run()
+    }
+}
diff --git a/src/imports/testlib/main.cpp b/src/imports/testlib/main.cpp
new file mode 100644 (file)
index 0000000..5ef07b9
--- /dev/null
@@ -0,0 +1,133 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 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 <QtDeclarative/qdeclarativeextensionplugin.h>
+#include <QtDeclarative/qdeclarative.h>
+#include <QtScript/qscriptvalue.h>
+#include <QtScript/qscriptcontext.h>
+#include <QtScript/qscriptcontextinfo.h>
+#include <QtScript/qscriptengine.h>
+#include "QtQuickTest/private/quicktestresult_p.h"
+#include "QtQuickTest/private/quicktestevent_p.h"
+QT_BEGIN_NAMESPACE
+
+QML_DECLARE_TYPE(QuickTestResult)
+QML_DECLARE_TYPE(QuickTestEvent)
+
+// Copied from qdeclarativedebughelper_p.h in Qt, to avoid a dependency
+// on a private header from Qt.
+class Q_DECLARATIVE_EXPORT QDeclarativeDebugHelper
+{
+public:
+    static QScriptEngine *getScriptEngine(QDeclarativeEngine *engine);
+    static void setAnimationSlowDownFactor(qreal factor);
+    static void enableDebugging();
+};
+
+static QScriptContext *qtest_find_frame(QScriptContext *ctx)
+{
+    qint32 frame = 1;
+    if (ctx->argumentCount() > 0)
+        frame = ctx->argument(0).toInt32();
+    ++frame;    // Exclude the native function; start at its caller.
+    while (ctx) {
+        if (frame-- <= 0)
+            break;
+        ctx = ctx->parentContext();
+    }
+    return ctx;
+}
+
+static QScriptValue qtest_caller_file
+    (QScriptContext *ctx, QScriptEngine *engine)
+{
+    ctx = qtest_find_frame(ctx);
+    if (ctx) {
+        QScriptContextInfo info(ctx);
+        return engine->newVariant(info.fileName());
+    }
+    return engine->newVariant(QLatin1String(""));
+}
+
+static QScriptValue qtest_caller_line
+    (QScriptContext *ctx, QScriptEngine *engine)
+{
+    ctx = qtest_find_frame(ctx);
+    if (ctx) {
+        QScriptContextInfo info(ctx);
+        return engine->newVariant(info.lineNumber());
+    }
+    return engine->newVariant(qint32(0));
+}
+
+class QTestQmlModule : public QDeclarativeExtensionPlugin
+{
+    Q_OBJECT
+public:
+    virtual void registerTypes(const char *uri)
+    {
+        Q_ASSERT(QLatin1String(uri) == QLatin1String("QtTest"));
+        qmlRegisterType<QuickTestResult>(uri,1,0,"TestResult");
+        qmlRegisterType<QuickTestEvent>(uri,1,0,"TestEvent");
+    }
+    void initializeEngine(QDeclarativeEngine *engine, const char *)
+    {
+        // Install some helper functions in the global "Qt" object
+        // for walking the stack and finding a caller's location.
+        // Normally we would use an exception's backtrace, but JSC
+        // only provides the top-most frame in the backtrace.
+        QScriptEngine *eng = QDeclarativeDebugHelper::getScriptEngine(engine);
+        QScriptValue qtObject
+            = eng->globalObject().property(QLatin1String("Qt"));
+        qtObject.setProperty
+            (QLatin1String("qtest_caller_file"),
+             eng->newFunction(qtest_caller_file));
+        qtObject.setProperty
+            (QLatin1String("qtest_caller_line"),
+             eng->newFunction(qtest_caller_line));
+    }
+};
+
+QT_END_NAMESPACE
+
+#include "main.moc"
+
+Q_EXPORT_PLUGIN2(qmltestplugin, QT_PREPEND_NAMESPACE(QTestQmlModule));
diff --git a/src/imports/testlib/qmldir b/src/imports/testlib/qmldir
new file mode 100644 (file)
index 0000000..9e872f9
--- /dev/null
@@ -0,0 +1,3 @@
+plugin qmltestplugin
+TestCase 1.0 TestCase.qml
+SignalSpy 1.0 SignalSpy.qml
diff --git a/src/imports/testlib/signalspy.h b/src/imports/testlib/signalspy.h
new file mode 100644 (file)
index 0000000..4a97959
--- /dev/null
@@ -0,0 +1,83 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 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$
+**
+****************************************************************************/
+
+#ifndef SIGNALSPY_H
+#define SIGNALSPY_H
+
+// This is a dummy header for defining the interface of "SignalSpy.qml" to qdoc.
+
+#include <QtDeclarative/qdeclarativeitem.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class SignalSpy : public QDeclarativeItem
+{
+    Q_OBJECT
+    Q_PROPERTY(QObject *target READ target WRITE setTarget NOTIFY targetChanged)
+    Q_PROPERTY(QString signalName READ signalName WRITE signalName NOTIFY signalNameChanged)
+    Q_PROPERTY(int count READ count countChanged)
+public:
+    SignalSpy(QDeclarativeItem *parent) : QDeclarativeItem(parent) {}
+    ~SignalSpy()
+
+    QObject *target() const;
+    void setTarget(QObject *target);
+
+    QString signalName() const;
+    void setSignalName(const QString &signalName);
+
+    int count() const;
+
+Q_SIGNALS:
+    void targetChanged();
+    void signalNameChanged();
+    void countChanged();
+};
+
+QML_DECLARE_TYPE(SignalSpy)
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/imports/testlib/signalspy.qdoc b/src/imports/testlib/signalspy.qdoc
new file mode 100644 (file)
index 0000000..3ed39c4
--- /dev/null
@@ -0,0 +1,146 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 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$
+**
+****************************************************************************/
+
+/*!
+    \qmlclass SignalSpy SignalSpy
+    \brief The SignalSpy item enables introspection of signal emission.
+    \since 4.8
+    \ingroup qtest::qml
+
+    In the following example, a SignalSpy is installed to watch the
+    "clicked" signal on a user-defined Button element.  When the signal
+    is emitted, the \l count property on the spy will be increased.
+
+    \code
+    Button {
+        id: button
+        SignalSpy {
+            id: spy
+            target: button
+            signalName: "clicked"
+        }
+        TestCase {
+            name: "ButtonClick"
+            function test_click() {
+                compare(spy.count, 0)
+                button.clicked();
+                compare(spy.count, 1)
+            }
+        }
+    }
+    \endcode
+
+    The above style of test is suitable for signals that are emitted
+    synchronously.  For asynchronous signals, the wait() method can be
+    used to block the test until the signal occurs (or a timeout expires).
+
+    \sa TestCase
+*/
+
+/*!
+    \qmlproperty object SignalSpy::target
+
+    This property defines the target object that will be used to
+    listen for emissions of the \l signalName signal.
+
+    \sa signalName, count
+*/
+
+/*!
+    \qmlproperty string SignalSpy::signalName
+
+    This property defines the name of the signal on \l target to
+    listen for.
+
+    \sa target, count
+*/
+
+/*!
+    \qmlproperty int SignalSpy::count
+
+    This property defines the number of times that \l signalName has
+    been emitted from \l target since the last call to clear().
+
+    \sa target, signalName, clear()
+*/
+
+/*!
+    \qmlmethod SignalSpy::clear()
+
+    Clears \l count to 0.
+
+    \sa count, wait()
+*/
+
+/*!
+    \qmlmethod SignalSpy::wait(timeout = 5000)
+
+    Waits for the signal \l signalName on \l target to be emitted,
+    for up to \a timeout milliseconds.  The test case will fail if
+    the signal is not emitted.
+
+    \code
+    SignalSpy {
+        id: spy
+        target: button
+        signalName: "clicked"
+    }
+
+    function test_async_click() {
+        ...
+        // do something that will cause clicked() to be emitted
+        ...
+        spy.wait()
+        compare(spy.count, 1)
+    }
+    \endcode
+
+    There are two possible scenarios: the signal has already been
+    emitted when wait() is called, or the signal has not yet been
+    emitted.  The wait() function handles the first scenario by immediately
+    returning if the signal has already occurred.
+
+    The clear() method can be used to discard information about signals
+    that have already occurred to synchronize wait() with future signal
+    emissions.
+
+    \sa clear(), TestCase::tryCompare()
+*/
diff --git a/src/imports/testlib/testcase.h b/src/imports/testlib/testcase.h
new file mode 100644 (file)
index 0000000..f7a1992
--- /dev/null
@@ -0,0 +1,94 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 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$
+**
+****************************************************************************/
+
+#ifndef TESTCASE_H
+#define TESTCASE_H
+
+// This is a dummy header for defining the interface of "TestCase.qml" to qdoc.
+
+#include <QtDeclarative/qdeclarativeitem.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class TestCase : public QDeclarativeItem
+{
+    Q_OBJECT
+    Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
+    Q_PROPERTY(bool when READ when WRITE setWhen NOTIFY whenChanged)
+    Q_PROPERTY(bool optional READ optional WRITE setOptional NOTIFY optionalChanged)
+    Q_PROPERTY(bool completed READ completed NOTIFY completedChanged)
+    Q_PROPERTY(bool running READ running NOTIFY runningChanged)
+    Q_PROPERTY(bool windowShown READ windowShown NOTIFY windowShownChanged)
+public:
+    TestCase(QDeclarativeItem *parent) : QDeclarativeItem(parent) {}
+    ~TestCase()
+
+    QString name() const;
+    void setName(const QString &name);
+
+    bool when() const;
+    void setWhen(bool when);
+
+    bool optional() const;
+    void setOptional(bool optional);
+
+    bool completed() const;
+    bool running() const;
+    bool windowShown() const;
+
+Q_SIGNALS:
+    void nameChanged();
+    void whenChanged();
+    void optionalChanged();
+    void completedChanged();
+    void runningChanged();
+    void windowShownChanged();
+};
+
+QML_DECLARE_TYPE(TestCase)
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/imports/testlib/testcase.qdoc b/src/imports/testlib/testcase.qdoc
new file mode 100644 (file)
index 0000000..bb7044f
--- /dev/null
@@ -0,0 +1,597 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 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$
+**
+****************************************************************************/
+
+/*!
+    \qmlclass TestCase TestCase
+    \brief The TestCase item represents a unit test case.
+    \since 4.8
+    \ingroup qtest::qml
+
+    \section1 Introduction to QML test cases
+
+    Test cases are written as JavaScript functions within a TestCase
+    element:
+
+    \code
+    import QtQuick 1.0
+    import QtQuickTest 1.0
+
+    TestCase {
+        name: "MathTests"
+
+        function test_math() {
+            compare(2 + 2, 4, "2 + 2 = 4")
+        }
+
+        function test_fail() {
+            compare(2 + 2, 5, "2 + 2 = 5")
+        }
+    }
+    \endcode
+
+    Functions whose names start with "test_" are treated as test cases
+    to be executed.  The \l name property is used to prefix the functions
+    in the output:
+
+    \code
+    ********* Start testing of MathTests *********
+    Config: Using QTest library 4.7.2, Qt 4.7.2
+    PASS   : MathTests::initTestCase()
+    FAIL!  : MathTests::test_fail() 2 + 2 = 5
+       Actual (): 4
+       Expected (): 5
+       Loc: [/home/.../tst_math.qml(12)]
+    PASS   : MathTests::test_math()
+    PASS   : MathTests::cleanupTestCase()
+    Totals: 3 passed, 1 failed, 0 skipped
+    ********* Finished testing of MathTests *********
+    \endcode
+
+    Because of the way JavaScript properties work, the order in which the
+    test functions are found is unpredictable.  To assist with predictability,
+    the test framework will sort the functions on ascending order of name.
+    This can help when there are two tests that must be run in order.
+
+    Multiple TestCase elements can be supplied.  The test program will exit
+    once they have all completed.  If a test case doesn't need to run
+    (because a precondition has failed), then \l optional can be set to true.
+
+    \section1 Data-driven tests
+
+    Table data can be provided to a test using a function name that ends
+    with "_data":
+
+    \code
+    import QtQuick 1.0
+    import QtQuickTest 1.0
+
+    TestCase {
+        name: "DataTests"
+
+        function test_table_data() {
+            return [
+                {tag: "2 + 2 = 4", a: 2, b: 2, answer: 4 },
+                {tag: "2 + 6 = 8", a: 2, b: 6, answer: 8 },
+            ]
+        }
+
+        function test_table(data) {
+            compare(data.a + data.b, data.answer)
+        }
+    }
+    \endcode
+
+    The test framework will iterate over all of the rows in the table
+    and pass each row to the test function.  As shown, the columns can be
+    extracted for use in the test.  The \c tag column is special - it is
+    printed by the test framework when a row fails, to help the reader
+    identify which case failed amongst a set of otherwise passing tests.
+
+    \section1 Benchmarks
+
+    Functions whose names start with "benchmark_" will be run multiple
+    times with the Qt benchmark framework, with an average timing value
+    reported for the runs.  This is equivalent to using the \c{QBENCHMARK}
+    macro in the C++ version of QTestLib.
+
+    \code
+    TestCase {
+        id: top
+        name: "CreateBenchmark"
+
+        function benchmark_create_component() {
+            var component = Qt.createComponent("item.qml")
+            var obj = component.createObject(top)
+            obj.destroy()
+            component.destroy()
+        }
+    }
+
+    RESULT : CreateBenchmark::benchmark_create_component:
+         0.23 msecs per iteration (total: 60, iterations: 256)
+    PASS   : CreateBenchmark::benchmark_create_component()
+    \endcode
+
+    To get the effect of the \c{QBENCHMARK_ONCE} macro, prefix the test
+    function name with "benchmark_once_".
+
+    \section1 Simulating keyboard and mouse events
+
+    The keyPress(), keyRelease(), and keyClick() methods can be used
+    to simulate keyboard events within unit tests.  The events are
+    delivered to the currently focused QML item.
+
+    \code
+    Rectangle {
+        width: 50; height: 50
+        focus: true
+
+        TestCase {
+            name: "KeyClick"
+            when: windowShown
+
+            function test_key_click() {
+                keyClick(Qt.Key_Left)
+                ...
+            }
+        }
+    }
+    \endcode
+
+    The mousePress(), mouseRelease(), mouseClick(), mouseDoubleClick(),
+    and mouseMove() methods can be used to simulate mouse events in a
+    similar fashion.
+
+    \bold{Note:} keyboard and mouse events can only be delivered once the
+    main window has been shown.  Attempts to deliver events before then
+    will fail.  Use the \l when and windowShown properties to track
+    when the main window has been shown.
+
+    \sa SignalSpy
+*/
+
+/*!
+    \qmlproperty string TestCase::name
+
+    This property defines the name of the test case for result reporting.
+    The default is the empty string.
+
+    \code
+    TestCase {
+        name: "ButtonTests"
+        ...
+    }
+    \endcode
+*/
+
+/*!
+    \qmlproperty bool TestCase::when
+
+    This property should be set to true when the application wants
+    the test cases to run.  The default value is true.  In the following
+    example, a test is run when the user presses the mouse button:
+
+    \code
+    Rectangle {
+        id: foo
+        width: 640; height: 480
+        color: "cyan"
+
+        MouseArea {
+            id: area
+            anchors.fill: parent
+        }
+
+        property bool bar: true
+
+        TestCase {
+            name: "ItemTests"
+            when: area.pressed
+            id: test1
+
+            function test_bar() {
+                verify(bar)
+            }
+        }
+    }
+    \endcode
+
+    The test application will exit once all \l TestCase elements
+    have been triggered and have run.  The \l optional property can
+    be used to exclude a \l TestCase element.
+
+    \sa optional, completed
+*/
+
+/*!
+    \qmlproperty bool TestCase::optional
+
+    Multiple \l TestCase elements can be supplied in a test application.
+    The application will exit once they have all completed.  If a test case
+    does not need to run (because a precondition has failed), then this
+    property can be set to true.  The default value is false.
+
+    \code
+    TestCase {
+        when: false
+        optional: true
+        function test_not_run() {
+            verify(false)
+        }
+    }
+    \endcode
+
+    \sa when, completed
+*/
+
+/*!
+    \qmlproperty bool TestCase::completed
+
+    This property will be set to true once the test case has completed
+    execution.  Test cases are only executed once.  The initial value
+    is false.
+
+    \sa running, when
+*/
+
+/*!
+    \qmlproperty bool TestCase::running
+
+    This property will be set to true while the test case is running.
+    The initial value is false, and the value will become false again
+    once the test case completes.
+
+    \sa completed, when
+*/
+
+/*!
+    \qmlproperty bool TestCase::windowShown
+
+    This property will be set to true after the QML viewing window has
+    been displayed.  Normally test cases run as soon as the test application
+    is loaded and before a window is displayed.  If the test case involves
+    visual elements and behaviors, then it may need to be delayed until
+    after the window is shown.
+
+    \code
+    Button {
+        id: button
+        onClicked: text = "Clicked"
+        TestCase {
+            name: "ClickTest"
+            when: windowShown
+            function test_click() {
+                button.clicked();
+                compare(button.text, "Clicked");
+            }
+        }
+    }
+    \endcode
+*/
+
+/*!
+    \qmlmethod TestCase::fail(message = "")
+
+    Fails the current test case, with the optional \a message.
+    Similar to \c{QFAIL(message)} in C++.
+*/
+
+/*!
+    \qmlmethod TestCase::verify(condition, message = "")
+
+    Fails the current test case if \a condition is false, and
+    displays the optional \a message.  Similar to \c{QVERIFY(condition)}
+    or \c{QVERIFY2(condition, message)} in C++.
+*/
+
+/*!
+    \qmlmethod TestCase::compare(actual, expected, message = "")
+
+    Fails the current test case if \a actual is not the same as
+    \a expected, and displays the optional \a message.  Similar
+    to \c{QCOMPARE(actual, expected)} in C++.
+
+    \sa tryCompare()
+*/
+
+/*!
+    \qmlmethod TestCase::tryCompare(obj, property, expected, timeout = 5000)
+
+    Fails the current test case if the specified \a property on \a obj
+    is not the same as \a expected.  The test will be retried multiple
+    times until the \a timeout (in milliseconds) is reached.
+
+    This function is intended for testing applications where a property
+    changes value based on asynchronous events.  Use compare() for testing
+    synchronous property changes.
+
+    \code
+    tryCompare(img, "status", BorderImage.Ready)
+    compare(img.width, 120)
+    compare(img.height, 120)
+    compare(img.horizontalTileMode, BorderImage.Stretch)
+    compare(img.verticalTileMode, BorderImage.Stretch)
+    \endcode
+
+    SignalSpy::wait() provides an alternative method to wait for a
+    signal to be emitted.
+
+    \sa compare(), SignalSpy::wait()
+*/
+
+/*!
+    \qmlmethod TestCase::skip(message = "")
+
+    Skips the current test case and prints the optional \a message.
+    If this is a data-driven test, then only the current row is skipped.
+    Similar to \c{QSKIP(message, SkipSingle)} in C++.
+
+    \sa skipAll()
+*/
+
+/*!
+    \qmlmethod TestCase::skipAll(message = "")
+
+    Skips the current test case and prints the optional \a message.
+    If this is a data-driven test, then all remaining rows are skipped.
+    Similar to \c{QSKIP(message, SkipAll)} in C++.
+
+    \sa skip()
+*/
+
+/*!
+    \qmlmethod TestCase::expectFail(tag, message)
+
+    In a data-driven test, marks the row associated with \a tag as
+    expected to fail.  When the fail occurs, display the \a message,
+    abort the test, and mark the test as passing.  Similar to
+    \c{QEXPECT_FAIL(tag, message, Abort)} in C++.
+
+    If the test is not data-driven, then \a tag must be set to
+    the empty string.
+
+    \sa expectFailContinue()
+*/
+
+/*!
+    \qmlmethod TestCase::expectFailContinue(tag, message)
+
+    In a data-driven test, marks the row associated with \a tag as
+    expected to fail.  When the fail occurs, display the \a message,
+    and then continue the test.  Similar to
+    \c{QEXPECT_FAIL(tag, message, Continue)} in C++.
+
+    If the test is not data-driven, then \a tag must be set to
+    the empty string.
+
+    \sa expectFail()
+*/
+
+/*!
+    \qmlmethod TestCase::warn(message)
+
+    Prints \a message as a warning message.  Similar to
+    \c{QWARN(message)} in C++.
+
+    \sa ignoreWarning()
+*/
+
+/*!
+    \qmlmethod TestCase::ignoreWarning(message)
+
+    Marks \a message as an ignored warning message.  When it occurs,
+    the warning will not be printed and the test passes.  If the message
+    does not occur, then the test will fail.  Similar to
+    \c{QTest::ignoreMessage(QtWarningMsg, message)} in C++.
+
+    \sa warn()
+*/
+
+/*!
+    \qmlmethod TestCase::wait(ms)
+
+    Waits for \a ms milliseconds while processing Qt events.
+
+    \sa sleep()
+*/
+
+/*!
+    \qmlmethod TestCase::sleep(ms)
+
+    Sleeps for \a ms milliseconds without processing Qt events.
+
+    \sa wait()
+*/
+
+/*!
+    \qmlmethod TestCase::keyClick(key, modifiers = Qt.NoModifier, delay = -1)
+
+    Simulates clicking of \a key with an optional \a modifier on the currently
+    focused item.  If \a delay is larger than 0, the test will wait for
+    \a delay milliseconds.
+
+    \sa keyPress(), keyRelease()
+*/
+
+/*!
+    \qmlmethod TestCase::keyPress(key, modifiers = Qt.NoModifier, delay = -1)
+
+    Simulates pressing a \a key with an optional \a modifier on the currently
+    focused item.  If \a delay is larger than 0, the test will wait for
+    \a delay milliseconds.
+
+    \bold{Note:} At some point you should release the key using keyRelease().
+
+    \sa keyRelease(), keyClick()
+*/
+
+/*!
+    \qmlmethod TestCase::keyRelease(key, modifiers = Qt.NoModifier, delay = -1)
+
+    Simulates releasing a \a key with an optional \a modifier on the currently
+    focused item.  If \a delay is larger than 0, the test will wait for
+    \a delay milliseconds.
+
+    \sa keyPress(), keyClick()
+*/
+
+/*!
+    \qmlmethod TestCase::mousePress(item, x, y, button = Qt.LeftButton, modifiers = Qt.NoModifier, delay = -1)
+
+    Simulates pressing a mouse \a button with an optional \a modifier
+    on an \a item.  The position is defined by \a x and \a y.  If \a delay is
+    specified, the test will wait for the specified amount of milliseconds
+    before the press.
+
+    The position given by \a x and \a y is transformed from the co-ordinate
+    system of \a item into window co-ordinates and then delivered.
+    If \a item is obscured by another item, or a child of \a item occupies
+    that position, then the event will be delivered to the other item instead.
+
+    \sa mouseRelease(), mouseClick(), mouseDoubleClick(), mouseMove()
+*/
+
+/*!
+    \qmlmethod TestCase::mouseRelease(item, x, y, button = Qt.LeftButton, modifiers = Qt.NoModifier, delay = -1)
+
+    Simulates releasing a mouse \a button with an optional \a modifier
+    on an \a item.  The position of the release is defined by \a x and \a y.
+    If \a delay is specified, the test will wait for the specified amount of
+    milliseconds before releasing the button.
+
+    The position given by \a x and \a y is transformed from the co-ordinate
+    system of \a item into window co-ordinates and then delivered.
+    If \a item is obscured by another item, or a child of \a item occupies
+    that position, then the event will be delivered to the other item instead.
+
+    \sa mousePress(), mouseClick(), mouseDoubleClick(), mouseMove()
+*/
+
+/*!
+    \qmlmethod TestCase::mouseClick(item, x, y, button = Qt.LeftButton, modifiers = Qt.NoModifier, delay = -1)
+
+    Simulates clicking a mouse \a button with an optional \a modifier
+    on an \a item.  The position of the click is defined by \a x and \a y.
+    If \a delay is specified, the test will wait for the specified amount of
+    milliseconds before pressing and before releasing the button.
+
+    The position given by \a x and \a y is transformed from the co-ordinate
+    system of \a item into window co-ordinates and then delivered.
+    If \a item is obscured by another item, or a child of \a item occupies
+    that position, then the event will be delivered to the other item instead.
+
+    \sa mousePress(), mouseRelease(), mouseDoubleClick(), mouseMove()
+*/
+
+/*!
+    \qmlmethod TestCase::mouseDoubleClick(item, x, y, button = Qt.LeftButton, modifiers = Qt.NoModifier, delay = -1)
+
+    Simulates double-clicking a mouse \a button with an optional \a modifier
+    on an \a item.  The position of the click is defined by \a x and \a y.
+    If \a delay is specified, the test will wait for the specified amount of
+    milliseconds before pressing and before releasing the button.
+
+    The position given by \a x and \a y is transformed from the co-ordinate
+    system of \a item into window co-ordinates and then delivered.
+    If \a item is obscured by another item, or a child of \a item occupies
+    that position, then the event will be delivered to the other item instead.
+
+    \sa mousePress(), mouseRelease(), mouseClick(), mouseMove()
+*/
+
+/*!
+    \qmlmethod TestCase::mouseMove(item, x, y, delay = -1)
+
+    Moves the mouse pointer to the position given by \a x and \a y within
+    \a item.  If a \a delay (in milliseconds) is given, the test will wait
+    before moving the mouse pointer.
+
+    The position given by \a x and \a y is transformed from the co-ordinate
+    system of \a item into window co-ordinates and then delivered.
+    If \a item is obscured by another item, or a child of \a item occupies
+    that position, then the event will be delivered to the other item instead.
+
+    \sa mousePress(), mouseRelease(), mouseClick(), mouseDoubleClick()
+*/
+
+/*!
+    \qmlmethod TestCase::initTestCase()
+
+    This function is called before any other test functions in the
+    \l TestCase element.  The default implementation does nothing.
+    The application can provide its own implementation to perform
+    test case initialization.
+
+    \sa cleanupTestCase(), init()
+*/
+
+/*!
+    \qmlmethod TestCase::cleanupTestCase()
+
+    This function is called after all other test functions in the
+    \l TestCase element have completed.  The default implementation
+    does nothing.  The application can provide its own implementation
+    to perform test case cleanup.
+
+    \sa initTestCase(), cleanup()
+*/
+
+/*!
+    \qmlmethod TestCase::init()
+
+    This function is called before each test function that is
+    executed in the \l TestCase element.  The default implementation
+    does nothing.  The application can provide its own implementation
+    to perform initialization before each test function.
+
+    \sa cleanup(), initTestCase()
+*/
+
+/*!
+    \qmlmethod TestCase::cleanup()
+
+    This function is called after each test function that is
+    executed in the \l TestCase element.  The default implementation
+    does nothing.  The application can provide its own implementation
+    to perform cleanup after each test function.
+
+    \sa init(), cleanupTestCase()
+*/
diff --git a/src/imports/testlib/testlib.pro b/src/imports/testlib/testlib.pro
new file mode 100644 (file)
index 0000000..cc29d53
--- /dev/null
@@ -0,0 +1,29 @@
+TARGET  = qmltestplugin
+TARGETPATH = QtTest
+include(../qimportbase.pri)
+
+CONFIG += qt plugin
+
+symbian {
+    CONFIG += epocallowdlldata
+    contains(QT_EDITION, OpenSource) {
+        TARGET.CAPABILITY = LocalServices NetworkServices ReadUserData UserEnvironment WriteUserData
+    } else {
+        TARGET.CAPABILITY = All -Tcb
+    }
+}
+
+QT += declarative script qmltest qmltest-private
+
+SOURCES += main.cpp
+HEADERS +=
+
+qdeclarativesources.files += \
+    qmldir \
+    TestCase.qml \
+    SignalSpy.qml \
+    testlogger.js
+
+qdeclarativesources.path += $$[QT_INSTALL_IMPORTS]/QtTest
+target.path += $$[QT_INSTALL_IMPORTS]/QtTest
+INSTALLS += qdeclarativesources target
diff --git a/src/imports/testlib/testlogger.js b/src/imports/testlib/testlogger.js
new file mode 100644 (file)
index 0000000..7fd33ca
--- /dev/null
@@ -0,0 +1,98 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 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$
+**
+****************************************************************************/
+
+.pragma library
+
+// We need a global place to store the results that can be
+// shared between multiple TestCase instances.  Because QML
+// creates a separate scope for every inclusion of this file,
+// we hijack the global "Qt" object to store our data.
+function log_init_results()
+{
+    if (!Qt.testResults) {
+        Qt.testResults = {
+            reportedStart: false,
+            nextId: 0,
+            testCases: []
+        }
+    }
+}
+
+function log_register_test(name)
+{
+    log_init_results()
+    var testId = Qt.testResults.nextId++
+    Qt.testResults.testCases.push(testId)
+    return testId
+}
+
+function log_optional_test(testId)
+{
+    log_init_results()
+    var index = Qt.testResults.testCases.indexOf(testId)
+    if (index >= 0)
+        Qt.testResults.testCases.splice(index, 1)
+}
+
+function log_mandatory_test(testId)
+{
+    log_init_results()
+    var index = Qt.testResults.testCases.indexOf(testId)
+    if (index == -1)
+        Qt.testResults.testCases.push(testId)
+}
+
+function log_start_test()
+{
+    log_init_results()
+    if (Qt.testResults.reportedStart)
+        return false
+    Qt.testResults.reportedStart = true
+    return true
+}
+
+function log_complete_test(testId)
+{
+    var index = Qt.testResults.testCases.indexOf(testId)
+    if (index >= 0)
+        Qt.testResults.testCases.splice(index, 1)
+    return Qt.testResults.testCases.length > 0
+}
diff --git a/src/qmltest/features/qmltestcase.prf b/src/qmltest/features/qmltestcase.prf
new file mode 100644 (file)
index 0000000..a3d66e6
--- /dev/null
@@ -0,0 +1,25 @@
+CONFIG += testcase
+
+!symbian {
+    INCLUDEPATH += $$[QT_INSTALL_HEADERS]/QtQuickTest
+} else {
+    load(data_caging_paths)
+
+    INCLUDEPATH+=$$MW_LAYER_PUBLIC_EXPORT_PATH(QtQuickTest)
+}
+
+QT += declarative
+
+win32:CONFIG(debug, debug|release) {
+    LIBS += -lQtQuickTest$${QT_LIBINFIX}d
+} else {
+    LIBS += -lQtQuickTest$${QT_LIBINFIX}
+}
+
+# If the .pro file specified an IMPORTPATH, then add that to
+# the command-line when the test is run.
+!isEmpty(IMPORTPATH) {
+    load(testcase)
+    for(import, IMPORTPATH): check.commands += -import \"$$import\"
+}
+DEFINES += QUICK_TEST_SOURCE_DIR=\"\\\"$$OUT_PWD\\\"\"
diff --git a/src/qmltest/qmltest.pro b/src/qmltest/qmltest.pro
new file mode 100644 (file)
index 0000000..de0dbe2
--- /dev/null
@@ -0,0 +1,48 @@
+load(qt_module)
+
+TARGET     = QtQuickTest
+QPRO_PWD   = $$PWD
+
+CONFIG += module
+CONFIG += dll warn_on
+MODULE_PRI += ../../modules/qt_qmltest.pri
+
+QT = testlib-private declarative script testlib
+DEFINES   += QT_BUILD_DECLARATIVE_LIB QT_NO_URL_CAST_FROM_STRING
+
+
+include($$QT_SOURCE_TREE/src/qbase.pri)
+
+# Install qmltestcase.prf into the Qt mkspecs so that "CONFIG += qmltestcase"
+# can be used in customer applications to build against QtQuickTest.
+feature.path = $$[QT_INSTALL_DATA]/mkspecs/features
+feature.files = $$PWD/features/qmltestcase.prf
+INSTALLS += feature
+
+symbian {
+    DEFINES += QT_MAKEDLL
+    CONFIG += epocallowdlldata
+    contains(QT_EDITION, OpenSource) {
+        TARGET.CAPABILITY = LocalServices NetworkServices ReadUserData UserEnvironment WriteUserData
+    } else {
+        TARGET.CAPABILITY = All -Tcb
+    }
+}
+
+INCLUDEPATH += $$PWD/QtQuickTest
+INCLUDEPATH += $$PWD
+
+SOURCES += \
+    $$PWD/quicktest.cpp \
+    $$PWD/quicktestevent.cpp \
+    $$PWD/quicktestresult.cpp
+HEADERS += \
+    $$PWD/quicktestglobal.h \
+    $$PWD/quicktest.h \
+    $$PWD/quicktestevent_p.h \
+    $$PWD/quicktestresult_p.h \
+    $$PWD/qtestoptions_p.h
+
+
+DEFINES += QT_BUILD_QUICK_TEST_LIB
+
diff --git a/src/qmltest/qtestoptions_p.h b/src/qmltest/qtestoptions_p.h
new file mode 100644 (file)
index 0000000..167f906
--- /dev/null
@@ -0,0 +1,67 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtTest module 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$
+**
+****************************************************************************/
+
+#ifndef QTESTOPTIONS_P_H
+#define QTESTOPTIONS_P_H
+
+#include <QtTest/qtest_global.h>
+
+#include <QtCore/qstring.h>
+#include <QtCore/qstringlist.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Test)
+
+namespace QTest
+{
+    extern Q_TESTLIB_EXPORT bool printAvailableFunctions;
+    extern Q_TESTLIB_EXPORT QStringList testFunctions;
+    extern Q_TESTLIB_EXPORT QStringList testTags;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/qmltest/quicktest.cpp b/src/qmltest/quicktest.cpp
new file mode 100644 (file)
index 0000000..19e15f2
--- /dev/null
@@ -0,0 +1,315 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 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 "quicktest.h"
+#include "quicktestresult_p.h"
+#include <QtTest/qtestsystem.h>
+#include "qtestoptions_p.h"
+#include <QApplication>
+#include <QtDeclarative/qdeclarative.h>
+#include <QtDeclarative/qdeclarativeview.h>
+#include <QtDeclarative/qdeclarativeengine.h>
+#include <QtDeclarative/qdeclarativecontext.h>
+#if defined(QML_VERSION) && QML_VERSION >= 0x020000
+#include <QtDeclarative/qsgview.h>
+#define QUICK_TEST_SCENEGRAPH 1
+#endif
+#include <QtScript/qscriptvalue.h>
+#include <QtScript/qscriptcontext.h>
+#include <QtScript/qscriptengine.h>
+#include <QtOpenGL/qgl.h>
+#include <QtCore/qurl.h>
+#include <QtCore/qfileinfo.h>
+#include <QtCore/qdir.h>
+#include <QtCore/qdiriterator.h>
+#include <QtCore/qfile.h>
+#include <QtCore/qdebug.h>
+#include <QtCore/qeventloop.h>
+#include <QtGui/qtextdocument.h>
+#include <stdio.h>
+
+QT_BEGIN_NAMESPACE
+
+// Copied from qdeclarativedebughelper_p.h in Qt, to avoid a dependency
+// on a private header from Qt.
+class Q_DECLARATIVE_EXPORT QDeclarativeDebugHelper
+{
+public:
+    static QScriptEngine *getScriptEngine(QDeclarativeEngine *engine);
+    static void setAnimationSlowDownFactor(qreal factor);
+    static void enableDebugging();
+};
+
+class QTestRootObject : public QObject
+{
+    Q_OBJECT
+    Q_PROPERTY(bool windowShown READ windowShown NOTIFY windowShownChanged)
+public:
+    QTestRootObject(QObject *parent = 0)
+        : QObject(parent), hasQuit(false), m_windowShown(false) {}
+
+    bool hasQuit;
+
+    bool windowShown() const { return m_windowShown; }
+    void setWindowShown(bool value) { m_windowShown = value; emit windowShownChanged(); }
+
+Q_SIGNALS:
+    void windowShownChanged();
+
+private Q_SLOTS:
+    void quit() { hasQuit = true; }
+
+private:
+    bool m_windowShown;
+};
+
+static inline QString stripQuotes(const QString &s)
+{
+    if (s.length() >= 2 && s.startsWith(QLatin1Char('"')) && s.endsWith(QLatin1Char('"')))
+        return s.mid(1, s.length() - 2);
+    else
+        return s;
+}
+
+int quick_test_main(int argc, char **argv, const char *name, quick_test_viewport_create createViewport, const char *sourceDir)
+{
+    QApplication app(argc, argv);
+
+    // Look for QML-specific command-line options.
+    //      -import dir         Specify an import directory.
+    //      -input dir          Specify the input directory for test cases.
+    //      -qtquick1           Run with QtQuick 1 rather than QtQuick 2.
+    QStringList imports;
+    QString testPath;
+    bool qtQuick2 = true;
+    int outargc = 1;
+    int index = 1;
+    while (index < argc) {
+        if (strcmp(argv[index], "-import") == 0 && (index + 1) < argc) {
+            imports += stripQuotes(QString::fromLocal8Bit(argv[index + 1]));
+            index += 2;
+        } else if (strcmp(argv[index], "-input") == 0 && (index + 1) < argc) {
+            testPath = stripQuotes(QString::fromLocal8Bit(argv[index + 1]));
+            index += 2;
+        } else if (strcmp(argv[index], "-opengl") == 0) {
+            ++index;
+        } else if (strcmp(argv[index], "-qtquick1") == 0) {
+            qtQuick2 = false;
+            ++index;
+        } else if (outargc != index) {
+            argv[outargc++] = argv[index++];
+        } else {
+            ++outargc;
+            ++index;
+        }
+    }
+    argv[outargc] = 0;
+    argc = outargc;
+
+    // Determine where to look for the test data.
+    if (testPath.isEmpty() && sourceDir)
+        testPath = QString::fromLocal8Bit(sourceDir);
+    if (testPath.isEmpty())
+        testPath = QLatin1String(".");
+
+    // Scan the test data directory recursively, looking for "tst_*.qml" files.
+    QStringList filters;
+    filters += QLatin1String("tst_*.qml");
+    QStringList files;
+    QDirIterator iter(testPath, filters, QDir::Files,
+                      QDirIterator::Subdirectories |
+                      QDirIterator::FollowSymlinks);
+    while (iter.hasNext())
+        files += iter.next();
+    files.sort();
+
+    // Bail out if we didn't find any test cases.
+    if (files.isEmpty()) {
+        qWarning() << argv[0] << ": could not find any test cases under"
+                   << testPath;
+        return 1;
+    }
+
+    // Parse the command-line arguments.
+    QuickTestResult::parseArgs(argc, argv);
+    QuickTestResult::setProgramName(name);
+
+    // Scan through all of the "tst_*.qml" files and run each of them
+    // in turn with a QDeclarativeView.
+#ifdef QUICK_TEST_SCENEGRAPH
+    if (qtQuick2) {
+        foreach (QString file, files) {
+            QFileInfo fi(file);
+            if (!fi.exists())
+                continue;
+            QSGView view;
+            QTestRootObject rootobj;
+            QEventLoop eventLoop;
+            QObject::connect(view.engine(), SIGNAL(quit()),
+                             &rootobj, SLOT(quit()));
+            QObject::connect(view.engine(), SIGNAL(quit()),
+                             &eventLoop, SLOT(quit()));
+            view.rootContext()->setContextProperty
+                (QLatin1String("qtest"), &rootobj);
+            QScriptEngine *engine;
+            engine = QDeclarativeDebugHelper::getScriptEngine(view.engine());
+            QScriptValue qtObject
+                = engine->globalObject().property(QLatin1String("Qt"));
+            qtObject.setProperty
+                (QLatin1String("qtest_wrapper"), QScriptValue(true));
+            qtObject.setProperty
+                (QLatin1String("qtest_printAvailableFunctions"),
+                 QScriptValue(QTest::printAvailableFunctions));
+            foreach (QString path, imports)
+                view.engine()->addImportPath(path);
+            QString path = fi.absoluteFilePath();
+            if (path.startsWith(QLatin1String(":/")))
+                view.setSource(QUrl(QLatin1String("qrc:") + path.mid(2)));
+            else
+                view.setSource(QUrl::fromLocalFile(path));
+            if (QTest::printAvailableFunctions)
+                continue;
+            if (view.status() == QSGView::Error) {
+                // Error compiling the test - flag failure in the log and continue.
+                QList<QDeclarativeError> errors = view.errors();
+                QuickTestResult results;
+                results.setTestCaseName(fi.baseName());
+                results.startLogging();
+                results.setFunctionName(QLatin1String("compile"));
+                results.setFunctionType(QuickTestResult::Func);
+                results.fail(errors.at(0).description(),
+                             errors.at(0).url().toString(),
+                             errors.at(0).line());
+                results.finishTestFunction();
+                results.setFunctionName(QString());
+                results.setFunctionType(QuickTestResult::NoWhere);
+                results.stopLogging();
+                continue;
+            }
+            if (!rootobj.hasQuit) {
+                // If the test already quit, then it was performed
+                // synchronously during setSource().  Otherwise it is
+                // an asynchronous test and we need to show the window
+                // and wait for the quit indication.
+                view.show();
+                QTest::qWaitForWindowShown(&view);
+                rootobj.setWindowShown(true);
+                if (!rootobj.hasQuit)
+                    eventLoop.exec();
+            }
+        }
+    } else
+#endif
+    {
+        foreach (QString file, files) {
+            QFileInfo fi(file);
+            if (!fi.exists())
+                continue;
+            QDeclarativeView view;
+            QTestRootObject rootobj;
+            QEventLoop eventLoop;
+            QObject::connect(view.engine(), SIGNAL(quit()),
+                             &rootobj, SLOT(quit()));
+            QObject::connect(view.engine(), SIGNAL(quit()),
+                             &eventLoop, SLOT(quit()));
+            if (createViewport)
+                view.setViewport((*createViewport)());
+            view.rootContext()->setContextProperty
+                (QLatin1String("qtest"), &rootobj);
+            QScriptEngine *engine;
+            engine = QDeclarativeDebugHelper::getScriptEngine(view.engine());
+            QScriptValue qtObject
+                = engine->globalObject().property(QLatin1String("Qt"));
+            qtObject.setProperty
+                (QLatin1String("qtest_wrapper"), QScriptValue(true));
+            qtObject.setProperty
+                (QLatin1String("qtest_printAvailableFunctions"),
+                 QScriptValue(QTest::printAvailableFunctions));
+            foreach (QString path, imports)
+                view.engine()->addImportPath(path);
+            QString path = fi.absoluteFilePath();
+            if (path.startsWith(QLatin1String(":/")))
+                view.setSource(QUrl(QLatin1String("qrc:") + path.mid(2)));
+            else
+                view.setSource(QUrl::fromLocalFile(path));
+            if (QTest::printAvailableFunctions)
+                continue;
+            if (view.status() == QDeclarativeView::Error) {
+                // Error compiling the test - flag failure in the log and continue.
+                QList<QDeclarativeError> errors = view.errors();
+                QuickTestResult results;
+                results.setTestCaseName(fi.baseName());
+                results.startLogging();
+                results.setFunctionName(QLatin1String("compile"));
+                results.setFunctionType(QuickTestResult::Func);
+                results.fail(errors.at(0).description(),
+                             errors.at(0).url().toString(),
+                             errors.at(0).line());
+                results.finishTestFunction();
+                results.setFunctionName(QString());
+                results.setFunctionType(QuickTestResult::NoWhere);
+                results.stopLogging();
+                continue;
+            }
+            if (!rootobj.hasQuit) {
+                // If the test already quit, then it was performed
+                // synchronously during setSource().  Otherwise it is
+                // an asynchronous test and we need to show the window
+                // and wait for the quit indication.
+                view.show();
+                QTest::qWaitForWindowShown(&view);
+                rootobj.setWindowShown(true);
+                if (!rootobj.hasQuit)
+                    eventLoop.exec();
+            }
+        }
+    }
+
+    // Flush the current logging stream.
+    QuickTestResult::setProgramName(0);
+
+    // Return the number of failures as the exit code.
+    return QuickTestResult::exitCode();
+}
+
+QT_END_NAMESPACE
+
+#include "quicktest.moc"
diff --git a/src/qmltest/quicktest.h b/src/qmltest/quicktest.h
new file mode 100644 (file)
index 0000000..60c25ec
--- /dev/null
@@ -0,0 +1,97 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 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$
+**
+****************************************************************************/
+
+#ifndef QUICKTEST_H
+#define QUICKTEST_H
+
+#include <QtQuickTest/quicktestglobal.h>
+#include <QtGui/qwidget.h>
+#ifdef QT_OPENGL_LIB
+#include <QtOpenGL/qgl.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+typedef QWidget *(*quick_test_viewport_create)();
+
+Q_QUICK_TEST_EXPORT int quick_test_main(int argc, char **argv, const char *name, quick_test_viewport_create createViewport, const char *sourceDir);
+
+#ifdef QUICK_TEST_SOURCE_DIR
+
+#define QUICK_TEST_MAIN(name) \
+    int main(int argc, char **argv) \
+    { \
+        return quick_test_main(argc, argv, #name, 0, QUICK_TEST_SOURCE_DIR); \
+    }
+
+#define QUICK_TEST_OPENGL_MAIN(name) \
+    static QWidget *name##_create_viewport() \
+    { \
+        return new QGLWidget(); \
+    } \
+    int main(int argc, char **argv) \
+    { \
+        return quick_test_main(argc, argv, #name, name##_create_viewport, QUICK_TEST_SOURCE_DIR); \
+    }
+
+#else
+
+#define QUICK_TEST_MAIN(name) \
+    int main(int argc, char **argv) \
+    { \
+        return quick_test_main(argc, argv, #name, 0, 0); \
+    }
+
+#define QUICK_TEST_OPENGL_MAIN(name) \
+    static QWidget *name##_create_viewport() \
+    { \
+        return new QGLWidget(); \
+    } \
+    int main(int argc, char **argv) \
+    { \
+        return quick_test_main(argc, argv, #name, name##_create_viewport, 0); \
+    }
+
+#endif
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/qmltest/quicktestevent.cpp b/src/qmltest/quicktestevent.cpp
new file mode 100644 (file)
index 0000000..894e29e
--- /dev/null
@@ -0,0 +1,258 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 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 "quicktestevent_p.h"
+#include <QtTest/qtestkeyboard.h>
+#include <QtDeclarative/qdeclarative.h>
+#include <QtDeclarative/qdeclarativeitem.h>
+#include <QtDeclarative/qdeclarativeview.h>
+#if defined(QML_VERSION) && QML_VERSION >= 0x020000
+#include <QtDeclarative/qsgitem.h>
+#include <QtDeclarative/qsgcanvas.h>
+#define QUICK_TEST_SCENEGRAPH 1
+#endif
+#include <QtGui/qgraphicsscene.h>
+
+QT_BEGIN_NAMESPACE
+
+QuickTestEvent::QuickTestEvent(QObject *parent)
+    : QObject(parent)
+{
+}
+
+QuickTestEvent::~QuickTestEvent()
+{
+}
+
+bool QuickTestEvent::keyPress(int key, int modifiers, int delay)
+{
+    QWidget *widget = eventWidget();
+    if (!widget)
+        return false;
+    QTest::keyPress(widget, Qt::Key(key), Qt::KeyboardModifiers(modifiers), delay);
+    return true;
+}
+
+bool QuickTestEvent::keyRelease(int key, int modifiers, int delay)
+{
+    QWidget *widget = eventWidget();
+    if (!widget)
+        return false;
+    QTest::keyRelease(widget, Qt::Key(key), Qt::KeyboardModifiers(modifiers), delay);
+    return true;
+}
+
+bool QuickTestEvent::keyClick(int key, int modifiers, int delay)
+{
+    QWidget *widget = eventWidget();
+    if (!widget)
+        return false;
+    QTest::keyClick(widget, Qt::Key(key), Qt::KeyboardModifiers(modifiers), delay);
+    return true;
+}
+
+namespace QTest {
+    extern int Q_TESTLIB_EXPORT defaultMouseDelay();
+};
+
+namespace QtQuickTest
+{
+    enum MouseAction { MousePress, MouseRelease, MouseClick, MouseDoubleClick, MouseMove };
+
+    static void mouseEvent(MouseAction action, QWidget *widget,
+                           QObject *item, Qt::MouseButton button,
+                           Qt::KeyboardModifiers stateKey, QPointF _pos, int delay=-1)
+    {
+        QTEST_ASSERT(widget);
+        QTEST_ASSERT(item);
+
+        if (delay == -1 || delay < QTest::defaultMouseDelay())
+            delay = QTest::defaultMouseDelay();
+        if (delay > 0)
+            QTest::qWait(delay);
+
+        if (action == MouseClick) {
+            mouseEvent(MousePress, widget, item, button, stateKey, _pos);
+            mouseEvent(MouseRelease, widget, item, button, stateKey, _pos);
+            return;
+        }
+
+        QPoint pos;
+        QDeclarativeView *view = qobject_cast<QDeclarativeView *>(widget);
+        QWidget *eventWidget = widget;
+#ifdef QUICK_TEST_SCENEGRAPH
+        QSGItem *sgitem = qobject_cast<QSGItem *>(item);
+        if (sgitem) {
+            pos = sgitem->mapToScene(_pos).toPoint();
+        } else
+#endif
+        {
+            QDeclarativeItem *ditem = qobject_cast<QDeclarativeItem *>(item);
+            if (!ditem) {
+                qWarning("Mouse event target is not an Item");
+                return;
+            }
+            pos = view->mapFromScene(ditem->mapToScene(_pos));
+            eventWidget = view->viewport();
+        }
+
+        QTEST_ASSERT(button == Qt::NoButton || button & Qt::MouseButtonMask);
+        QTEST_ASSERT(stateKey == 0 || stateKey & Qt::KeyboardModifierMask);
+
+        stateKey &= static_cast<unsigned int>(Qt::KeyboardModifierMask);
+
+        QMouseEvent me(QEvent::User, QPoint(), Qt::LeftButton, button, stateKey);
+        switch (action)
+        {
+            case MousePress:
+                me = QMouseEvent(QEvent::MouseButtonPress, pos, widget->mapToGlobal(pos), button, button, stateKey);
+                break;
+            case MouseRelease:
+                me = QMouseEvent(QEvent::MouseButtonRelease, pos, widget->mapToGlobal(pos), button, 0, stateKey);
+                break;
+            case MouseDoubleClick:
+                me = QMouseEvent(QEvent::MouseButtonDblClick, pos, widget->mapToGlobal(pos), button, button, stateKey);
+                break;
+            case MouseMove:
+                QCursor::setPos(widget->mapToGlobal(pos));
+                qApp->processEvents();
+                return;
+            default:
+                QTEST_ASSERT(false);
+        }
+        QSpontaneKeyEvent::setSpontaneous(&me);
+        if (!qApp->notify(eventWidget, &me)) {
+            static const char *mouseActionNames[] =
+                { "MousePress", "MouseRelease", "MouseClick", "MouseDoubleClick", "MouseMove" };
+            QString warning = QString::fromLatin1("Mouse event \"%1\" not accepted by receiving widget");
+            QTest::qWarn(warning.arg(QString::fromLatin1(mouseActionNames[static_cast<int>(action)])).toAscii().data());
+        }
+    }
+};
+
+bool QuickTestEvent::mousePress
+    (QObject *item, qreal x, qreal y, int button,
+     int modifiers, int delay)
+{
+    QWidget *view = eventWidget();
+    if (!view)
+        return false;
+    QtQuickTest::mouseEvent(QtQuickTest::MousePress, view, item,
+                            Qt::MouseButton(button),
+                            Qt::KeyboardModifiers(modifiers),
+                            QPointF(x, y), delay);
+    return true;
+}
+
+bool QuickTestEvent::mouseRelease
+    (QObject *item, qreal x, qreal y, int button,
+     int modifiers, int delay)
+{
+    QWidget *view = eventWidget();
+    if (!view)
+        return false;
+    QtQuickTest::mouseEvent(QtQuickTest::MouseRelease, view, item,
+                            Qt::MouseButton(button),
+                            Qt::KeyboardModifiers(modifiers),
+                            QPointF(x, y), delay);
+    return true;
+}
+
+bool QuickTestEvent::mouseClick
+    (QObject *item, qreal x, qreal y, int button,
+     int modifiers, int delay)
+{
+    QWidget *view = eventWidget();
+    if (!view)
+        return false;
+    QtQuickTest::mouseEvent(QtQuickTest::MouseClick, view, item,
+                            Qt::MouseButton(button),
+                            Qt::KeyboardModifiers(modifiers),
+                            QPointF(x, y), delay);
+    return true;
+}
+
+bool QuickTestEvent::mouseDoubleClick
+    (QObject *item, qreal x, qreal y, int button,
+     int modifiers, int delay)
+{
+    QWidget *view = eventWidget();
+    if (!view)
+        return false;
+    QtQuickTest::mouseEvent(QtQuickTest::MouseDoubleClick, view, item,
+                            Qt::MouseButton(button),
+                            Qt::KeyboardModifiers(modifiers),
+                            QPointF(x, y), delay);
+    return true;
+}
+
+bool QuickTestEvent::mouseMove
+    (QObject *item, qreal x, qreal y, int delay)
+{
+    QWidget *view = eventWidget();
+    if (!view)
+        return false;
+    QtQuickTest::mouseEvent(QtQuickTest::MouseMove, view, item,
+                            Qt::NoButton, Qt::NoModifier,
+                            QPointF(x, y), delay);
+    return true;
+}
+
+QWidget *QuickTestEvent::eventWidget()
+{
+#ifdef QUICK_TEST_SCENEGRAPH
+    QSGItem *sgitem = qobject_cast<QSGItem *>(parent());
+    if (sgitem)
+        return sgitem->canvas();
+#endif
+    QDeclarativeItem *item = qobject_cast<QDeclarativeItem *>(parent());
+    if (!item)
+        return 0;
+    QGraphicsScene *s = item->scene();
+    if (!s)
+        return 0;
+    QList<QGraphicsView *> views = s->views();
+    if (views.isEmpty())
+        return 0;
+    return views.at(0);
+}
+
+QT_END_NAMESPACE
diff --git a/src/qmltest/quicktestevent_p.h b/src/qmltest/quicktestevent_p.h
new file mode 100644 (file)
index 0000000..1f5926f
--- /dev/null
@@ -0,0 +1,78 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 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$
+**
+****************************************************************************/
+
+#ifndef QUICKTESTEVENT_P_H
+#define QUICKTESTEVENT_P_H
+
+#include <QtQuickTest/quicktestglobal.h>
+#include <QtCore/qobject.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_QUICK_TEST_EXPORT QuickTestEvent : public QObject
+{
+    Q_OBJECT
+public:
+    QuickTestEvent(QObject *parent = 0);
+    ~QuickTestEvent();
+
+public Q_SLOTS:
+    bool keyPress(int key, int modifiers, int delay);
+    bool keyRelease(int key, int modifiers, int delay);
+    bool keyClick(int key, int modifiers, int delay);
+
+    bool mousePress(QObject *item, qreal x, qreal y, int button,
+                    int modifiers, int delay);
+    bool mouseRelease(QObject *item, qreal x, qreal y, int button,
+                      int modifiers, int delay);
+    bool mouseClick(QObject *item, qreal x, qreal y, int button,
+                    int modifiers, int delay);
+    bool mouseDoubleClick(QObject *item, qreal x, qreal y, int button,
+                          int modifiers, int delay);
+    bool mouseMove(QObject *item, qreal x, qreal y, int delay);
+
+private:
+    QWidget *eventWidget();
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/qmltest/quicktestglobal.h b/src/qmltest/quicktestglobal.h
new file mode 100644 (file)
index 0000000..0c71b5c
--- /dev/null
@@ -0,0 +1,73 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 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$
+**
+****************************************************************************/
+
+#ifndef TESTQUICKGLOBAL_H
+#define TESTQUICKGLOBAL_H
+
+#include <QtCore/qglobal.h>
+
+QT_LICENSED_MODULE(QtQuickTest)
+#if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN)
+#  if defined(QT_NODLL)
+#    undef QT_MAKEDLL
+#    undef QT_DLL
+#  elif defined(QT_MAKEDLL)        /* create a Qt DLL library */
+#    if defined(QT_DLL)
+#      undef QT_DLL
+#    endif
+#    if defined(QT_BUILD_QUICK_TEST_LIB)
+#        define Q_QUICK_TEST_EXPORT Q_DECL_EXPORT
+#    else
+#        define Q_QUICK_TEST_EXPORT Q_DECL_IMPORT
+#    endif
+#  elif defined(QT_DLL) /* use a Qt DLL library */
+#    define Q_QUICK_TEST_EXPORT Q_DECL_IMPORT
+#  endif
+#endif
+#if !defined(Q_QUICK_TEST_EXPORT)
+#   if defined(QT_SHARED)
+#       define Q_QUICK_TEST_EXPORT Q_DECL_EXPORT
+#   else
+#       define Q_QUICK_TEST_EXPORT
+#   endif
+#endif
+
+#endif
diff --git a/src/qmltest/quicktestresult.cpp b/src/qmltest/quicktestresult.cpp
new file mode 100644 (file)
index 0000000..59fea96
--- /dev/null
@@ -0,0 +1,630 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 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 "quicktestresult_p.h"
+#include <QtTest/qtestcase.h>
+#include <QtTest/qtestsystem.h>
+#include <QtTest/private/qtestresult_p.h>
+#include <QtTest/private/qtesttable_p.h>
+#include <QtTest/private/qtestlog_p.h>
+#include "qtestoptions_p.h"
+#include <QtTest/qbenchmark.h>
+#include <QtTest/private/qbenchmark_p.h>
+#include <QtCore/qset.h>
+#include <QtCore/qmap.h>
+#include <QtCore/qbytearray.h>
+#include <QtCore/qcoreapplication.h>
+#include <QtCore/qdebug.h>
+
+QT_BEGIN_NAMESPACE
+
+static const char *globalProgramName = 0;
+static bool loggingStarted = false;
+static QBenchmarkGlobalData globalBenchmarkData;
+
+class QuickTestResultPrivate
+{
+public:
+    QuickTestResultPrivate()
+        : table(0)
+        , benchmarkIter(0)
+        , benchmarkData(0)
+        , iterCount(0)
+    {
+    }
+    ~QuickTestResultPrivate()
+    {
+        delete table;
+        delete benchmarkIter;
+        delete benchmarkData;
+    }
+
+    QByteArray intern(const QString &str);
+    void updateTestObjectName();
+
+    QString testCaseName;
+    QString functionName;
+    QSet<QByteArray> internedStrings;
+    QTestTable *table;
+    QTest::QBenchmarkIterationController *benchmarkIter;
+    QBenchmarkTestMethodData *benchmarkData;
+    int iterCount;
+    QList<QBenchmarkResult> results;
+};
+
+QByteArray QuickTestResultPrivate::intern(const QString &str)
+{
+    QByteArray bstr = str.toUtf8();
+    return *(internedStrings.insert(bstr));
+}
+
+void QuickTestResultPrivate::updateTestObjectName()
+{
+    // In plain logging mode we use the TestCase name as the
+    // class name so that multiple TestCase elements will report
+    // results with "testCase::function".  In XML logging mode,
+    // we use the program name as the class name and report test
+    // functions as "testCase__function".
+    if (QTestLog::logMode() == QTestLog::Plain) {
+        if (testCaseName.isEmpty()) {
+            QTestResult::setCurrentTestObject(globalProgramName);
+        } else if (QTestLog::logMode() == QTestLog::Plain) {
+            QTestResult::setCurrentTestObject
+                (intern(testCaseName).constData());
+        }
+    } else {
+        QTestResult::setCurrentTestObject(globalProgramName);
+    }
+}
+
+QuickTestResult::QuickTestResult(QObject *parent)
+    : QObject(parent), d_ptr(new QuickTestResultPrivate)
+{
+    if (!QBenchmarkGlobalData::current)
+        QBenchmarkGlobalData::current = &globalBenchmarkData;
+}
+
+QuickTestResult::~QuickTestResult()
+{
+}
+
+/*!
+    \qmlproperty string TestResult::testCaseName
+
+    This property defines the name of current TestCase element
+    that is running test cases.
+
+    \sa functionName
+*/
+QString QuickTestResult::testCaseName() const
+{
+    Q_D(const QuickTestResult);
+    return d->testCaseName;
+}
+
+void QuickTestResult::setTestCaseName(const QString &name)
+{
+    Q_D(QuickTestResult);
+    d->testCaseName = name;
+    d->updateTestObjectName();
+    emit testCaseNameChanged();
+}
+
+/*!
+    \qmlproperty string TestResult::functionName
+
+    This property defines the name of current test function
+    within a TestCase element that is running.  If this string is
+    empty, then no function is currently running.
+
+    \sa testCaseName
+*/
+QString QuickTestResult::functionName() const
+{
+    Q_D(const QuickTestResult);
+    return d->functionName;
+}
+
+void QuickTestResult::setFunctionName(const QString &name)
+{
+    Q_D(QuickTestResult);
+    if (!name.isEmpty()) {
+        // In plain logging mode, we use the function name directly.
+        // In XML logging mode, we use "testCase__functionName" as the
+        // program name is acting as the class name.
+        if (QTestLog::logMode() == QTestLog::Plain ||
+                d->testCaseName.isEmpty()) {
+            QTestResult::setCurrentTestFunction
+                (d->intern(name).constData());
+        } else {
+            QString fullName = d->testCaseName + QLatin1String("__") + name;
+            QTestResult::setCurrentTestFunction
+                (d->intern(fullName).constData());
+        }
+    } else {
+        QTestResult::setCurrentTestFunction(0);
+    }
+    d->functionName = name;
+    emit functionNameChanged();
+}
+
+QuickTestResult::FunctionType QuickTestResult::functionType() const
+{
+    return FunctionType(QTestResult::currentTestLocation());
+}
+
+void QuickTestResult::setFunctionType(FunctionType type)
+{
+    QTestResult::setCurrentTestLocation(QTestResult::TestLocation(type));
+    emit functionTypeChanged();
+}
+
+/*!
+    \qmlproperty string TestResult::dataTag
+
+    This property defines the tag for the current row in a
+    data-driven test, or an empty string if not a data-driven test.
+*/
+QString QuickTestResult::dataTag() const
+{
+    const char *tag = QTestResult::currentDataTag();
+    if (tag)
+        return QString::fromUtf8(tag);
+    else
+        return QString();
+}
+
+void QuickTestResult::setDataTag(const QString &tag)
+{
+    if (!tag.isEmpty()) {
+        QTestData *data = &(QTest::newRow(tag.toUtf8().constData()));
+        QTestResult::setCurrentTestData(data);
+        emit dataTagChanged();
+    } else {
+        QTestResult::setCurrentTestData(0);
+    }
+}
+
+/*!
+    \qmlproperty bool TestResult::failed
+
+    This property returns true if the current test function has
+    failed; false otherwise.  The fail state is reset when
+    functionName is changed or finishTestFunction() is called.
+
+    \sa skipped, dataFailed
+*/
+bool QuickTestResult::isFailed() const
+{
+    return QTestResult::testFailed();
+}
+
+/*!
+    \qmlproperty bool TestResult::dataFailed
+
+    This property returns true if the current data function has
+    failed; false otherwise.  The fail state is reset when
+    functionName is changed or finishTestFunction() is called.
+
+    \sa failed
+*/
+bool QuickTestResult::isDataFailed() const
+{
+    return QTestResult::currentTestFailed();
+}
+
+/*!
+    \qmlproperty bool TestResult::skipped
+
+    This property returns true if the current test function was
+    marked as skipped; false otherwise.
+
+    \sa failed
+*/
+bool QuickTestResult::isSkipped() const
+{
+    return QTestResult::skipCurrentTest();
+}
+
+void QuickTestResult::setSkipped(bool skip)
+{
+    QTestResult::setSkipCurrentTest(skip);
+    emit skippedChanged();
+}
+
+/*!
+    \qmlproperty int TestResult::passCount
+
+    This property returns the number of tests that have passed.
+
+    \sa failCount, skipCount
+*/
+int QuickTestResult::passCount() const
+{
+    return QTestResult::passCount();
+}
+
+/*!
+    \qmlproperty int TestResult::failCount
+
+    This property returns the number of tests that have failed.
+
+    \sa passCount, skipCount
+*/
+int QuickTestResult::failCount() const
+{
+    return QTestResult::failCount();
+}
+
+/*!
+    \qmlproperty int TestResult::skipCount
+
+    This property returns the number of tests that have been skipped.
+
+    \sa passCount, failCount
+*/
+int QuickTestResult::skipCount() const
+{
+    return QTestResult::skipCount();
+}
+
+/*!
+    \qmlproperty list<string> TestResult::functionsToRun
+
+    This property returns the list of function names to be run.
+*/
+QStringList QuickTestResult::functionsToRun() const
+{
+    return QTest::testFunctions;
+}
+
+/*!
+    \qmlmethod TestResult::reset()
+
+    Resets all pass/fail/skip counters and prepare for testing.
+*/
+void QuickTestResult::reset()
+{
+    if (!globalProgramName)     // Only if run via qmlviewer.
+        QTestResult::reset();
+}
+
+/*!
+    \qmlmethod TestResult::startLogging()
+
+    Starts logging to the test output stream and writes the
+    test header.
+
+    \sa stopLogging()
+*/
+void QuickTestResult::startLogging()
+{
+    // The program name is used for logging headers and footers if it
+    // is set.  Otherwise the test case name is used.
+    Q_D(QuickTestResult);
+    if (loggingStarted)
+        return;
+    const char *saved = QTestResult::currentTestObjectName();
+    if (globalProgramName) {
+        QTestResult::setCurrentTestObject(globalProgramName);
+    } else {
+        QTestResult::setCurrentTestObject
+            (d->intern(d->testCaseName).constData());
+    }
+    QTestLog::startLogging();
+    QTestResult::setCurrentTestObject(saved);
+    loggingStarted = true;
+}
+
+/*!
+    \qmlmethod TestResult::stopLogging()
+
+    Writes the test footer to the test output stream and then stops logging.
+
+    \sa startLogging()
+*/
+void QuickTestResult::stopLogging()
+{
+    Q_D(QuickTestResult);
+    if (globalProgramName)
+        return;     // Logging will be stopped by setProgramName(0).
+    const char *saved = QTestResult::currentTestObjectName();
+    QTestResult::setCurrentTestObject(d->intern(d->testCaseName).constData());
+    QTestLog::stopLogging();
+    QTestResult::setCurrentTestObject(saved);
+}
+
+void QuickTestResult::initTestTable()
+{
+    Q_D(QuickTestResult);
+    delete d->table;
+    d->table = new QTestTable;
+}
+
+void QuickTestResult::clearTestTable()
+{
+    Q_D(QuickTestResult);
+    delete d->table;
+    d->table = 0;
+}
+
+void QuickTestResult::finishTestFunction()
+{
+    QTestResult::finishedCurrentTestFunction();
+}
+
+static QString qtest_fixFile(const QString &file)
+{
+    if (file.startsWith(QLatin1String("file://")))
+        return file.mid(7);
+    else
+        return file;
+}
+
+void QuickTestResult::fail
+    (const QString &message, const QString &file, int line)
+{
+    QTestResult::addFailure(message.toLatin1().constData(),
+                            qtest_fixFile(file).toLatin1().constData(), line);
+}
+
+bool QuickTestResult::verify
+    (bool success, const QString &message, const QString &file, int line)
+{
+    if (!success && message.isEmpty()) {
+        return QTestResult::verify
+            (success, "verify()", "",
+             qtest_fixFile(file).toLatin1().constData(), line);
+    } else {
+        return QTestResult::verify
+            (success, message.toLatin1().constData(), "",
+             qtest_fixFile(file).toLatin1().constData(), line);
+    }
+}
+
+bool QuickTestResult::compare
+    (bool success, const QString &message,
+     const QString &val1, const QString &val2,
+     const QString &file, int line)
+{
+    if (success) {
+        return QTestResult::compare
+            (success, message.toLocal8Bit().constData(),
+             qtest_fixFile(file).toLatin1().constData(), line);
+    } else {
+        return QTestResult::compare
+            (success, message.toLocal8Bit().constData(),
+             QTest::toString(val1.toLatin1().constData()),
+             QTest::toString(val2.toLatin1().constData()),
+             "", "",
+             qtest_fixFile(file).toLatin1().constData(), line);
+    }
+}
+
+void QuickTestResult::skipSingle
+    (const QString &message, const QString &file, int line)
+{
+    QTestResult::addSkip(message.toLatin1().constData(), QTest::SkipSingle,
+                         qtest_fixFile(file).toLatin1().constData(), line);
+}
+
+void QuickTestResult::skipAll
+    (const QString &message, const QString &file, int line)
+{
+    QTestResult::addSkip(message.toLatin1().constData(), QTest::SkipAll,
+                         qtest_fixFile(file).toLatin1().constData(), line);
+    QTestResult::setSkipCurrentTest(true);
+}
+
+bool QuickTestResult::expectFail
+    (const QString &tag, const QString &comment, const QString &file, int line)
+{
+    return QTestResult::expectFail
+        (tag.toLatin1().constData(),
+         QTest::toString(comment.toLatin1().constData()),
+         QTest::Abort, qtest_fixFile(file).toLatin1().constData(), line);
+}
+
+bool QuickTestResult::expectFailContinue
+    (const QString &tag, const QString &comment, const QString &file, int line)
+{
+    return QTestResult::expectFail
+        (tag.toLatin1().constData(),
+         QTest::toString(comment.toLatin1().constData()),
+         QTest::Continue, qtest_fixFile(file).toLatin1().constData(), line);
+}
+
+void QuickTestResult::warn(const QString &message)
+{
+    QTestLog::warn(message.toLatin1().constData());
+}
+
+void QuickTestResult::ignoreWarning(const QString &message)
+{
+    QTestResult::ignoreMessage(QtWarningMsg, message.toLatin1().constData());
+}
+
+void QuickTestResult::wait(int ms)
+{
+    QTest::qWait(ms);
+}
+
+void QuickTestResult::sleep(int ms)
+{
+    QTest::qSleep(ms);
+}
+
+void QuickTestResult::startMeasurement()
+{
+    Q_D(QuickTestResult);
+    delete d->benchmarkData;
+    d->benchmarkData = new QBenchmarkTestMethodData();
+    QBenchmarkTestMethodData::current = d->benchmarkData;
+    d->iterCount = (QBenchmarkGlobalData::current->measurer->needsWarmupIteration()) ? -1 : 0;
+    d->results.clear();
+}
+
+void QuickTestResult::beginDataRun()
+{
+    QBenchmarkTestMethodData::current->beginDataRun();
+}
+
+void QuickTestResult::endDataRun()
+{
+    Q_D(QuickTestResult);
+    QBenchmarkTestMethodData::current->endDataRun();
+    if (d->iterCount > -1)  // iteration -1 is the warmup iteration.
+        d->results.append(QBenchmarkTestMethodData::current->result);
+
+    if (QBenchmarkGlobalData::current->verboseOutput) {
+        if (d->iterCount == -1) {
+            qDebug() << "warmup stage result      :" << QBenchmarkTestMethodData::current->result.value;
+        } else {
+            qDebug() << "accumulation stage result:" << QBenchmarkTestMethodData::current->result.value;
+        }
+    }
+}
+
+bool QuickTestResult::measurementAccepted()
+{
+    return QBenchmarkTestMethodData::current->resultsAccepted();
+}
+
+static QBenchmarkResult qMedian(const QList<QBenchmarkResult> &container)
+{
+    const int count = container.count();
+    if (count == 0)
+        return QBenchmarkResult();
+
+    if (count == 1)
+        return container.at(0);
+
+    QList<QBenchmarkResult> containerCopy = container;
+    qSort(containerCopy);
+
+    const int middle = count / 2;
+
+    // ### handle even-sized containers here by doing an aritmetic mean of the two middle items.
+    return containerCopy.at(middle);
+}
+
+bool QuickTestResult::needsMoreMeasurements()
+{
+    Q_D(QuickTestResult);
+    ++(d->iterCount);
+    if (d->iterCount < QBenchmarkGlobalData::current->adjustMedianIterationCount())
+        return true;
+    if (QBenchmarkTestMethodData::current->resultsAccepted())
+        QTestLog::addBenchmarkResult(qMedian(d->results));
+    return false;
+}
+
+void QuickTestResult::startBenchmark(RunMode runMode, const QString &tag)
+{
+    QBenchmarkTestMethodData::current->result = QBenchmarkResult();
+    QBenchmarkTestMethodData::current->resultAccepted = false;
+    QBenchmarkGlobalData::current->context.tag = tag;
+    QBenchmarkGlobalData::current->context.slotName = functionName();
+
+    Q_D(QuickTestResult);
+    delete d->benchmarkIter;
+    d->benchmarkIter = new QTest::QBenchmarkIterationController
+        (QTest::QBenchmarkIterationController::RunMode(runMode));
+}
+
+bool QuickTestResult::isBenchmarkDone() const
+{
+    Q_D(const QuickTestResult);
+    if (d->benchmarkIter)
+        return d->benchmarkIter->isDone();
+    else
+        return true;
+}
+
+void QuickTestResult::nextBenchmark()
+{
+    Q_D(QuickTestResult);
+    if (d->benchmarkIter)
+        d->benchmarkIter->next();
+}
+
+void QuickTestResult::stopBenchmark()
+{
+    Q_D(QuickTestResult);
+    delete d->benchmarkIter;
+    d->benchmarkIter = 0;
+}
+
+namespace QTest {
+    void qtest_qParseArgs(int argc, char *argv[], bool qml);
+};
+
+void QuickTestResult::parseArgs(int argc, char *argv[])
+{
+    if (!QBenchmarkGlobalData::current)
+        QBenchmarkGlobalData::current = &globalBenchmarkData;
+    QTest::qtest_qParseArgs(argc, argv, true);
+}
+
+void QuickTestResult::setProgramName(const char *name)
+{
+    if (name) {
+        QTestResult::reset();
+    } else if (!name && loggingStarted) {
+        QTestResult::setCurrentTestObject(globalProgramName);
+        QTestLog::stopLogging();
+        QTestResult::setCurrentTestObject(0);
+    }
+    globalProgramName = name;
+}
+
+int QuickTestResult::exitCode()
+{
+#if defined(QTEST_NOEXITCODE)
+    return 0;
+#else
+    // make sure our exit code is never going above 127
+    // since that could wrap and indicate 0 test fails
+    return qMin(QTestResult::failCount(), 127);
+#endif
+}
+
+QT_END_NAMESPACE
diff --git a/src/qmltest/quicktestresult_p.h b/src/qmltest/quicktestresult_p.h
new file mode 100644 (file)
index 0000000..d9ae694
--- /dev/null
@@ -0,0 +1,179 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 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$
+**
+****************************************************************************/
+
+#ifndef QUICKTESTRESULT_P_H
+#define QUICKTESTRESULT_P_H
+
+#include <QtQuickTest/quicktestglobal.h>
+#include <QtCore/qobject.h>
+#include <QtCore/qstring.h>
+#include <QtCore/qstringlist.h>
+#include <QtCore/qscopedpointer.h>
+
+QT_BEGIN_NAMESPACE
+
+class QuickTestResultPrivate;
+
+class Q_QUICK_TEST_EXPORT QuickTestResult : public QObject
+{
+    Q_OBJECT
+    Q_ENUMS(FunctionType RunMode)
+    Q_PROPERTY(QString testCaseName READ testCaseName WRITE setTestCaseName NOTIFY testCaseNameChanged)
+    Q_PROPERTY(QString functionName READ functionName WRITE setFunctionName NOTIFY functionNameChanged)
+    Q_PROPERTY(FunctionType functionType READ functionType WRITE setFunctionType NOTIFY functionTypeChanged)
+    Q_PROPERTY(QString dataTag READ dataTag WRITE setDataTag NOTIFY dataTagChanged)
+    Q_PROPERTY(bool failed READ isFailed)
+    Q_PROPERTY(bool dataFailed READ isDataFailed)
+    Q_PROPERTY(bool skipped READ isSkipped WRITE setSkipped NOTIFY skippedChanged)
+    Q_PROPERTY(int passCount READ passCount)
+    Q_PROPERTY(int failCount READ failCount)
+    Q_PROPERTY(int skipCount READ skipCount)
+    Q_PROPERTY(QStringList functionsToRun READ functionsToRun)
+public:
+    QuickTestResult(QObject *parent = 0);
+    ~QuickTestResult();
+
+    // Values must match QTestResult::TestLocation.
+    enum FunctionType
+    {
+        NoWhere = 0,
+        DataFunc = 1,
+        InitFunc = 2,
+        Func = 3,
+        CleanupFunc = 4
+    };
+
+    // Values must match QBenchmarkIterationController::RunMode.
+    enum RunMode
+    {
+        RepeatUntilValidMeasurement,
+        RunOnce
+    };
+
+    QString testCaseName() const;
+    void setTestCaseName(const QString &name);
+
+    QString functionName() const;
+    void setFunctionName(const QString &name);
+
+    FunctionType functionType() const;
+    void setFunctionType(FunctionType type);
+
+    QString dataTag() const;
+    void setDataTag(const QString &tag);
+
+    bool isFailed() const;
+    bool isDataFailed() const;
+
+    bool isSkipped() const;
+    void setSkipped(bool skip);
+
+    int passCount() const;
+    int failCount() const;
+    int skipCount() const;
+
+    QStringList functionsToRun() const;
+
+public Q_SLOTS:
+    void reset();
+
+    void startLogging();
+    void stopLogging();
+
+    void initTestTable();
+    void clearTestTable();
+
+    void finishTestFunction();
+
+    void fail(const QString &message, const QString &file, int line);
+    bool verify(bool success, const QString &message,
+                const QString &file, int line);
+    bool compare(bool success, const QString &message,
+                 const QString &val1, const QString &val2,
+                 const QString &file, int line);
+    void skipSingle(const QString &message, const QString &file, int line);
+    void skipAll(const QString &message, const QString &file, int line);
+    bool expectFail(const QString &tag, const QString &comment,
+                    const QString &file, int line);
+    bool expectFailContinue(const QString &tag, const QString &comment,
+                            const QString &file, int line);
+    void warn(const QString &message);
+
+    void ignoreWarning(const QString &message);
+
+    void wait(int ms);
+    void sleep(int ms);
+
+    void startMeasurement();
+    void beginDataRun();
+    void endDataRun();
+    bool measurementAccepted();
+    bool needsMoreMeasurements();
+
+    void startBenchmark(RunMode runMode, const QString &tag);
+    bool isBenchmarkDone() const;
+    void nextBenchmark();
+    void stopBenchmark();
+
+public:
+    // Helper functions for the C++ main() shell.
+    static void parseArgs(int argc, char *argv[]);
+    static void setProgramName(const char *name);
+    static int exitCode();
+
+Q_SIGNALS:
+    void programNameChanged();
+    void testCaseNameChanged();
+    void functionNameChanged();
+    void functionTypeChanged();
+    void dataTagChanged();
+    void skippedChanged();
+
+private:
+    QScopedPointer<QuickTestResultPrivate> d_ptr;
+
+    Q_DECLARE_PRIVATE(QuickTestResult)
+    Q_DISABLE_COPY(QuickTestResult)
+};
+
+QT_END_NAMESPACE
+
+#endif
index 27cc875..e8f77e6 100644 (file)
@@ -1,3 +1,5 @@
 TEMPLATE = subdirs
 CONFIG += ordered
-SUBDIRS += declarative  plugins imports
+SUBDIRS += declarative plugins imports
+contains(QT_CONFIG, qmltest): SUBDIRS += qmltest
+
index 42ea13d..5ec7230 100644 (file)
@@ -1,5 +1,6 @@
 %modules = ( # path to module name map
     "QtDeclarative" => "$basedir/src/declarative",
+    "QtQuickTest" => "$basedir/src/qmltest",
 );
 %moduleheaders = ( # restrict the module headers to those found in relative path
 );
@@ -9,9 +10,11 @@
     "gui" => "#include <QtGui/QtGui>\n",
     "script" => "#include <QtScript/QtScript>\n",
     "network" => "#include <QtNetwork/QtNetwork>\n",
+    "testlib" => "#include <QtTest/QtTest>\n",
 );
 %modulepris = (
     "QtDeclarative" => "$basedir/modules/qt_declarative.pri",
+    "QtQuickTest" => "$basedir/modules/qt_qmltest.pri",
 );
 # Modules and programs, and their dependencies.
 # Each of the module version specifiers can take one of the following values:
@@ -29,4 +32,8 @@
         "QtSql" => "0c637cb07ba3c9b353e7e483a209537485cc4e2a",
         "QtCore" => "0c637cb07ba3c9b353e7e483a209537485cc4e2a",
     },
+    "QtQuickTest" => {
+        "QtTest" => "0c637cb07ba3c9b353e7e483a209537485cc4e2a",
+        "QtDeclarative" => "THIS_REPOSITORY",
+    },
 );
index 1edeaaa..2543261 100644 (file)
@@ -2,4 +2,6 @@ TEMPLATE=subdirs
 SUBDIRS=\
     declarative \
 
+contains(QT_CONFIG, qmltest): SUBDIRS += qmltest
+
 !cross_compile:                             SUBDIRS += host.pro
diff --git a/tests/auto/qmltest/buttonclick/Button.qml b/tests/auto/qmltest/buttonclick/Button.qml
new file mode 100644 (file)
index 0000000..6b195ff
--- /dev/null
@@ -0,0 +1,74 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 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$
+**
+****************************************************************************/
+
+import QtQuick 2.0
+
+Rectangle {
+    id: container
+
+    property string text: "Button"
+
+    signal clicked
+
+    width: buttonLabel.width + 20; height: buttonLabel.height + 5
+    border { width: 1; color: "black" }
+    smooth: true
+    radius: 8
+
+    // color the button with a gradient
+    gradient: Gradient {
+        GradientStop { position: 0.0; color: "blue" }
+        GradientStop { position: 1.0; color: "lightblue" }
+    }
+
+    MouseArea {
+        id: mouseArea
+        anchors.fill: parent
+        onClicked: container.clicked();
+    }
+
+    Text {
+        id: buttonLabel
+        anchors.centerIn: container
+        color: "white"
+        text: container.text
+    }
+}
diff --git a/tests/auto/qmltest/buttonclick/tst_buttonclick.qml b/tests/auto/qmltest/buttonclick/tst_buttonclick.qml
new file mode 100644 (file)
index 0000000..a875daa
--- /dev/null
@@ -0,0 +1,66 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 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$
+**
+****************************************************************************/
+
+import QtQuick 2.0
+import QtTest 1.0
+
+Button {
+    id: button
+    onClicked: text = "Clicked"
+
+    SignalSpy {
+        id: spy
+        target: button
+        signalName: "clicked"
+    }
+
+    TestCase {
+        name: "ButtonClick"
+        when: windowShown
+
+        function test_click() {
+            compare(spy.count, 0)
+            button.clicked();
+            compare(button.text, "Clicked");
+            compare(spy.count, 1)
+        }
+    }
+}
diff --git a/tests/auto/qmltest/createbenchmark/item.qml b/tests/auto/qmltest/createbenchmark/item.qml
new file mode 100644 (file)
index 0000000..e3a3491
--- /dev/null
@@ -0,0 +1,75 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module 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$
+**
+****************************************************************************/
+
+import QtQuick 2.0
+
+Item {
+    Item {}
+    Item {}
+    Item {}
+    Item {}
+    Item {}
+    Item {}
+    Item {}
+    Item {}
+    Item {}
+    Item {}
+    Item {}
+    Item {}
+    Item {}
+    Item {}
+    Item {}
+    Item {}
+    Item {}
+    Item {}
+    Item {}
+    Item {}
+    Item {}
+    Item {}
+    Item {}
+    Item {}
+    Item {}
+    Item {}
+    Item {}
+    Item {}
+    Item {}
+    Item {}
+}
diff --git a/tests/auto/qmltest/createbenchmark/tst_createbenchmark.qml b/tests/auto/qmltest/createbenchmark/tst_createbenchmark.qml
new file mode 100644 (file)
index 0000000..b484020
--- /dev/null
@@ -0,0 +1,55 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 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$
+**
+****************************************************************************/
+
+import QtQuick 2.0
+import QtTest 1.0
+
+TestCase {
+    id: top
+    name: "CreateBenchmark"
+
+    function benchmark_create_component() {
+        var component = Qt.createComponent("item.qml")
+        var obj = component.createObject(top)
+        obj.destroy()
+        component.destroy()
+    }
+}
diff --git a/tests/auto/qmltest/events/tst_events.qml b/tests/auto/qmltest/events/tst_events.qml
new file mode 100644 (file)
index 0000000..bc358d9
--- /dev/null
@@ -0,0 +1,86 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 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$
+**
+****************************************************************************/
+
+import QtQuick 2.0
+import QtTest 1.0
+
+Rectangle {
+    width: 50; height: 50
+    id: top
+    focus: true
+
+    property bool leftKeyPressed: false
+    property bool leftKeyReleased: false
+
+    Keys.onLeftPressed: {
+        leftKeyPressed = true
+    }
+
+    Keys.onReleased: {
+        if (event.key == Qt.Key_Left)
+            leftKeyReleased = true
+    }
+
+    property bool mouseHasBeenClicked: false
+
+    MouseArea {
+        anchors.fill: parent
+        onClicked: {
+            mouseHasBeenClicked = true
+        }
+    }
+
+    TestCase {
+        name: "Events"
+        when: windowShown       // Must have this line for events to work.
+
+        function test_key_click() {
+            keyClick(Qt.Key_Left)
+            tryCompare(top, "leftKeyPressed", true)
+            tryCompare(top, "leftKeyReleased", true)
+        }
+
+        function test_mouse_click() {
+            mouseClick(top, 25, 30)
+            tryCompare(top, "mouseHasBeenClicked", true)
+        }
+    }
+}
diff --git a/tests/auto/qmltest/qdecarativebinding/tst_binding.qml b/tests/auto/qmltest/qdecarativebinding/tst_binding.qml
new file mode 100644 (file)
index 0000000..5c883c5
--- /dev/null
@@ -0,0 +1,75 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 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$
+**
+****************************************************************************/
+
+import QtQuick 2.0
+import QtTest 1.0
+
+Rectangle {
+    id: screen
+    width: 320; height: 240
+    property string text
+    property bool changeColor: false
+
+    Text { id: s1; text: "Hello" }
+    Rectangle { id: r1; width: 1; height: 1; color: "yellow" }
+    Rectangle { id: r2; width: 1; height: 1; color: "red" }
+
+    Binding { target: screen; property: "text"; value: s1.text; id: binding1 }
+    Binding { target: screen; property: "color"; value: r1.color }
+    Binding { target: screen; property: "color"; when: screen.changeColor == true; value: r2.color; id: binding3 }
+
+    TestCase {
+        name: "Binding"
+
+        function test_binding() {
+            compare(screen.color, "#ffff00")    // Yellow
+            compare(screen.text, "Hello")
+            verify(!binding3.when)
+
+            screen.changeColor = true
+            compare(screen.color, "#ff0000")    // Red
+
+            verify(binding1.target == screen)
+            compare(binding1.property, "text")
+            compare(binding1.value, "Hello")
+        }
+    }
+}
diff --git a/tests/auto/qmltest/qdecarativebinding/tst_binding2.qml b/tests/auto/qmltest/qdecarativebinding/tst_binding2.qml
new file mode 100644 (file)
index 0000000..85e1951
--- /dev/null
@@ -0,0 +1,70 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 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$
+**
+****************************************************************************/
+
+import QtQuick 2.0
+import QtTest 1.0
+
+Rectangle {
+    id: screen
+    width: 320; height: 240
+    property string text
+    property bool changeColor: false
+
+    Text { id: s1; text: "Hello" }
+    Rectangle { id: r1; width: 1; height: 1; color: "yellow" }
+    Rectangle { id: r2; width: 1; height: 1; color: "red" }
+
+    Binding { target: screen; property: "text"; value: s1.text }
+    Binding { target: screen; property: "color"; value: r1.color }
+    Binding { target: screen; property: "color"; value: r2.color; when: screen.changeColor == true }
+
+    TestCase {
+        name: "Binding2"
+
+        function test_binding2() {
+            compare(screen.color, "#ffff00")    // Yellow
+            compare(screen.text, "Hello")
+
+            screen.changeColor = true
+            compare(screen.color, "#ff0000")    // Red
+        }
+    }
+}
diff --git a/tests/auto/qmltest/qdecarativeborderimage/InvalidSciFile.qml b/tests/auto/qmltest/qdecarativeborderimage/InvalidSciFile.qml
new file mode 100644 (file)
index 0000000..d8a6d89
--- /dev/null
@@ -0,0 +1,48 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 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$
+**
+****************************************************************************/
+
+import QtQuick 2.0
+
+BorderImage {
+    source: "invalid.sci"
+    width: 300
+    height: 300
+}
diff --git a/tests/auto/qmltest/qdecarativeborderimage/colors-round.sci b/tests/auto/qmltest/qdecarativeborderimage/colors-round.sci
new file mode 100644 (file)
index 0000000..5d2f49f
--- /dev/null
@@ -0,0 +1,7 @@
+border.left:10
+border.top:20
+border.right:30
+border.bottom:40
+horizontalTileRule:Round
+verticalTileRule:Repeat
+source:colors.png
diff --git a/tests/auto/qmltest/qdecarativeborderimage/colors.png b/tests/auto/qmltest/qdecarativeborderimage/colors.png
new file mode 100644 (file)
index 0000000..dfb62f3
Binary files /dev/null and b/tests/auto/qmltest/qdecarativeborderimage/colors.png differ
diff --git a/tests/auto/qmltest/qdecarativeborderimage/invalid.sci b/tests/auto/qmltest/qdecarativeborderimage/invalid.sci
new file mode 100644 (file)
index 0000000..98c72c9
--- /dev/null
@@ -0,0 +1,7 @@
+border.left:10
+border.top:20
+border.down:30
+border.up:40
+horizontalTileRule:Roun
+verticalTileRule:Repea
+source:colors.png
diff --git a/tests/auto/qmltest/qdecarativeborderimage/tst_borderimage.qml b/tests/auto/qmltest/qdecarativeborderimage/tst_borderimage.qml
new file mode 100644 (file)
index 0000000..4c2c369
--- /dev/null
@@ -0,0 +1,247 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 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$
+**
+****************************************************************************/
+
+import QtQuick 2.0
+import QtTest 1.0
+
+Item {
+    id: top
+
+    BorderImage {
+        id: noSource
+        source: ""
+    }
+
+    property string srcImage: "colors.png"
+
+    BorderImage {
+        id: clearSource
+        source: srcImage
+    }
+
+    BorderImage {
+        id: resized
+        source: "colors.png"
+        width: 300
+        height: 300
+    }
+
+    BorderImage {
+        id: smooth
+        source: "colors.png"
+        smooth: true
+        width: 300
+        height: 300
+    }
+
+    BorderImage {
+        id: tileModes1
+        source: "colors.png"
+        width: 100
+        height: 300
+        horizontalTileMode: BorderImage.Repeat
+        verticalTileMode: BorderImage.Repeat
+    }
+
+    BorderImage {
+        id: tileModes2
+        source: "colors.png"
+        width: 300
+        height: 150
+        horizontalTileMode: BorderImage.Round
+        verticalTileMode: BorderImage.Round
+    }
+
+    TestCase {
+        name: "BorderImage"
+
+        function test_noSource() {
+            compare(noSource.source, "")
+            compare(noSource.width, 0)
+            compare(noSource.height, 0)
+            compare(noSource.horizontalTileMode, BorderImage.Stretch)
+            compare(noSource.verticalTileMode, BorderImage.Stretch)
+        }
+
+        function test_imageSource_data() {
+            return [
+                {
+                    tag: "local",
+                    source: "colors.png",
+                    remote: false,
+                    error: ""
+                },
+                {
+                    tag: "local not found",
+                    source: "no-such-file.png",
+                    remote: false,
+                    error: "SUBinline:1:21: QML BorderImage: Cannot open: SUBno-such-file.png"
+                }
+                // TODO: remote tests that need to use http
+            ]
+        }
+
+        function test_imageSource(row) {
+            var expectError = (row.error.length != 0)
+            if (expectError) {
+                var parentUrl = Qt.resolvedUrl(".")
+                ignoreWarning(row.error.replace(/SUB/g, parentUrl))
+            }
+
+            var img = Qt.createQmlObject
+                ('import QtQuick 1.0; BorderImage { source: "' +
+                    row.source + '" }', top)
+
+            if (row.remote)
+                tryCompare(img, "status", BorderImage.Loading)
+
+            if (!expectError) {
+                tryCompare(img, "status", BorderImage.Ready)
+                compare(img.width, 120)
+                compare(img.height, 120)
+                compare(img.horizontalTileMode, BorderImage.Stretch)
+                compare(img.verticalTileMode, BorderImage.Stretch)
+            } else {
+                tryCompare(img, "status", BorderImage.Error)
+            }
+
+            img.destroy()
+        }
+
+        function test_clearSource() {
+            compare(clearSource.source, Qt.resolvedUrl("colors.png"))
+            compare(clearSource.width, 120)
+            compare(clearSource.height, 120)
+
+            srcImage = ""
+            compare(clearSource.source, "")
+            compare(clearSource.width, 0)
+            compare(clearSource.height, 0)
+        }
+
+        function test_resized() {
+            compare(resized.width, 300)
+            compare(resized.height, 300)
+            compare(resized.horizontalTileMode, BorderImage.Stretch)
+            compare(resized.verticalTileMode, BorderImage.Stretch)
+        }
+
+        function test_smooth() {
+            compare(smooth.smooth, true)
+            compare(smooth.width, 300)
+            compare(smooth.height, 300)
+            compare(smooth.horizontalTileMode, BorderImage.Stretch)
+            compare(smooth.verticalTileMode, BorderImage.Stretch)
+        }
+
+        function test_tileModes() {
+            compare(tileModes1.width, 100)
+            compare(tileModes1.height, 300)
+            compare(tileModes1.horizontalTileMode, BorderImage.Repeat)
+            compare(tileModes1.verticalTileMode, BorderImage.Repeat)
+
+            compare(tileModes2.width, 300)
+            compare(tileModes2.height, 150)
+            compare(tileModes2.horizontalTileMode, BorderImage.Round)
+            compare(tileModes2.verticalTileMode, BorderImage.Round)
+        }
+
+        function test_sciSource_data() {
+            return [
+                {
+                    tag: "local",
+                    source: "colors-round.sci",
+                    remote: false,
+                    valid: true
+                },
+                {
+                    tag: "local not found",
+                    source: "no-such-file.sci",
+                    remote: false,
+                    valid: false
+                }
+                // TODO: remote tests that need to use http
+            ]
+        }
+
+        function test_sciSource(row) {
+            var img = Qt.createQmlObject
+                ('import QtQuick 1.0; BorderImage { source: "' +
+                    row.source + '"; width: 300; height: 300 }', top)
+
+            if (row.remote)
+                tryCompare(img, "status", BorderImage.Loading)
+
+            compare(img.source, Qt.resolvedUrl(row.source))
+            compare(img.width, 300)
+            compare(img.height, 300)
+
+            if (row.valid) {
+                tryCompare(img, "status", BorderImage.Ready)
+                compare(img.border.left, 10)
+                compare(img.border.top, 20)
+                compare(img.border.right, 30)
+                compare(img.border.bottom, 40)
+                compare(img.horizontalTileMode, BorderImage.Round)
+                compare(img.verticalTileMode, BorderImage.Repeat)
+            } else {
+                tryCompare(img, "status", BorderImage.Error)
+            }
+
+            img.destroy()
+        }
+
+
+        function test_invalidSciFile() {
+            ignoreWarning("QDeclarativeGridScaledImage: Invalid tile rule specified. Using Stretch.") // for "Roun"
+            ignoreWarning("QDeclarativeGridScaledImage: Invalid tile rule specified. Using Stretch.") // for "Repea"
+
+            var component = Qt.createComponent("InvalidSciFile.qml")
+            var invalidSciFile = component.createObject(top)
+
+            compare(invalidSciFile.status, Image.Error)
+            compare(invalidSciFile.width, 300)
+            compare(invalidSciFile.height, 300)
+            compare(invalidSciFile.horizontalTileMode, BorderImage.Stretch)
+            compare(invalidSciFile.verticalTileMode, BorderImage.Stretch)
+        }
+    }
+}
diff --git a/tests/auto/qmltest/qmltest.pro b/tests/auto/qmltest/qmltest.pro
new file mode 100644 (file)
index 0000000..3ee655d
--- /dev/null
@@ -0,0 +1,11 @@
+TEMPLATE=app
+TARGET=tst_qmltest
+CONFIG += warn_on qmltestcase
+SOURCES += tst_qmltest.cpp
+
+OTHER_FILES += \
+    selftests/tst_selftests.qml \
+    qdecarativebinding/tst_binding2.qml \
+    qdecarativebinding/tst_binding.qml \
+    selftests/tst_compare.qml \
+    selftests/tst_compare_quickobjects.qml
diff --git a/tests/auto/qmltest/selftests/tst_compare.qml b/tests/auto/qmltest/selftests/tst_compare.qml
new file mode 100644 (file)
index 0000000..b775b75
--- /dev/null
@@ -0,0 +1,1391 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 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$
+**
+****************************************************************************/
+
+import QtQuick 2.0
+import QtTest 1.0
+
+TestCase {
+    name: "SelfTests_compare"
+
+    function test_primitives_and_constants() {
+        compare(qtest_compareInternal(null, null), true, "null");
+        compare(qtest_compareInternal(null, {}), false, "null");
+        compare(qtest_compareInternal(null, undefined), false, "null");
+        compare(qtest_compareInternal(null, 0), false, "null");
+        compare(qtest_compareInternal(null, false), false, "null");
+        compare(qtest_compareInternal(null, ''), false, "null");
+        compare(qtest_compareInternal(null, []), false, "null");
+
+        compare(qtest_compareInternal(undefined, undefined), true, "undefined");
+        compare(qtest_compareInternal(undefined, null), false, "undefined");
+        compare(qtest_compareInternal(undefined, 0), false, "undefined");
+        compare(qtest_compareInternal(undefined, false), false, "undefined");
+        compare(qtest_compareInternal(undefined, {}), false, "undefined");
+        compare(qtest_compareInternal(undefined, []), false, "undefined");
+        compare(qtest_compareInternal(undefined, ""), false, "undefined");
+
+        // Nan usually doest not equal to Nan using the '==' operator.
+        // Only isNaN() is able to do it.
+        compare(qtest_compareInternal(0/0, 0/0), true, "NaN"); // NaN VS NaN
+        compare(qtest_compareInternal(1/0, 2/0), true, "Infinity"); // Infinity VS Infinity
+        compare(qtest_compareInternal(-1/0, 2/0), false, "-Infinity, Infinity"); // -Infinity VS Infinity
+        compare(qtest_compareInternal(-1/0, -2/0), true, "-Infinity, -Infinity"); // -Infinity VS -Infinity
+        compare(qtest_compareInternal(0/0, 1/0), false, "NaN, Infinity"); // Nan VS Infinity
+        compare(qtest_compareInternal(1/0, 0/0), false, "NaN, Infinity"); // Nan VS Infinity
+        compare(qtest_compareInternal(0/0, null), false, "NaN");
+        compare(qtest_compareInternal(0/0, undefined), false, "NaN");
+        compare(qtest_compareInternal(0/0, 0), false, "NaN");
+        compare(qtest_compareInternal(0/0, false), false, "NaN");
+        //compare(qtest_compareInternal(0/0, function () {}), false, "NaN");       // Do we really need that?
+        compare(qtest_compareInternal(1/0, null), false, "NaN, Infinity");
+        compare(qtest_compareInternal(1/0, undefined), false, "NaN, Infinity");
+        compare(qtest_compareInternal(1/0, 0), false, "NaN, Infinity");
+        compare(qtest_compareInternal(1/0, 1), false, "NaN, Infinity");
+        compare(qtest_compareInternal(1/0, false), false, "NaN, Infinity");
+        compare(qtest_compareInternal(1/0, true), false, "NaN, Infinity");
+        //compare(qtest_compareInternal(1/0, function () {}), false, "NaN");       // Do we really need that?
+
+        compare(qtest_compareInternal(0, 0), true, "number");
+        compare(qtest_compareInternal(0, 1), false, "number");
+        compare(qtest_compareInternal(1, 0), false, "number");
+        compare(qtest_compareInternal(1, 1), true, "number");
+        compare(qtest_compareInternal(1.1, 1.1), true, "number");
+        compare(qtest_compareInternal(0.0000005, 0.0000005), true, "number");
+        compare(qtest_compareInternal(0, ''), false, "number");
+        compare(qtest_compareInternal(0, '0'), false, "number");
+        compare(qtest_compareInternal(1, '1'), false, "number");
+        compare(qtest_compareInternal(0, false), false, "number");
+        compare(qtest_compareInternal(1, true), false, "number");
+
+        compare(qtest_compareInternal(true, true), true, "boolean");
+        compare(qtest_compareInternal(true, false), false, "boolean");
+        compare(qtest_compareInternal(false, true), false, "boolean");
+        compare(qtest_compareInternal(false, 0), false, "boolean");
+        compare(qtest_compareInternal(false, null), false, "boolean");
+        compare(qtest_compareInternal(false, undefined), false, "boolean");
+        compare(qtest_compareInternal(true, 1), false, "boolean");
+        compare(qtest_compareInternal(true, null), false, "boolean");
+        compare(qtest_compareInternal(true, undefined), false, "boolean");
+
+        compare(qtest_compareInternal('', ''), true, "string");
+        compare(qtest_compareInternal('a', 'a'), true, "string");
+        compare(qtest_compareInternal("foobar", "foobar"), true, "string");
+        compare(qtest_compareInternal("foobar", "foo"), false, "string");
+        compare(qtest_compareInternal('', 0), false, "string");
+        compare(qtest_compareInternal('', false), false, "string");
+        compare(qtest_compareInternal('', null), false, "string");
+        compare(qtest_compareInternal('', undefined), false, "string");
+
+        // Short annotation VS new annotation
+        compare(qtest_compareInternal(0, new Number()), true, "short annotation VS new annotation");
+        compare(qtest_compareInternal(new Number(), 0), true, "short annotation VS new annotation");
+        compare(qtest_compareInternal(1, new Number(1)), true, "short annotation VS new annotation");
+        compare(qtest_compareInternal(new Number(1), 1), true, "short annotation VS new annotation");
+        compare(qtest_compareInternal(new Number(0), 1), false, "short annotation VS new annotation");
+        compare(qtest_compareInternal(0, new Number(1)), false, "short annotation VS new annotation");
+
+        compare(qtest_compareInternal(new String(), ""), true, "short annotation VS new annotation");
+        compare(qtest_compareInternal("", new String()), true, "short annotation VS new annotation");
+        compare(qtest_compareInternal(new String("My String"), "My String"), true, "short annotation VS new annotation");
+        compare(qtest_compareInternal("My String", new String("My String")), true, "short annotation VS new annotation");
+        compare(qtest_compareInternal("Bad String", new String("My String")), false, "short annotation VS new annotation");
+        compare(qtest_compareInternal(new String("Bad String"), "My String"), false, "short annotation VS new annotation");
+
+        compare(qtest_compareInternal(false, new Boolean()), true, "short annotation VS new annotation");
+        compare(qtest_compareInternal(new Boolean(), false), true, "short annotation VS new annotation");
+        compare(qtest_compareInternal(true, new Boolean(true)), true, "short annotation VS new annotation");
+        compare(qtest_compareInternal(new Boolean(true), true), true, "short annotation VS new annotation");
+        compare(qtest_compareInternal(true, new Boolean(1)), true, "short annotation VS new annotation");
+        compare(qtest_compareInternal(false, new Boolean(false)), true, "short annotation VS new annotation");
+        compare(qtest_compareInternal(new Boolean(false), false), true, "short annotation VS new annotation");
+        compare(qtest_compareInternal(false, new Boolean(0)), true, "short annotation VS new annotation");
+        compare(qtest_compareInternal(true, new Boolean(false)), false, "short annotation VS new annotation");
+        compare(qtest_compareInternal(new Boolean(false), true), false, "short annotation VS new annotation");
+
+        compare(qtest_compareInternal(new Object(), {}), true, "short annotation VS new annotation");
+        compare(qtest_compareInternal({}, new Object()), true, "short annotation VS new annotation");
+        compare(qtest_compareInternal(new Object(), {a:1}), false, "short annotation VS new annotation");
+        compare(qtest_compareInternal({a:1}, new Object()), false, "short annotation VS new annotation");
+        compare(qtest_compareInternal({a:undefined}, new Object()), false, "short annotation VS new annotation");
+        compare(qtest_compareInternal(new Object(), {a:undefined}), false, "short annotation VS new annotation");
+    }
+
+    function test_objects_basics() {
+        compare(qtest_compareInternal({}, {}), true);
+        compare(qtest_compareInternal({}, null), false);
+        compare(qtest_compareInternal({}, undefined), false);
+        compare(qtest_compareInternal({}, 0), false);
+        compare(qtest_compareInternal({}, false), false);
+
+        // This test is a hard one, it is very important
+        // REASONS:
+        //      1) They are of the same type "object"
+        //      2) [] instanceof Object is true
+        //      3) Their properties are the same (doesn't exists)
+        compare(qtest_compareInternal({}, []), false);
+
+        compare(qtest_compareInternal({a:1}, {a:1}), true);
+        compare(qtest_compareInternal({a:1}, {a:"1"}), false);
+        compare(qtest_compareInternal({a:[]}, {a:[]}), true);
+        compare(qtest_compareInternal({a:{}}, {a:null}), false);
+        compare(qtest_compareInternal({a:1}, {}), false);
+        compare(qtest_compareInternal({}, {a:1}), false);
+
+        // Hard ones
+        compare(qtest_compareInternal({a:undefined}, {}), false);
+        compare(qtest_compareInternal({}, {a:undefined}), false);
+        compare(qtest_compareInternal(
+            {
+                a: [{ bar: undefined }]
+            },
+            {
+                a: [{ bat: undefined }]
+            }
+        ), false);
+    }
+
+    function test_arrays_basics() {
+        compare(qtest_compareInternal([], []), true);
+
+        // May be a hard one, can invoke a crash at execution.
+        // because their types are both "object" but null isn't
+        // like a true object, it doesn't have any property at all.
+        compare(qtest_compareInternal([], null), false);
+
+        compare(qtest_compareInternal([], undefined), false);
+        compare(qtest_compareInternal([], false), false);
+        compare(qtest_compareInternal([], 0), false);
+        compare(qtest_compareInternal([], ""), false);
+
+        // May be a hard one, but less hard
+        // than {} with [] (note the order)
+        compare(qtest_compareInternal([], {}), false);
+
+        compare(qtest_compareInternal([null],[]), false);
+        compare(qtest_compareInternal([undefined],[]), false);
+        compare(qtest_compareInternal([],[null]), false);
+        compare(qtest_compareInternal([],[undefined]), false);
+        compare(qtest_compareInternal([null],[undefined]), false);
+        compare(qtest_compareInternal([[]],[[]]), true);
+        compare(qtest_compareInternal([[],[],[]],[[],[],[]]), true);
+        compare(qtest_compareInternal(
+                                [[],[],[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]],
+                                [[],[],[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]),
+                                true);
+        compare(qtest_compareInternal(
+                                [[],[],[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]],
+                                [[],[],[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]), // shorter
+                                false);
+        compare(qtest_compareInternal(
+                                [[],[],[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[{}]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]],
+                                [[],[],[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]), // deepest element not an array
+                                false);
+
+        // same multidimensional
+        compare(qtest_compareInternal(
+                                [1,2,3,4,5,6,7,8,9, [
+                                    1,2,3,4,5,6,7,8,9, [
+                                        1,2,3,4,5,[
+                                            [6,7,8,9, [
+                                                [
+                                                    1,2,3,4,[
+                                                        2,3,4,[
+                                                            1,2,[
+                                                                1,2,3,4,[
+                                                                    1,2,3,4,5,6,7,8,9,[
+                                                                        0
+                                                                    ],1,2,3,4,5,6,7,8,9
+                                                                ],5,6,7,8,9
+                                                            ],4,5,6,7,8,9
+                                                        ],5,6,7,8,9
+                                                    ],5,6,7
+                                                ]
+                                            ]
+                                        ]
+                                    ]
+                                ]]],
+                                [1,2,3,4,5,6,7,8,9, [
+                                    1,2,3,4,5,6,7,8,9, [
+                                        1,2,3,4,5,[
+                                            [6,7,8,9, [
+                                                [
+                                                    1,2,3,4,[
+                                                        2,3,4,[
+                                                            1,2,[
+                                                                1,2,3,4,[
+                                                                    1,2,3,4,5,6,7,8,9,[
+                                                                        0
+                                                                    ],1,2,3,4,5,6,7,8,9
+                                                                ],5,6,7,8,9
+                                                            ],4,5,6,7,8,9
+                                                        ],5,6,7,8,9
+                                                    ],5,6,7
+                                                ]
+                                            ]
+                                        ]
+                                    ]
+                                ]]]),
+                                true, "Multidimensional");
+
+        // different multidimensional
+        compare(qtest_compareInternal(
+                                [1,2,3,4,5,6,7,8,9, [
+                                    1,2,3,4,5,6,7,8,9, [
+                                        1,2,3,4,5,[
+                                            [6,7,8,9, [
+                                                [
+                                                    1,2,3,4,[
+                                                        2,3,4,[
+                                                            1,2,[
+                                                                1,2,3,4,[
+                                                                    1,2,3,4,5,6,7,8,9,[
+                                                                        0
+                                                                    ],1,2,3,4,5,6,7,8,9
+                                                                ],5,6,7,8,9
+                                                            ],4,5,6,7,8,9
+                                                        ],5,6,7,8,9
+                                                    ],5,6,7
+                                                ]
+                                            ]
+                                        ]
+                                    ]
+                                ]]],
+                                [1,2,3,4,5,6,7,8,9, [
+                                    1,2,3,4,5,6,7,8,9, [
+                                        1,2,3,4,5,[
+                                            [6,7,8,9, [
+                                                [
+                                                    1,2,3,4,[
+                                                        2,3,4,[
+                                                            1,2,[
+                                                                '1',2,3,4,[                 // string instead of number
+                                                                    1,2,3,4,5,6,7,8,9,[
+                                                                        0
+                                                                    ],1,2,3,4,5,6,7,8,9
+                                                                ],5,6,7,8,9
+                                                            ],4,5,6,7,8,9
+                                                        ],5,6,7,8,9
+                                                    ],5,6,7
+                                                ]
+                                            ]
+                                        ]
+                                    ]
+                                ]]]),
+                                false, "Multidimensional");
+
+        // different multidimensional
+        compare(qtest_compareInternal(
+                                [1,2,3,4,5,6,7,8,9, [
+                                    1,2,3,4,5,6,7,8,9, [
+                                        1,2,3,4,5,[
+                                            [6,7,8,9, [
+                                                [
+                                                    1,2,3,4,[
+                                                        2,3,4,[
+                                                            1,2,[
+                                                                1,2,3,4,[
+                                                                    1,2,3,4,5,6,7,8,9,[
+                                                                        0
+                                                                    ],1,2,3,4,5,6,7,8,9
+                                                                ],5,6,7,8,9
+                                                            ],4,5,6,7,8,9
+                                                        ],5,6,7,8,9
+                                                    ],5,6,7
+                                                ]
+                                            ]
+                                        ]
+                                    ]
+                                ]]],
+                                [1,2,3,4,5,6,7,8,9, [
+                                    1,2,3,4,5,6,7,8,9, [
+                                        1,2,3,4,5,[
+                                            [6,7,8,9, [
+                                                [
+                                                    1,2,3,4,[
+                                                        2,3,[                   // missing an element (4)
+                                                            1,2,[
+                                                                1,2,3,4,[
+                                                                    1,2,3,4,5,6,7,8,9,[
+                                                                        0
+                                                                    ],1,2,3,4,5,6,7,8,9
+                                                                ],5,6,7,8,9
+                                                            ],4,5,6,7,8,9
+                                                        ],5,6,7,8,9
+                                                    ],5,6,7
+                                                ]
+                                            ]
+                                        ]
+                                    ]
+                                ]]]),
+                                false, "Multidimensional");
+    }
+
+    function test_date_instances() {
+        // Date, we don't need to test Date.parse() because it returns a number.
+        // Only test the Date instances by setting them a fix date.
+        // The date use is midnight January 1, 1970
+
+        var d1 = new Date();
+        d1.setTime(0); // fix the date
+
+        var d2 = new Date();
+        d2.setTime(0); // fix the date
+
+        var d3 = new Date(); // The very now
+
+        // Anyway their types differs, just in case the code fails in the order in which it deals with date
+        compare(qtest_compareInternal(d1, 0), false); // d1.valueOf() returns 0, but d1 and 0 are different
+        // test same values date and different instances equality
+        compare(qtest_compareInternal(d1, d2), true);
+        // test different date and different instances difference
+        compare(qtest_compareInternal(d1, d3), false);
+
+        // try to fool equiv by adding a valueOf function to an object
+        // that would return the same value of a real date instance.
+        var d4 = new Date();
+        d4.setFullYear(2010);
+        d4.setMonth(1);
+        d4.setDate(1);
+        d4.setHours(1);
+        d4.setMinutes(1);
+        d4.setSeconds(1);
+        d4.setMilliseconds(1);
+        var o4 = {
+            valueOf: function () {
+                return d4.valueOf();
+            }
+        }
+        compare(qtest_compareInternal(d4, o4), false); // o4 isn't an instance of Date
+    }
+
+
+    function test_regexp() {
+        // Must test cases that imply those traps:
+        // var a = /./;
+        // a instanceof Object;        // Oops
+        // a instanceof RegExp;        // Oops
+        // typeof a === "function";    // Oops, false in IE and Opera, true in FF and Safari ("object")
+
+        // Tests same regex with same modifiers in different order
+        var r = /foo/;
+        var r5 = /foo/gim;
+        var r6 = /foo/gmi;
+        var r7 = /foo/igm;
+        var r8 = /foo/img;
+        var r9 = /foo/mig;
+        var r10 = /foo/mgi;
+        var ri1 = /foo/i;
+        var ri2 = /foo/i;
+        var rm1 = /foo/m;
+        var rm2 = /foo/m;
+        var rg1 = /foo/g;
+        var rg2 = /foo/g;
+
+        compare(qtest_compareInternal(r5, r6), true, "Modifier order");
+        compare(qtest_compareInternal(r5, r7), true, "Modifier order");
+        compare(qtest_compareInternal(r5, r8), true, "Modifier order");
+        compare(qtest_compareInternal(r5, r9), true, "Modifier order");
+        compare(qtest_compareInternal(r5, r10), true, "Modifier order");
+        compare(qtest_compareInternal(r, r5), false, "Modifier");
+
+        compare(qtest_compareInternal(ri1, ri2), true, "Modifier");
+        compare(qtest_compareInternal(r, ri1), false, "Modifier");
+        compare(qtest_compareInternal(ri1, rm1), false, "Modifier");
+        compare(qtest_compareInternal(r, rm1), false, "Modifier");
+        compare(qtest_compareInternal(rm1, ri1), false, "Modifier");
+        compare(qtest_compareInternal(rm1, rm2), true, "Modifier");
+        compare(qtest_compareInternal(rg1, rm1), false, "Modifier");
+        compare(qtest_compareInternal(rm1, rg1), false, "Modifier");
+        compare(qtest_compareInternal(rg1, rg2), true, "Modifier");
+
+        // Different regex, same modifiers
+        var r11 = /[a-z]/gi;
+        var r13 = /[0-9]/gi; // oops! different
+        compare(qtest_compareInternal(r11, r13), false, "Regex pattern");
+
+        var r14 = /0/ig;
+        var r15 = /"0"/ig; // oops! different
+        compare(qtest_compareInternal(r14, r15), false, "Regex pattern");
+
+        var r1 = /[\n\r\u2028\u2029]/g;
+        var r2 = /[\n\r\u2028\u2029]/g;
+        var r3 = /[\n\r\u2028\u2028]/g; // differs from r1
+        var r4 = /[\n\r\u2028\u2029]/;  // differs from r1
+
+        compare(qtest_compareInternal(r1, r2), true, "Regex pattern");
+        compare(qtest_compareInternal(r1, r3), false, "Regex pattern");
+        compare(qtest_compareInternal(r1, r4), false, "Regex pattern");
+
+        // More complex regex
+        var regex1 = "^[-_.a-z0-9]+@([-_a-z0-9]+\\.)+([A-Za-z][A-Za-z]|[A-Za-z][A-Za-z][A-Za-z])|(([0-9][0-9]?|[0-1][0-9][0-9]|[2][0-4][0-9]|[2][5][0-5]))$";
+        var regex2 = "^[-_.a-z0-9]+@([-_a-z0-9]+\\.)+([A-Za-z][A-Za-z]|[A-Za-z][A-Za-z][A-Za-z])|(([0-9][0-9]?|[0-1][0-9][0-9]|[2][0-4][0-9]|[2][5][0-5]))$";
+        // regex 3 is different: '.' not escaped
+        var regex3 = "^[-_.a-z0-9]+@([-_a-z0-9]+.)+([A-Za-z][A-Za-z]|[A-Za-z][A-Za-z][A-Za-z])|(([0-9][0-9]?|[0-1][0-9][0-9]|[2][0-4][0-9]|[2][5][0-5]))$";
+
+        var r21 = new RegExp(regex1);
+        var r22 = new RegExp(regex2);
+        var r23 = new RegExp(regex3); // diff from r21, not same pattern
+        var r23a = new RegExp(regex3, "gi"); // diff from r23, not same modifier
+        var r24a = new RegExp(regex3, "ig"); // same as r23a
+
+        compare(qtest_compareInternal(r21, r22), true, "Complex Regex");
+        compare(qtest_compareInternal(r21, r23), false, "Complex Regex");
+        compare(qtest_compareInternal(r23, r23a), false, "Complex Regex");
+        compare(qtest_compareInternal(r23a, r24a), true, "Complex Regex");
+
+        // typeof r1 is "function" in some browsers and "object" in others so we must cover this test
+        var re = / /;
+        compare(qtest_compareInternal(re, function () {}), false, "Regex internal");
+        compare(qtest_compareInternal(re, {}), false, "Regex internal");
+    }
+
+
+    function test_complex_objects() {
+
+        function fn1() {
+            return "fn1";
+        }
+        function fn2() {
+            return "fn2";
+        }
+
+        // Try to invert the order of some properties to make sure it is covered.
+        // It can failed when properties are compared between unsorted arrays.
+        compare(qtest_compareInternal(
+            {
+                a: 1,
+                b: null,
+                c: [{}],
+                d: {
+                    a: 3.14159,
+                    b: false,
+                    c: {
+                        e: fn1,
+                        f: [[[]]],
+                        g: {
+                            j: {
+                                k: {
+                                    n: {
+                                        r: "r",
+                                        s: [1,2,3],
+                                        t: undefined,
+                                        u: 0,
+                                        v: {
+                                            w: {
+                                                x: {
+                                                    y: "Yahoo!",
+                                                    z: null
+                                                }
+                                            }
+                                        }
+                                    },
+                                    q: [],
+                                    p: 1/0,
+                                    o: 99
+                                },
+                                l: undefined,
+                                m: null
+                            }
+                        },
+                        d: 0,
+                        i: true,
+                        h: "false"
+                    }
+                },
+                e: undefined,
+                g: "",
+                h: "h",
+                f: {},
+                i: []
+            },
+            {
+                a: 1,
+                b: null,
+                c: [{}],
+                d: {
+                    b: false,
+                    a: 3.14159,
+                    c: {
+                        d: 0,
+                        e: fn1,
+                        f: [[[]]],
+                        g: {
+                            j: {
+                                k: {
+                                    n: {
+                                        r: "r",
+                                        t: undefined,
+                                        u: 0,
+                                        s: [1,2,3],
+                                        v: {
+                                            w: {
+                                                x: {
+                                                    z: null,
+                                                    y: "Yahoo!"
+                                                }
+                                            }
+                                        }
+                                    },
+                                    o: 99,
+                                    p: 1/0,
+                                    q: []
+                                },
+                                l: undefined,
+                                m: null
+                            }
+                        },
+                        i: true,
+                        h: "false"
+                    }
+                },
+                e: undefined,
+                g: "",
+                f: {},
+                h: "h",
+                i: []
+            }
+        ), true);
+
+        compare(qtest_compareInternal(
+            {
+                a: 1,
+                b: null,
+                c: [{}],
+                d: {
+                    a: 3.14159,
+                    b: false,
+                    c: {
+                        d: 0,
+                        e: fn1,
+                        f: [[[]]],
+                        g: {
+                            j: {
+                                k: {
+                                    n: {
+                                        //r: "r",   // different: missing a property
+                                        s: [1,2,3],
+                                        t: undefined,
+                                        u: 0,
+                                        v: {
+                                            w: {
+                                                x: {
+                                                    y: "Yahoo!",
+                                                    z: null
+                                                }
+                                            }
+                                        }
+                                    },
+                                    o: 99,
+                                    p: 1/0,
+                                    q: []
+                                },
+                                l: undefined,
+                                m: null
+                            }
+                        },
+                        h: "false",
+                        i: true
+                    }
+                },
+                e: undefined,
+                f: {},
+                g: "",
+                h: "h",
+                i: []
+            },
+            {
+                a: 1,
+                b: null,
+                c: [{}],
+                d: {
+                    a: 3.14159,
+                    b: false,
+                    c: {
+                        d: 0,
+                        e: fn1,
+                        f: [[[]]],
+                        g: {
+                            j: {
+                                k: {
+                                    n: {
+                                        r: "r",
+                                        s: [1,2,3],
+                                        t: undefined,
+                                        u: 0,
+                                        v: {
+                                            w: {
+                                                x: {
+                                                    y: "Yahoo!",
+                                                    z: null
+                                                }
+                                            }
+                                        }
+                                    },
+                                    o: 99,
+                                    p: 1/0,
+                                    q: []
+                                },
+                                l: undefined,
+                                m: null
+                            }
+                        },
+                        h: "false",
+                        i: true
+                    }
+                },
+                e: undefined,
+                f: {},
+                g: "",
+                h: "h",
+                i: []
+            }
+        ), false);
+
+        compare(qtest_compareInternal(
+            {
+                a: 1,
+                b: null,
+                c: [{}],
+                d: {
+                    a: 3.14159,
+                    b: false,
+                    c: {
+                        d: 0,
+                        e: fn1,
+                        f: [[[]]],
+                        g: {
+                            j: {
+                                k: {
+                                    n: {
+                                        r: "r",
+                                        s: [1,2,3],
+                                        t: undefined,
+                                        u: 0,
+                                        v: {
+                                            w: {
+                                                x: {
+                                                    y: "Yahoo!",
+                                                    z: null
+                                                }
+                                            }
+                                        }
+                                    },
+                                    o: 99,
+                                    p: 1/0,
+                                    q: []
+                                },
+                                l: undefined,
+                                m: null
+                            }
+                        },
+                        h: "false",
+                        i: true
+                    }
+                },
+                e: undefined,
+                f: {},
+                g: "",
+                h: "h",
+                i: []
+            },
+            {
+                a: 1,
+                b: null,
+                c: [{}],
+                d: {
+                    a: 3.14159,
+                    b: false,
+                    c: {
+                        d: 0,
+                        e: fn1,
+                        f: [[[]]],
+                        g: {
+                            j: {
+                                k: {
+                                    n: {
+                                        r: "r",
+                                        s: [1,2,3],
+                                        //t: undefined,                 // different: missing a property with an undefined value
+                                        u: 0,
+                                        v: {
+                                            w: {
+                                                x: {
+                                                    y: "Yahoo!",
+                                                    z: null
+                                                }
+                                            }
+                                        }
+                                    },
+                                    o: 99,
+                                    p: 1/0,
+                                    q: []
+                                },
+                                l: undefined,
+                                m: null
+                            }
+                        },
+                        h: "false",
+                        i: true
+                    }
+                },
+                e: undefined,
+                f: {},
+                g: "",
+                h: "h",
+                i: []
+            }
+        ), false);
+
+        compare(qtest_compareInternal(
+            {
+                a: 1,
+                b: null,
+                c: [{}],
+                d: {
+                    a: 3.14159,
+                    b: false,
+                    c: {
+                        d: 0,
+                        e: fn1,
+                        f: [[[]]],
+                        g: {
+                            j: {
+                                k: {
+                                    n: {
+                                        r: "r",
+                                        s: [1,2,3],
+                                        t: undefined,
+                                        u: 0,
+                                        v: {
+                                            w: {
+                                                x: {
+                                                    y: "Yahoo!",
+                                                    z: null
+                                                }
+                                            }
+                                        }
+                                    },
+                                    o: 99,
+                                    p: 1/0,
+                                    q: []
+                                },
+                                l: undefined,
+                                m: null
+                            }
+                        },
+                        h: "false",
+                        i: true
+                    }
+                },
+                e: undefined,
+                f: {},
+                g: "",
+                h: "h",
+                i: []
+            },
+            {
+                a: 1,
+                b: null,
+                c: [{}],
+                d: {
+                    a: 3.14159,
+                    b: false,
+                    c: {
+                        d: 0,
+                        e: fn1,
+                        f: [[[]]],
+                        g: {
+                            j: {
+                                k: {
+                                    n: {
+                                        r: "r",
+                                        s: [1,2,3],
+                                        t: undefined,
+                                        u: 0,
+                                        v: {
+                                            w: {
+                                                x: {
+                                                    y: "Yahoo!",
+                                                    z: null
+                                                }
+                                            }
+                                        }
+                                    },
+                                    o: 99,
+                                    p: 1/0,
+                                    q: {}           // different was []
+                                },
+                                l: undefined,
+                                m: null
+                            }
+                        },
+                        h: "false",
+                        i: true
+                    }
+                },
+                e: undefined,
+                f: {},
+                g: "",
+                h: "h",
+                i: []
+            }
+        ), false);
+
+        var same1 = {
+            a: [
+                "string", null, 0, "1", 1, {
+                    prop: null,
+                    foo: [1,2,null,{}, [], [1,2,3]],
+                    bar: undefined
+                }, 3, "Hey!", "Κάνε πάντα γνωρίζουμε ας των, μηχανής επιδιόρθωσης επιδιορθώσεις ώς μια. Κλπ ας"
+            ],
+            unicode: "老 汉语中存在 港澳和海外的华人圈中 贵州 我去了书店 现在尚有争",
+            b: "b",
+            c: fn1
+        };
+
+        var same2 = {
+            a: [
+                "string", null, 0, "1", 1, {
+                    prop: null,
+                    foo: [1,2,null,{}, [], [1,2,3]],
+                    bar: undefined
+                }, 3, "Hey!", "Κάνε πάντα γνωρίζουμε ας των, μηχανής επιδιόρθωσης επιδιορθώσεις ώς μια. Κλπ ας"
+            ],
+            unicode: "老 汉语中存在 港澳和海外的华人圈中 贵州 我去了书店 现在尚有争",
+            b: "b",
+            c: fn1
+        };
+
+        var diff1 = {
+            a: [
+                "string", null, 0, "1", 1, {
+                    prop: null,
+                    foo: [1,2,null,{}, [], [1,2,3,4]], // different: 4 was add to the array
+                    bar: undefined
+                }, 3, "Hey!", "Κάνε πάντα γνωρίζουμε ας των, μηχανής επιδιόρθωσης επιδιορθώσεις ώς μια. Κλπ ας"
+            ],
+            unicode: "老 汉语中存在 港澳和海外的华人圈中 贵州 我去了书店 现在尚有争",
+            b: "b",
+            c: fn1
+        };
+
+        var diff2 = {
+            a: [
+                "string", null, 0, "1", 1, {
+                    prop: null,
+                    foo: [1,2,null,{}, [], [1,2,3]],
+                    newprop: undefined, // different: newprop was added
+                    bar: undefined
+                }, 3, "Hey!", "Κάνε πάντα γνωρίζουμε ας των, μηχανής επιδιόρθωσης επιδιορθώσεις ώς μια. Κλπ ας"
+            ],
+            unicode: "老 汉语中存在 港澳和海外的华人圈中 贵州 我去了书店 现在尚有争",
+            b: "b",
+            c: fn1
+        };
+
+        var diff3 = {
+            a: [
+                "string", null, 0, "1", 1, {
+                    prop: null,
+                    foo: [1,2,null,{}, [], [1,2,3]],
+                    bar: undefined
+                }, 3, "Hey!", "Κάνε πάντα γνωρίζουμε ας των, μηχανής επιδιόρθωσης επιδιορθώσεις ώς μια. Κλπ α" // different: missing last char
+            ],
+            unicode: "老 汉语中存在 港澳和海外的华人圈中 贵州 我去了书店 现在尚有争",
+            b: "b",
+            c: fn1
+        };
+
+        var diff4 = {
+            a: [
+                "string", null, 0, "1", 1, {
+                    prop: null,
+                    foo: [1,2,undefined,{}, [], [1,2,3]], // different: undefined instead of null
+                    bar: undefined
+                }, 3, "Hey!", "Κάνε πάντα γνωρίζουμε ας των, μηχανής επιδιόρθωσης επιδιορθώσεις ώς μια. Κλπ ας"
+            ],
+            unicode: "老 汉语中存在 港澳和海外的华人圈中 贵州 我去了书店 现在尚有争",
+            b: "b",
+            c: fn1
+        };
+
+        var diff5 = {
+            a: [
+                "string", null, 0, "1", 1, {
+                    prop: null,
+                    foo: [1,2,null,{}, [], [1,2,3]],
+                    bat: undefined // different: property name not "bar"
+                }, 3, "Hey!", "Κάνε πάντα γνωρίζουμε ας των, μηχανής επιδιόρθωσης επιδιορθώσεις ώς μια. Κλπ ας"
+            ],
+            unicode: "老 汉语中存在 港澳和海外的华人圈中 贵州 我去了书店 现在尚有争",
+            b: "b",
+            c: fn1
+        };
+
+        compare(qtest_compareInternal(same1, same2), true);
+        compare(qtest_compareInternal(same2, same1), true);
+        compare(qtest_compareInternal(same2, diff1), false);
+        compare(qtest_compareInternal(diff1, same2), false);
+
+        compare(qtest_compareInternal(same1, diff1), false);
+        compare(qtest_compareInternal(same1, diff2), false);
+        compare(qtest_compareInternal(same1, diff3), false);
+        compare(qtest_compareInternal(same1, diff3), false);
+        compare(qtest_compareInternal(same1, diff4), false);
+        compare(qtest_compareInternal(same1, diff5), false);
+        compare(qtest_compareInternal(diff5, diff1), false);
+    }
+
+
+    function test_complex_arrays() {
+
+        function fn() {
+        }
+
+        compare(qtest_compareInternal(
+                    [1, 2, 3, true, {}, null, [
+                        {
+                            a: ["", '1', 0]
+                        },
+                        5, 6, 7
+                    ], "foo"],
+                    [1, 2, 3, true, {}, null, [
+                        {
+                            a: ["", '1', 0]
+                        },
+                        5, 6, 7
+                    ], "foo"]),
+                true);
+
+        compare(qtest_compareInternal(
+                    [1, 2, 3, true, {}, null, [
+                        {
+                            a: ["", '1', 0]
+                        },
+                        5, 6, 7
+                    ], "foo"],
+                    [1, 2, 3, true, {}, null, [
+                        {
+                            b: ["", '1', 0]         // not same property name
+                        },
+                        5, 6, 7
+                    ], "foo"]),
+                false);
+
+        var a = [{
+            b: fn,
+            c: false,
+            "do": "reserved word",
+            "for": {
+                ar: [3,5,9,"hey!", [], {
+                    ar: [1,[
+                        3,4,6,9, null, [], []
+                    ]],
+                    e: fn,
+                    f: undefined
+                }]
+            },
+            e: 0.43445
+        }, 5, "string", 0, fn, false, null, undefined, 0, [
+            4,5,6,7,8,9,11,22,33,44,55,"66", null, [], [[[[[3]]]], "3"], {}, 1/0
+        ], [], [[[], "foo", null, {
+            n: 1/0,
+            z: {
+                a: [3,4,5,6,"yep!", undefined, undefined],
+                b: {}
+            }
+        }, {}]]];
+
+        compare(qtest_compareInternal(a,
+                [{
+                    b: fn,
+                    c: false,
+                    "do": "reserved word",
+                    "for": {
+                        ar: [3,5,9,"hey!", [], {
+                            ar: [1,[
+                                3,4,6,9, null, [], []
+                            ]],
+                            e: fn,
+                            f: undefined
+                        }]
+                    },
+                    e: 0.43445
+                }, 5, "string", 0, fn, false, null, undefined, 0, [
+                    4,5,6,7,8,9,11,22,33,44,55,"66", null, [], [[[[[3]]]], "3"], {}, 1/0
+                ], [], [[[], "foo", null, {
+                    n: 1/0,
+                    z: {
+                        a: [3,4,5,6,"yep!", undefined, undefined],
+                        b: {}
+                    }
+                }, {}]]]), true);
+
+        compare(qtest_compareInternal(a,
+                [{
+                    b: fn,
+                    c: false,
+                    "do": "reserved word",
+                    "for": {
+                        ar: [3,5,9,"hey!", [], {
+                            ar: [1,[
+                                3,4,6,9, null, [], []
+                            ]],
+                            e: fn,
+                            f: undefined
+                        }]
+                    },
+                    e: 0.43445
+                }, 5, "string", 0, fn, false, null, undefined, 0, [
+                    4,5,6,7,8,9,11,22,33,44,55,"66", null, [], [[[[[2]]]], "3"], {}, 1/0    // different: [[[[[2]]]]] instead of [[[[[3]]]]]
+                ], [], [[[], "foo", null, {
+                    n: 1/0,
+                    z: {
+                        a: [3,4,5,6,"yep!", undefined, undefined],
+                        b: {}
+                    }
+                }, {}]]]), false);
+
+        compare(qtest_compareInternal(a,
+                [{
+                    b: fn,
+                    c: false,
+                    "do": "reserved word",
+                    "for": {
+                        ar: [3,5,9,"hey!", [], {
+                            ar: [1,[
+                                3,4,6,9, null, [], []
+                            ]],
+                            e: fn,
+                            f: undefined
+                        }]
+                    },
+                    e: 0.43445
+                }, 5, "string", 0, fn, false, null, undefined, 0, [
+                    4,5,6,7,8,9,11,22,33,44,55,"66", null, [], [[[[[3]]]], "3"], {}, 1/0
+                ], [], [[[], "foo", null, {
+                    n: -1/0,                                                                // different, -Infinity instead of Infinity
+                    z: {
+                        a: [3,4,5,6,"yep!", undefined, undefined],
+                        b: {}
+                    }
+                }, {}]]]), false);
+
+        compare(qtest_compareInternal(a,
+                [{
+                    b: fn,
+                    c: false,
+                    "do": "reserved word",
+                    "for": {
+                        ar: [3,5,9,"hey!", [], {
+                            ar: [1,[
+                                3,4,6,9, null, [], []
+                            ]],
+                            e: fn,
+                            f: undefined
+                        }]
+                    },
+                    e: 0.43445
+                }, 5, "string", 0, fn, false, null, undefined, 0, [
+                    4,5,6,7,8,9,11,22,33,44,55,"66", null, [], [[[[[3]]]], "3"], {}, 1/0
+                ], [], [[[], "foo", {                                                       // different: null is missing
+                    n: 1/0,
+                    z: {
+                        a: [3,4,5,6,"yep!", undefined, undefined],
+                        b: {}
+                    }
+                }, {}]]]), false);
+
+        compare(qtest_compareInternal(a,
+                [{
+                    b: fn,
+                    c: false,
+                    "do": "reserved word",
+                    "for": {
+                        ar: [3,5,9,"hey!", [], {
+                            ar: [1,[
+                                3,4,6,9, null, [], []
+                            ]],
+                            e: fn
+                                                                                    // different: missing property f: undefined
+                        }]
+                    },
+                    e: 0.43445
+                }, 5, "string", 0, fn, false, null, undefined, 0, [
+                    4,5,6,7,8,9,11,22,33,44,55,"66", null, [], [[[[[3]]]], "3"], {}, 1/0
+                ], [], [[[], "foo", null, {
+                    n: 1/0,
+                    z: {
+                        a: [3,4,5,6,"yep!", undefined, undefined],
+                        b: {}
+                    }
+                }, {}]]]), false);
+    }
+
+
+    function test_prototypal_inheritance() {
+        function Gizmo(id) {
+            this.id = id;
+        }
+
+        function Hoozit(id) {
+            this.id = id;
+        }
+        Hoozit.prototype = new Gizmo();
+
+        var gizmo = new Gizmo("ok");
+        var hoozit = new Hoozit("ok");
+
+        // Try this test many times after test on instances that hold function
+        // to make sure that our code does not mess with last object constructor memoization.
+        compare(qtest_compareInternal(function () {}, function () {}), false);
+
+        // Hoozit inherit from Gizmo
+        // hoozit instanceof Hoozit; // true
+        // hoozit instanceof Gizmo; // true
+        compare(qtest_compareInternal(hoozit, gizmo), true);
+
+        Gizmo.prototype.bar = true; // not a function just in case we skip them
+
+        // Hoozit inherit from Gizmo
+        // They are equivalent
+        compare(qtest_compareInternal(hoozit, gizmo), true);
+
+        // Make sure this is still true !important
+        // The reason for this is that I forgot to reset the last
+        // caller to where it were called from.
+        compare(qtest_compareInternal(function () {}, function () {}), false);
+
+        // Make sure this is still true !important
+        compare(qtest_compareInternal(hoozit, gizmo), true);
+
+        Hoozit.prototype.foo = true; // not a function just in case we skip them
+
+        // Gizmo does not inherit from Hoozit
+        // gizmo instanceof Gizmo; // true
+        // gizmo instanceof Hoozit; // false
+        // They are not equivalent
+        compare(qtest_compareInternal(hoozit, gizmo), false);
+
+        // Make sure this is still true !important
+        compare(qtest_compareInternal(function () {}, function () {}), false);
+    }
+
+
+    function test_instances() {
+        function A() {}
+        var a1 = new A();
+        var a2 = new A();
+
+        function B() {
+            this.fn = function () {};
+        }
+        var b1 = new B();
+        var b2 = new B();
+
+        compare(qtest_compareInternal(a1, a2), true, "Same property, same constructor");
+
+        // b1.fn and b2.fn are functions but they are different references
+        // But we decided to skip function for instances.
+        expectFail("", "Don't know if we want to take over function checking like in QUnit")
+        compare(qtest_compareInternal(b1, b2), true, "Same property, same constructor");
+        compare(qtest_compareInternal(a1, b1), false, "Same properties but different constructor"); // failed
+
+        function Car(year) {
+            var privateVar = 0;
+            this.year = year;
+            this.isOld = function() {
+                return year > 10;
+            };
+        }
+
+        function Human(year) {
+            var privateVar = 1;
+            this.year = year;
+            this.isOld = function() {
+                return year > 80;
+            };
+        }
+
+        var car = new Car(30);
+        var carSame = new Car(30);
+        var carDiff = new Car(10);
+        var human = new Human(30);
+
+        var diff = {
+            year: 30
+        };
+
+        var same = {
+            year: 30,
+            isOld: function () {}
+        };
+
+        compare(qtest_compareInternal(car, car), true);
+        compare(qtest_compareInternal(car, carDiff), false);
+        compare(qtest_compareInternal(car, carSame), true);
+        compare(qtest_compareInternal(car, human), false);
+    }
+
+
+    function test_complex_instances_nesting() {
+    //"Complex Instances Nesting (with function value in literals and/or in nested instances)"
+        function A(fn) {
+            this.a = {};
+            this.fn = fn;
+            this.b = {a: []};
+            this.o = {};
+            this.fn1 = fn;
+        }
+        function B(fn) {
+            this.fn = fn;
+            this.fn1 = function () {};
+            this.a = new A(function () {});
+        }
+
+        function fnOutside() {
+        }
+
+        function C(fn) {
+            function fnInside() {
+            }
+            this.x = 10;
+            this.fn = fn;
+            this.fn1 = function () {};
+            this.fn2 = fnInside;
+            this.fn3 = {
+                a: true,
+                b: fnOutside // ok make reference to a function in all instances scope
+            };
+            this.o1 = {};
+
+            // This function will be ignored.
+            // Even if it is not visible for all instances (e.g. locked in a closures),
+            // it is from a  property that makes part of an instance (e.g. from the C constructor)
+            this.b1 = new B(function () {});
+            this.b2 = new B({
+                x: {
+                    b2: new B(function() {})
+                }
+            });
+        }
+
+        function D(fn) {
+            function fnInside() {
+            }
+            this.x = 10;
+            this.fn = fn;
+            this.fn1 = function () {};
+            this.fn2 = fnInside;
+            this.fn3 = {
+                a: true,
+                b: fnOutside, // ok make reference to a function in all instances scope
+
+                // This function won't be ingored.
+                // It isn't visible for all C insances
+                // and it is not in a property of an instance. (in an Object instances e.g. the object literal)
+                c: fnInside
+            };
+            this.o1 = {};
+
+            // This function will be ignored.
+            // Even if it is not visible for all instances (e.g. locked in a closures),
+            // it is from a  property that makes part of an instance (e.g. from the C constructor)
+            this.b1 = new B(function () {});
+            this.b2 = new B({
+                x: {
+                    b2: new B(function() {})
+                }
+            });
+        }
+
+        function E(fn) {
+            function fnInside() {
+            }
+            this.x = 10;
+            this.fn = fn;
+            this.fn1 = function () {};
+            this.fn2 = fnInside;
+            this.fn3 = {
+                a: true,
+                b: fnOutside // ok make reference to a function in all instances scope
+            };
+            this.o1 = {};
+
+            // This function will be ignored.
+            // Even if it is not visible for all instances (e.g. locked in a closures),
+            // it is from a  property that makes part of an instance (e.g. from the C constructor)
+            this.b1 = new B(function () {});
+            this.b2 = new B({
+                x: {
+                    b1: new B({a: function() {}}),
+                    b2: new B(function() {})
+                }
+            });
+        }
+
+
+        var a1 = new A(function () {});
+        var a2 = new A(function () {});
+        expectFail("", "Don't know if we want to take over function checking like in QUnit")
+        compare(qtest_compareInternal(a1, a2), true);
+
+        compare(qtest_compareInternal(a1, a2), true); // different instances
+
+        var b1 = new B(function () {});
+        var b2 = new B(function () {});
+        compare(qtest_compareInternal(a1, a2), true);
+
+        var c1 = new C(function () {});
+        var c2 = new C(function () {});
+        compare(qtest_compareInternal(c1, c2), true);
+
+        var d1 = new D(function () {});
+        var d2 = new D(function () {});
+        compare(qtest_compareInternal(d1, d2), false);
+
+        var e1 = new E(function () {});
+        var e2 = new E(function () {});
+        compare(qtest_compareInternal(e1, e2), false);
+
+    }
+}
diff --git a/tests/auto/qmltest/selftests/tst_compare_quickobjects.qml b/tests/auto/qmltest/selftests/tst_compare_quickobjects.qml
new file mode 100644 (file)
index 0000000..7a8dc74
--- /dev/null
@@ -0,0 +1,81 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 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$
+**
+****************************************************************************/
+
+import QtQuick 2.0
+import QtTest 1.0
+
+TestCase {
+    name: "SelfTests_compare_QuickObjects"
+    id: testParent
+
+    Rectangle {
+        id: item1
+        color: "#000000"
+    }
+    Rectangle {
+        id: item2
+        color: "#000000"
+    }
+    Rectangle {
+        id: item3
+        color: "#ffffff"
+    }
+
+    Component {
+        id: item4
+
+        Rectangle {
+            color: "#ffffff"
+        }
+    }
+
+    function test_quickobjects() {
+        compare(qtest_compareInternal(item1, item1), true, "Identical QtQuick instances");
+        compare(qtest_compareInternal(item1, item3), false, "QtQuick instances with different properties");
+
+        expectFail("", "Unsure if we want this.");
+        compare(qtest_compareInternal(item1, item2), true, "QtQuick instances with same properties");
+
+        expectFail("", "Unsure if we want this.");
+        compare(qtest_compareInternal(item4.createObject(testParent),
+                                      item4.createObject(testParent)), true, "QtQuick dynamic instances");
+    }
+}
diff --git a/tests/auto/qmltest/selftests/tst_selftests.qml b/tests/auto/qmltest/selftests/tst_selftests.qml
new file mode 100644 (file)
index 0000000..16a539e
--- /dev/null
@@ -0,0 +1,307 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 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$
+**
+****************************************************************************/
+
+import QtQuick 2.0
+import QtTest 1.0
+
+TestCase {
+    name: "SelfTests"
+
+    // Replace the TestResult functions in "testCase" with hooks
+    // that record the events but don't send them to QTestLib.
+    QtObject {
+        id: functions
+        property string failmsg: "cleaned"
+        property string actual: ""
+        property string expected: ""
+        property variant functionsToRun: []
+
+        function fail(msg, file, line) {
+            failmsg = msg
+        }
+
+        function verify(cond, msg, file, line) {
+            if (cond) {
+                failmsg = "verify-ok"
+                return true
+            } else {
+                failmsg = msg
+                return false
+            }
+        }
+
+        function compare(success, msg, act, exp, file, line) {
+            if (success) {
+                failmsg = "compare-ok"
+                actual = ""
+                expected = ""
+                return true
+            } else {
+                failmsg = msg
+                actual = act
+                expected = exp
+                return false
+            }
+        }
+
+        function skipSingle(msg, file, line) {
+            failmsg = "skipSingle:" + msg
+        }
+
+        function skipAll(msg, file, line) {
+            failmsg = "skipAll:" + msg
+        }
+    }
+
+    TestCase {
+        id: testCase
+        when: false
+        optional: true
+        qtest_results: functions
+    }
+
+    function init() {
+        compare(functions.failmsg, "cleaned") // Checks for previous cleanup()
+        functions.failmsg = "invalid"
+    }
+
+    function cleanup() {
+        functions.failmsg = "cleaned"
+    }
+
+    function test_fail() {
+        compare(functions.failmsg, "invalid") // Checks that init() was run
+
+        var caught = false
+        try {
+            testCase.fail("foo")
+        } catch (e) {
+            compare(e.message, "QtQuickTest::fail")
+            compare(functions.failmsg, "foo")
+            caught = true
+        }
+        verify(caught)
+
+        caught = false
+        try {
+            testCase.fail()
+        } catch (e) {
+            compare(e.message, "QtQuickTest::fail")
+            compare(functions.failmsg, "")
+            caught = true
+        }
+        verify(caught)
+
+        caught = false
+        try {
+            testCase.fail(false)
+        } catch (e) {
+            compare(e.message, "QtQuickTest::fail")
+            compare(functions.failmsg, "false")
+            caught = true
+        }
+        verify(caught)
+
+        caught = false
+        try {
+            testCase.fail(3)
+        } catch (e) {
+            compare(e.message, "QtQuickTest::fail")
+            compare(functions.failmsg, "3")
+            caught = true
+        }
+        verify(caught)
+    }
+
+    function test_verify() {
+        compare(functions.failmsg, "invalid") // Checks that init() was run
+
+        try {
+            testCase.verify(true)
+        } catch (e) {
+            fail("verify(true) did not succeed")
+        }
+        compare(functions.failmsg, "verify-ok")
+
+        var caught = false;
+        try {
+            testCase.verify(false, "foo")
+        } catch (e) {
+            compare(e.message, "QtQuickTest::fail")
+            compare(functions.failmsg, "foo")
+            caught = true
+        }
+        verify(caught)
+
+        caught = false;
+        try {
+            testCase.verify(false)
+        } catch (e) {
+            compare(e.message, "QtQuickTest::fail")
+            compare(functions.failmsg, "")
+            caught = true
+        }
+        verify(caught)
+    }
+
+    function test_compare() {
+        compare(functions.failmsg, "invalid") // Checks that init() was run
+
+        try {
+            testCase.compare(23, 23)
+        } catch (e) {
+            fail("compare(23, 23) did not succeed")
+        }
+        compare(functions.failmsg, "compare-ok")
+
+        var caught = false;
+        try {
+            testCase.compare(23, 42, "foo")
+        } catch (e) {
+            compare(e.message, "QtQuickTest::fail")
+            compare(functions.failmsg, "foo")
+            compare(functions.actual, "23")
+            compare(functions.expected, "42")
+            caught = true
+        }
+        verify(caught)
+
+        caught = false;
+        try {
+            testCase.compare("abcdef", 42)
+        } catch (e) {
+            compare(e.message, "QtQuickTest::fail")
+            compare(functions.failmsg, "Compared values are not the same")
+            compare(functions.actual, "abcdef")
+            compare(functions.expected, "42")
+            caught = true
+        }
+        verify(caught)
+
+        caught = false;
+        try {
+            testCase.compare(Qt.vector3d(1, 2, 3), Qt.vector3d(-1, 2, 3), "x")
+        } catch (e) {
+            compare(e.message, "QtQuickTest::fail")
+            compare(functions.failmsg, "x")
+            compare(functions.actual, "Qt.vector3d(1, 2, 3)")
+            compare(functions.expected, "Qt.vector3d(-1, 2, 3)")
+            caught = true
+        }
+        verify(caught)
+
+        caught = false;
+        try {
+            testCase.compare(Qt.vector3d(1, 2, 3), Qt.vector3d(1, -2, 3), "y")
+        } catch (e) {
+            compare(e.message, "QtQuickTest::fail")
+            compare(functions.failmsg, "y")
+            compare(functions.actual, "Qt.vector3d(1, 2, 3)")
+            compare(functions.expected, "Qt.vector3d(1, -2, 3)")
+            caught = true
+        }
+        verify(caught)
+
+        caught = false;
+        try {
+            testCase.compare(Qt.vector3d(1, 2, 3), Qt.vector3d(1, 2, -3), "z")
+        } catch (e) {
+            compare(e.message, "QtQuickTest::fail")
+            compare(functions.failmsg, "z")
+            compare(functions.actual, "Qt.vector3d(1, 2, 3)")
+            compare(functions.expected, "Qt.vector3d(1, 2, -3)")
+            caught = true
+        }
+        verify(caught)
+
+        caught = false;
+        try {
+            testCase.compare(Qt.vector3d(1, 2, 3), Qt.vector3d(1, 2, 3))
+        } catch (e) {
+            fail("vector compare did not succeed")
+        }
+        compare(functions.failmsg, "compare-ok")
+    }
+
+    function test_skip() {
+        compare(functions.failmsg, "invalid") // Checks that init() was run
+
+        var caught = false
+        try {
+            testCase.skip("foo")
+        } catch (e) {
+            compare(e.message, "QtQuickTest::skip")
+            compare(functions.failmsg, "skipSingle:foo")
+            caught = true
+        }
+        verify(caught)
+
+        caught = false
+        try {
+            testCase.skip()
+        } catch (e) {
+            compare(e.message, "QtQuickTest::skip")
+            compare(functions.failmsg, "skipSingle:")
+            caught = true
+        }
+        verify(caught)
+
+        caught = false
+        try {
+            testCase.skipAll("foo")
+        } catch (e) {
+            compare(e.message, "QtQuickTest::skip")
+            compare(functions.failmsg, "skipAll:foo")
+            caught = true
+        }
+        verify(caught)
+
+        caught = false
+        try {
+            testCase.skipAll()
+        } catch (e) {
+            compare(e.message, "QtQuickTest::skip")
+            compare(functions.failmsg, "skipAll:")
+            caught = true
+        }
+        verify(caught)
+    }
+}
diff --git a/tests/auto/qmltest/tst_qmltest.cpp b/tests/auto/qmltest/tst_qmltest.cpp
new file mode 100644 (file)
index 0000000..37d47ac
--- /dev/null
@@ -0,0 +1,43 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 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 <QtQuickTest/quicktest.h>
+QUICK_TEST_MAIN(qmlauto)
diff --git a/tools/qmltestrunner/main.cpp b/tools/qmltestrunner/main.cpp
new file mode 100644 (file)
index 0000000..47f34ee
--- /dev/null
@@ -0,0 +1,75 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 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 <QtQuickTest/quicktest.h>
+#include <QtCore/qstring.h>
+#ifdef QT_OPENGL_LIB
+#include <QtOpenGL/qgl.h>
+#endif
+
+#ifdef QT_OPENGL_LIB
+
+static QWidget *qmltestrunner_create_gl_viewport()
+{
+    return new QGLWidget();
+}
+
+#endif
+
+int main(int argc, char **argv)
+{
+#ifdef QT_OPENGL_LIB
+    bool isOpenGL = false;
+    for (int index = 1; index < argc; ++index) {
+        if (strcmp(argv[index], "-opengl") == 0) {
+            isOpenGL = true;
+            break;
+        }
+    }
+    if (isOpenGL) {
+        return quick_test_main(argc, argv, "qmltestrunner",
+                               qmltestrunner_create_gl_viewport, ".");
+    } else
+#endif
+    {
+        return quick_test_main(argc, argv, "qmltestrunner", 0, ".");
+    }
+}
diff --git a/tools/qmltestrunner/qmltestrunner.pro b/tools/qmltestrunner/qmltestrunner.pro
new file mode 100644 (file)
index 0000000..b2aabf6
--- /dev/null
@@ -0,0 +1,11 @@
+TEMPLATE = app
+TARGET = qmltestrunner
+CONFIG += warn_on qmltestcase
+SOURCES += main.cpp
+
+contains(QT_CONFIG, opengl)|contains(QT_CONFIG, opengles1)|contains(QT_CONFIG, opengles2) {
+    QT += opengl
+}
+
+target.path = $$[QT_INSTALL_BINS]
+INSTALLS += target
index ec83a1e..b1a896b 100644 (file)
@@ -1,2 +1,4 @@
 TEMPLATE = subdirs
 SUBDIRS +=  qmlviewer qmlscene qmlplugindump
+contains(QT_CONFIG, quicktest): SUBDIRS += qmltestrunner
+