From decc287134139c61da5610afc060a6ca8d09f368 Mon Sep 17 00:00:00 2001 From: Richard Moe Gustavsen Date: Tue, 4 Aug 2009 15:59:25 +0200 Subject: Cocoa: Menus show old selected values. We never told Cocoa that it needed to redraw the window view when a window was shown. This is implicit if the window is shown for the first time, but needs to be done explicit if you hide and show it again. Task-number: 254672 Reviewed-by: bnilsen --- src/gui/kernel/qwidget_mac.mm | 6 ++++++ tests/auto/qwidget_window/tst_qwidget_window.cpp | 24 +++++++++++++++++++++++- 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/src/gui/kernel/qwidget_mac.mm b/src/gui/kernel/qwidget_mac.mm index 8913c89..057df81 100644 --- a/src/gui/kernel/qwidget_mac.mm +++ b/src/gui/kernel/qwidget_mac.mm @@ -3249,6 +3249,12 @@ void QWidgetPrivate::show_sys() #ifndef QT_MAC_USE_COCOA SizeWindow(window, q->width(), q->height(), true); #endif + +#ifdef QT_MAC_USE_COCOA + // Make sure that we end up sending a repaint event to + // the widget if the window has been visible one before: + [qt_mac_get_contentview_for(window) setNeedsDisplay:YES]; +#endif if(qt_mac_is_macsheet(q)) { qt_event_request_showsheet(q); } else if(qt_mac_is_macdrawer(q)) { diff --git a/tests/auto/qwidget_window/tst_qwidget_window.cpp b/tests/auto/qwidget_window/tst_qwidget_window.cpp index f059abe..6dddfe8 100644 --- a/tests/auto/qwidget_window/tst_qwidget_window.cpp +++ b/tests/auto/qwidget_window/tst_qwidget_window.cpp @@ -78,6 +78,7 @@ private slots: void tst_windowFilePath(); void tst_showWithoutActivating(); + void tst_paintEventOnSecondShow(); }; void tst_QWidget_window::initTestCase() @@ -150,7 +151,9 @@ class TestWidget : public QWidget { public: int m_first, m_next; - void reset(){ m_first = m_next = 0; } + bool paintEventReceived; + + void reset(){ m_first = m_next = 0; paintEventReceived = false; } bool event(QEvent *event) { switch (event->type()) { @@ -162,6 +165,10 @@ public: m_next = event->type(); else m_first = event->type(); + break; + case QEvent::Paint: + paintEventReceived = true; + break; default: break; } @@ -300,5 +307,20 @@ void tst_QWidget_window::tst_showWithoutActivating() #endif // Q_WS_X11 } +void tst_QWidget_window::tst_paintEventOnSecondShow() +{ + TestWidget w; + w.show(); + w.hide(); + + w.reset(); + w.show(); +#ifdef Q_WS_X11 + QTest::qWait(500); +#endif + QApplication::processEvents(); + QVERIFY(w.paintEventReceived); +} + QTEST_MAIN(tst_QWidget_window) #include "tst_qwidget_window.moc" -- cgit v0.12 From 118c82b0988c671045de448ffabc7ba95f015a69 Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Wed, 5 Aug 2009 10:42:46 +0200 Subject: Fixes hangup when pressing key in QListWidget If there is severals matching items but all of them are disabled, it would have produced an infinite loop. Block the loop once we reach an already matched item. Task-number: 258949 Reviewed-by: Thierry --- src/gui/itemviews/qabstractitemview.cpp | 7 +++++++ tests/auto/qlistwidget/tst_qlistwidget.cpp | 23 ++++++++++++++++++++++- 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/src/gui/itemviews/qabstractitemview.cpp b/src/gui/itemviews/qabstractitemview.cpp index 8594968..f7d5f1b 100644 --- a/src/gui/itemviews/qabstractitemview.cpp +++ b/src/gui/itemviews/qabstractitemview.cpp @@ -2666,6 +2666,7 @@ void QAbstractItemView::keyboardSearch(const QString &search) QModelIndex current = start; QModelIndexList match; QModelIndex firstMatch; + QModelIndex startMatch; QModelIndexList previous; do { match = d->model->match(current, Qt::DisplayRole, searchString); @@ -2682,6 +2683,12 @@ void QAbstractItemView::keyboardSearch(const QString &search) if (row >= d->model->rowCount(firstMatch.parent())) row = 0; current = firstMatch.sibling(row, firstMatch.column()); + + //avoid infinite loop if all the matching items are disabled. + if (!startMatch.isValid()) + startMatch = firstMatch; + else if (startMatch == firstMatch) + break; } } while (current != start && firstMatch.isValid()); } diff --git a/tests/auto/qlistwidget/tst_qlistwidget.cpp b/tests/auto/qlistwidget/tst_qlistwidget.cpp index a56a470..e38ef20 100644 --- a/tests/auto/qlistwidget/tst_qlistwidget.cpp +++ b/tests/auto/qlistwidget/tst_qlistwidget.cpp @@ -128,6 +128,8 @@ private slots: void setSortingEnabled(); void task199503_crashWhenCleared(); void task217070_scrollbarsAdjusted(); + void task258949_keypressHangup(); + protected slots: void rowsAboutToBeInserted(const QModelIndex &parent, int first, int last) @@ -994,7 +996,7 @@ void tst_QListWidget::sortHiddenItems() for (int k = 0; k < tw->count(); ++k) QCOMPARE(persistent.at(k).row(), expectedRows.at(k)); - + delete tw; } @@ -1498,5 +1500,24 @@ void tst_QListWidget::task217070_scrollbarsAdjusted() } } +void tst_QListWidget::task258949_keypressHangup() +{ + QListWidget lw; + for (int y = 0; y < 5; y++) { + QListWidgetItem *lwi = new QListWidgetItem(&lw); + lwi->setText(y ? "1" : "0"); + if (y) + lwi->setFlags(Qt::ItemIsSelectable); + } + + lw.show(); + lw.setCurrentIndex(lw.model()->index(0,0)); + QCOMPARE(lw.currentIndex(), lw.model()->index(0,0)); + QTest::qWait(30); + QTest::keyPress(&lw, '1'); //this used to freeze + QTest::qWait(30); + QCOMPARE(lw.currentIndex(), lw.model()->index(0,0)); +} + QTEST_MAIN(tst_QListWidget) #include "tst_qlistwidget.moc" -- cgit v0.12 From 5f52d473eec0f1b46200b06dd7f5e16cb5c57c05 Mon Sep 17 00:00:00 2001 From: Markus Goetz Date: Wed, 5 Aug 2009 10:57:13 +0200 Subject: Fix compilation when QT_NO_HTTP is defined Note however you still need to -nomake examples -nomake demos when configuring Qt. Reviewed-by: Thiago Task: 259179 --- src/network/access/qhttpnetworkheader.cpp | 3 +++ src/network/access/qhttpnetworkreply_p.h | 1 + src/network/access/qhttpnetworkrequest.cpp | 4 ++++ src/qt3support/network/q3http.cpp | 2 +- src/qt3support/network/q3http.h | 5 ++--- src/qt3support/network/q3network.cpp | 2 +- tools/assistant/tools/assistant/installdialog.cpp | 2 ++ tools/assistant/tools/assistant/installdialog.h | 4 ++++ 8 files changed, 18 insertions(+), 5 deletions(-) diff --git a/src/network/access/qhttpnetworkheader.cpp b/src/network/access/qhttpnetworkheader.cpp index 5af9764..88cc484 100644 --- a/src/network/access/qhttpnetworkheader.cpp +++ b/src/network/access/qhttpnetworkheader.cpp @@ -41,6 +41,7 @@ #include "qhttpnetworkheader_p.h" +#ifndef QT_NO_HTTP QT_BEGIN_NAMESPACE @@ -121,3 +122,5 @@ bool QHttpNetworkHeaderPrivate::operator==(const QHttpNetworkHeaderPrivate &othe QT_END_NAMESPACE + +#endif diff --git a/src/network/access/qhttpnetworkreply_p.h b/src/network/access/qhttpnetworkreply_p.h index 76aa947..65ed4ce 100644 --- a/src/network/access/qhttpnetworkreply_p.h +++ b/src/network/access/qhttpnetworkreply_p.h @@ -52,6 +52,7 @@ // // We mean it. // +#include #ifndef QT_NO_HTTP #ifndef QT_NO_COMPRESS diff --git a/src/network/access/qhttpnetworkrequest.cpp b/src/network/access/qhttpnetworkrequest.cpp index 02ba629..32d51f3 100644 --- a/src/network/access/qhttpnetworkrequest.cpp +++ b/src/network/access/qhttpnetworkrequest.cpp @@ -41,6 +41,8 @@ #include "qhttpnetworkrequest_p.h" +#ifndef QT_NO_HTTP + QT_BEGIN_NAMESPACE QHttpNetworkRequestPrivate::QHttpNetworkRequestPrivate(QHttpNetworkRequest::Operation op, @@ -259,3 +261,5 @@ int QHttpNetworkRequest::minorVersion() const QT_END_NAMESPACE +#endif + diff --git a/src/qt3support/network/q3http.cpp b/src/qt3support/network/q3http.cpp index a38edad..e44dfe8 100644 --- a/src/qt3support/network/q3http.cpp +++ b/src/qt3support/network/q3http.cpp @@ -42,7 +42,7 @@ #include #include "q3http.h" -#ifndef QT_NO_NETWORKPROTOCOL_HTTP +#ifndef QT_NO_HTTP #include "q3socket.h" #include "qtextstream.h" diff --git a/src/qt3support/network/q3http.h b/src/qt3support/network/q3http.h index 93ab00e..5311764 100644 --- a/src/qt3support/network/q3http.h +++ b/src/qt3support/network/q3http.h @@ -52,8 +52,7 @@ QT_BEGIN_HEADER QT_BEGIN_NAMESPACE QT_MODULE(Qt3Support) - -#ifndef QT_NO_NETWORKPROTOCOL_HTTP +#ifndef QT_NO_HTTP class Q3Socket; class QTimerEvent; @@ -269,7 +268,7 @@ private: friend class Q3HttpPGHRequest; }; -#endif // QT_NO_NETWORKPROTOCOL_HTTP +#endif // QT_NO_HTTP QT_END_NAMESPACE diff --git a/src/qt3support/network/q3network.cpp b/src/qt3support/network/q3network.cpp index 3a6a6f0..1f918d1 100644 --- a/src/qt3support/network/q3network.cpp +++ b/src/qt3support/network/q3network.cpp @@ -63,7 +63,7 @@ void q3InitNetworkProtocols() #ifndef QT_NO_NETWORKPROTOCOL_FTP Q3NetworkProtocol::registerNetworkProtocol( QLatin1String("ftp"), new Q3NetworkProtocolFactory< Q3Ftp > ); #endif -#ifndef QT_NO_NETWORKPROTOCOL_HTTP +#ifndef QT_NO_HTTP Q3NetworkProtocol::registerNetworkProtocol( QLatin1String("http"), new Q3NetworkProtocolFactory< Q3Http > ); #endif } diff --git a/tools/assistant/tools/assistant/installdialog.cpp b/tools/assistant/tools/assistant/installdialog.cpp index 5a8dfea..2574f1f 100644 --- a/tools/assistant/tools/assistant/installdialog.cpp +++ b/tools/assistant/tools/assistant/installdialog.cpp @@ -56,6 +56,7 @@ #include QT_BEGIN_NAMESPACE +#ifndef QT_NO_HTTP #define QCH_FILENAME 92943 #define QCH_NAMESPACE 92944 @@ -335,4 +336,5 @@ void InstallDialog::browseDirectories() m_ui.pathLineEdit->setText(dir); } +#endif QT_END_NAMESPACE diff --git a/tools/assistant/tools/assistant/installdialog.h b/tools/assistant/tools/assistant/installdialog.h index 62759ec..9e18a22b9 100644 --- a/tools/assistant/tools/assistant/installdialog.h +++ b/tools/assistant/tools/assistant/installdialog.h @@ -47,6 +47,8 @@ #include #include "ui_installdialog.h" +#ifndef QT_NO_HTTP + QT_BEGIN_NAMESPACE class QHttp; @@ -98,4 +100,6 @@ private: QT_END_NAMESPACE +#endif + #endif // INSTALLDIALOG_H -- cgit v0.12 From cb599c5ea32e8e5ff81318038b432272f107b1fe Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Thu, 30 Jul 2009 12:58:06 +0200 Subject: Fix compilation on AIX: -I/usr/include cannot be used. The reason is that the C++ compiler needs to add -I/usr/vacpp/include before -I/usr/include, so our adding of -I/usr/include changes the order. This causes a compilation error in the C++ header xlocinfo.h. In any case, these checks done in qmake are unnecessary. If the OpenSSL headers are in one of those include paths, they will be found on their own already. Reviewed-By: Bradley T. Hughes (cherry picked from commit 04f7834fcd8db4ecb6a4c53de42ac83f571b37c8) --- config.tests/unix/openssl/openssl.pri | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/config.tests/unix/openssl/openssl.pri b/config.tests/unix/openssl/openssl.pri index bc95479..f069396 100644 --- a/config.tests/unix/openssl/openssl.pri +++ b/config.tests/unix/openssl/openssl.pri @@ -1,9 +1,3 @@ -!cross_compile { - TRY_INCLUDEPATHS = /include /usr/include /usr/local/include $$QMAKE_INCDIR $$INCLUDEPATH - # LSB doesn't allow using headers from /include or /usr/include - linux-lsb-g++:TRY_INCLUDEPATHS = $$QMAKE_INCDIR $$INCLUDEPATH - for(p, TRY_INCLUDEPATHS) { - pp = $$join(p, "", "", "/openssl") - exists($$pp):INCLUDEPATH *= $$p - } -} +# Empty file since Qt 4.6 +# I'm too lazy to find all places where this file is included + -- cgit v0.12 From 90480b9a25568858d1383e0aab6f5708a7dabd4f Mon Sep 17 00:00:00 2001 From: Alexis Menard Date: Wed, 5 Aug 2009 13:19:29 +0200 Subject: Fix a bug when activating HideNameFilterDetails on Windows filedialog. The HideNameFilterDetails was not taken in account for windows file dialog. This patch fix that. For Windows Vista and later we use now the new COMMON_ITEM_DIALOG API (in master) where it add always the filter extension like *.txt so no point to take that flag in account. Task-number: None, during testing Reviewed-by: prasanth --- src/gui/dialogs/qfiledialog.cpp | 2 +- src/gui/dialogs/qfiledialog_win.cpp | 28 ++++++++++++++++++---------- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/src/gui/dialogs/qfiledialog.cpp b/src/gui/dialogs/qfiledialog.cpp index c8ce162..6977731 100644 --- a/src/gui/dialogs/qfiledialog.cpp +++ b/src/gui/dialogs/qfiledialog.cpp @@ -219,7 +219,7 @@ Q_GUI_EXPORT _qt_filedialog_save_filename_hook qt_filedialog_save_filename_hook the native file dialog is used unless you use a subclass of QFileDialog that contains the Q_OBJECT macro. \value ReadOnly Indicates that the model is readonly. - \value HideNameFilterDetails Indicates if the is hidden or not. + \value HideNameFilterDetails Indicates if the filter extension (e.g. *.bmp) is hidden or not. This value is obsolete and does nothing since Qt 4.5: diff --git a/src/gui/dialogs/qfiledialog_win.cpp b/src/gui/dialogs/qfiledialog_win.cpp index 9a478aa..37a25e5 100644 --- a/src/gui/dialogs/qfiledialog_win.cpp +++ b/src/gui/dialogs/qfiledialog_win.cpp @@ -163,15 +163,22 @@ static QStringList qt_win_make_filters_list(const QString &filter) } // Makes a NUL-oriented Windows filter from a Qt filter. -static QString qt_win_filter(const QString &filter) +static QString qt_win_filter(const QString &filter, bool hideFiltersDetails) { QStringList filterLst = qt_win_make_filters_list(filter); QStringList::Iterator it = filterLst.begin(); QString winfilters; + QRegExp r(QString::fromLatin1(qt_file_dialog_filter_reg_exp)); for (; it != filterLst.end(); ++it) { QString subfilter = *it; if (!subfilter.isEmpty()) { - winfilters += subfilter; + if (hideFiltersDetails) { + int index = r.indexIn(subfilter); + if (index >= 0) + winfilters += r.cap(1); + } else { + winfilters += subfilter; + } winfilters += QChar(); winfilters += qt_win_extract_filter(subfilter); winfilters += QChar(); @@ -377,11 +384,12 @@ QString qt_win_get_open_file_name(const QFileDialogArgs &args, modal_widget.setAttribute(Qt::WA_NoChildEventsForParent, true); modal_widget.setParent(args.parent, Qt::Window); QApplicationPrivate::enterModal(&modal_widget); + bool hideFiltersDetails = args.options & QFileDialog::HideNameFilterDetails; QT_WA({ // Use Unicode strings and API OPENFILENAME* ofn = qt_win_make_OFN(args.parent, args.selection, args.directory, args.caption, - qt_win_filter(args.filter), + qt_win_filter(args.filter, hideFiltersDetails), QFileDialog::ExistingFile, args.options); if (idx) @@ -395,7 +403,7 @@ QString qt_win_get_open_file_name(const QFileDialogArgs &args, // Use ANSI strings and API OPENFILENAMEA* ofn = qt_win_make_OFNA(args.parent, args.selection, args.directory, args.caption, - qt_win_filter(args.filter), + qt_win_filter(args.filter, hideFiltersDetails), QFileDialog::ExistingFile, args.options); if (idx) @@ -452,7 +460,7 @@ QString qt_win_get_save_file_name(const QFileDialogArgs &args, modal_widget.setAttribute(Qt::WA_NoChildEventsForParent, true); modal_widget.setParent(args.parent, Qt::Window); QApplicationPrivate::enterModal(&modal_widget); - + bool hideFiltersDetails = args.options & QFileDialog::HideNameFilterDetails; // This block is used below for the lpstrDefExt member. // Note that the current MSDN docs document this member wrong. // It should rather be documented as "the default extension if no extension was given and if the @@ -469,12 +477,11 @@ QString qt_win_get_save_file_name(const QFileDialogArgs &args, defaultSaveExt.clear(); } } - QT_WA({ // Use Unicode strings and API OPENFILENAME *ofn = qt_win_make_OFN(args.parent, args.selection, args.directory, args.caption, - qt_win_filter(args.filter), + qt_win_filter(args.filter, hideFiltersDetails), QFileDialog::AnyFile, args.options); @@ -491,7 +498,7 @@ QString qt_win_get_save_file_name(const QFileDialogArgs &args, // Use ANSI strings and API OPENFILENAMEA *ofn = qt_win_make_OFNA(args.parent, args.selection, args.directory, args.caption, - qt_win_filter(args.filter), + qt_win_filter(args.filter, hideFiltersDetails), QFileDialog::AnyFile, args.options); QByteArray asciiExt = defaultSaveExt.toAscii(); @@ -558,10 +565,11 @@ QStringList qt_win_get_open_file_names(const QFileDialogArgs &args, modal_widget.setAttribute(Qt::WA_NoChildEventsForParent, true); modal_widget.setParent(args.parent, Qt::Window); QApplicationPrivate::enterModal(&modal_widget); + bool hideFiltersDetails = args.options & QFileDialog::HideNameFilterDetails; QT_WA({ OPENFILENAME* ofn = qt_win_make_OFN(args.parent, args.selection, args.directory, args.caption, - qt_win_filter(args.filter), + qt_win_filter(args.filter, hideFiltersDetails), QFileDialog::ExistingFiles, args.options); if (idx) @@ -594,7 +602,7 @@ QStringList qt_win_get_open_file_names(const QFileDialogArgs &args, } , { OPENFILENAMEA* ofn = qt_win_make_OFNA(args.parent, args.selection, args.directory, args.caption, - qt_win_filter(args.filter), + qt_win_filter(args.filter, hideFiltersDetails), QFileDialog::ExistingFiles, args.options); if (idx) -- cgit v0.12 From 56b349951a70f3ab95e334e41e37f017e91cf481 Mon Sep 17 00:00:00 2001 From: Rohan McGovern Date: Thu, 6 Aug 2009 11:04:23 +1000 Subject: Cleaned up test naming and platform-specific tests. When an autotest fails to compile, there's no way to determine which testcase(s) have been prevented from running. Our results parsing tools have been guessing, under the assumption that a directory called `qdogwalker' always contains a testcase named `tst_qdogwalker'. That wasn't true for all our tests, so let's make it true. Also changed the platform-specific tests so that qmake will simply skip those tests on unsupported platforms, instead of wasting time compiling a useless QTEST_NOOP_MAIN test. --- tests/auto/_networkselftest/_networkselftest.pro | 6 - .../auto/_networkselftest/tst_networkselftest.cpp | 586 ----- tests/auto/auto.pro | 7 +- tests/auto/macgui/macgui.pro | 10 +- tests/auto/macgui/tst_gui.cpp | 277 -- tests/auto/macgui/tst_macgui.cpp | 278 ++ tests/auto/networkselftest/networkselftest.pro | 6 + tests/auto/networkselftest/tst_networkselftest.cpp | 586 +++++ .../auto/qaccessibility_mac/qaccessibility_mac.pro | 23 +- .../qaccessibility_mac/tst_qaccessibility_mac.cpp | 64 +- tests/auto/qcopchannel/qcopchannel.pro | 1 + tests/auto/qcopchannel/test/test.pro | 8 - tests/auto/qcopchannel/testSend/testSend.pro | 1 + tests/auto/qcssparser/qcssparser.pro | 2 +- tests/auto/qcssparser/tst_cssparser.cpp | 1616 ------------ tests/auto/qcssparser/tst_qcssparser.cpp | 1617 ++++++++++++ tests/auto/qdbuspendingcall/qdbuspendingcall.pro | 5 +- tests/auto/qdbuspendingreply/qdbuspendingreply.pro | 4 +- tests/auto/qdirectpainter/qdirectpainter.pro | 4 +- .../runDirectPainter/runDirectPainter.pro | 1 + tests/auto/qdirectpainter/test/test.pro | 9 +- tests/auto/qicoimageformat/qicoimageformat.pro | 2 +- tests/auto/qicoimageformat/tst_qicoimageformat.cpp | 299 +++ .../auto/qicoimageformat/tst_qticoimageformat.cpp | 298 --- tests/auto/qmultiscreen/qmultiscreen.pro | 2 +- tests/auto/qpointarray/.gitignore | 1 - tests/auto/qpointarray/qpointarray.pro | 6 - tests/auto/qpointarray/tst_qpointarray.cpp | 95 - tests/auto/qpolygon/.gitignore | 1 + tests/auto/qpolygon/qpolygon.pro | 6 + tests/auto/qpolygon/tst_qpolygon.cpp | 95 + tests/auto/qresourceengine/qresourceengine.pro | 2 +- tests/auto/qresourceengine/tst_qresourceengine.cpp | 462 ++++ tests/auto/qresourceengine/tst_resourceengine.cpp | 461 ---- tests/auto/qscriptextqobject/.gitignore | 1 + tests/auto/qscriptextqobject/qscriptextqobject.pro | 5 + .../qscriptextqobject/tst_qscriptextqobject.cpp | 2734 ++++++++++++++++++++ .../qscriptjstestsuite/tst_qscriptjstestsuite.cpp | 9 +- tests/auto/qscriptqobject/.gitignore | 1 - tests/auto/qscriptqobject/qscriptqobject.pro | 5 - tests/auto/qscriptqobject/tst_qscriptqobject.cpp | 2734 -------------------- .../qscriptv8testsuite/tst_qscriptv8testsuite.cpp | 7 +- .../qtextscriptengine/tst_qtextscriptengine.cpp | 36 +- 43 files changed, 6183 insertions(+), 6190 deletions(-) delete mode 100644 tests/auto/_networkselftest/_networkselftest.pro delete mode 100644 tests/auto/_networkselftest/tst_networkselftest.cpp delete mode 100644 tests/auto/macgui/tst_gui.cpp create mode 100644 tests/auto/macgui/tst_macgui.cpp create mode 100644 tests/auto/networkselftest/networkselftest.pro create mode 100644 tests/auto/networkselftest/tst_networkselftest.cpp delete mode 100644 tests/auto/qcssparser/tst_cssparser.cpp create mode 100644 tests/auto/qcssparser/tst_qcssparser.cpp create mode 100644 tests/auto/qicoimageformat/tst_qicoimageformat.cpp delete mode 100644 tests/auto/qicoimageformat/tst_qticoimageformat.cpp delete mode 100644 tests/auto/qpointarray/.gitignore delete mode 100644 tests/auto/qpointarray/qpointarray.pro delete mode 100644 tests/auto/qpointarray/tst_qpointarray.cpp create mode 100644 tests/auto/qpolygon/.gitignore create mode 100644 tests/auto/qpolygon/qpolygon.pro create mode 100644 tests/auto/qpolygon/tst_qpolygon.cpp create mode 100644 tests/auto/qresourceengine/tst_qresourceengine.cpp delete mode 100644 tests/auto/qresourceengine/tst_resourceengine.cpp create mode 100644 tests/auto/qscriptextqobject/.gitignore create mode 100644 tests/auto/qscriptextqobject/qscriptextqobject.pro create mode 100644 tests/auto/qscriptextqobject/tst_qscriptextqobject.cpp delete mode 100644 tests/auto/qscriptqobject/.gitignore delete mode 100644 tests/auto/qscriptqobject/qscriptqobject.pro delete mode 100644 tests/auto/qscriptqobject/tst_qscriptqobject.cpp diff --git a/tests/auto/_networkselftest/_networkselftest.pro b/tests/auto/_networkselftest/_networkselftest.pro deleted file mode 100644 index 9e2ad0e..0000000 --- a/tests/auto/_networkselftest/_networkselftest.pro +++ /dev/null @@ -1,6 +0,0 @@ -load(qttest_p4) - -SOURCES += tst_networkselftest.cpp -QT = core network -DEFINES += SRCDIR=\\\"$$PWD\\\" - diff --git a/tests/auto/_networkselftest/tst_networkselftest.cpp b/tests/auto/_networkselftest/tst_networkselftest.cpp deleted file mode 100644 index cb82733..0000000 --- a/tests/auto/_networkselftest/tst_networkselftest.cpp +++ /dev/null @@ -1,586 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** 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 either Technology Preview License Agreement or the -** Beta Release License Agreement. -** -** 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.0, included in the file LGPL_EXCEPTION.txt in this -** package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** If you are unsure which license is appropriate for your use, please -** contact the sales department at http://www.qtsoftware.com/contact. -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include -#include -#include "../network-settings.h" - -class tst_NetworkSelfTest: public QObject -{ - Q_OBJECT -private slots: - void hostTest(); - void dnsResolution_data(); - void dnsResolution(); - void serverReachability(); - void remotePortsOpen_data(); - void remotePortsOpen(); - - // specific protocol tests - void ftpServer(); - void imapServer(); - void httpServer(); - void httpsServer(); - void httpProxy(); - void httpProxyBasicAuth(); - void httpProxyNtlmAuth(); - void socks5Proxy(); - void socks5ProxyAuth(); -}; - -class Chat -{ -public: - enum Type { - Reconnect, - Send, - Expect, - SkipBytes, - DiscardUntil, - DiscardUntilDisconnect, - Disconnect, - RemoteDisconnect, - StartEncryption - }; - Chat(Type t, const QByteArray &d) - : data(d), type(t) - { - } - Chat(Type t, int val = 0) - : value(val), type(t) - { - } - - static inline Chat send(const QByteArray &data) - { return Chat(Send, data); } - static inline Chat expect(const QByteArray &data) - { return Chat(Expect, data); } - static inline Chat discardUntil(const QByteArray &data) - { return Chat(DiscardUntil, data); } - static inline Chat skipBytes(int count) - { return Chat(SkipBytes, count); } - - QByteArray data; - int value; - Type type; -}; - -static QString prettyByteArray(const QByteArray &array) -{ - // any control chars? - QString result; - result.reserve(array.length() + array.length() / 3); - for (int i = 0; i < array.length(); ++i) { - char c = array.at(i); - switch (c) { - case '\n': - result += "\\n"; - continue; - case '\r': - result += "\\r"; - continue; - case '\t': - result += "\\t"; - continue; - case '"': - result += "\\\""; - continue; - default: - break; - } - - if (c < 0x20 || uchar(c) >= 0x7f) { - result += '\\'; - result += QString::number(uchar(c), 8); - } else { - result += c; - } - } - return result; -} - -static bool doSocketRead(QTcpSocket *socket, int minBytesAvailable, int timeout = 2000) -{ - QTime timer; - timer.start(); - forever { - if (socket->bytesAvailable() >= minBytesAvailable) - return true; - if (socket->state() == QAbstractSocket::UnconnectedState - || timer.elapsed() >= timeout) - return false; - if (!socket->waitForReadyRead(timeout - timer.elapsed())) - return false; - } -} - -static bool doSocketFlush(QTcpSocket *socket, int timeout = 2000) -{ -#ifndef QT_NO_OPENSSL - QSslSocket *sslSocket = qobject_cast(socket); -#endif - QTime timer; - timer.start(); - forever { - if (socket->bytesToWrite() == 0 -#ifndef QT_NO_OPENSSL - && sslSocket->encryptedBytesToWrite() == 0 -#endif - ) - return true; - if (socket->state() == QAbstractSocket::UnconnectedState - || timer.elapsed() >= timeout) - return false; - if (!socket->waitForBytesWritten(timeout - timer.elapsed())) - return false; - } -} - -static void netChat(int port, const QList &chat) -{ -#ifndef QT_NO_OPENSSL - QSslSocket socket; -#else - QTcpSocket socket; -#endif - - socket.connectToHost(QtNetworkSettings::serverName(), port); - qDebug() << 0 << "Connecting to server on port" << port; - QVERIFY2(socket.waitForConnected(10000), - QString("Failed to connect to server in step 0: %1").arg(socket.errorString()).toLocal8Bit()); - - // now start the chat - QList::ConstIterator it = chat.constBegin(); - for (int i = 1; it != chat.constEnd(); ++it, ++i) { - switch (it->type) { - case Chat::Expect: { - qDebug() << i << "Expecting" << prettyByteArray(it->data); - if (!doSocketRead(&socket, it->data.length())) - QFAIL(QString("Failed to receive data in step %1: timeout").arg(i).toLocal8Bit()); - - // pop that many bytes off the socket - QByteArray received = socket.read(it->data.length()); - - // is it what we expected? - QVERIFY2(received == it->data, - QString("Did not receive expected data in step %1: data received was:\n%2") - .arg(i).arg(prettyByteArray(received)).toLocal8Bit()); - - break; - } - - case Chat::DiscardUntil: - qDebug() << i << "Discarding until" << prettyByteArray(it->data); - while (true) { - // scan the buffer until we have our string - if (!doSocketRead(&socket, it->data.length())) - QFAIL(QString("Failed to receive data in step %1: timeout").arg(i).toLocal8Bit()); - - QByteArray buffer; - buffer.resize(socket.bytesAvailable()); - socket.peek(buffer.data(), socket.bytesAvailable()); - - int pos = buffer.indexOf(it->data); - if (pos == -1) { - // data not found, keep trying - continue; - } - - buffer = socket.read(pos + it->data.length()); - qDebug() << i << "Discarded" << prettyByteArray(buffer); - break; - } - break; - - case Chat::SkipBytes: { - qDebug() << i << "Skipping" << it->value << "bytes"; - if (!doSocketRead(&socket, it->value)) - QFAIL(QString("Failed to receive data in step %1: timeout").arg(i).toLocal8Bit()); - - // now discard the bytes - QByteArray buffer = socket.read(it->value); - qDebug() << i << "Skipped" << prettyByteArray(buffer); - break; - } - - case Chat::Send: { - qDebug() << i << "Sending" << prettyByteArray(it->data); - socket.write(it->data); - if (!doSocketFlush(&socket)) { - QVERIFY2(socket.state() == QAbstractSocket::ConnectedState, - QString("Socket disconnected while sending data in step %1").arg(i).toLocal8Bit()); - QFAIL(QString("Failed to send data in step %1: timeout").arg(i).toLocal8Bit()); - } - break; - } - - case Chat::Disconnect: - qDebug() << i << "Disconnecting from host"; - socket.disconnectFromHost(); - - // is this the last command? - if (it + 1 != chat.constEnd()) - break; - - // fall through: - case Chat::RemoteDisconnect: - case Chat::DiscardUntilDisconnect: - qDebug() << i << "Waiting for remote disconnect"; - if (socket.state() != QAbstractSocket::UnconnectedState) - socket.waitForDisconnected(10000); - QVERIFY2(socket.state() == QAbstractSocket::UnconnectedState, - QString("Socket did not disconnect as expected in step %1").arg(i).toLocal8Bit()); - - // any data left? - if (it->type == Chat::DiscardUntilDisconnect) { - QByteArray buffer = socket.readAll(); - qDebug() << i << "Discarded in the process:" << prettyByteArray(buffer); - } - - if (socket.bytesAvailable() != 0) - QFAIL(QString("Unexpected bytes still on buffer when disconnecting in step %1:\n%2") - .arg(i).arg(prettyByteArray(socket.readAll())).toLocal8Bit()); - break; - - case Chat::Reconnect: - qDebug() << i << "Reconnecting to server on port" << port; - socket.connectToHost(QtNetworkSettings::serverName(), port); - QVERIFY2(socket.waitForConnected(10000), - QString("Failed to reconnect to server in step %1: %2").arg(i).arg(socket.errorString()).toLocal8Bit()); - break; - - case Chat::StartEncryption: -#ifdef QT_NO_OPENSSL - QFAIL("Internal error: SSL required for this test"); -#else - qDebug() << i << "Starting client encryption"; - socket.ignoreSslErrors(); - socket.startClientEncryption(); - QVERIFY2(socket.waitForEncrypted(5000), - QString("Failed to start client encryption in step %1: %2").arg(i) - .arg(socket.errorString()).toLocal8Bit()); - break; -#endif - } - } -} - -void tst_NetworkSelfTest::hostTest() -{ - // this is a localhost self-test - QHostInfo localhost = QHostInfo::fromName("localhost"); - QCOMPARE(localhost.error(), QHostInfo::NoError); - QVERIFY(!localhost.addresses().isEmpty()); - - QTcpServer server; - QVERIFY(server.listen()); - - QTcpSocket socket; - socket.connectToHost("127.0.0.1", server.serverPort()); - QVERIFY(socket.waitForConnected(10000)); -} - -void tst_NetworkSelfTest::dnsResolution_data() -{ - QTest::addColumn("hostName"); - QTest::newRow("local-name") << QtNetworkSettings::serverLocalName(); - QTest::newRow("fqdn") << QtNetworkSettings::serverName(); -} - -void tst_NetworkSelfTest::dnsResolution() -{ - QFETCH(QString, hostName); - QHostInfo resolved = QHostInfo::fromName(hostName); - QVERIFY2(resolved.error() == QHostInfo::NoError, - QString("Failed to resolve hostname %1: %2").arg(hostName, resolved.errorString()).toLocal8Bit()); -} - -void tst_NetworkSelfTest::serverReachability() -{ - // check that we get a proper error connecting to port 1 - QTcpSocket socket; - socket.connectToHost(QtNetworkSettings::serverName(), 1); - socket.waitForConnected(10000); - QVERIFY2(socket.state() == QAbstractSocket::UnconnectedState, "Socket connected unexpectedly!"); - QVERIFY2(socket.error() == QAbstractSocket::ConnectionRefusedError, - QString("Could not reach server: %1").arg(socket.errorString()).toLocal8Bit()); -} - -void tst_NetworkSelfTest::remotePortsOpen_data() -{ - QTest::addColumn("portNumber"); - QTest::newRow("ftp") << 21; - QTest::newRow("ssh") << 22; - QTest::newRow("imap") << 143; - QTest::newRow("http") << 80; - QTest::newRow("https") << 443; - QTest::newRow("http-proxy") << 3128; - QTest::newRow("http-proxy-auth-basic") << 3129; - QTest::newRow("http-proxy-auth-ntlm") << 3130; - QTest::newRow("socks5-proxy") << 1080; - QTest::newRow("socks5-proxy-auth") << 1081; -} - -void tst_NetworkSelfTest::remotePortsOpen() -{ - QFETCH(int, portNumber); - QTcpSocket socket; - socket.connectToHost(QtNetworkSettings::serverName(), portNumber); - - if (!socket.waitForConnected(10000)) { - if (socket.error() == QAbstractSocket::SocketTimeoutError) - QFAIL(QString("Network timeout connecting to the server on port %1").arg(portNumber).toLocal8Bit()); - else - QFAIL(QString("Error connecting to server on port %1: %2").arg(portNumber).arg(socket.errorString()).toLocal8Bit()); - } - QVERIFY(socket.state() == QAbstractSocket::ConnectedState); -} - -static QList ftpChat() -{ - return QList() << Chat::expect("220") - << Chat::discardUntil("\r\n") - << Chat::send("USER anonymous\r\n") - << Chat::expect("331") - << Chat::discardUntil("\r\n") - << Chat::send("PASS user@hostname\r\n") - << Chat::expect("230") - << Chat::discardUntil("\r\n") - << Chat::send("QUIT\r\n") - << Chat::expect("221") - << Chat::discardUntil("\r\n") - << Chat::RemoteDisconnect; -} - -void tst_NetworkSelfTest::ftpServer() -{ - netChat(21, ftpChat()); -} - -void tst_NetworkSelfTest::imapServer() -{ - netChat(143, QList() - << Chat::expect("* OK ") - << Chat::discardUntil("\r\n") - << Chat::send("1 CAPABILITY\r\n") - << Chat::expect("* CAPABILITY ") - << Chat::discardUntil("1 OK") - << Chat::discardUntil("\r\n") - << Chat::send("2 LOGOUT\r\n") - << Chat::discardUntil("2 OK") - << Chat::discardUntil("\r\n") - << Chat::RemoteDisconnect); -} - -void tst_NetworkSelfTest::httpServer() -{ - netChat(80, QList() - // HTTP/0.9 chat: - << Chat::send("GET /\r\n") - << Chat::DiscardUntilDisconnect - - // HTTP/1.0 chat: - << Chat::Reconnect - << Chat::send("GET / HTTP/1.0\r\n" - "Host: " + QtNetworkSettings::serverName().toLatin1() + "\r\n" - "Connection: close\r\n" - "\r\n") - << Chat::expect("HTTP/1.") - << Chat::discardUntil(" ") - << Chat::expect("200 ") - << Chat::DiscardUntilDisconnect - - // HTTP/1.0 POST: - << Chat::Reconnect - << Chat::send("POST / HTTP/1.0\r\n" - "Content-Length: 5\r\n" - "Host: " + QtNetworkSettings::serverName().toLatin1() + "\r\n" - "Connection: close\r\n" - "\r\n" - "Hello") - << Chat::expect("HTTP/1.") - << Chat::discardUntil(" ") - << Chat::expect("200 ") - << Chat::DiscardUntilDisconnect - ); -} - -void tst_NetworkSelfTest::httpsServer() -{ -#ifndef QT_NO_OPENSSL - netChat(443, QList() - << Chat::StartEncryption - << Chat::send("GET / HTTP/1.0\r\n" - "Host: " + QtNetworkSettings::serverName().toLatin1() + "\r\n" - "Connection: close\r\n" - "\r\n") - << Chat::expect("HTTP/1.") - << Chat::discardUntil(" ") - << Chat::expect("200 ") - << Chat::DiscardUntilDisconnect); -#else - QSKIP("SSL not enabled, cannot test", SkipAll); -#endif -} - -void tst_NetworkSelfTest::httpProxy() -{ - netChat(3128, QList() - // proxy GET - << Chat::send("GET http://" + QtNetworkSettings::serverName().toLatin1() + "/ HTTP/1.0\r\n" - "Host: " + QtNetworkSettings::serverName().toLatin1() + "\r\n" - "Proxy-connection: close\r\n" - "\r\n") - << Chat::expect("HTTP/1.") - << Chat::discardUntil(" ") - << Chat::expect("200 ") - << Chat::DiscardUntilDisconnect - - // proxy CONNECT - << Chat::Reconnect - << Chat::send("CONNECT " + QtNetworkSettings::serverName().toLatin1() + ":21 HTTP/1.0\r\n" - "\r\n") - << Chat::expect("HTTP/1.") - << Chat::discardUntil(" ") - << Chat::expect("200 ") - << Chat::discardUntil("\r\n\r\n") - << ftpChat()); -} - -void tst_NetworkSelfTest::httpProxyBasicAuth() -{ - netChat(3129, QList() - // test auth required response - << Chat::send("GET http://" + QtNetworkSettings::serverName().toLatin1() + "/ HTTP/1.0\r\n" - "Host: " + QtNetworkSettings::serverName().toLatin1() + "\r\n" - "Proxy-connection: close\r\n" - "\r\n") - << Chat::expect("HTTP/1.") - << Chat::discardUntil(" ") - << Chat::expect("407 ") - << Chat::discardUntil("\r\nProxy-Authenticate: Basic realm=\"") - << Chat::DiscardUntilDisconnect - - // now try sending our credentials - << Chat::Reconnect - << Chat::send("GET http://" + QtNetworkSettings::serverName().toLatin1() + "/ HTTP/1.0\r\n" - "Host: " + QtNetworkSettings::serverName().toLatin1() + "\r\n" - "Proxy-connection: close\r\n" - "Proxy-Authorization: Basic cXNvY2tzdGVzdDpwYXNzd29yZA==\r\n" - "\r\n") - << Chat::expect("HTTP/1.") - << Chat::discardUntil(" ") - << Chat::expect("200 ") - << Chat::DiscardUntilDisconnect); -} - -void tst_NetworkSelfTest::httpProxyNtlmAuth() -{ - netChat(3130, QList() - // test auth required response - << Chat::send("GET http://" + QtNetworkSettings::serverName().toLatin1() + "/ HTTP/1.0\r\n" - "Host: " + QtNetworkSettings::serverName().toLatin1() + "\r\n" - "Proxy-connection: keep-alive\r\n" // NTLM auth will disconnect - "\r\n") - << Chat::expect("HTTP/1.") - << Chat::discardUntil(" ") - << Chat::expect("407 ") - << Chat::discardUntil("\r\nProxy-Authenticate: NTLM\r\n") - << Chat::DiscardUntilDisconnect - ); -} - -// SOCKSv5 is a binary protocol -static const char handshakeNoAuth[] = "\5\1\0"; -static const char handshakeOkNoAuth[] = "\5\0"; -static const char handshakeAuthPassword[] = "\5\1\2\1\12qsockstest\10password"; -static const char handshakeOkPasswdAuth[] = "\5\2\1\0"; -static const char handshakeAuthNotOk[] = "\5\377"; -static const char connect1[] = "\5\1\0\1\177\0\0\1\0\25"; // Connect IPv4 127.0.0.1 port 21 -static const char connect2[] = "\5\1\0\3\11localhost\0\25"; // Connect hostname localhost 21 -static const char connected[] = "\5\0\0"; - -void tst_NetworkSelfTest::socks5Proxy() -{ - netChat(1080, QList() - // IP address connection - << Chat::send(QByteArray(handshakeNoAuth, -1 + sizeof handshakeNoAuth)) - << Chat::expect(QByteArray(handshakeOkNoAuth, -1 + sizeof handshakeOkNoAuth)) - << Chat::send(QByteArray(connect1, -1 + sizeof connect1)) - << Chat::expect(QByteArray(connected, -1 + sizeof connected)) - << Chat::expect("\1") // IPv4 address following - << Chat::skipBytes(6) // the server's local address and port - << ftpChat() - - // hostname connection - << Chat::Reconnect - << Chat::send(QByteArray(handshakeNoAuth, -1 + sizeof handshakeNoAuth)) - << Chat::expect(QByteArray(handshakeOkNoAuth, -1 + sizeof handshakeOkNoAuth)) - << Chat::send(QByteArray(connect2, -1 + sizeof connect2)) - << Chat::expect(QByteArray(connected, -1 + sizeof connected)) - << Chat::expect("\1") // IPv4 address following - << Chat::skipBytes(6) // the server's local address and port - << ftpChat() - ); -} - -void tst_NetworkSelfTest::socks5ProxyAuth() -{ - netChat(1081, QList() - // unauthenticated connect -- will get error - << Chat::send(QByteArray(handshakeNoAuth, -1 + sizeof handshakeNoAuth)) - << Chat::expect(QByteArray(handshakeAuthNotOk, -1 + sizeof handshakeAuthNotOk)) - << Chat::RemoteDisconnect - - // now try to connect with authentication - << Chat::Reconnect - << Chat::send(QByteArray(handshakeAuthPassword, -1 + sizeof handshakeAuthPassword)) - << Chat::expect(QByteArray(handshakeOkPasswdAuth, -1 + sizeof handshakeOkPasswdAuth)) - << Chat::send(QByteArray(connect1, -1 + sizeof connect1)) - << Chat::expect(QByteArray(connected, -1 + sizeof connected)) - << Chat::expect("\1") // IPv4 address following - << Chat::skipBytes(6) // the server's local address and port - << ftpChat() - ); -} - -QTEST_MAIN(tst_NetworkSelfTest) -#include "tst_networkselftest.moc" diff --git a/tests/auto/auto.pro b/tests/auto/auto.pro index fd887fd..10257d9 100644 --- a/tests/auto/auto.pro +++ b/tests/auto/auto.pro @@ -4,7 +4,7 @@ TEMPLATE = subdirs !wince*:SUBDIRS += \ headers -SUBDIRS += _networkselftest \ +SUBDIRS += \ bic \ collections \ compile \ @@ -17,6 +17,7 @@ SUBDIRS += _networkselftest \ # mediaobject_wince_ds9 \ This is Windows CE only (we test the second phonon backend ds9 here) moc \ modeltest \ + networkselftest \ q3accel \ q3action \ q3actiongroup \ @@ -224,8 +225,8 @@ SUBDIRS += _networkselftest \ qpixmapfilter \ qplaintextedit \ qpoint \ - qpointarray \ qpointer \ + qpolygon \ qprinter \ qprinterinfo \ qprocess \ @@ -247,9 +248,9 @@ SUBDIRS += _networkselftest \ qscriptcontextinfo \ qscriptengine \ qscriptengineagent \ + qscriptextqobject \ qscriptjstestsuite \ qscriptv8testsuite \ - qscriptqobject \ qscriptstring \ qscriptvalue \ qscriptvalueiterator \ diff --git a/tests/auto/macgui/macgui.pro b/tests/auto/macgui/macgui.pro index dc64627..0ed2350 100644 --- a/tests/auto/macgui/macgui.pro +++ b/tests/auto/macgui/macgui.pro @@ -4,12 +4,8 @@ DEPENDPATH += . INCLUDEPATH += . # Input -SOURCES += tst_gui.cpp - -mac { - SOURCES += guitest.cpp - HEADERS += guitest.h -} - +SOURCES += tst_macgui.cpp guitest.cpp +HEADERS += guitest.h +requires(mac) diff --git a/tests/auto/macgui/tst_gui.cpp b/tests/auto/macgui/tst_gui.cpp deleted file mode 100644 index 635023a..0000000 --- a/tests/auto/macgui/tst_gui.cpp +++ /dev/null @@ -1,277 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** 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 either Technology Preview License Agreement or the -** Beta Release License Agreement. -** -** 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.0, included in the file LGPL_EXCEPTION.txt in this -** package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** If you are unsure which license is appropriate for your use, please -** contact the sales department at http://www.qtsoftware.com/contact. -** $QT_END_LICENSE$ -** -****************************************************************************/ - - -#include -#include -#include -#include -#include -#include -#include - -#include - -#ifdef Q_OS_MAC - -class tst_gui : public GuiTester -{ -Q_OBJECT -private slots: - void scrollbarPainting(); - - void dummy(); - void splashScreenModality(); - void dialogModality(); - void nonModalOrder(); - - void spinBoxArrowButtons(); -}; - - -QPixmap grabWindowContents(QWidget * widget) -{ - return QPixmap::grabWindow(widget->winId()); -} - -/* - Test that vertical and horizontal mac-style scrollbars paint their - entire area. -*/ -void tst_gui::scrollbarPainting() -{ - ColorWidget colorWidget; - colorWidget.resize(400, 400); - - QSize scrollBarSize; - - QScrollBar verticalScrollbar(&colorWidget); - verticalScrollbar.move(10, 10); - scrollBarSize = verticalScrollbar.sizeHint(); - scrollBarSize.setHeight(200); - verticalScrollbar.resize(scrollBarSize); - - QScrollBar horizontalScrollbar(&colorWidget); - horizontalScrollbar.move(30, 10); - horizontalScrollbar.setOrientation(Qt::Horizontal); - scrollBarSize = horizontalScrollbar.sizeHint(); - scrollBarSize.setWidth(200); - horizontalScrollbar.resize(scrollBarSize); - - colorWidget.show(); - colorWidget.raise(); - QTest::qWait(100); - - QPixmap pixmap = grabWindowContents(&colorWidget); - - QVERIFY(isContent(pixmap.toImage(), verticalScrollbar.geometry(), GuiTester::Horizontal)); - QVERIFY(isContent(pixmap.toImage(), horizontalScrollbar.geometry(), GuiTester::Vertical)); -} - -// When running the auto-tests on scruffy, the first enter-the-event-loop-and-wait-for-a-click -// test that runs always times out, so we have this dummy test. -void tst_gui::dummy() -{ - QPixmap pix(100, 100); - QSplashScreen splash(pix); - splash.show(); - - QMessageBox *box = new QMessageBox(); - box->setText("accessible?"); - box->show(); - - // Find the "OK" button and schedule a press. - InterfaceChildPair interface = wn.find(QAccessible::Name, "OK", box); - QVERIFY(interface.iface); - const int delay = 1000; - clickLater(interface, Qt::LeftButton, delay); - - // Show dialog and and enter event loop. - connect(wn.getWidget(interface), SIGNAL(clicked()), SLOT(exitLoopSlot())); - const int timeout = 4; - QTestEventLoop::instance().enterLoop(timeout); -} - -/* - Test that a message box pops up in front of a QSplashScreen. -*/ -void tst_gui::splashScreenModality() -{ - QPixmap pix(300, 300); - QSplashScreen splash(pix); - splash.show(); - - QMessageBox box; - //box.setWindowFlags(box.windowFlags() | Qt::WindowStaysOnTopHint); - box.setText("accessible?"); - box.show(); - - // Find the "OK" button and schedule a press. - InterfaceChildPair interface = wn.find(QAccessible::Name, "OK", &box); - QVERIFY(interface.iface); - const int delay = 1000; - clickLater(interface, Qt::LeftButton, delay); - - // Show dialog and and enter event loop. - connect(wn.getWidget(interface), SIGNAL(clicked()), SLOT(exitLoopSlot())); - const int timeout = 4; - QTestEventLoop::instance().enterLoop(timeout); - QVERIFY(QTestEventLoop::instance().timeout() == false); -} - - -/* - Test that a non-modal dialog created as a child of a modal dialog is - shown in front. -*/ -void tst_gui::dialogModality() -{ - QDialog d; - d.setModal(true); - d.show(); - - QProgressDialog progress(&d); - progress.setValue(2); - - InterfaceChildPair interface = wn.find(QAccessible::Name, "Cancel", &progress); - QVERIFY(interface.iface); - const int delay = 2000; - clickLater(interface, Qt::LeftButton, delay); - - connect(&progress, SIGNAL(canceled()), SLOT(exitLoopSlot())); - - const int timeout = 3; - QTestEventLoop::instance().enterLoop(timeout); - QVERIFY(QTestEventLoop::instance().timeout() == false); -} - -class PrimaryWindowDialog : public QDialog -{ -Q_OBJECT -public: - PrimaryWindowDialog(); - QWidget *secondaryWindow; - QWidget *frontWidget; -public slots: - void showSecondaryWindow(); - void test(); -}; - -PrimaryWindowDialog::PrimaryWindowDialog() : QDialog(0) -{ - frontWidget = 0; - secondaryWindow = new ColorWidget(this); - secondaryWindow->setWindowFlags(Qt::Window); - secondaryWindow->resize(400, 400); - secondaryWindow->move(100, 100); - QTimer::singleShot(1000, this, SLOT(showSecondaryWindow())); - QTimer::singleShot(2000, this, SLOT(test())); - QTimer::singleShot(3000, this, SLOT(close())); -} - -void PrimaryWindowDialog::showSecondaryWindow() -{ - secondaryWindow->show(); -} - -void PrimaryWindowDialog::test() -{ - frontWidget = QApplication::widgetAt(secondaryWindow->mapToGlobal(QPoint(100, 100))); -} - -/* - Test that a non-modal child window of a modal dialog is shown in front - of the dialog even if the dialog becomes modal after the child window - is created. -*/ -void tst_gui::nonModalOrder() -{ - clearSequence(); - PrimaryWindowDialog primary; - primary.resize(400, 400); - primary.move(100, 100); - primary.exec(); - QCOMPARE(primary.frontWidget, primary.secondaryWindow); -} - -/* - Test that the QSpinBox buttons are correctly positioned with the Mac style. -*/ -void tst_gui::spinBoxArrowButtons() -{ - ColorWidget colorWidget; - colorWidget.resize(200, 200); - QSpinBox spinBox(&colorWidget); - QSpinBox spinBox2(&colorWidget); - spinBox2.move(0, 100); - colorWidget.show(); - QTest::qWait(100); - - // Grab an unfocused spin box. - const QImage noFocus = grabWindowContents(&colorWidget).toImage(); - - // Set focus by clicking the less button. - InterfaceChildPair lessInterface = wn.find(QAccessible::Name, "Less", &spinBox); - QVERIFY(lessInterface.iface); - const int delay = 500; - clickLater(lessInterface, Qt::LeftButton, delay); - const int timeout = 1; - QTestEventLoop::instance().enterLoop(timeout); - - // Grab a focused spin box. - const QImage focus = grabWindowContents(&colorWidget).toImage(); - - // Compare the arrow area of the less button to see if it moved. - const QRect lessRect = lessInterface.iface->rect(lessInterface.possibleChild); - const QRect lessLocalRect(colorWidget.mapFromGlobal(lessRect.topLeft()), colorWidget.mapFromGlobal(lessRect.bottomRight())); - const QRect compareRect = lessLocalRect.adjusted(5, 3, -5, -7); - QVERIFY(noFocus.copy(compareRect) == focus.copy(compareRect)); -} - -QTEST_MAIN(tst_gui) - -#else - -QTEST_NOOP_MAIN - -#endif - -#include "tst_gui.moc" diff --git a/tests/auto/macgui/tst_macgui.cpp b/tests/auto/macgui/tst_macgui.cpp new file mode 100644 index 0000000..627dc82 --- /dev/null +++ b/tests/auto/macgui/tst_macgui.cpp @@ -0,0 +1,278 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include +#include +#include +#include +#include +#include +#include + +#include + +#ifdef Q_OS_MAC + +class tst_MacGui : public GuiTester +{ +Q_OBJECT +private slots: + void scrollbarPainting(); + + void dummy(); + void splashScreenModality(); + void dialogModality(); + void nonModalOrder(); + + void spinBoxArrowButtons(); +}; + + +QPixmap grabWindowContents(QWidget * widget) +{ + return QPixmap::grabWindow(widget->winId()); +} + +/* + Test that vertical and horizontal mac-style scrollbars paint their + entire area. +*/ +void tst_MacGui::scrollbarPainting() +{ + ColorWidget colorWidget; + colorWidget.resize(400, 400); + + QSize scrollBarSize; + + QScrollBar verticalScrollbar(&colorWidget); + verticalScrollbar.move(10, 10); + scrollBarSize = verticalScrollbar.sizeHint(); + scrollBarSize.setHeight(200); + verticalScrollbar.resize(scrollBarSize); + + QScrollBar horizontalScrollbar(&colorWidget); + horizontalScrollbar.move(30, 10); + horizontalScrollbar.setOrientation(Qt::Horizontal); + scrollBarSize = horizontalScrollbar.sizeHint(); + scrollBarSize.setWidth(200); + horizontalScrollbar.resize(scrollBarSize); + + colorWidget.show(); + colorWidget.raise(); + QTest::qWait(100); + + QPixmap pixmap = grabWindowContents(&colorWidget); + + QVERIFY(isContent(pixmap.toImage(), verticalScrollbar.geometry(), GuiTester::Horizontal)); + QVERIFY(isContent(pixmap.toImage(), horizontalScrollbar.geometry(), GuiTester::Vertical)); +} + +// When running the auto-tests on scruffy, the first enter-the-event-loop-and-wait-for-a-click +// test that runs always times out, so we have this dummy test. +void tst_MacGui::dummy() +{ + QPixmap pix(100, 100); + QSplashScreen splash(pix); + splash.show(); + + QMessageBox *box = new QMessageBox(); + box->setText("accessible?"); + box->show(); + + // Find the "OK" button and schedule a press. + InterfaceChildPair interface = wn.find(QAccessible::Name, "OK", box); + QVERIFY(interface.iface); + const int delay = 1000; + clickLater(interface, Qt::LeftButton, delay); + + // Show dialog and and enter event loop. + connect(wn.getWidget(interface), SIGNAL(clicked()), SLOT(exitLoopSlot())); + const int timeout = 4; + QTestEventLoop::instance().enterLoop(timeout); +} + +/* + Test that a message box pops up in front of a QSplashScreen. +*/ +void tst_MacGui::splashScreenModality() +{ + QPixmap pix(300, 300); + QSplashScreen splash(pix); + splash.show(); + + QMessageBox box; + //box.setWindowFlags(box.windowFlags() | Qt::WindowStaysOnTopHint); + box.setText("accessible?"); + box.show(); + + // Find the "OK" button and schedule a press. + InterfaceChildPair interface = wn.find(QAccessible::Name, "OK", &box); + QVERIFY(interface.iface); + const int delay = 1000; + clickLater(interface, Qt::LeftButton, delay); + + // Show dialog and and enter event loop. + connect(wn.getWidget(interface), SIGNAL(clicked()), SLOT(exitLoopSlot())); + const int timeout = 4; + QTestEventLoop::instance().enterLoop(timeout); + QVERIFY(QTestEventLoop::instance().timeout() == false); +} + + +/* + Test that a non-modal dialog created as a child of a modal dialog is + shown in front. +*/ +void tst_MacGui::dialogModality() +{ + QDialog d; + d.setModal(true); + d.show(); + + QProgressDialog progress(&d); + progress.setValue(2); + + InterfaceChildPair interface = wn.find(QAccessible::Name, "Cancel", &progress); + QVERIFY(interface.iface); + const int delay = 2000; + clickLater(interface, Qt::LeftButton, delay); + + connect(&progress, SIGNAL(canceled()), SLOT(exitLoopSlot())); + + const int timeout = 3; + QTestEventLoop::instance().enterLoop(timeout); + QVERIFY(QTestEventLoop::instance().timeout() == false); +} + +class PrimaryWindowDialog : public QDialog +{ +Q_OBJECT +public: + PrimaryWindowDialog(); + QWidget *secondaryWindow; + QWidget *frontWidget; +public slots: + void showSecondaryWindow(); + void test(); +}; + +PrimaryWindowDialog::PrimaryWindowDialog() : QDialog(0) +{ + frontWidget = 0; + secondaryWindow = new ColorWidget(this); + secondaryWindow->setWindowFlags(Qt::Window); + secondaryWindow->resize(400, 400); + secondaryWindow->move(100, 100); + QTimer::singleShot(1000, this, SLOT(showSecondaryWindow())); + QTimer::singleShot(2000, this, SLOT(test())); + QTimer::singleShot(3000, this, SLOT(close())); +} + +void PrimaryWindowDialog::showSecondaryWindow() +{ + secondaryWindow->show(); +} + +void PrimaryWindowDialog::test() +{ + frontWidget = QApplication::widgetAt(secondaryWindow->mapToGlobal(QPoint(100, 100))); +} + +/* + Test that a non-modal child window of a modal dialog is shown in front + of the dialog even if the dialog becomes modal after the child window + is created. +*/ +void tst_MacGui::nonModalOrder() +{ + clearSequence(); + PrimaryWindowDialog primary; + primary.resize(400, 400); + primary.move(100, 100); + primary.exec(); + QCOMPARE(primary.frontWidget, primary.secondaryWindow); +} + +/* + Test that the QSpinBox buttons are correctly positioned with the Mac style. +*/ +void tst_MacGui::spinBoxArrowButtons() +{ + ColorWidget colorWidget; + colorWidget.resize(200, 200); + QSpinBox spinBox(&colorWidget); + QSpinBox spinBox2(&colorWidget); + spinBox2.move(0, 100); + colorWidget.show(); + QTest::qWait(100); + + // Grab an unfocused spin box. + const QImage noFocus = grabWindowContents(&colorWidget).toImage(); + + // Set focus by clicking the less button. + InterfaceChildPair lessInterface = wn.find(QAccessible::Name, "Less", &spinBox); + QVERIFY(lessInterface.iface); + const int delay = 500; + clickLater(lessInterface, Qt::LeftButton, delay); + const int timeout = 1; + QTestEventLoop::instance().enterLoop(timeout); + + // Grab a focused spin box. + const QImage focus = grabWindowContents(&colorWidget).toImage(); + + // Compare the arrow area of the less button to see if it moved. + const QRect lessRect = lessInterface.iface->rect(lessInterface.possibleChild); + const QRect lessLocalRect(colorWidget.mapFromGlobal(lessRect.topLeft()), colorWidget.mapFromGlobal(lessRect.bottomRight())); + const QRect compareRect = lessLocalRect.adjusted(5, 3, -5, -7); + QVERIFY(noFocus.copy(compareRect) == focus.copy(compareRect)); +} + +QTEST_MAIN(tst_MacGui) + +#else + +QTEST_NOOP_MAIN + +#endif + +#include "tst_macgui.moc" + diff --git a/tests/auto/networkselftest/networkselftest.pro b/tests/auto/networkselftest/networkselftest.pro new file mode 100644 index 0000000..9e2ad0e --- /dev/null +++ b/tests/auto/networkselftest/networkselftest.pro @@ -0,0 +1,6 @@ +load(qttest_p4) + +SOURCES += tst_networkselftest.cpp +QT = core network +DEFINES += SRCDIR=\\\"$$PWD\\\" + diff --git a/tests/auto/networkselftest/tst_networkselftest.cpp b/tests/auto/networkselftest/tst_networkselftest.cpp new file mode 100644 index 0000000..cb82733 --- /dev/null +++ b/tests/auto/networkselftest/tst_networkselftest.cpp @@ -0,0 +1,586 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include "../network-settings.h" + +class tst_NetworkSelfTest: public QObject +{ + Q_OBJECT +private slots: + void hostTest(); + void dnsResolution_data(); + void dnsResolution(); + void serverReachability(); + void remotePortsOpen_data(); + void remotePortsOpen(); + + // specific protocol tests + void ftpServer(); + void imapServer(); + void httpServer(); + void httpsServer(); + void httpProxy(); + void httpProxyBasicAuth(); + void httpProxyNtlmAuth(); + void socks5Proxy(); + void socks5ProxyAuth(); +}; + +class Chat +{ +public: + enum Type { + Reconnect, + Send, + Expect, + SkipBytes, + DiscardUntil, + DiscardUntilDisconnect, + Disconnect, + RemoteDisconnect, + StartEncryption + }; + Chat(Type t, const QByteArray &d) + : data(d), type(t) + { + } + Chat(Type t, int val = 0) + : value(val), type(t) + { + } + + static inline Chat send(const QByteArray &data) + { return Chat(Send, data); } + static inline Chat expect(const QByteArray &data) + { return Chat(Expect, data); } + static inline Chat discardUntil(const QByteArray &data) + { return Chat(DiscardUntil, data); } + static inline Chat skipBytes(int count) + { return Chat(SkipBytes, count); } + + QByteArray data; + int value; + Type type; +}; + +static QString prettyByteArray(const QByteArray &array) +{ + // any control chars? + QString result; + result.reserve(array.length() + array.length() / 3); + for (int i = 0; i < array.length(); ++i) { + char c = array.at(i); + switch (c) { + case '\n': + result += "\\n"; + continue; + case '\r': + result += "\\r"; + continue; + case '\t': + result += "\\t"; + continue; + case '"': + result += "\\\""; + continue; + default: + break; + } + + if (c < 0x20 || uchar(c) >= 0x7f) { + result += '\\'; + result += QString::number(uchar(c), 8); + } else { + result += c; + } + } + return result; +} + +static bool doSocketRead(QTcpSocket *socket, int minBytesAvailable, int timeout = 2000) +{ + QTime timer; + timer.start(); + forever { + if (socket->bytesAvailable() >= minBytesAvailable) + return true; + if (socket->state() == QAbstractSocket::UnconnectedState + || timer.elapsed() >= timeout) + return false; + if (!socket->waitForReadyRead(timeout - timer.elapsed())) + return false; + } +} + +static bool doSocketFlush(QTcpSocket *socket, int timeout = 2000) +{ +#ifndef QT_NO_OPENSSL + QSslSocket *sslSocket = qobject_cast(socket); +#endif + QTime timer; + timer.start(); + forever { + if (socket->bytesToWrite() == 0 +#ifndef QT_NO_OPENSSL + && sslSocket->encryptedBytesToWrite() == 0 +#endif + ) + return true; + if (socket->state() == QAbstractSocket::UnconnectedState + || timer.elapsed() >= timeout) + return false; + if (!socket->waitForBytesWritten(timeout - timer.elapsed())) + return false; + } +} + +static void netChat(int port, const QList &chat) +{ +#ifndef QT_NO_OPENSSL + QSslSocket socket; +#else + QTcpSocket socket; +#endif + + socket.connectToHost(QtNetworkSettings::serverName(), port); + qDebug() << 0 << "Connecting to server on port" << port; + QVERIFY2(socket.waitForConnected(10000), + QString("Failed to connect to server in step 0: %1").arg(socket.errorString()).toLocal8Bit()); + + // now start the chat + QList::ConstIterator it = chat.constBegin(); + for (int i = 1; it != chat.constEnd(); ++it, ++i) { + switch (it->type) { + case Chat::Expect: { + qDebug() << i << "Expecting" << prettyByteArray(it->data); + if (!doSocketRead(&socket, it->data.length())) + QFAIL(QString("Failed to receive data in step %1: timeout").arg(i).toLocal8Bit()); + + // pop that many bytes off the socket + QByteArray received = socket.read(it->data.length()); + + // is it what we expected? + QVERIFY2(received == it->data, + QString("Did not receive expected data in step %1: data received was:\n%2") + .arg(i).arg(prettyByteArray(received)).toLocal8Bit()); + + break; + } + + case Chat::DiscardUntil: + qDebug() << i << "Discarding until" << prettyByteArray(it->data); + while (true) { + // scan the buffer until we have our string + if (!doSocketRead(&socket, it->data.length())) + QFAIL(QString("Failed to receive data in step %1: timeout").arg(i).toLocal8Bit()); + + QByteArray buffer; + buffer.resize(socket.bytesAvailable()); + socket.peek(buffer.data(), socket.bytesAvailable()); + + int pos = buffer.indexOf(it->data); + if (pos == -1) { + // data not found, keep trying + continue; + } + + buffer = socket.read(pos + it->data.length()); + qDebug() << i << "Discarded" << prettyByteArray(buffer); + break; + } + break; + + case Chat::SkipBytes: { + qDebug() << i << "Skipping" << it->value << "bytes"; + if (!doSocketRead(&socket, it->value)) + QFAIL(QString("Failed to receive data in step %1: timeout").arg(i).toLocal8Bit()); + + // now discard the bytes + QByteArray buffer = socket.read(it->value); + qDebug() << i << "Skipped" << prettyByteArray(buffer); + break; + } + + case Chat::Send: { + qDebug() << i << "Sending" << prettyByteArray(it->data); + socket.write(it->data); + if (!doSocketFlush(&socket)) { + QVERIFY2(socket.state() == QAbstractSocket::ConnectedState, + QString("Socket disconnected while sending data in step %1").arg(i).toLocal8Bit()); + QFAIL(QString("Failed to send data in step %1: timeout").arg(i).toLocal8Bit()); + } + break; + } + + case Chat::Disconnect: + qDebug() << i << "Disconnecting from host"; + socket.disconnectFromHost(); + + // is this the last command? + if (it + 1 != chat.constEnd()) + break; + + // fall through: + case Chat::RemoteDisconnect: + case Chat::DiscardUntilDisconnect: + qDebug() << i << "Waiting for remote disconnect"; + if (socket.state() != QAbstractSocket::UnconnectedState) + socket.waitForDisconnected(10000); + QVERIFY2(socket.state() == QAbstractSocket::UnconnectedState, + QString("Socket did not disconnect as expected in step %1").arg(i).toLocal8Bit()); + + // any data left? + if (it->type == Chat::DiscardUntilDisconnect) { + QByteArray buffer = socket.readAll(); + qDebug() << i << "Discarded in the process:" << prettyByteArray(buffer); + } + + if (socket.bytesAvailable() != 0) + QFAIL(QString("Unexpected bytes still on buffer when disconnecting in step %1:\n%2") + .arg(i).arg(prettyByteArray(socket.readAll())).toLocal8Bit()); + break; + + case Chat::Reconnect: + qDebug() << i << "Reconnecting to server on port" << port; + socket.connectToHost(QtNetworkSettings::serverName(), port); + QVERIFY2(socket.waitForConnected(10000), + QString("Failed to reconnect to server in step %1: %2").arg(i).arg(socket.errorString()).toLocal8Bit()); + break; + + case Chat::StartEncryption: +#ifdef QT_NO_OPENSSL + QFAIL("Internal error: SSL required for this test"); +#else + qDebug() << i << "Starting client encryption"; + socket.ignoreSslErrors(); + socket.startClientEncryption(); + QVERIFY2(socket.waitForEncrypted(5000), + QString("Failed to start client encryption in step %1: %2").arg(i) + .arg(socket.errorString()).toLocal8Bit()); + break; +#endif + } + } +} + +void tst_NetworkSelfTest::hostTest() +{ + // this is a localhost self-test + QHostInfo localhost = QHostInfo::fromName("localhost"); + QCOMPARE(localhost.error(), QHostInfo::NoError); + QVERIFY(!localhost.addresses().isEmpty()); + + QTcpServer server; + QVERIFY(server.listen()); + + QTcpSocket socket; + socket.connectToHost("127.0.0.1", server.serverPort()); + QVERIFY(socket.waitForConnected(10000)); +} + +void tst_NetworkSelfTest::dnsResolution_data() +{ + QTest::addColumn("hostName"); + QTest::newRow("local-name") << QtNetworkSettings::serverLocalName(); + QTest::newRow("fqdn") << QtNetworkSettings::serverName(); +} + +void tst_NetworkSelfTest::dnsResolution() +{ + QFETCH(QString, hostName); + QHostInfo resolved = QHostInfo::fromName(hostName); + QVERIFY2(resolved.error() == QHostInfo::NoError, + QString("Failed to resolve hostname %1: %2").arg(hostName, resolved.errorString()).toLocal8Bit()); +} + +void tst_NetworkSelfTest::serverReachability() +{ + // check that we get a proper error connecting to port 1 + QTcpSocket socket; + socket.connectToHost(QtNetworkSettings::serverName(), 1); + socket.waitForConnected(10000); + QVERIFY2(socket.state() == QAbstractSocket::UnconnectedState, "Socket connected unexpectedly!"); + QVERIFY2(socket.error() == QAbstractSocket::ConnectionRefusedError, + QString("Could not reach server: %1").arg(socket.errorString()).toLocal8Bit()); +} + +void tst_NetworkSelfTest::remotePortsOpen_data() +{ + QTest::addColumn("portNumber"); + QTest::newRow("ftp") << 21; + QTest::newRow("ssh") << 22; + QTest::newRow("imap") << 143; + QTest::newRow("http") << 80; + QTest::newRow("https") << 443; + QTest::newRow("http-proxy") << 3128; + QTest::newRow("http-proxy-auth-basic") << 3129; + QTest::newRow("http-proxy-auth-ntlm") << 3130; + QTest::newRow("socks5-proxy") << 1080; + QTest::newRow("socks5-proxy-auth") << 1081; +} + +void tst_NetworkSelfTest::remotePortsOpen() +{ + QFETCH(int, portNumber); + QTcpSocket socket; + socket.connectToHost(QtNetworkSettings::serverName(), portNumber); + + if (!socket.waitForConnected(10000)) { + if (socket.error() == QAbstractSocket::SocketTimeoutError) + QFAIL(QString("Network timeout connecting to the server on port %1").arg(portNumber).toLocal8Bit()); + else + QFAIL(QString("Error connecting to server on port %1: %2").arg(portNumber).arg(socket.errorString()).toLocal8Bit()); + } + QVERIFY(socket.state() == QAbstractSocket::ConnectedState); +} + +static QList ftpChat() +{ + return QList() << Chat::expect("220") + << Chat::discardUntil("\r\n") + << Chat::send("USER anonymous\r\n") + << Chat::expect("331") + << Chat::discardUntil("\r\n") + << Chat::send("PASS user@hostname\r\n") + << Chat::expect("230") + << Chat::discardUntil("\r\n") + << Chat::send("QUIT\r\n") + << Chat::expect("221") + << Chat::discardUntil("\r\n") + << Chat::RemoteDisconnect; +} + +void tst_NetworkSelfTest::ftpServer() +{ + netChat(21, ftpChat()); +} + +void tst_NetworkSelfTest::imapServer() +{ + netChat(143, QList() + << Chat::expect("* OK ") + << Chat::discardUntil("\r\n") + << Chat::send("1 CAPABILITY\r\n") + << Chat::expect("* CAPABILITY ") + << Chat::discardUntil("1 OK") + << Chat::discardUntil("\r\n") + << Chat::send("2 LOGOUT\r\n") + << Chat::discardUntil("2 OK") + << Chat::discardUntil("\r\n") + << Chat::RemoteDisconnect); +} + +void tst_NetworkSelfTest::httpServer() +{ + netChat(80, QList() + // HTTP/0.9 chat: + << Chat::send("GET /\r\n") + << Chat::DiscardUntilDisconnect + + // HTTP/1.0 chat: + << Chat::Reconnect + << Chat::send("GET / HTTP/1.0\r\n" + "Host: " + QtNetworkSettings::serverName().toLatin1() + "\r\n" + "Connection: close\r\n" + "\r\n") + << Chat::expect("HTTP/1.") + << Chat::discardUntil(" ") + << Chat::expect("200 ") + << Chat::DiscardUntilDisconnect + + // HTTP/1.0 POST: + << Chat::Reconnect + << Chat::send("POST / HTTP/1.0\r\n" + "Content-Length: 5\r\n" + "Host: " + QtNetworkSettings::serverName().toLatin1() + "\r\n" + "Connection: close\r\n" + "\r\n" + "Hello") + << Chat::expect("HTTP/1.") + << Chat::discardUntil(" ") + << Chat::expect("200 ") + << Chat::DiscardUntilDisconnect + ); +} + +void tst_NetworkSelfTest::httpsServer() +{ +#ifndef QT_NO_OPENSSL + netChat(443, QList() + << Chat::StartEncryption + << Chat::send("GET / HTTP/1.0\r\n" + "Host: " + QtNetworkSettings::serverName().toLatin1() + "\r\n" + "Connection: close\r\n" + "\r\n") + << Chat::expect("HTTP/1.") + << Chat::discardUntil(" ") + << Chat::expect("200 ") + << Chat::DiscardUntilDisconnect); +#else + QSKIP("SSL not enabled, cannot test", SkipAll); +#endif +} + +void tst_NetworkSelfTest::httpProxy() +{ + netChat(3128, QList() + // proxy GET + << Chat::send("GET http://" + QtNetworkSettings::serverName().toLatin1() + "/ HTTP/1.0\r\n" + "Host: " + QtNetworkSettings::serverName().toLatin1() + "\r\n" + "Proxy-connection: close\r\n" + "\r\n") + << Chat::expect("HTTP/1.") + << Chat::discardUntil(" ") + << Chat::expect("200 ") + << Chat::DiscardUntilDisconnect + + // proxy CONNECT + << Chat::Reconnect + << Chat::send("CONNECT " + QtNetworkSettings::serverName().toLatin1() + ":21 HTTP/1.0\r\n" + "\r\n") + << Chat::expect("HTTP/1.") + << Chat::discardUntil(" ") + << Chat::expect("200 ") + << Chat::discardUntil("\r\n\r\n") + << ftpChat()); +} + +void tst_NetworkSelfTest::httpProxyBasicAuth() +{ + netChat(3129, QList() + // test auth required response + << Chat::send("GET http://" + QtNetworkSettings::serverName().toLatin1() + "/ HTTP/1.0\r\n" + "Host: " + QtNetworkSettings::serverName().toLatin1() + "\r\n" + "Proxy-connection: close\r\n" + "\r\n") + << Chat::expect("HTTP/1.") + << Chat::discardUntil(" ") + << Chat::expect("407 ") + << Chat::discardUntil("\r\nProxy-Authenticate: Basic realm=\"") + << Chat::DiscardUntilDisconnect + + // now try sending our credentials + << Chat::Reconnect + << Chat::send("GET http://" + QtNetworkSettings::serverName().toLatin1() + "/ HTTP/1.0\r\n" + "Host: " + QtNetworkSettings::serverName().toLatin1() + "\r\n" + "Proxy-connection: close\r\n" + "Proxy-Authorization: Basic cXNvY2tzdGVzdDpwYXNzd29yZA==\r\n" + "\r\n") + << Chat::expect("HTTP/1.") + << Chat::discardUntil(" ") + << Chat::expect("200 ") + << Chat::DiscardUntilDisconnect); +} + +void tst_NetworkSelfTest::httpProxyNtlmAuth() +{ + netChat(3130, QList() + // test auth required response + << Chat::send("GET http://" + QtNetworkSettings::serverName().toLatin1() + "/ HTTP/1.0\r\n" + "Host: " + QtNetworkSettings::serverName().toLatin1() + "\r\n" + "Proxy-connection: keep-alive\r\n" // NTLM auth will disconnect + "\r\n") + << Chat::expect("HTTP/1.") + << Chat::discardUntil(" ") + << Chat::expect("407 ") + << Chat::discardUntil("\r\nProxy-Authenticate: NTLM\r\n") + << Chat::DiscardUntilDisconnect + ); +} + +// SOCKSv5 is a binary protocol +static const char handshakeNoAuth[] = "\5\1\0"; +static const char handshakeOkNoAuth[] = "\5\0"; +static const char handshakeAuthPassword[] = "\5\1\2\1\12qsockstest\10password"; +static const char handshakeOkPasswdAuth[] = "\5\2\1\0"; +static const char handshakeAuthNotOk[] = "\5\377"; +static const char connect1[] = "\5\1\0\1\177\0\0\1\0\25"; // Connect IPv4 127.0.0.1 port 21 +static const char connect2[] = "\5\1\0\3\11localhost\0\25"; // Connect hostname localhost 21 +static const char connected[] = "\5\0\0"; + +void tst_NetworkSelfTest::socks5Proxy() +{ + netChat(1080, QList() + // IP address connection + << Chat::send(QByteArray(handshakeNoAuth, -1 + sizeof handshakeNoAuth)) + << Chat::expect(QByteArray(handshakeOkNoAuth, -1 + sizeof handshakeOkNoAuth)) + << Chat::send(QByteArray(connect1, -1 + sizeof connect1)) + << Chat::expect(QByteArray(connected, -1 + sizeof connected)) + << Chat::expect("\1") // IPv4 address following + << Chat::skipBytes(6) // the server's local address and port + << ftpChat() + + // hostname connection + << Chat::Reconnect + << Chat::send(QByteArray(handshakeNoAuth, -1 + sizeof handshakeNoAuth)) + << Chat::expect(QByteArray(handshakeOkNoAuth, -1 + sizeof handshakeOkNoAuth)) + << Chat::send(QByteArray(connect2, -1 + sizeof connect2)) + << Chat::expect(QByteArray(connected, -1 + sizeof connected)) + << Chat::expect("\1") // IPv4 address following + << Chat::skipBytes(6) // the server's local address and port + << ftpChat() + ); +} + +void tst_NetworkSelfTest::socks5ProxyAuth() +{ + netChat(1081, QList() + // unauthenticated connect -- will get error + << Chat::send(QByteArray(handshakeNoAuth, -1 + sizeof handshakeNoAuth)) + << Chat::expect(QByteArray(handshakeAuthNotOk, -1 + sizeof handshakeAuthNotOk)) + << Chat::RemoteDisconnect + + // now try to connect with authentication + << Chat::Reconnect + << Chat::send(QByteArray(handshakeAuthPassword, -1 + sizeof handshakeAuthPassword)) + << Chat::expect(QByteArray(handshakeOkPasswdAuth, -1 + sizeof handshakeOkPasswdAuth)) + << Chat::send(QByteArray(connect1, -1 + sizeof connect1)) + << Chat::expect(QByteArray(connected, -1 + sizeof connected)) + << Chat::expect("\1") // IPv4 address following + << Chat::skipBytes(6) // the server's local address and port + << ftpChat() + ); +} + +QTEST_MAIN(tst_NetworkSelfTest) +#include "tst_networkselftest.moc" diff --git a/tests/auto/qaccessibility_mac/qaccessibility_mac.pro b/tests/auto/qaccessibility_mac/qaccessibility_mac.pro index b6829dc..b32a7e5 100644 --- a/tests/auto/qaccessibility_mac/qaccessibility_mac.pro +++ b/tests/auto/qaccessibility_mac/qaccessibility_mac.pro @@ -4,21 +4,20 @@ TARGET = tst_qaccessibility_mac RESOURCES = qaccessibility_mac.qrc -mac { +requires(mac) + # this setup should support both building as an autotest # (where uilib isn't built by default), and when running shadow # builds (where QTDIR points to the build directory). # autotest + shadow build is not supported :) - exists($$(QTDIR)/tools/designer/src/lib/uilib/uilib.pri) { - include($$(QTDIR)/tools/designer/src/lib/uilib/uilib.pri) - INCLUDEPATH += $$(QTDIR)/tools/designer/src/uitools - SOURCES += $$(QTDIR)/tools/designer/src/uitools/quiloader.cpp - HEADERS += $$(QTDIR)/tools/designer/src/uitools/quiloader.h - } else { - CONFIG += uitools - } - QT += xml - LIBS += -framework ApplicationServices -framework Carbon +exists($$(QTDIR)/tools/designer/src/lib/uilib/uilib.pri) { + include($$(QTDIR)/tools/designer/src/lib/uilib/uilib.pri) + INCLUDEPATH += $$(QTDIR)/tools/designer/src/uitools + SOURCES += $$(QTDIR)/tools/designer/src/uitools/quiloader.cpp + HEADERS += $$(QTDIR)/tools/designer/src/uitools/quiloader.h +} else { + CONFIG += uitools } - +QT += xml +LIBS += -framework ApplicationServices -framework Carbon diff --git a/tests/auto/qaccessibility_mac/tst_qaccessibility_mac.cpp b/tests/auto/qaccessibility_mac/tst_qaccessibility_mac.cpp index b81fa12..2af6813 100644 --- a/tests/auto/qaccessibility_mac/tst_qaccessibility_mac.cpp +++ b/tests/auto/qaccessibility_mac/tst_qaccessibility_mac.cpp @@ -73,7 +73,7 @@ Q_DECLARE_METATYPE(AXUIElementRef); typedef QCFType QCFArrayRef; -class tst_accessibility_mac : public QObject +class tst_qaccessibility_mac : public QObject { Q_OBJECT public slots: @@ -665,7 +665,7 @@ void testAppAndForm(AXUIElementRef application) VERIFY_ELEMENT(form, application, "AXWindow"); } -void tst_accessibility_mac::printInfo() +void tst_qaccessibility_mac::printInfo() { AXUIElementRef currentApplication = AXUIElementCreateApplication(getpid()); printElementInfo(currentApplication); @@ -674,7 +674,7 @@ void tst_accessibility_mac::printInfo() /* Tests for form.ui */ -void tst_accessibility_mac::testForm() +void tst_qaccessibility_mac::testForm() { // Get reference to the current application. AXUIElementRef currentApplication = AXUIElementCreateApplication(getpid()); @@ -685,7 +685,7 @@ void tst_accessibility_mac::testForm() /* Tests for buttons.ui */ -void tst_accessibility_mac::testButtons() +void tst_qaccessibility_mac::testButtons() { // Get reference to the current application. AXUIElementRef currentApplication = AXUIElementCreateApplication(getpid()); @@ -714,7 +714,7 @@ void tst_accessibility_mac::testButtons() VERIFY_ROLE_DESCRIPTION(brain, "button"); } -void tst_accessibility_mac::testLabel() +void tst_qaccessibility_mac::testLabel() { // Get reference to the current application. AXUIElementRef currentApplication = AXUIElementCreateApplication(getpid()); @@ -731,7 +731,7 @@ void tst_accessibility_mac::testLabel() /* Tests for lineedit.ui */ -void tst_accessibility_mac::testLineEdit() +void tst_qaccessibility_mac::testLineEdit() { // Get reference to the current application. AXUIElementRef currentApplication = AXUIElementCreateApplication(getpid()); @@ -746,7 +746,7 @@ void tst_accessibility_mac::testLineEdit() /* Tests for groups.ui */ -void tst_accessibility_mac::testGroups() +void tst_qaccessibility_mac::testGroups() { // Get reference to the current application. AXUIElementRef currentApplication = AXUIElementCreateApplication(getpid()); @@ -769,7 +769,7 @@ void tst_accessibility_mac::testGroups() /* Tests for tabs.ui */ -void tst_accessibility_mac::testTabWidget() +void tst_qaccessibility_mac::testTabWidget() { { // Test that the QTabWidget hierarchy is what we expect it to be. QTabWidget tabWidget; @@ -873,7 +873,7 @@ void tst_accessibility_mac::testTabWidget() } } -void tst_accessibility_mac::testTabBar() +void tst_qaccessibility_mac::testTabBar() { QTabBar tabBar; tabBar.addTab("Tab A"); @@ -924,7 +924,7 @@ void tst_accessibility_mac::testTabBar() } } -void tst_accessibility_mac::testComboBox() +void tst_qaccessibility_mac::testComboBox() { // Get reference to the current application. AXUIElementRef currentApplication = AXUIElementCreateApplication(getpid()); @@ -940,7 +940,7 @@ void tst_accessibility_mac::testComboBox() QVERIFY(performAction(comboBox, "AXPress")); } -void tst_accessibility_mac::testDeleteWidget() +void tst_qaccessibility_mac::testDeleteWidget() { const QString buttonTitle = "Hi there"; QWidget *form = new QWidget(0, Qt::Window); @@ -964,7 +964,7 @@ void tst_accessibility_mac::testDeleteWidget() delete form; } -void tst_accessibility_mac::testDeleteWidgets() +void tst_qaccessibility_mac::testDeleteWidgets() { const QString buttonTitle = "Hi there"; const int repeats = 10; @@ -1047,7 +1047,7 @@ void tst_accessibility_mac::testDeleteWidgets() } -void tst_accessibility_mac::testMultipleWindows() +void tst_qaccessibility_mac::testMultipleWindows() { const QString formATitle("FormA"); const QString formBTitle("FormB"); @@ -1077,7 +1077,7 @@ void tst_accessibility_mac::testMultipleWindows() delete formA; } -void tst_accessibility_mac::testHiddenWidgets() +void tst_qaccessibility_mac::testHiddenWidgets() { const QString windowTitle ="a widget"; QWidget * const window = new QWidget(0); @@ -1108,7 +1108,7 @@ void tst_accessibility_mac::testHiddenWidgets() delete window; }; -void tst_accessibility_mac::testActions() +void tst_qaccessibility_mac::testActions() { // create a window with a push button const QString windowTitle ="a widget"; @@ -1145,7 +1145,7 @@ void tst_accessibility_mac::testActions() delete window; }; -void tst_accessibility_mac::testChangeState() +void tst_qaccessibility_mac::testChangeState() { const QString windowTitle ="a widget"; QWidget * const window = new QWidget(); @@ -1215,7 +1215,7 @@ void tst_accessibility_mac::testChangeState() delete window; } -void tst_accessibility_mac::testSlider() +void tst_qaccessibility_mac::testSlider() { const QString windowTitle = "a widget"; QWidget * const window = new QWidget(); @@ -1241,7 +1241,7 @@ void tst_accessibility_mac::testSlider() delete slider; } -void tst_accessibility_mac::testScrollArea() +void tst_qaccessibility_mac::testScrollArea() { QWidget window; const QString windowTitle = "window"; @@ -1368,7 +1368,7 @@ void tst_accessibility_mac::testScrollArea() } } -void tst_accessibility_mac::testListView() +void tst_qaccessibility_mac::testListView() { QWidget window; const QString windowTitle("window"); @@ -1451,7 +1451,7 @@ void tst_accessibility_mac::testListView() QVERIFY(contains(listElement, C)); } -void tst_accessibility_mac::testTableView() +void tst_qaccessibility_mac::testTableView() { QWidget window; const QString windowTitle("window"); @@ -1647,7 +1647,7 @@ void tst_accessibility_mac::testTableView() // QTest::qWait(1000000); } -void tst_accessibility_mac::testScrollBar() +void tst_qaccessibility_mac::testScrollBar() { { QScrollBar scrollBar; @@ -1693,7 +1693,7 @@ void tst_accessibility_mac::testScrollBar() } } -void tst_accessibility_mac::testSplitter() +void tst_qaccessibility_mac::testSplitter() { const AXUIElementRef currentApplication = AXUIElementCreateApplication(getpid()); testAppAndForm(currentApplication); @@ -1730,7 +1730,7 @@ void tst_accessibility_mac::testSplitter() } } -void tst_accessibility_mac::testTextEdit() +void tst_qaccessibility_mac::testTextEdit() { QWidget window; const QString windowTitle("window"); @@ -1796,13 +1796,13 @@ void testModelLessItemView(QAbstractItemView *itemView, const QByteArray &role) delete itemView; } -void tst_accessibility_mac::testItemViewsWithoutModel() +void tst_qaccessibility_mac::testItemViewsWithoutModel() { testModelLessItemView(new QListView(), "AXList"); testModelLessItemView(new QTableView(), "AXTable"); } -void tst_accessibility_mac::testQAElement() +void tst_qaccessibility_mac::testQAElement() { { QAElement element; @@ -1825,7 +1825,7 @@ void tst_accessibility_mac::testQAElement() } -void tst_accessibility_mac::testQAInterface() +void tst_qaccessibility_mac::testQAInterface() { { QAInterface interface; @@ -1855,7 +1855,7 @@ void tst_accessibility_mac::testQAInterface() } } -void tst_accessibility_mac::uitests_data() +void tst_qaccessibility_mac::uitests_data() { QTest::addColumn("uiFilename"); QTest::addColumn("testSlot"); @@ -1871,7 +1871,7 @@ void tst_accessibility_mac::uitests_data() QTest::newRow("splitters") << "splitters.ui" << SLOT(testSplitter()); } -void tst_accessibility_mac::uitests() +void tst_qaccessibility_mac::uitests() { QFETCH(QString, uiFilename); QFETCH(QString, testSlot); @@ -1901,7 +1901,7 @@ void tst_accessibility_mac::uitests() delete window; } -void tst_accessibility_mac::tests_data() +void tst_qaccessibility_mac::tests_data() { QTest::addColumn("testSlot"); QTest::newRow("deleteWidget") << SLOT(testDeleteWidget()); @@ -1919,7 +1919,7 @@ void tst_accessibility_mac::tests_data() QTest::newRow("tabbar") << SLOT(testTabBar()); } -void tst_accessibility_mac::tests() +void tst_qaccessibility_mac::tests() { QFETCH(QString, testSlot); runTest(testSlot); @@ -1930,7 +1930,7 @@ void tst_accessibility_mac::tests() kAXErrorAPIDisabled error, indicating that the accessible API is disabled, which it isn't.) To work around this, we run the tests in a callback slot called from the main event loop. */ -void tst_accessibility_mac::runTest(const QString &testSlot) +void tst_qaccessibility_mac::runTest(const QString &testSlot) { // The Accessibility interface must be enabled to run this test. if (!AXAPIEnabled()) @@ -1947,7 +1947,7 @@ void tst_accessibility_mac::runTest(const QString &testSlot) } -QTEST_APPLESS_MAIN(tst_accessibility_mac) +QTEST_APPLESS_MAIN(tst_qaccessibility_mac) #else // defined(Q_WS_MAC) && !defined (QT_MAC_USE_COCOA) diff --git a/tests/auto/qcopchannel/qcopchannel.pro b/tests/auto/qcopchannel/qcopchannel.pro index 29f7834..427430f 100644 --- a/tests/auto/qcopchannel/qcopchannel.pro +++ b/tests/auto/qcopchannel/qcopchannel.pro @@ -3,4 +3,5 @@ SUBDIRS = testSend SUBDIRS += test +requires(embedded) diff --git a/tests/auto/qcopchannel/test/test.pro b/tests/auto/qcopchannel/test/test.pro index 48a218e..8c7cc5b 100644 --- a/tests/auto/qcopchannel/test/test.pro +++ b/tests/auto/qcopchannel/test/test.pro @@ -3,12 +3,4 @@ load(qttest_p4) SOURCES += ../tst_qcopchannel.cpp TARGET = ../tst_qcopchannel -win32 { - CONFIG(debug, debug|release) { - TARGET = ../../debug/tst_qcopchannel -} else { - TARGET = ../../release/tst_qcopchannel - } -} - diff --git a/tests/auto/qcopchannel/testSend/testSend.pro b/tests/auto/qcopchannel/testSend/testSend.pro index f78341c..ebce3dd 100644 --- a/tests/auto/qcopchannel/testSend/testSend.pro +++ b/tests/auto/qcopchannel/testSend/testSend.pro @@ -2,4 +2,5 @@ load(qttest_p4) SOURCES = main.cpp TARGET = testSend +requires(embedded) diff --git a/tests/auto/qcssparser/qcssparser.pro b/tests/auto/qcssparser/qcssparser.pro index 57d6804..2f99142 100644 --- a/tests/auto/qcssparser/qcssparser.pro +++ b/tests/auto/qcssparser/qcssparser.pro @@ -1,5 +1,5 @@ load(qttest_p4) -SOURCES += tst_cssparser.cpp +SOURCES += tst_qcssparser.cpp DEFINES += SRCDIR=\\\"$$PWD\\\" QT += xml diff --git a/tests/auto/qcssparser/tst_cssparser.cpp b/tests/auto/qcssparser/tst_cssparser.cpp deleted file mode 100644 index c905688..0000000 --- a/tests/auto/qcssparser/tst_cssparser.cpp +++ /dev/null @@ -1,1616 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** 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 either Technology Preview License Agreement or the -** Beta Release License Agreement. -** -** 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.0, included in the file LGPL_EXCEPTION.txt in this -** package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** If you are unsure which license is appropriate for your use, please -** contact the sales department at http://www.qtsoftware.com/contact. -** $QT_END_LICENSE$ -** -****************************************************************************/ -#include -#include - -//TESTED_CLASS=QCss -//TESTED_FILES=gui/text/qcssparser.cpp gui/text/qcssparser_p.h - -#include "private/qcssparser_p.h" - -class tst_CssParser : public QObject -{ - Q_OBJECT -private slots: - void scanner_data(); - void scanner(); - void term_data(); - void term(); - void expr_data(); - void expr(); - void import(); - void media(); - void page(); - void ruleset(); - void selector_data(); - void selector(); - void prio(); - void escapes(); - void malformedDeclarations_data(); - void malformedDeclarations(); - void invalidAtKeywords(); - void marginValue(); - void marginValue_data(); - void colorValue_data(); - void colorValue(); - void styleSelector_data(); - void styleSelector(); - void specificity_data(); - void specificity(); - void specificitySort_data(); - void specificitySort(); - void rulesForNode_data(); - void rulesForNode(); - void shorthandBackgroundProperty_data(); - void shorthandBackgroundProperty(); - void pseudoElement_data(); - void pseudoElement(); - void gradient_data(); - void gradient(); - void extractFontFamily_data(); - void extractFontFamily(); - void extractBorder_data(); - void extractBorder(); - void noTextDecoration(); - void quotedAndUnquotedIdentifiers(); -}; - -void tst_CssParser::scanner_data() -{ - QTest::addColumn("input"); - QTest::addColumn("output"); - -#if !defined(Q_OS_IRIX) && !defined(Q_OS_WINCE) - QDir d(SRCDIR); -#else - QDir d(QDir::current()); -#endif - d.cd("testdata"); - d.cd("scanner"); - foreach (QFileInfo test, d.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot)) { - QString dir = test.absoluteFilePath() + QDir::separator(); - QTest::newRow(qPrintable(test.baseName())) - << dir + "input" - << dir + "output" - ; - } -} - -static void debug(const QVector &symbols, int index = -1) -{ - qDebug() << "all symbols:"; - for (int i = 0; i < symbols.count(); ++i) - qDebug() << "(" << i << "); Token:" << QCss::Scanner::tokenName(symbols.at(i).token) << "; Lexem:" << symbols.at(i).lexem(); - if (index != -1) - qDebug() << "failure at index" << index; -} - -//static void debug(const QCss::Parser &p) { debug(p.symbols); } - -void tst_CssParser::scanner() -{ - QFETCH(QString, input); - QFETCH(QString, output); - - QFile inputFile(input); - QVERIFY(inputFile.open(QIODevice::ReadOnly|QIODevice::Text)); - QVector symbols; - QCss::Scanner::scan(QCss::Scanner::preprocess(QString::fromUtf8(inputFile.readAll())), &symbols); - - QVERIFY(symbols.count() > 1); - QVERIFY(symbols.last().token == QCss::S); - QVERIFY(symbols.last().lexem() == QLatin1String("\n")); - symbols.remove(symbols.count() - 1, 1); - - QFile outputFile(output); - QVERIFY(outputFile.open(QIODevice::ReadOnly|QIODevice::Text)); - QStringList lines; - while (!outputFile.atEnd()) { - QString line = QString::fromUtf8(outputFile.readLine()); - if (line.endsWith(QLatin1Char('\n'))) - line.chop(1); - lines.append(line); - } - - if (lines.count() != symbols.count()) { - debug(symbols); - QCOMPARE(lines.count(), symbols.count()); - } - - for (int i = 0; i < lines.count(); ++i) { - QStringList l = lines.at(i).split(QChar::fromLatin1('|')); - QCOMPARE(l.count(), 2); - const QString expectedToken = l.at(0); - const QString expectedLexem = l.at(1); - QString actualToken = QString::fromLatin1(QCss::Scanner::tokenName(symbols.at(i).token)); - if (actualToken != expectedToken) { - debug(symbols, i); - QCOMPARE(actualToken, expectedToken); - } - if (symbols.at(i).lexem() != expectedLexem) { - debug(symbols, i); - QCOMPARE(symbols.at(i).lexem(), expectedLexem); - } - } -} - -Q_DECLARE_METATYPE(QCss::Value) - -void tst_CssParser::term_data() -{ - QTest::addColumn("parseSuccess"); - QTest::addColumn("css"); - QTest::addColumn("expectedValue"); - - QCss::Value val; - - val.type = QCss::Value::Percentage; - val.variant = QVariant(double(200)); - QTest::newRow("percentage") << true << "200%" << val; - - val.type = QCss::Value::Length; - val.variant = QString("10px"); - QTest::newRow("px") << true << "10px" << val; - - val.type = QCss::Value::Length; - val.variant = QString("10cm"); - QTest::newRow("cm") << true << "10cm" << val; - - val.type = QCss::Value::Length; - val.variant = QString("10mm"); - QTest::newRow("mm") << true << "10mm" << val; - - val.type = QCss::Value::Length; - val.variant = QString("10pt"); - QTest::newRow("pt") << true << "10pt" << val; - - val.type = QCss::Value::Length; - val.variant = QString("10pc"); - QTest::newRow("pc") << true << "10pc" << val; - - val.type = QCss::Value::Length; - val.variant = QString("42in"); - QTest::newRow("inch") << true << "42in" << val; - - val.type = QCss::Value::Length; - val.variant = QString("10deg"); - QTest::newRow("deg") << true << "10deg" << val; - - val.type = QCss::Value::Length; - val.variant = QString("10rad"); - QTest::newRow("rad") << true << "10rad" << val; - - val.type = QCss::Value::Length; - val.variant = QString("10grad"); - QTest::newRow("grad") << true << "10grad" << val; - - val.type = QCss::Value::Length; - val.variant = QString("10ms"); - QTest::newRow("time") << true << "10ms" << val; - - val.type = QCss::Value::Length; - val.variant = QString("10s"); - QTest::newRow("times") << true << "10s" << val; - - val.type = QCss::Value::Length; - val.variant = QString("10hz"); - QTest::newRow("hz") << true << "10hz" << val; - - val.type = QCss::Value::Length; - val.variant = QString("10khz"); - QTest::newRow("khz") << true << "10khz" << val; - - val.type = QCss::Value::Length; - val.variant = QString("10myunit"); - QTest::newRow("dimension") << true << "10myunit" << val; - - val.type = QCss::Value::Percentage; - - val.type = QCss::Value::Percentage; - val.variant = QVariant(double(-200)); - QTest::newRow("minuspercentage") << true << "-200%" << val; - - val.type = QCss::Value::Length; - val.variant = QString("10em"); - QTest::newRow("ems") << true << "10em" << val; - - val.type = QCss::Value::String; - val.variant = QVariant(QString("foo")); - QTest::newRow("string") << true << "\"foo\"" << val; - - val.type = QCss::Value::Function; - val.variant = QVariant(QStringList() << "myFunc" << "23, (nested text)"); - QTest::newRow("function") << true << "myFunc(23, (nested text))" << val; - - QTest::newRow("function_failure") << false << "myFunction((blah)" << val; - QTest::newRow("function_failure2") << false << "+myFunc(23, (nested text))" << val; - - val.type = QCss::Value::Color; - val.variant = QVariant(QColor("#12ff34")); - QTest::newRow("hexcolor") << true << "#12ff34" << val; - - val.type = QCss::Value::Color; - val.variant = QVariant(QColor("#ffbb00")); - QTest::newRow("hexcolor2") << true << "#fb0" << val; - - QTest::ignoreMessage(QtWarningMsg, "QCssParser::parseHexColor: Unknown color name '#cafebabe'"); - QTest::newRow("hexcolor_failure") << false << "#cafebabe" << val; - - val.type = QCss::Value::Uri; - val.variant = QString("www.kde.org"); - QTest::newRow("uri1") << true << "url(\"www.kde.org\")" << val; - - QTest::newRow("uri2") << true << "url(www.kde.org)" << val; - - val.type = QCss::Value::KnownIdentifier; - val.variant = int(QCss::Value_Italic); - QTest::newRow("italic") << true << "italic" << val; - - val.type = QCss::Value::KnownIdentifier; - val.variant = int(QCss::Value_Italic); - QTest::newRow("ItaLIc") << true << "ItaLIc" << val; -} - -void tst_CssParser::term() -{ - QFETCH(bool, parseSuccess); - QFETCH(QString, css); - QFETCH(QCss::Value, expectedValue); - - QCss::Parser parser(css); - QCss::Value val; - QVERIFY(parser.testTerm()); - QCOMPARE(parser.parseTerm(&val), parseSuccess); - if (parseSuccess) { - QCOMPARE(int(val.type), int(expectedValue.type)); - if (val.variant != expectedValue.variant) { - qDebug() << "val.variant:" << val.variant << "expectedValue.variant:" << expectedValue.variant; - QCOMPARE(val.variant, expectedValue.variant); - } - } -} - -Q_DECLARE_METATYPE(QVector) - -void tst_CssParser::expr_data() -{ - QTest::addColumn("parseSuccess"); - QTest::addColumn("css"); - QTest::addColumn >("expectedValues"); - - QVector values; - QCss::Value val; - - QCss::Value comma; - comma.type = QCss::Value::TermOperatorComma; - - val.type = QCss::Value::Identifier; - val.variant = QLatin1String("foo"); - values << val; - values << comma; - val.variant = QLatin1String("bar"); - values << val; - values << comma; - val.variant = QLatin1String("baz"); - values << val; - QTest::newRow("list") << true << "foo, bar, baz" << values; - values.clear(); -} - -void tst_CssParser::expr() -{ - QFETCH(bool, parseSuccess); - QFETCH(QString, css); - QFETCH(QVector, expectedValues); - - QCss::Parser parser(css); - QVector values; - QVERIFY(parser.testExpr()); - QCOMPARE(parser.parseExpr(&values), parseSuccess); - if (parseSuccess) { - QCOMPARE(values.count(), expectedValues.count()); - - for (int i = 0; i < values.count(); ++i) { - QCOMPARE(int(values.at(i).type), int(expectedValues.at(i).type)); - QCOMPARE(values.at(i).variant, expectedValues.at(i).variant); - } - } -} - -void tst_CssParser::import() -{ - QCss::Parser parser("@import \"plainstring\";"); - QVERIFY(parser.testImport()); - QCss::ImportRule rule; - QVERIFY(parser.parseImport(&rule)); - QCOMPARE(rule.href, QString("plainstring")); - - parser = QCss::Parser("@import url(\"www.kde.org\") print/*comment*/,screen;"); - QVERIFY(parser.testImport()); - QVERIFY(parser.parseImport(&rule)); - QCOMPARE(rule.href, QString("www.kde.org")); - QCOMPARE(rule.media.count(), 2); - QCOMPARE(rule.media.at(0), QString("print")); - QCOMPARE(rule.media.at(1), QString("screen")); -} - -void tst_CssParser::media() -{ - QCss::Parser parser("@media print/*comment*/,screen /*comment to ignore*/{ }"); - QVERIFY(parser.testMedia()); - QCss::MediaRule rule; - QVERIFY(parser.parseMedia(&rule)); - QCOMPARE(rule.media.count(), 2); - QCOMPARE(rule.media.at(0), QString("print")); - QCOMPARE(rule.media.at(1), QString("screen")); - QVERIFY(rule.styleRules.isEmpty()); -} - -void tst_CssParser::page() -{ - QCss::Parser parser("@page :first/*comment to ignore*/{ }"); - QVERIFY(parser.testPage()); - QCss::PageRule rule; - QVERIFY(parser.parsePage(&rule)); - QCOMPARE(rule.selector, QString("first")); - QVERIFY(rule.declarations.isEmpty()); -} - -void tst_CssParser::ruleset() -{ - { - QCss::Parser parser("p/*foo*/{ }"); - QVERIFY(parser.testRuleset()); - QCss::StyleRule rule; - QVERIFY(parser.parseRuleset(&rule)); - QCOMPARE(rule.selectors.count(), 1); - QCOMPARE(rule.selectors.at(0).basicSelectors.count(), 1); - QCOMPARE(rule.selectors.at(0).basicSelectors.at(0).elementName, QString("p")); - QVERIFY(rule.declarations.isEmpty()); - } - - { - QCss::Parser parser("p/*comment*/,div{ }"); - QVERIFY(parser.testRuleset()); - QCss::StyleRule rule; - QVERIFY(parser.parseRuleset(&rule)); - QCOMPARE(rule.selectors.count(), 2); - QCOMPARE(rule.selectors.at(0).basicSelectors.count(), 1); - QCOMPARE(rule.selectors.at(0).basicSelectors.at(0).elementName, QString("p")); - QCOMPARE(rule.selectors.at(1).basicSelectors.count(), 1); - QCOMPARE(rule.selectors.at(1).basicSelectors.at(0).elementName, QString("div")); - QVERIFY(rule.declarations.isEmpty()); - } - - { - QCss::Parser parser(":before, :after { }"); - QVERIFY(parser.testRuleset()); - QCss::StyleRule rule; - QVERIFY(parser.parseRuleset(&rule)); - QCOMPARE(rule.selectors.count(), 2); - - QCOMPARE(rule.selectors.at(0).basicSelectors.count(), 1); - QCOMPARE(rule.selectors.at(0).basicSelectors.at(0).pseudos.count(), 1); - QCOMPARE(rule.selectors.at(0).basicSelectors.at(0).pseudos.at(0).name, QString("before")); - - QCOMPARE(rule.selectors.at(1).basicSelectors.count(), 1); - QCOMPARE(rule.selectors.at(1).basicSelectors.at(0).pseudos.count(), 1); - QCOMPARE(rule.selectors.at(1).basicSelectors.at(0).pseudos.at(0).name, QString("after")); - - QVERIFY(rule.declarations.isEmpty()); - } - -} - -Q_DECLARE_METATYPE(QCss::Selector) - -void tst_CssParser::selector_data() -{ - QTest::addColumn("css"); - QTest::addColumn("expectedSelector"); - - { - QCss::Selector sel; - QCss::BasicSelector basic; - - basic.elementName = "p"; - basic.relationToNext = QCss::BasicSelector::MatchNextSelectorIfPreceeds; - sel.basicSelectors << basic; - - basic = QCss::BasicSelector(); - basic.elementName = "div"; - sel.basicSelectors << basic; - - QTest::newRow("comment") << QString("p/* */+ div") << sel; - } - - { - QCss::Selector sel; - QCss::BasicSelector basic; - - basic.elementName = QString(); - sel.basicSelectors << basic; - - QTest::newRow("any") << QString("*") << sel; - } - - { - QCss::Selector sel; - QCss::BasicSelector basic; - - basic.elementName = "e"; - sel.basicSelectors << basic; - - QTest::newRow("element") << QString("e") << sel; - } - - { - QCss::Selector sel; - QCss::BasicSelector basic; - - basic.elementName = "e"; - basic.relationToNext = QCss::BasicSelector::MatchNextSelectorIfAncestor; - sel.basicSelectors << basic; - - basic.elementName = "f"; - basic.relationToNext = QCss::BasicSelector::NoRelation; - sel.basicSelectors << basic; - - QTest::newRow("descendant") << QString("e f") << sel; - } - - { - QCss::Selector sel; - QCss::BasicSelector basic; - - basic.elementName = "e"; - basic.relationToNext = QCss::BasicSelector::MatchNextSelectorIfParent; - sel.basicSelectors << basic; - - basic.elementName = "f"; - basic.relationToNext = QCss::BasicSelector::NoRelation; - sel.basicSelectors << basic; - - QTest::newRow("parent") << QString("e > f") << sel; - } - - { - QCss::Selector sel; - QCss::BasicSelector basic; - - basic.elementName = "e"; - QCss::Pseudo pseudo; - pseudo.name = "first-child"; - basic.pseudos.append(pseudo); - sel.basicSelectors << basic; - - QTest::newRow("first-child") << QString("e:first-child") << sel; - } - - { - QCss::Selector sel; - QCss::BasicSelector basic; - - basic.elementName = "e"; - QCss::Pseudo pseudo; - pseudo.name = "c"; - pseudo.function = "lang"; - basic.pseudos.append(pseudo); - sel.basicSelectors << basic; - - QTest::newRow("lang") << QString("e:lang(c)") << sel; - } - - { - QCss::Selector sel; - QCss::BasicSelector basic; - - basic.elementName = "e"; - basic.relationToNext = QCss::BasicSelector::MatchNextSelectorIfPreceeds; - sel.basicSelectors << basic; - - basic.elementName = "f"; - basic.relationToNext = QCss::BasicSelector::NoRelation; - sel.basicSelectors << basic; - - QTest::newRow("precede") << QString("e + f") << sel; - } - - { - QCss::Selector sel; - QCss::BasicSelector basic; - - basic.elementName = "e"; - QCss::AttributeSelector attrSel; - attrSel.name = "foo"; - basic.attributeSelectors << attrSel; - sel.basicSelectors << basic; - - QTest::newRow("attr") << QString("e[foo]") << sel; - } - - { - QCss::Selector sel; - QCss::BasicSelector basic; - - basic.elementName = "e"; - QCss::AttributeSelector attrSel; - attrSel.name = "foo"; - attrSel.value = "warning"; - attrSel.valueMatchCriterium = QCss::AttributeSelector::MatchEqual; - basic.attributeSelectors << attrSel; - sel.basicSelectors << basic; - - QTest::newRow("attr-equal") << QString("e[foo=\"warning\"]") << sel; - } - - { - QCss::Selector sel; - QCss::BasicSelector basic; - - basic.elementName = "e"; - QCss::AttributeSelector attrSel; - attrSel.name = "foo"; - attrSel.value = "warning"; - attrSel.valueMatchCriterium = QCss::AttributeSelector::MatchContains; - basic.attributeSelectors << attrSel; - sel.basicSelectors << basic; - - QTest::newRow("attr-contains") << QString("e[foo~=\"warning\"]") << sel; - } - - { - QCss::Selector sel; - QCss::BasicSelector basic; - - basic.elementName = "e"; - QCss::AttributeSelector attrSel; - attrSel.name = "lang"; - attrSel.value = "en"; - attrSel.valueMatchCriterium = QCss::AttributeSelector::MatchBeginsWith; - basic.attributeSelectors << attrSel; - sel.basicSelectors << basic; - - QTest::newRow("attr-contains") << QString("e[lang|=\"en\"]") << sel; - } - - { - QCss::Selector sel; - QCss::BasicSelector basic; - - basic.elementName = "div"; - - QCss::AttributeSelector attrSel; - attrSel.name = "class"; - attrSel.valueMatchCriterium = QCss::AttributeSelector::MatchContains; - attrSel.value = "warning"; - basic.attributeSelectors.append(attrSel); - - attrSel.value = "foo"; - basic.attributeSelectors.append(attrSel); - - sel.basicSelectors << basic; - - QTest::newRow("class") << QString("div.warning.foo") << sel; - } - - { - QCss::Selector sel; - QCss::BasicSelector basic; - - basic.elementName = "e"; - basic.ids << "myid"; - sel.basicSelectors << basic; - - QTest::newRow("id") << QString("e#myid") << sel; - } -} - -void tst_CssParser::selector() -{ - QFETCH(QString, css); - QFETCH(QCss::Selector, expectedSelector); - - QCss::Parser parser(css); - QVERIFY(parser.testSelector()); - QCss::Selector selector; - QVERIFY(parser.parseSelector(&selector)); - - QCOMPARE(selector.basicSelectors.count(), expectedSelector.basicSelectors.count()); - for (int i = 0; i < selector.basicSelectors.count(); ++i) { - const QCss::BasicSelector sel = selector.basicSelectors.at(i); - const QCss::BasicSelector expectedSel = expectedSelector.basicSelectors.at(i); - QCOMPARE(sel.elementName, expectedSel.elementName); - QCOMPARE(int(sel.relationToNext), int(expectedSel.relationToNext)); - - QCOMPARE(sel.pseudos.count(), expectedSel.pseudos.count()); - for (int i = 0; i < sel.pseudos.count(); ++i) { - QCOMPARE(sel.pseudos.at(i).name, expectedSel.pseudos.at(i).name); - QCOMPARE(sel.pseudos.at(i).function, expectedSel.pseudos.at(i).function); - } - - QCOMPARE(sel.attributeSelectors.count(), expectedSel.attributeSelectors.count()); - for (int i = 0; i < sel.attributeSelectors.count(); ++i) { - QCOMPARE(sel.attributeSelectors.at(i).name, expectedSel.attributeSelectors.at(i).name); - QCOMPARE(sel.attributeSelectors.at(i).value, expectedSel.attributeSelectors.at(i).value); - QCOMPARE(int(sel.attributeSelectors.at(i).valueMatchCriterium), int(expectedSel.attributeSelectors.at(i).valueMatchCriterium)); - } - } -} - -void tst_CssParser::prio() -{ - { - QCss::Parser parser("!important"); - QVERIFY(parser.testPrio()); - } - { - QCss::Parser parser("!impOrTAnt"); - QVERIFY(parser.testPrio()); - } - { - QCss::Parser parser("!\"important\""); - QVERIFY(!parser.testPrio()); - QCOMPARE(parser.index, 0); - } - { - QCss::Parser parser("!importbleh"); - QVERIFY(!parser.testPrio()); - QCOMPARE(parser.index, 0); - } -} - -void tst_CssParser::escapes() -{ - QCss::Parser parser("\\hello"); - parser.test(QCss::IDENT); - QCOMPARE(parser.lexem(), QString("hello")); -} - -void tst_CssParser::malformedDeclarations_data() -{ - QTest::addColumn("css"); - - QTest::newRow("1") << QString("p { color:green }"); - QTest::newRow("2") << QString("p { color:green; color } /* malformed declaration missing ':', value */"); - QTest::newRow("3") << QString("p { color:red; color; color:green } /* same with expected recovery */"); - QTest::newRow("4") << QString("p { color:green; color: } /* malformed declaration missing value */"); - QTest::newRow("5") << QString("p { color:red; color:; color:green } /* same with expected recovery */"); - QTest::newRow("6") << QString("p { color:green; color{;color:maroon} } /* unexpected tokens { } */"); - QTest::newRow("7") << QString("p { color:red; color{;color:maroon}; color:green } /* same with recovery */"); -} - -void tst_CssParser::malformedDeclarations() -{ - QFETCH(QString, css); - QCss::Parser parser(css); - QVERIFY(parser.testRuleset()); - QCss::StyleRule rule; - QVERIFY(parser.parseRuleset(&rule)); - - QCOMPARE(rule.selectors.count(), 1); - QCOMPARE(rule.selectors.at(0).basicSelectors.count(), 1); - QCOMPARE(rule.selectors.at(0).basicSelectors.at(0).elementName, QString("p")); - - QVERIFY(rule.declarations.count() >= 1); - QCOMPARE(int(rule.declarations.last().d->propertyId), int(QCss::Color)); - QCOMPARE(rule.declarations.last().d->values.count(), 1); - QCOMPARE(int(rule.declarations.last().d->values.at(0).type), int(QCss::Value::Identifier)); - QCOMPARE(rule.declarations.last().d->values.at(0).variant.toString(), QString("green")); -} - -void tst_CssParser::invalidAtKeywords() -{ - QCss::Parser parser("" - "@three-dee {" - " @background-lighting {" - " azimuth: 30deg;" - " elevation: 190deg;" - " }" - " h1 { color: red }" - "}" - "h1 { color: blue }"); - - QCss::StyleSheet sheet; - QVERIFY(parser.parse(&sheet)); - - QCOMPARE(sheet.styleRules.count() + sheet.nameIndex.count(), 1); - QCss::StyleRule rule = (!sheet.styleRules.isEmpty()) ? - sheet.styleRules.at(0) : *sheet.nameIndex.begin(); - - QCOMPARE(rule.selectors.count(), 1); - QCOMPARE(rule.selectors.at(0).basicSelectors.count(), 1); - QCOMPARE(rule.selectors.at(0).basicSelectors.at(0).elementName, QString("h1")); - - QCOMPARE(rule.declarations.count(), 1); - QCOMPARE(int(rule.declarations.at(0).d->propertyId), int(QCss::Color)); - QCOMPARE(rule.declarations.at(0).d->values.count(), 1); - QCOMPARE(int(rule.declarations.at(0).d->values.at(0).type), int(QCss::Value::Identifier)); - QCOMPARE(rule.declarations.at(0).d->values.at(0).variant.toString(), QString("blue")); -} - -Q_DECLARE_METATYPE(QColor) - -void tst_CssParser::colorValue_data() -{ - QTest::addColumn("css"); - QTest::addColumn("expectedColor"); - - QTest::newRow("identifier") << "color: black" << QColor("black"); - QTest::newRow("string") << "color: \"green\"" << QColor("green"); - QTest::newRow("hexcolor") << "color: #12af0e" << QColor(0x12, 0xaf, 0x0e); - QTest::newRow("functional1") << "color: rgb(21, 45, 73)" << QColor(21, 45, 73); - QTest::newRow("functional2") << "color: rgb(100%, 0%, 100%)" << QColor(0xff, 0, 0xff); - QTest::newRow("rgba") << "color: rgba(10, 20, 30, 40)" << QColor(10, 20, 30, 40); - QTest::newRow("rgb") << "color: rgb(10, 20, 30, 40)" << QColor(10, 20, 30, 40); - QTest::newRow("hsl") << "color: hsv(10, 20, 30)" << QColor::fromHsv(10, 20, 30, 255); - QTest::newRow("hsla") << "color: hsva(10, 20, 30, 40)" << QColor::fromHsv(10, 20, 30, 40); - QTest::newRow("invalid1") << "color: rgb(why, does, it, always, rain, on, me)" << QColor(); - QTest::newRow("invalid2") << "color: rgba(i, meant, norway)" << QColor(); - QTest::newRow("role") << "color: palette(base)" << qApp->palette().color(QPalette::Base); - QTest::newRow("role2") << "color: palette( window-text ) " << qApp->palette().color(QPalette::WindowText); - QTest::newRow("transparent") << "color: transparent" << QColor(Qt::transparent); -} - -void tst_CssParser::colorValue() -{ - QFETCH(QString, css); - QFETCH(QColor, expectedColor); - - QCss::Parser parser(css); - QCss::Declaration decl; - QVERIFY(parser.parseNextDeclaration(&decl)); - const QColor col = decl.colorValue(); - QVERIFY(expectedColor.isValid() == col.isValid()); - QCOMPARE(col, expectedColor); -} - -class DomStyleSelector : public QCss::StyleSelector -{ -public: - inline DomStyleSelector(const QDomDocument &doc, const QCss::StyleSheet &sheet) - : doc(doc) - { - styleSheets.append(sheet); - } - - virtual QStringList nodeNames(NodePtr node) const { return QStringList(reinterpret_cast(node.ptr)->tagName()); } - virtual QString attribute(NodePtr node, const QString &name) const { return reinterpret_cast(node.ptr)->attribute(name); } - virtual bool hasAttribute(NodePtr node, const QString &name) const { return reinterpret_cast(node.ptr)->hasAttribute(name); } - virtual bool hasAttributes(NodePtr node) const { return reinterpret_cast(node.ptr)->hasAttributes(); } - - virtual bool isNullNode(NodePtr node) const { - return reinterpret_cast(node.ptr)->isNull(); - } - virtual NodePtr parentNode(NodePtr node) const { - NodePtr parent; - parent.ptr = new QDomElement(reinterpret_cast(node.ptr)->parentNode().toElement()); - return parent; - } - virtual NodePtr duplicateNode(NodePtr node) const { - NodePtr n; - n.ptr = new QDomElement(*reinterpret_cast(node.ptr)); - return n; - } - virtual NodePtr previousSiblingNode(NodePtr node) const { - NodePtr sibling; - sibling.ptr = new QDomElement(reinterpret_cast(node.ptr)->previousSiblingElement()); - return sibling; - } - virtual void freeNode(NodePtr node) const { - delete reinterpret_cast(node.ptr); - } - -private: - QDomDocument doc; -}; - -Q_DECLARE_METATYPE(QDomDocument); - -void tst_CssParser::marginValue_data() -{ - QTest::addColumn("css"); - QTest::addColumn("expectedMargin"); - - QFont f; - int ex = QFontMetrics(f).xHeight(); - int em = QFontMetrics(f).height(); - - QTest::newRow("one value") << "margin: 1px" << "1 1 1 1"; - QTest::newRow("two values") << "margin: 1px 2px" << "1 2 1 2"; - QTest::newRow("three value") << "margin: 1px 2px 3px" << "1 2 3 2"; - QTest::newRow("four values") << "margin: 1px 2px 3px 4px" << "1 2 3 4"; - QTest::newRow("default px") << "margin: 1 2 3 4" << "1 2 3 4"; - QTest::newRow("no unit") << "margin: 1 2 3 4" << "1 2 3 4"; - QTest::newRow("em") << "margin: 1ex 2ex 3ex 4ex" << QString("%1 %2 %3 %4").arg(ex).arg(2*ex).arg(3*ex).arg(4*ex); - QTest::newRow("ex") << "margin: 1 2em 3px 4ex" << QString("%1 %2 %3 %4").arg(1).arg(2*em).arg(3).arg(4*ex); - - f.setPointSize(20); - f.setBold(true); - ex = QFontMetrics(f).xHeight(); - em = QFontMetrics(f).height(); - QTest::newRow("em2") << "font: bold 20pt; margin: 1ex 2ex 3ex 4ex" << QString("%1 %2 %3 %4").arg(ex).arg(2*ex).arg(3*ex).arg(4*ex); - QTest::newRow("ex2") << "margin: 1 2em 3px 4ex; font-size: 20pt; font-weight: bold;" << QString("%1 %2 %3 %4").arg(1).arg(2*em).arg(3).arg(4*ex); - - QTest::newRow("crap") << "margin: crap" << "0 0 0 0"; -} - -void tst_CssParser::marginValue() -{ - QFETCH(QString, css); - QFETCH(QString, expectedMargin); - - QDomDocument doc; - QVERIFY(doc.setContent(QLatin1String(" "))); - - css.prepend("dummy {"); - css.append("}"); - - QCss::Parser parser(css); - QCss::StyleSheet sheet; - QVERIFY(parser.parse(&sheet)); - - DomStyleSelector testSelector(doc, sheet); - QDomElement e = doc.documentElement().firstChildElement(); - QCss::StyleSelector::NodePtr n; - n.ptr = &e; - QVector rules = testSelector.styleRulesForNode(n); - QVector decls = rules.at(0).declarations; - QCss::ValueExtractor v(decls); - - { - int m[4]; - int p[4]; - int spacing; - v.extractBox(m, p, &spacing); - QString str = QString("%1 %2 %3 %4").arg(m[0]).arg(m[1]).arg(m[2]).arg(m[3]); - QCOMPARE(str, expectedMargin); - } -} - -void tst_CssParser::styleSelector_data() -{ - QTest::addColumn("match"); - QTest::addColumn("selector"); - QTest::addColumn("xml"); - QTest::addColumn("elementToCheck"); - - QTest::newRow("plain") << true << QString("p") << QString("

") << QString(); - QTest::newRow("noplain") << false << QString("bar") << QString("

") << QString(); - - QTest::newRow("class") << true << QString(".foo") << QString("

") << QString(); - QTest::newRow("noclass") << false << QString(".bar") << QString("

") << QString(); - - QTest::newRow("attrset") << true << QString("[justset]") << QString("

") << QString(); - QTest::newRow("notattrset") << false << QString("[justset]") << QString("

") << QString(); - - QTest::newRow("attrmatch") << true << QString("[foo=bar]") << QString("

") << QString(); - QTest::newRow("noattrmatch") << false << QString("[foo=bar]") << QString("

") << QString(); - - QTest::newRow("contains") << true << QString("[foo~=bar]") << QString("

") << QString(); - QTest::newRow("notcontains") << false << QString("[foo~=bar]") << QString("

") << QString(); - - QTest::newRow("beingswith") << true << QString("[foo|=bar]") << QString("

") << QString(); - QTest::newRow("notbeingswith") << false << QString("[foo|=bar]") << QString("

") << QString(); - - QTest::newRow("attr2") << true << QString("[bar=foo]") << QString("

") << QString(); - - QTest::newRow("universal1") << true << QString("*") << QString("

") << QString(); - - QTest::newRow("universal3") << false << QString("*[foo=bar]") << QString("

") << QString(); - QTest::newRow("universal4") << true << QString("*[foo=bar]") << QString("

") << QString(); - - QTest::newRow("universal5") << false << QString("[foo=bar]") << QString("

") << QString(); - QTest::newRow("universal6") << true << QString("[foo=bar]") << QString("

") << QString(); - - QTest::newRow("universal7") << true << QString(".charfmt1") << QString("

") << QString(); - - QTest::newRow("id") << true << QString("#blub") << QString("

") << QString(); - QTest::newRow("noid") << false << QString("#blub") << QString("

") << QString(); - - QTest::newRow("childselector") << true << QString("parent > child") - << QString("") - << QString("parent/child"); - - QTest::newRow("nochildselector2") << false << QString("parent > child") - << QString("") - << QString("child/parent"); - - QTest::newRow("nochildselector3") << false << QString("parent > child") - << QString("") - << QString("parent/intermediate/child"); - - QTest::newRow("childselector2") << true << QString("parent[foo=bar] > child") - << QString("") - << QString("parent/child"); - - QTest::newRow("nochildselector4") << false << QString("parent[foo=bar] > child") - << QString("") - << QString("parent/child"); - - QTest::newRow("nochildselector5") << false << QString("parent[foo=bar] > child") - << QString("") - << QString("parent/parent/child"); - - QTest::newRow("childselectors") << true << QString("grandparent > parent > child") - << QString("") - << QString("grandparent/parent/child"); - - QTest::newRow("descendant") << true << QString("grandparent child") - << QString("") - << QString("grandparent/parent/child"); - - QTest::newRow("nodescendant") << false << QString("grandparent child") - << QString("") - << QString("other/parent/child"); - - QTest::newRow("descendant2") << true << QString("grandgrandparent grandparent child") - << QString("") - << QString("grandgrandparent/inbetween/grandparent/parent/child"); - - QTest::newRow("combined") << true << QString("grandparent parent > child") - << QString("") - << QString("grandparent/inbetween/parent/child"); - - QTest::newRow("combined2") << true << QString("grandparent > parent child") - << QString("") - << QString("grandparent/parent/inbetween/child"); - - QTest::newRow("combined3") << true << QString("grandparent > parent child") - << QString("") - << QString("grandparent/parent/inbetween/child"); - - QTest::newRow("nocombined") << false << QString("grandparent parent > child") - << QString("") - << QString("inbetween/parent/child"); - - QTest::newRow("nocombined2") << false << QString("grandparent parent > child") - << QString("") - << QString("parent/child"); - - QTest::newRow("previoussibling") << true << QString("p1 + p2") - << QString("") - << QString("p2"); - - QTest::newRow("noprevioussibling") << false << QString("p2 + p1") - << QString("") - << QString("p2"); - - QTest::newRow("ancestry_firstmismatch") << false << QString("parent child[foo=bar]") - << QString("") - << QString("parent/child"); - - QTest::newRow("unknown-pseudo") << false << QString("p:enabled:foobar") << QString("

") << QString(); -} - -void tst_CssParser::styleSelector() -{ - QFETCH(bool, match); - QFETCH(QString, selector); - QFETCH(QString, xml); - QFETCH(QString, elementToCheck); - - QString css = QString("%1 { background-color: green }").arg(selector); - QCss::Parser parser(css); - QCss::StyleSheet sheet; - QVERIFY(parser.parse(&sheet)); - - QDomDocument doc; - xml.prepend(""); - xml.append(""); - QVERIFY(doc.setContent(xml)); - - DomStyleSelector testSelector(doc, sheet); - - QDomElement e = doc.documentElement(); - if (elementToCheck.isEmpty()) { - e = e.firstChildElement(); - } else { - QStringList path = elementToCheck.split(QLatin1Char('/')); - do { - e = e.namedItem(path.takeFirst()).toElement(); - } while (!path.isEmpty()); - } - QVERIFY(!e.isNull()); - QCss::StyleSelector::NodePtr n; - n.ptr = &e; - QVector decls = testSelector.declarationsForNode(n); - - if (match) { - QCOMPARE(decls.count(), 1); - QCOMPARE(int(decls.at(0).d->propertyId), int(QCss::BackgroundColor)); - QCOMPARE(decls.at(0).d->values.count(), 1); - QCOMPARE(int(decls.at(0).d->values.at(0).type), int(QCss::Value::Identifier)); - QCOMPARE(decls.at(0).d->values.at(0).variant.toString(), QString("green")); - } else { - QVERIFY(decls.isEmpty()); - } -} - -void tst_CssParser::specificity_data() -{ - QTest::addColumn("selector"); - QTest::addColumn("specificity"); - - QTest::newRow("universal") << QString("*") << 0; - - QTest::newRow("elements+pseudos1") << QString("foo") << 1; - QTest::newRow("elements+pseudos2") << QString("foo *[blah]") << 1 + (1 * 0x10); - - // should strictly speaking be '2', but we don't support pseudo-elements yet, - // only pseudo-classes - QTest::newRow("elements+pseudos3") << QString("li:first-line") << 1 + (1 * 0x10); - - QTest::newRow("elements+pseudos4") << QString("ul li") << 2; - QTest::newRow("elements+pseudos5") << QString("ul ol+li") << 3; - QTest::newRow("elements+pseudos6") << QString("h1 + *[rel=up]") << 1 + (1 * 0x10); - - QTest::newRow("elements+pseudos7") << QString("ul ol li.red") << 3 + (1 * 0x10); - QTest::newRow("elements+pseudos8") << QString("li.red.level") << 1 + (2 * 0x10); - QTest::newRow("id") << QString("#x34y") << 1 * 0x100; -} - -void tst_CssParser::specificity() -{ - QFETCH(QString, selector); - - QString css = QString("%1 { }").arg(selector); - QCss::Parser parser(css); - QCss::StyleSheet sheet; - QVERIFY(parser.parse(&sheet)); - - QCOMPARE(sheet.styleRules.count() + sheet.nameIndex.count() + sheet.idIndex.count() , 1); - QCss::StyleRule rule = (!sheet.styleRules.isEmpty()) ? sheet.styleRules.at(0) - : (!sheet.nameIndex.isEmpty()) ? *sheet.nameIndex.begin() - : *sheet.idIndex.begin(); - QCOMPARE(rule.selectors.count(), 1); - QTEST(rule.selectors.at(0).specificity(), "specificity"); -} - -void tst_CssParser::specificitySort_data() -{ - QTest::addColumn("firstSelector"); - QTest::addColumn("secondSelector"); - QTest::addColumn("xml"); - - QTest::newRow("universal1") << QString("*") << QString("p") << QString("

"); - QTest::newRow("attr") << QString("p") << QString("p[foo=bar]") << QString("

"); - QTest::newRow("id") << QString("p") << QString("#hey") << QString("

"); - QTest::newRow("id2") << QString("[id=hey]") << QString("#hey") << QString("

"); - QTest::newRow("class") << QString("p") << QString(".hey") << QString("

"); -} - -void tst_CssParser::specificitySort() -{ - QFETCH(QString, firstSelector); - QFETCH(QString, secondSelector); - QFETCH(QString, xml); - - firstSelector.append(" { color: green; }"); - secondSelector.append(" { color: red; }"); - - QDomDocument doc; - xml.prepend(""); - xml.append(""); - QVERIFY(doc.setContent(xml)); - - for (int i = 0; i < 2; ++i) { - QString css; - if (i == 0) - css = firstSelector + secondSelector; - else - css = secondSelector + firstSelector; - - QCss::Parser parser(css); - QCss::StyleSheet sheet; - QVERIFY(parser.parse(&sheet)); - - DomStyleSelector testSelector(doc, sheet); - - QDomElement e = doc.documentElement().firstChildElement(); - QCss::StyleSelector::NodePtr n; - n.ptr = &e; - QVector decls = testSelector.declarationsForNode(n); - - QCOMPARE(decls.count(), 2); - - QCOMPARE(int(decls.at(0).d->propertyId), int(QCss::Color)); - QCOMPARE(decls.at(0).d->values.count(), 1); - QCOMPARE(int(decls.at(0).d->values.at(0).type), int(QCss::Value::Identifier)); - QCOMPARE(decls.at(0).d->values.at(0).variant.toString(), QString("green")); - - QCOMPARE(int(decls.at(1).d->propertyId), int(QCss::Color)); - QCOMPARE(decls.at(1).d->values.count(), 1); - QCOMPARE(int(decls.at(1).d->values.at(0).type), int(QCss::Value::Identifier)); - QCOMPARE(decls.at(1).d->values.at(0).variant.toString(), QString("red")); - } -} - -void tst_CssParser::rulesForNode_data() -{ - QTest::addColumn("xml"); - QTest::addColumn("css"); - QTest::addColumn("pseudoClass"); - QTest::addColumn("declCount"); - QTest::addColumn("value0"); - QTest::addColumn("value1"); - - QTest::newRow("universal1") << QString("

") << QString("* { color: red }") - << (quint64)QCss::PseudoClass_Unspecified << 1 << "red" << ""; - - QTest::newRow("basic") << QString("

") << QString("p:enabled { color: red; bg:blue; }") - << (quint64)QCss::PseudoClass_Enabled << 2 << "red" << "blue"; - - QTest::newRow("single") << QString("

") - << QString("p:enabled { color: red; } *:hover { color: white }") - << (quint64)QCss::PseudoClass_Hover << 1 << "white" << ""; - - QTest::newRow("multisel") << QString("

") - << QString("p:enabled { color: red; } p:hover { color: gray } *:hover { color: white } ") - << (quint64)QCss::PseudoClass_Hover << 2 << "white" << "gray"; - - QTest::newRow("multisel2") << QString("

") - << QString("p:enabled { color: red; } p:hover:focus { color: gray } *:hover { color: white } ") - << quint64(QCss::PseudoClass_Hover|QCss::PseudoClass_Focus) << 2 << "white" << "gray"; - - QTest::newRow("multisel3-diffspec") << QString("

") - << QString("p:enabled { color: red; } p:hover:focus { color: gray } *:hover { color: white } ") - << quint64(QCss::PseudoClass_Hover) << 1 << "white" << ""; - - QTest::newRow("!-1") << QString("

") - << QString("p:checked:!hover { color: red; } p:checked:hover { color: gray } p:checked { color: white }") - << quint64(QCss::PseudoClass_Hover|QCss::PseudoClass_Checked) << 2 << "white" << "gray"; - - QTest::newRow("!-2") << QString("

") - << QString("p:checked:!hover:!pressed { color: red; } p:!checked:hover { color: gray } p:!focus { color: blue }") - << quint64(QCss::PseudoClass_Focus) << 0 << "" << ""; - - QTest::newRow("!-3") << QString("

") - << QString("p:checked:!hover:!pressed { color: red; } p:!checked:hover { color: gray } p:!focus { color: blue; }") - << quint64(QCss::PseudoClass_Pressed) << 1 << "blue" << ""; -} - -void tst_CssParser::rulesForNode() -{ - QFETCH(QString, xml); - QFETCH(QString, css); - QFETCH(quint64, pseudoClass); - QFETCH(int, declCount); - QFETCH(QString, value0); - QFETCH(QString, value1); - - QDomDocument doc; - xml.prepend(""); - xml.append(""); - QVERIFY(doc.setContent(xml)); - - QCss::Parser parser(css); - QCss::StyleSheet sheet; - QVERIFY(parser.parse(&sheet)); - - DomStyleSelector testSelector(doc, sheet); - QDomElement e = doc.documentElement().firstChildElement(); - QCss::StyleSelector::NodePtr n; - n.ptr = &e; - QVector rules = testSelector.styleRulesForNode(n); - - QVector decls; - for (int i = 0; i < rules.count(); i++) { - const QCss::Selector &selector = rules.at(i).selectors.at(0); - quint64 negated = 0; - quint64 cssClass = selector.pseudoClass(&negated); - if ((cssClass == QCss::PseudoClass_Unspecified) - || ((((cssClass & pseudoClass) == cssClass)) && ((negated & pseudoClass) == 0))) - decls += rules.at(i).declarations; - } - - QVERIFY(decls.count() == declCount); - - if (declCount > 0) - QCOMPARE(decls.at(0).d->values.at(0).variant.toString(), value0); - if (declCount > 1) - QCOMPARE(decls.at(1).d->values.at(0).variant.toString(), value1); -} - -void tst_CssParser::shorthandBackgroundProperty_data() -{ - QTest::addColumn("css"); - QTest::addColumn("expectedBrush"); - QTest::addColumn("expectedImage"); - QTest::addColumn("expectedRepeatValue"); - QTest::addColumn("expectedAlignment"); - - QTest::newRow("simple color") << "background: red" << QBrush(QColor("red")) << QString() << int(QCss::Repeat_XY) << int(Qt::AlignLeft | Qt::AlignTop); - QTest::newRow("plain color") << "background-color: red" << QBrush(QColor("red")) << QString() << int(QCss::Repeat_XY) << int(Qt::AlignLeft | Qt::AlignTop); - QTest::newRow("palette color") << "background-color: palette(mid)" << qApp->palette().mid() << QString() << int(QCss::Repeat_XY) << int(Qt::AlignLeft | Qt::AlignTop); - QTest::newRow("multiple") << "background: url(chess.png) blue repeat-y" << QBrush(QColor("blue")) << QString("chess.png") << int(QCss::Repeat_Y) << int(Qt::AlignLeft | Qt::AlignTop); - QTest::newRow("plain alignment") << "background-position: center" << QBrush() << QString() << int(QCss::Repeat_XY) << int(Qt::AlignCenter); - QTest::newRow("plain alignment2") << "background-position: left top" << QBrush() << QString() << int(QCss::Repeat_XY) << int(Qt::AlignLeft | Qt::AlignTop); - QTest::newRow("plain alignment3") << "background-position: left" << QBrush() << QString() << int(QCss::Repeat_XY) << int(Qt::AlignLeft | Qt::AlignVCenter); - QTest::newRow("multi") << "background: left url(blah.png) repeat-x" << QBrush() << QString("blah.png") << int(QCss::Repeat_X) << int(Qt::AlignLeft | Qt::AlignVCenter); - QTest::newRow("multi2") << "background: url(blah.png) repeat-x top" << QBrush() << QString("blah.png") << int(QCss::Repeat_X) << int(Qt::AlignTop | Qt::AlignHCenter); - QTest::newRow("multi3") << "background: url(blah.png) top right" << QBrush() << QString("blah.png") << int(QCss::Repeat_XY) << int(Qt::AlignTop | Qt::AlignRight); -} - -void tst_CssParser::shorthandBackgroundProperty() -{ - QFETCH(QString, css); - - QDomDocument doc; - QVERIFY(doc.setContent(QLatin1String(" "))); - - css.prepend("dummy {"); - css.append("}"); - - QCss::Parser parser(css); - QCss::StyleSheet sheet; - QVERIFY(parser.parse(&sheet)); - - DomStyleSelector testSelector(doc, sheet); - QDomElement e = doc.documentElement().firstChildElement(); - QCss::StyleSelector::NodePtr n; - n.ptr = &e; - QVector rules = testSelector.styleRulesForNode(n); - QVector decls = rules.at(0).declarations; - QCss::ValueExtractor v(decls); - - QBrush brush; - QString image; - QCss::Repeat repeat = QCss::Repeat_XY; - Qt::Alignment alignment = Qt::AlignTop | Qt::AlignLeft; - QCss::Origin origin = QCss::Origin_Padding; - QCss::Attachment attachment; - QCss::Origin ignoredOrigin; - v.extractBackground(&brush, &image, &repeat, &alignment, &origin, &attachment, &ignoredOrigin); - - QFETCH(QBrush, expectedBrush); - QVERIFY(expectedBrush.color() == brush.color()); - - QTEST(image, "expectedImage"); - QTEST(int(repeat), "expectedRepeatValue"); - QTEST(int(alignment), "expectedAlignment"); -} - -void tst_CssParser::pseudoElement_data() -{ - QTest::addColumn("css"); - QTest::addColumn("pseudoElement"); - QTest::addColumn("declCount"); - - // QComboBox::dropDown { border-image: blah; } - QTest::newRow("no pseudo-elements") << QString("dummy:hover { color: red }") << "" << 1; - QTest::newRow("no pseudo-elements") << QString("dummy:hover { color: red }") << "pe" << 0; - - QTest::newRow("1 pseudo-element (1)") << QString("dummy::pe:hover { color: red }") << "pe" << 1; - QTest::newRow("1 pseudo-element (2)") << QString("dummy::pe:hover { color: red }") << "x" << 0; - QTest::newRow("1 pseudo-element (2)") << QString("whatever::pe:hover { color: red }") << "pe" << 0; - - QTest::newRow("1 pseudo-element (3)") - << QString("dummy { color: white; } dummy::pe:hover { color: red }") << "x" << 0; - QTest::newRow("1 pseudo-element (4)") - << QString("dummy { color: white; } dummy::pe:hover { color: red } dummy { x:y }") << "" << 2; - QTest::newRow("1 pseudo-element (5)") - << QString("dummy { color: white; } dummy::pe:hover { color: red }") << "pe" << 1; - QTest::newRow("1 pseudo-element (6)") - << QString("dummy { color: white; } dummy::pe:hover { color: red } dummy::pe:checked { x: y} ") << "pe" << 2; - - QTest::newRow("2 pseudo-elements (1)") - << QString("dummy { color: white; } dummy::pe1:hover { color: red } dummy::pe2:checked { x: y} ") - << "" << 1; - QTest::newRow("2 pseudo-elements (1)") - << QString("dummy { color: white; } dummy::pe1:hover { color: red } dummy::pe2:checked { x: y} ") - << "pe1" << 1; - QTest::newRow("2 pseudo-elements (2)") - << QString("dummy { color: white; } dummy::pe1:hover { color: red } dummy::pe2:checked { x: y} ") - << "pe2" << 1; -} - -void tst_CssParser::pseudoElement() -{ - QFETCH(QString, css); - QFETCH(QString, pseudoElement); - QFETCH(int, declCount); - - QDomDocument doc; - QVERIFY(doc.setContent(QLatin1String(" "))); - - QCss::Parser parser(css); - QCss::StyleSheet sheet; - QVERIFY(parser.parse(&sheet)); - - DomStyleSelector testSelector(doc, sheet); - QDomElement e = doc.documentElement().firstChildElement(); - QCss::StyleSelector::NodePtr n; - n.ptr = &e; - QVector rules = testSelector.styleRulesForNode(n); - QVector decls; - for (int i = 0; i < rules.count(); i++) { - const QCss::Selector& selector = rules.at(i).selectors.at(0); - if (pseudoElement.compare(selector.pseudoElement(), Qt::CaseInsensitive) != 0) - continue; - decls += rules.at(i).declarations; - - } - QVERIFY(decls.count() == declCount); -} - -void tst_CssParser::gradient_data() -{ - QTest::addColumn("css"); - QTest::addColumn("type"); - QTest::addColumn("start"); - QTest::addColumn("finalStop"); - QTest::addColumn("spread"); - QTest::addColumn("stop0"); - QTest::addColumn("color0"); - QTest::addColumn("stop1"); - QTest::addColumn("color1"); - - QTest::newRow("color-string") << - "selection-background-color: qlineargradient(x1:1, y1:2, x2:3, y2:4, " - "stop:0.2 red, stop:0.5 green)" << "linear" << QPointF(1, 2) << QPointF(3, 4) - << 0 << qreal(0.2) << QColor("red") << qreal(0.5) << QColor("green"); - - QTest::newRow("color-#") << - "selection-background-color: qlineargradient(x1:0, y1:0, x2:0, y2:1, " - "spread: reflect, stop:0.2 #123, stop:0.5 #456)" << "linear" << QPointF(0, 0) << QPointF(0, 1) - << 1 << qreal(0.2) << QColor("#123") << qreal(0.5) << QColor("#456"); - - QTest::newRow("color-rgb") << - "selection-background-color: qlineargradient(x1:0, y1:0, x2:0, y2:1, " - "spread: reflect, stop:0.2 rgb(1, 2, 3), stop:0.5 rgba(1, 2, 3, 4))" << "linear" << QPointF(0, 0) << QPointF(0, 1) - << 1 << qreal(0.2) << QColor(1, 2, 3) << qreal(0.5) << QColor(1, 2, 3, 4); - - QTest::newRow("color-spaces") << - "selection-background-color: qlineargradient(x1: 0, y1 :0,x2:0, y2 : 1 , " - "spread: reflect, stop:0.2 rgb(1, 2, 3), stop: 0.5 rgba(1, 2, 3, 4))" << "linear" << QPointF(0, 0) << QPointF(0, 1) - << 1 << qreal(0.2) << QColor(1, 2, 3) << qreal(0.5) << QColor(1, 2, 3, 4); - - QTest::newRow("conical gradient") << - "selection-background-color: qconicalgradient(cx: 4, cy : 2, angle: 23, " - "spread: repeat, stop:0.2 rgb(1, 2, 3), stop:0.5 rgba(1, 2, 3, 4))" << "conical" << QPointF(4, 2) << QPointF() - << 2 << qreal(0.2) << QColor(1, 2, 3) << qreal(0.5) << QColor(1, 2, 3, 4); - - /* wont pass: stop values are expected to be sorted - QTest::newRow("unsorted-stop") << - "selection-background: lineargradient(x1:0, y1:0, x2:0, y2:1, " - "stop:0.5 green, stop:0.2 red)" << QPointF(0, 0) << QPointF(0, 1) - 0 << 0.2 << QColor("red") << 0.5 << QColor("green"); - */ -} - -void tst_CssParser::gradient() -{ - QFETCH(QString, css); - QFETCH(QString, type); - QFETCH(QPointF, finalStop); - QFETCH(QPointF, start); - QFETCH(int, spread); - QFETCH(qreal, stop0); QFETCH(QColor, color0); - QFETCH(qreal, stop1); QFETCH(QColor, color1); - - QDomDocument doc; - QVERIFY(doc.setContent(QLatin1String(" "))); - - css.prepend("dummy {"); - css.append("}"); - - QCss::Parser parser(css); - QCss::StyleSheet sheet; - QVERIFY(parser.parse(&sheet)); - - DomStyleSelector testSelector(doc, sheet); - QDomElement e = doc.documentElement().firstChildElement(); - QCss::StyleSelector::NodePtr n; - n.ptr = &e; - QVector rules = testSelector.styleRulesForNode(n); - QVector decls = rules.at(0).declarations; - QCss::ValueExtractor ve(decls); - QBrush fg, sfg; - QBrush sbg, abg; - QVERIFY(ve.extractPalette(&fg, &sfg, &sbg, &abg)); - if (type == "linear") { - QVERIFY(sbg.style() == Qt::LinearGradientPattern); - const QLinearGradient *lg = static_cast(sbg.gradient()); - QCOMPARE(lg->start(), start); - QCOMPARE(lg->finalStop(), finalStop); - } else if (type == "conical") { - QVERIFY(sbg.style() == Qt::ConicalGradientPattern); - const QConicalGradient *cg = static_cast(sbg.gradient()); - QCOMPARE(cg->center(), start); - } - const QGradient *g = sbg.gradient(); - QCOMPARE(g->spread(), QGradient::Spread(spread)); - QVERIFY(g->stops().at(0).first == stop0); - QVERIFY(g->stops().at(0).second == color0); - QVERIFY(g->stops().at(1).first == stop1); - QVERIFY(g->stops().at(1).second == color1); -} - -void tst_CssParser::extractFontFamily_data() -{ - QTest::addColumn("css"); - QTest::addColumn("expectedFamily"); - - QTest::newRow("quoted-family-name") << "font-family: 'Times New Roman'" << QString("Times New Roman"); - QTest::newRow("unquoted-family-name") << "font-family: Times New Roman" << QString("Times New Roman"); - QTest::newRow("unquoted-family-name2") << "font-family: Times New Roman" << QString("Times New Roman"); - QTest::newRow("multiple") << "font-family: Times New Roman , foobar, 'baz'" << QString("Times New Roman"); - QTest::newRow("multiple2") << "font-family: invalid, Times New Roman " << QString("Times New Roman"); - QTest::newRow("invalid") << "font-family: invalid" << QFontInfo(QFont("invalid font")).family(); - QTest::newRow("shorthand") << "font: 12pt Times New Roman" << QString("Times New Roman"); - QTest::newRow("shorthand multiple quote") << "font: 12pt invalid, \"Times New Roman\" " << QString("Times New Roman"); - QTest::newRow("shorthand multiple") << "font: 12pt invalid, Times New Roman " << QString("Times New Roman"); -} - -void tst_CssParser::extractFontFamily() -{ - QFETCH(QString, css); - css.prepend("dummy {"); - css.append("}"); - - QCss::Parser parser(css); - QCss::StyleSheet sheet; - QVERIFY(parser.parse(&sheet)); - - QCOMPARE(sheet.styleRules.count() + sheet.nameIndex.count(), 1); - QCss::StyleRule rule = (!sheet.styleRules.isEmpty()) ? - sheet.styleRules.at(0) : *sheet.nameIndex.begin(); - - const QVector decls = rule.declarations; - QVERIFY(!decls.isEmpty()); - QCss::ValueExtractor extractor(decls); - - int adjustment = 0; - QFont fnt; - extractor.extractFont(&fnt, &adjustment); - QFontInfo info(fnt); - QTEST(info.family(), "expectedFamily"); -} - -void tst_CssParser::extractBorder_data() -{ - QTest::addColumn("css"); - QTest::addColumn("expectedTopWidth"); - QTest::addColumn("expectedTopStyle"); - QTest::addColumn("expectedTopColor"); - - QTest::newRow("all values") << "border: 2px solid green" << 2 << (int)QCss::BorderStyle_Solid << QColor("green"); - QTest::newRow("palette") << "border: 2px solid palette(highlight)" << 2 << (int)QCss::BorderStyle_Solid << qApp->palette().color(QPalette::Highlight); - QTest::newRow("just width") << "border: 2px" << 2 << (int)QCss::BorderStyle_None << QColor(); - QTest::newRow("just style") << "border: solid" << 0 << (int)QCss::BorderStyle_Solid << QColor(); - QTest::newRow("just color") << "border: green" << 0 << (int)QCss::BorderStyle_None << QColor("green"); - QTest::newRow("width+style") << "border: 2px solid" << 2 << (int)QCss::BorderStyle_Solid << QColor(); - QTest::newRow("style+color") << "border: solid green" << 0 << (int)QCss::BorderStyle_Solid << QColor("green"); - QTest::newRow("width+color") << "border: 3px green" << 3 << (int)QCss::BorderStyle_None << QColor("green"); - QTest::newRow("groove style") << "border: groove" << 0 << (int)QCss::BorderStyle_Groove << QColor(); - QTest::newRow("ridge style") << "border: ridge" << 0 << (int)QCss::BorderStyle_Ridge << QColor(); - QTest::newRow("double style") << "border: double" << 0 << (int)QCss::BorderStyle_Double << QColor(); - QTest::newRow("inset style") << "border: inset" << 0 << (int)QCss::BorderStyle_Inset << QColor(); - QTest::newRow("outset style") << "border: outset" << 0 << (int)QCss::BorderStyle_Outset << QColor(); - QTest::newRow("dashed style") << "border: dashed" << 0 << (int)QCss::BorderStyle_Dashed << QColor(); - QTest::newRow("dotted style") << "border: dotted" << 0 << (int)QCss::BorderStyle_Dotted << QColor(); - QTest::newRow("dot-dash style") << "border: dot-dash" << 0 << (int)QCss::BorderStyle_DotDash << QColor(); - QTest::newRow("dot-dot-dash style") << "border: dot-dot-dash" << 0 << (int)QCss::BorderStyle_DotDotDash << QColor(); - - QTest::newRow("top-width+color") << "border-top: 3px green" << 3 << (int)QCss::BorderStyle_None << QColor("green"); -} - -void tst_CssParser::extractBorder() -{ - QFETCH(QString, css); - QFETCH(int, expectedTopWidth); - QFETCH(int, expectedTopStyle); - QFETCH(QColor, expectedTopColor); - - css.prepend("dummy {"); - css.append("}"); - - QCss::Parser parser(css); - QCss::StyleSheet sheet; - QVERIFY(parser.parse(&sheet)); - - QCOMPARE(sheet.styleRules.count() + sheet.nameIndex.count(), 1); - QCss::StyleRule rule = (!sheet.styleRules.isEmpty()) ? - sheet.styleRules.at(0) : *sheet.nameIndex.begin(); - const QVector decls = rule.declarations; - QVERIFY(!decls.isEmpty()); - QCss::ValueExtractor extractor(decls); - - int widths[4]; - QBrush colors[4]; - QCss::BorderStyle styles[4]; - QSize radii[4]; - - extractor.extractBorder(widths, colors, styles, radii); - QVERIFY(widths[QCss::TopEdge] == expectedTopWidth); - QVERIFY(styles[QCss::TopEdge] == expectedTopStyle); - QVERIFY(colors[QCss::TopEdge] == expectedTopColor); -} - -void tst_CssParser::noTextDecoration() -{ - QCss::Parser parser("dummy { text-decoration: none; }"); - QCss::StyleSheet sheet; - QVERIFY(parser.parse(&sheet)); - - QCOMPARE(sheet.styleRules.count() + sheet.nameIndex.count(), 1); - QCss::StyleRule rule = (!sheet.styleRules.isEmpty()) ? - sheet.styleRules.at(0) : *sheet.nameIndex.begin(); - const QVector decls = rule.declarations; - QVERIFY(!decls.isEmpty()); - QCss::ValueExtractor extractor(decls); - - int adjustment = 0; - QFont f; - f.setUnderline(true); - f.setOverline(true); - f.setStrikeOut(true); - QVERIFY(extractor.extractFont(&f, &adjustment)); - - QVERIFY(!f.underline()); - QVERIFY(!f.overline()); - QVERIFY(!f.strikeOut()); -} - -void tst_CssParser::quotedAndUnquotedIdentifiers() -{ - QCss::Parser parser("foo { font-style: \"italic\"; font-weight: bold }"); - QCss::StyleSheet sheet; - QVERIFY(parser.parse(&sheet)); - - QCOMPARE(sheet.styleRules.count() + sheet.nameIndex.count(), 1); - QCss::StyleRule rule = (!sheet.styleRules.isEmpty()) ? - sheet.styleRules.at(0) : *sheet.nameIndex.begin(); - const QVector decls = rule.declarations; - QCOMPARE(decls.size(), 2); - - QCOMPARE(decls.at(0).d->values.first().type, QCss::Value::String); - QCOMPARE(decls.at(0).d->property, QLatin1String("font-style")); - QCOMPARE(decls.at(0).d->values.first().toString(), QLatin1String("italic")); - - QCOMPARE(decls.at(1).d->values.first().type, QCss::Value::KnownIdentifier); - QCOMPARE(decls.at(1).d->property, QLatin1String("font-weight")); - QCOMPARE(decls.at(1).d->values.first().toString(), QLatin1String("bold")); -} - -QTEST_MAIN(tst_CssParser) -#include "tst_cssparser.moc" diff --git a/tests/auto/qcssparser/tst_qcssparser.cpp b/tests/auto/qcssparser/tst_qcssparser.cpp new file mode 100644 index 0000000..33d85fa --- /dev/null +++ b/tests/auto/qcssparser/tst_qcssparser.cpp @@ -0,0 +1,1617 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include +#include + +//TESTED_CLASS=QCss +//TESTED_FILES=gui/text/qcssparser.cpp gui/text/qcssparser_p.h + +#include "private/qcssparser_p.h" + +class tst_QCssParser : public QObject +{ + Q_OBJECT +private slots: + void scanner_data(); + void scanner(); + void term_data(); + void term(); + void expr_data(); + void expr(); + void import(); + void media(); + void page(); + void ruleset(); + void selector_data(); + void selector(); + void prio(); + void escapes(); + void malformedDeclarations_data(); + void malformedDeclarations(); + void invalidAtKeywords(); + void marginValue(); + void marginValue_data(); + void colorValue_data(); + void colorValue(); + void styleSelector_data(); + void styleSelector(); + void specificity_data(); + void specificity(); + void specificitySort_data(); + void specificitySort(); + void rulesForNode_data(); + void rulesForNode(); + void shorthandBackgroundProperty_data(); + void shorthandBackgroundProperty(); + void pseudoElement_data(); + void pseudoElement(); + void gradient_data(); + void gradient(); + void extractFontFamily_data(); + void extractFontFamily(); + void extractBorder_data(); + void extractBorder(); + void noTextDecoration(); + void quotedAndUnquotedIdentifiers(); +}; + +void tst_QCssParser::scanner_data() +{ + QTest::addColumn("input"); + QTest::addColumn("output"); + +#if !defined(Q_OS_IRIX) && !defined(Q_OS_WINCE) + QDir d(SRCDIR); +#else + QDir d(QDir::current()); +#endif + d.cd("testdata"); + d.cd("scanner"); + foreach (QFileInfo test, d.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot)) { + QString dir = test.absoluteFilePath() + QDir::separator(); + QTest::newRow(qPrintable(test.baseName())) + << dir + "input" + << dir + "output" + ; + } +} + +static void debug(const QVector &symbols, int index = -1) +{ + qDebug() << "all symbols:"; + for (int i = 0; i < symbols.count(); ++i) + qDebug() << "(" << i << "); Token:" << QCss::Scanner::tokenName(symbols.at(i).token) << "; Lexem:" << symbols.at(i).lexem(); + if (index != -1) + qDebug() << "failure at index" << index; +} + +//static void debug(const QCss::Parser &p) { debug(p.symbols); } + +void tst_QCssParser::scanner() +{ + QFETCH(QString, input); + QFETCH(QString, output); + + QFile inputFile(input); + QVERIFY(inputFile.open(QIODevice::ReadOnly|QIODevice::Text)); + QVector symbols; + QCss::Scanner::scan(QCss::Scanner::preprocess(QString::fromUtf8(inputFile.readAll())), &symbols); + + QVERIFY(symbols.count() > 1); + QVERIFY(symbols.last().token == QCss::S); + QVERIFY(symbols.last().lexem() == QLatin1String("\n")); + symbols.remove(symbols.count() - 1, 1); + + QFile outputFile(output); + QVERIFY(outputFile.open(QIODevice::ReadOnly|QIODevice::Text)); + QStringList lines; + while (!outputFile.atEnd()) { + QString line = QString::fromUtf8(outputFile.readLine()); + if (line.endsWith(QLatin1Char('\n'))) + line.chop(1); + lines.append(line); + } + + if (lines.count() != symbols.count()) { + debug(symbols); + QCOMPARE(lines.count(), symbols.count()); + } + + for (int i = 0; i < lines.count(); ++i) { + QStringList l = lines.at(i).split(QChar::fromLatin1('|')); + QCOMPARE(l.count(), 2); + const QString expectedToken = l.at(0); + const QString expectedLexem = l.at(1); + QString actualToken = QString::fromLatin1(QCss::Scanner::tokenName(symbols.at(i).token)); + if (actualToken != expectedToken) { + debug(symbols, i); + QCOMPARE(actualToken, expectedToken); + } + if (symbols.at(i).lexem() != expectedLexem) { + debug(symbols, i); + QCOMPARE(symbols.at(i).lexem(), expectedLexem); + } + } +} + +Q_DECLARE_METATYPE(QCss::Value) + +void tst_QCssParser::term_data() +{ + QTest::addColumn("parseSuccess"); + QTest::addColumn("css"); + QTest::addColumn("expectedValue"); + + QCss::Value val; + + val.type = QCss::Value::Percentage; + val.variant = QVariant(double(200)); + QTest::newRow("percentage") << true << "200%" << val; + + val.type = QCss::Value::Length; + val.variant = QString("10px"); + QTest::newRow("px") << true << "10px" << val; + + val.type = QCss::Value::Length; + val.variant = QString("10cm"); + QTest::newRow("cm") << true << "10cm" << val; + + val.type = QCss::Value::Length; + val.variant = QString("10mm"); + QTest::newRow("mm") << true << "10mm" << val; + + val.type = QCss::Value::Length; + val.variant = QString("10pt"); + QTest::newRow("pt") << true << "10pt" << val; + + val.type = QCss::Value::Length; + val.variant = QString("10pc"); + QTest::newRow("pc") << true << "10pc" << val; + + val.type = QCss::Value::Length; + val.variant = QString("42in"); + QTest::newRow("inch") << true << "42in" << val; + + val.type = QCss::Value::Length; + val.variant = QString("10deg"); + QTest::newRow("deg") << true << "10deg" << val; + + val.type = QCss::Value::Length; + val.variant = QString("10rad"); + QTest::newRow("rad") << true << "10rad" << val; + + val.type = QCss::Value::Length; + val.variant = QString("10grad"); + QTest::newRow("grad") << true << "10grad" << val; + + val.type = QCss::Value::Length; + val.variant = QString("10ms"); + QTest::newRow("time") << true << "10ms" << val; + + val.type = QCss::Value::Length; + val.variant = QString("10s"); + QTest::newRow("times") << true << "10s" << val; + + val.type = QCss::Value::Length; + val.variant = QString("10hz"); + QTest::newRow("hz") << true << "10hz" << val; + + val.type = QCss::Value::Length; + val.variant = QString("10khz"); + QTest::newRow("khz") << true << "10khz" << val; + + val.type = QCss::Value::Length; + val.variant = QString("10myunit"); + QTest::newRow("dimension") << true << "10myunit" << val; + + val.type = QCss::Value::Percentage; + + val.type = QCss::Value::Percentage; + val.variant = QVariant(double(-200)); + QTest::newRow("minuspercentage") << true << "-200%" << val; + + val.type = QCss::Value::Length; + val.variant = QString("10em"); + QTest::newRow("ems") << true << "10em" << val; + + val.type = QCss::Value::String; + val.variant = QVariant(QString("foo")); + QTest::newRow("string") << true << "\"foo\"" << val; + + val.type = QCss::Value::Function; + val.variant = QVariant(QStringList() << "myFunc" << "23, (nested text)"); + QTest::newRow("function") << true << "myFunc(23, (nested text))" << val; + + QTest::newRow("function_failure") << false << "myFunction((blah)" << val; + QTest::newRow("function_failure2") << false << "+myFunc(23, (nested text))" << val; + + val.type = QCss::Value::Color; + val.variant = QVariant(QColor("#12ff34")); + QTest::newRow("hexcolor") << true << "#12ff34" << val; + + val.type = QCss::Value::Color; + val.variant = QVariant(QColor("#ffbb00")); + QTest::newRow("hexcolor2") << true << "#fb0" << val; + + QTest::ignoreMessage(QtWarningMsg, "QCssParser::parseHexColor: Unknown color name '#cafebabe'"); + QTest::newRow("hexcolor_failure") << false << "#cafebabe" << val; + + val.type = QCss::Value::Uri; + val.variant = QString("www.kde.org"); + QTest::newRow("uri1") << true << "url(\"www.kde.org\")" << val; + + QTest::newRow("uri2") << true << "url(www.kde.org)" << val; + + val.type = QCss::Value::KnownIdentifier; + val.variant = int(QCss::Value_Italic); + QTest::newRow("italic") << true << "italic" << val; + + val.type = QCss::Value::KnownIdentifier; + val.variant = int(QCss::Value_Italic); + QTest::newRow("ItaLIc") << true << "ItaLIc" << val; +} + +void tst_QCssParser::term() +{ + QFETCH(bool, parseSuccess); + QFETCH(QString, css); + QFETCH(QCss::Value, expectedValue); + + QCss::Parser parser(css); + QCss::Value val; + QVERIFY(parser.testTerm()); + QCOMPARE(parser.parseTerm(&val), parseSuccess); + if (parseSuccess) { + QCOMPARE(int(val.type), int(expectedValue.type)); + if (val.variant != expectedValue.variant) { + qDebug() << "val.variant:" << val.variant << "expectedValue.variant:" << expectedValue.variant; + QCOMPARE(val.variant, expectedValue.variant); + } + } +} + +Q_DECLARE_METATYPE(QVector) + +void tst_QCssParser::expr_data() +{ + QTest::addColumn("parseSuccess"); + QTest::addColumn("css"); + QTest::addColumn >("expectedValues"); + + QVector values; + QCss::Value val; + + QCss::Value comma; + comma.type = QCss::Value::TermOperatorComma; + + val.type = QCss::Value::Identifier; + val.variant = QLatin1String("foo"); + values << val; + values << comma; + val.variant = QLatin1String("bar"); + values << val; + values << comma; + val.variant = QLatin1String("baz"); + values << val; + QTest::newRow("list") << true << "foo, bar, baz" << values; + values.clear(); +} + +void tst_QCssParser::expr() +{ + QFETCH(bool, parseSuccess); + QFETCH(QString, css); + QFETCH(QVector, expectedValues); + + QCss::Parser parser(css); + QVector values; + QVERIFY(parser.testExpr()); + QCOMPARE(parser.parseExpr(&values), parseSuccess); + if (parseSuccess) { + QCOMPARE(values.count(), expectedValues.count()); + + for (int i = 0; i < values.count(); ++i) { + QCOMPARE(int(values.at(i).type), int(expectedValues.at(i).type)); + QCOMPARE(values.at(i).variant, expectedValues.at(i).variant); + } + } +} + +void tst_QCssParser::import() +{ + QCss::Parser parser("@import \"plainstring\";"); + QVERIFY(parser.testImport()); + QCss::ImportRule rule; + QVERIFY(parser.parseImport(&rule)); + QCOMPARE(rule.href, QString("plainstring")); + + parser = QCss::Parser("@import url(\"www.kde.org\") print/*comment*/,screen;"); + QVERIFY(parser.testImport()); + QVERIFY(parser.parseImport(&rule)); + QCOMPARE(rule.href, QString("www.kde.org")); + QCOMPARE(rule.media.count(), 2); + QCOMPARE(rule.media.at(0), QString("print")); + QCOMPARE(rule.media.at(1), QString("screen")); +} + +void tst_QCssParser::media() +{ + QCss::Parser parser("@media print/*comment*/,screen /*comment to ignore*/{ }"); + QVERIFY(parser.testMedia()); + QCss::MediaRule rule; + QVERIFY(parser.parseMedia(&rule)); + QCOMPARE(rule.media.count(), 2); + QCOMPARE(rule.media.at(0), QString("print")); + QCOMPARE(rule.media.at(1), QString("screen")); + QVERIFY(rule.styleRules.isEmpty()); +} + +void tst_QCssParser::page() +{ + QCss::Parser parser("@page :first/*comment to ignore*/{ }"); + QVERIFY(parser.testPage()); + QCss::PageRule rule; + QVERIFY(parser.parsePage(&rule)); + QCOMPARE(rule.selector, QString("first")); + QVERIFY(rule.declarations.isEmpty()); +} + +void tst_QCssParser::ruleset() +{ + { + QCss::Parser parser("p/*foo*/{ }"); + QVERIFY(parser.testRuleset()); + QCss::StyleRule rule; + QVERIFY(parser.parseRuleset(&rule)); + QCOMPARE(rule.selectors.count(), 1); + QCOMPARE(rule.selectors.at(0).basicSelectors.count(), 1); + QCOMPARE(rule.selectors.at(0).basicSelectors.at(0).elementName, QString("p")); + QVERIFY(rule.declarations.isEmpty()); + } + + { + QCss::Parser parser("p/*comment*/,div{ }"); + QVERIFY(parser.testRuleset()); + QCss::StyleRule rule; + QVERIFY(parser.parseRuleset(&rule)); + QCOMPARE(rule.selectors.count(), 2); + QCOMPARE(rule.selectors.at(0).basicSelectors.count(), 1); + QCOMPARE(rule.selectors.at(0).basicSelectors.at(0).elementName, QString("p")); + QCOMPARE(rule.selectors.at(1).basicSelectors.count(), 1); + QCOMPARE(rule.selectors.at(1).basicSelectors.at(0).elementName, QString("div")); + QVERIFY(rule.declarations.isEmpty()); + } + + { + QCss::Parser parser(":before, :after { }"); + QVERIFY(parser.testRuleset()); + QCss::StyleRule rule; + QVERIFY(parser.parseRuleset(&rule)); + QCOMPARE(rule.selectors.count(), 2); + + QCOMPARE(rule.selectors.at(0).basicSelectors.count(), 1); + QCOMPARE(rule.selectors.at(0).basicSelectors.at(0).pseudos.count(), 1); + QCOMPARE(rule.selectors.at(0).basicSelectors.at(0).pseudos.at(0).name, QString("before")); + + QCOMPARE(rule.selectors.at(1).basicSelectors.count(), 1); + QCOMPARE(rule.selectors.at(1).basicSelectors.at(0).pseudos.count(), 1); + QCOMPARE(rule.selectors.at(1).basicSelectors.at(0).pseudos.at(0).name, QString("after")); + + QVERIFY(rule.declarations.isEmpty()); + } + +} + +Q_DECLARE_METATYPE(QCss::Selector) + +void tst_QCssParser::selector_data() +{ + QTest::addColumn("css"); + QTest::addColumn("expectedSelector"); + + { + QCss::Selector sel; + QCss::BasicSelector basic; + + basic.elementName = "p"; + basic.relationToNext = QCss::BasicSelector::MatchNextSelectorIfPreceeds; + sel.basicSelectors << basic; + + basic = QCss::BasicSelector(); + basic.elementName = "div"; + sel.basicSelectors << basic; + + QTest::newRow("comment") << QString("p/* */+ div") << sel; + } + + { + QCss::Selector sel; + QCss::BasicSelector basic; + + basic.elementName = QString(); + sel.basicSelectors << basic; + + QTest::newRow("any") << QString("*") << sel; + } + + { + QCss::Selector sel; + QCss::BasicSelector basic; + + basic.elementName = "e"; + sel.basicSelectors << basic; + + QTest::newRow("element") << QString("e") << sel; + } + + { + QCss::Selector sel; + QCss::BasicSelector basic; + + basic.elementName = "e"; + basic.relationToNext = QCss::BasicSelector::MatchNextSelectorIfAncestor; + sel.basicSelectors << basic; + + basic.elementName = "f"; + basic.relationToNext = QCss::BasicSelector::NoRelation; + sel.basicSelectors << basic; + + QTest::newRow("descendant") << QString("e f") << sel; + } + + { + QCss::Selector sel; + QCss::BasicSelector basic; + + basic.elementName = "e"; + basic.relationToNext = QCss::BasicSelector::MatchNextSelectorIfParent; + sel.basicSelectors << basic; + + basic.elementName = "f"; + basic.relationToNext = QCss::BasicSelector::NoRelation; + sel.basicSelectors << basic; + + QTest::newRow("parent") << QString("e > f") << sel; + } + + { + QCss::Selector sel; + QCss::BasicSelector basic; + + basic.elementName = "e"; + QCss::Pseudo pseudo; + pseudo.name = "first-child"; + basic.pseudos.append(pseudo); + sel.basicSelectors << basic; + + QTest::newRow("first-child") << QString("e:first-child") << sel; + } + + { + QCss::Selector sel; + QCss::BasicSelector basic; + + basic.elementName = "e"; + QCss::Pseudo pseudo; + pseudo.name = "c"; + pseudo.function = "lang"; + basic.pseudos.append(pseudo); + sel.basicSelectors << basic; + + QTest::newRow("lang") << QString("e:lang(c)") << sel; + } + + { + QCss::Selector sel; + QCss::BasicSelector basic; + + basic.elementName = "e"; + basic.relationToNext = QCss::BasicSelector::MatchNextSelectorIfPreceeds; + sel.basicSelectors << basic; + + basic.elementName = "f"; + basic.relationToNext = QCss::BasicSelector::NoRelation; + sel.basicSelectors << basic; + + QTest::newRow("precede") << QString("e + f") << sel; + } + + { + QCss::Selector sel; + QCss::BasicSelector basic; + + basic.elementName = "e"; + QCss::AttributeSelector attrSel; + attrSel.name = "foo"; + basic.attributeSelectors << attrSel; + sel.basicSelectors << basic; + + QTest::newRow("attr") << QString("e[foo]") << sel; + } + + { + QCss::Selector sel; + QCss::BasicSelector basic; + + basic.elementName = "e"; + QCss::AttributeSelector attrSel; + attrSel.name = "foo"; + attrSel.value = "warning"; + attrSel.valueMatchCriterium = QCss::AttributeSelector::MatchEqual; + basic.attributeSelectors << attrSel; + sel.basicSelectors << basic; + + QTest::newRow("attr-equal") << QString("e[foo=\"warning\"]") << sel; + } + + { + QCss::Selector sel; + QCss::BasicSelector basic; + + basic.elementName = "e"; + QCss::AttributeSelector attrSel; + attrSel.name = "foo"; + attrSel.value = "warning"; + attrSel.valueMatchCriterium = QCss::AttributeSelector::MatchContains; + basic.attributeSelectors << attrSel; + sel.basicSelectors << basic; + + QTest::newRow("attr-contains") << QString("e[foo~=\"warning\"]") << sel; + } + + { + QCss::Selector sel; + QCss::BasicSelector basic; + + basic.elementName = "e"; + QCss::AttributeSelector attrSel; + attrSel.name = "lang"; + attrSel.value = "en"; + attrSel.valueMatchCriterium = QCss::AttributeSelector::MatchBeginsWith; + basic.attributeSelectors << attrSel; + sel.basicSelectors << basic; + + QTest::newRow("attr-contains") << QString("e[lang|=\"en\"]") << sel; + } + + { + QCss::Selector sel; + QCss::BasicSelector basic; + + basic.elementName = "div"; + + QCss::AttributeSelector attrSel; + attrSel.name = "class"; + attrSel.valueMatchCriterium = QCss::AttributeSelector::MatchContains; + attrSel.value = "warning"; + basic.attributeSelectors.append(attrSel); + + attrSel.value = "foo"; + basic.attributeSelectors.append(attrSel); + + sel.basicSelectors << basic; + + QTest::newRow("class") << QString("div.warning.foo") << sel; + } + + { + QCss::Selector sel; + QCss::BasicSelector basic; + + basic.elementName = "e"; + basic.ids << "myid"; + sel.basicSelectors << basic; + + QTest::newRow("id") << QString("e#myid") << sel; + } +} + +void tst_QCssParser::selector() +{ + QFETCH(QString, css); + QFETCH(QCss::Selector, expectedSelector); + + QCss::Parser parser(css); + QVERIFY(parser.testSelector()); + QCss::Selector selector; + QVERIFY(parser.parseSelector(&selector)); + + QCOMPARE(selector.basicSelectors.count(), expectedSelector.basicSelectors.count()); + for (int i = 0; i < selector.basicSelectors.count(); ++i) { + const QCss::BasicSelector sel = selector.basicSelectors.at(i); + const QCss::BasicSelector expectedSel = expectedSelector.basicSelectors.at(i); + QCOMPARE(sel.elementName, expectedSel.elementName); + QCOMPARE(int(sel.relationToNext), int(expectedSel.relationToNext)); + + QCOMPARE(sel.pseudos.count(), expectedSel.pseudos.count()); + for (int i = 0; i < sel.pseudos.count(); ++i) { + QCOMPARE(sel.pseudos.at(i).name, expectedSel.pseudos.at(i).name); + QCOMPARE(sel.pseudos.at(i).function, expectedSel.pseudos.at(i).function); + } + + QCOMPARE(sel.attributeSelectors.count(), expectedSel.attributeSelectors.count()); + for (int i = 0; i < sel.attributeSelectors.count(); ++i) { + QCOMPARE(sel.attributeSelectors.at(i).name, expectedSel.attributeSelectors.at(i).name); + QCOMPARE(sel.attributeSelectors.at(i).value, expectedSel.attributeSelectors.at(i).value); + QCOMPARE(int(sel.attributeSelectors.at(i).valueMatchCriterium), int(expectedSel.attributeSelectors.at(i).valueMatchCriterium)); + } + } +} + +void tst_QCssParser::prio() +{ + { + QCss::Parser parser("!important"); + QVERIFY(parser.testPrio()); + } + { + QCss::Parser parser("!impOrTAnt"); + QVERIFY(parser.testPrio()); + } + { + QCss::Parser parser("!\"important\""); + QVERIFY(!parser.testPrio()); + QCOMPARE(parser.index, 0); + } + { + QCss::Parser parser("!importbleh"); + QVERIFY(!parser.testPrio()); + QCOMPARE(parser.index, 0); + } +} + +void tst_QCssParser::escapes() +{ + QCss::Parser parser("\\hello"); + parser.test(QCss::IDENT); + QCOMPARE(parser.lexem(), QString("hello")); +} + +void tst_QCssParser::malformedDeclarations_data() +{ + QTest::addColumn("css"); + + QTest::newRow("1") << QString("p { color:green }"); + QTest::newRow("2") << QString("p { color:green; color } /* malformed declaration missing ':', value */"); + QTest::newRow("3") << QString("p { color:red; color; color:green } /* same with expected recovery */"); + QTest::newRow("4") << QString("p { color:green; color: } /* malformed declaration missing value */"); + QTest::newRow("5") << QString("p { color:red; color:; color:green } /* same with expected recovery */"); + QTest::newRow("6") << QString("p { color:green; color{;color:maroon} } /* unexpected tokens { } */"); + QTest::newRow("7") << QString("p { color:red; color{;color:maroon}; color:green } /* same with recovery */"); +} + +void tst_QCssParser::malformedDeclarations() +{ + QFETCH(QString, css); + QCss::Parser parser(css); + QVERIFY(parser.testRuleset()); + QCss::StyleRule rule; + QVERIFY(parser.parseRuleset(&rule)); + + QCOMPARE(rule.selectors.count(), 1); + QCOMPARE(rule.selectors.at(0).basicSelectors.count(), 1); + QCOMPARE(rule.selectors.at(0).basicSelectors.at(0).elementName, QString("p")); + + QVERIFY(rule.declarations.count() >= 1); + QCOMPARE(int(rule.declarations.last().d->propertyId), int(QCss::Color)); + QCOMPARE(rule.declarations.last().d->values.count(), 1); + QCOMPARE(int(rule.declarations.last().d->values.at(0).type), int(QCss::Value::Identifier)); + QCOMPARE(rule.declarations.last().d->values.at(0).variant.toString(), QString("green")); +} + +void tst_QCssParser::invalidAtKeywords() +{ + QCss::Parser parser("" + "@three-dee {" + " @background-lighting {" + " azimuth: 30deg;" + " elevation: 190deg;" + " }" + " h1 { color: red }" + "}" + "h1 { color: blue }"); + + QCss::StyleSheet sheet; + QVERIFY(parser.parse(&sheet)); + + QCOMPARE(sheet.styleRules.count() + sheet.nameIndex.count(), 1); + QCss::StyleRule rule = (!sheet.styleRules.isEmpty()) ? + sheet.styleRules.at(0) : *sheet.nameIndex.begin(); + + QCOMPARE(rule.selectors.count(), 1); + QCOMPARE(rule.selectors.at(0).basicSelectors.count(), 1); + QCOMPARE(rule.selectors.at(0).basicSelectors.at(0).elementName, QString("h1")); + + QCOMPARE(rule.declarations.count(), 1); + QCOMPARE(int(rule.declarations.at(0).d->propertyId), int(QCss::Color)); + QCOMPARE(rule.declarations.at(0).d->values.count(), 1); + QCOMPARE(int(rule.declarations.at(0).d->values.at(0).type), int(QCss::Value::Identifier)); + QCOMPARE(rule.declarations.at(0).d->values.at(0).variant.toString(), QString("blue")); +} + +Q_DECLARE_METATYPE(QColor) + +void tst_QCssParser::colorValue_data() +{ + QTest::addColumn("css"); + QTest::addColumn("expectedColor"); + + QTest::newRow("identifier") << "color: black" << QColor("black"); + QTest::newRow("string") << "color: \"green\"" << QColor("green"); + QTest::newRow("hexcolor") << "color: #12af0e" << QColor(0x12, 0xaf, 0x0e); + QTest::newRow("functional1") << "color: rgb(21, 45, 73)" << QColor(21, 45, 73); + QTest::newRow("functional2") << "color: rgb(100%, 0%, 100%)" << QColor(0xff, 0, 0xff); + QTest::newRow("rgba") << "color: rgba(10, 20, 30, 40)" << QColor(10, 20, 30, 40); + QTest::newRow("rgb") << "color: rgb(10, 20, 30, 40)" << QColor(10, 20, 30, 40); + QTest::newRow("hsl") << "color: hsv(10, 20, 30)" << QColor::fromHsv(10, 20, 30, 255); + QTest::newRow("hsla") << "color: hsva(10, 20, 30, 40)" << QColor::fromHsv(10, 20, 30, 40); + QTest::newRow("invalid1") << "color: rgb(why, does, it, always, rain, on, me)" << QColor(); + QTest::newRow("invalid2") << "color: rgba(i, meant, norway)" << QColor(); + QTest::newRow("role") << "color: palette(base)" << qApp->palette().color(QPalette::Base); + QTest::newRow("role2") << "color: palette( window-text ) " << qApp->palette().color(QPalette::WindowText); + QTest::newRow("transparent") << "color: transparent" << QColor(Qt::transparent); +} + +void tst_QCssParser::colorValue() +{ + QFETCH(QString, css); + QFETCH(QColor, expectedColor); + + QCss::Parser parser(css); + QCss::Declaration decl; + QVERIFY(parser.parseNextDeclaration(&decl)); + const QColor col = decl.colorValue(); + QVERIFY(expectedColor.isValid() == col.isValid()); + QCOMPARE(col, expectedColor); +} + +class DomStyleSelector : public QCss::StyleSelector +{ +public: + inline DomStyleSelector(const QDomDocument &doc, const QCss::StyleSheet &sheet) + : doc(doc) + { + styleSheets.append(sheet); + } + + virtual QStringList nodeNames(NodePtr node) const { return QStringList(reinterpret_cast(node.ptr)->tagName()); } + virtual QString attribute(NodePtr node, const QString &name) const { return reinterpret_cast(node.ptr)->attribute(name); } + virtual bool hasAttribute(NodePtr node, const QString &name) const { return reinterpret_cast(node.ptr)->hasAttribute(name); } + virtual bool hasAttributes(NodePtr node) const { return reinterpret_cast(node.ptr)->hasAttributes(); } + + virtual bool isNullNode(NodePtr node) const { + return reinterpret_cast(node.ptr)->isNull(); + } + virtual NodePtr parentNode(NodePtr node) const { + NodePtr parent; + parent.ptr = new QDomElement(reinterpret_cast(node.ptr)->parentNode().toElement()); + return parent; + } + virtual NodePtr duplicateNode(NodePtr node) const { + NodePtr n; + n.ptr = new QDomElement(*reinterpret_cast(node.ptr)); + return n; + } + virtual NodePtr previousSiblingNode(NodePtr node) const { + NodePtr sibling; + sibling.ptr = new QDomElement(reinterpret_cast(node.ptr)->previousSiblingElement()); + return sibling; + } + virtual void freeNode(NodePtr node) const { + delete reinterpret_cast(node.ptr); + } + +private: + QDomDocument doc; +}; + +Q_DECLARE_METATYPE(QDomDocument); + +void tst_QCssParser::marginValue_data() +{ + QTest::addColumn("css"); + QTest::addColumn("expectedMargin"); + + QFont f; + int ex = QFontMetrics(f).xHeight(); + int em = QFontMetrics(f).height(); + + QTest::newRow("one value") << "margin: 1px" << "1 1 1 1"; + QTest::newRow("two values") << "margin: 1px 2px" << "1 2 1 2"; + QTest::newRow("three value") << "margin: 1px 2px 3px" << "1 2 3 2"; + QTest::newRow("four values") << "margin: 1px 2px 3px 4px" << "1 2 3 4"; + QTest::newRow("default px") << "margin: 1 2 3 4" << "1 2 3 4"; + QTest::newRow("no unit") << "margin: 1 2 3 4" << "1 2 3 4"; + QTest::newRow("em") << "margin: 1ex 2ex 3ex 4ex" << QString("%1 %2 %3 %4").arg(ex).arg(2*ex).arg(3*ex).arg(4*ex); + QTest::newRow("ex") << "margin: 1 2em 3px 4ex" << QString("%1 %2 %3 %4").arg(1).arg(2*em).arg(3).arg(4*ex); + + f.setPointSize(20); + f.setBold(true); + ex = QFontMetrics(f).xHeight(); + em = QFontMetrics(f).height(); + QTest::newRow("em2") << "font: bold 20pt; margin: 1ex 2ex 3ex 4ex" << QString("%1 %2 %3 %4").arg(ex).arg(2*ex).arg(3*ex).arg(4*ex); + QTest::newRow("ex2") << "margin: 1 2em 3px 4ex; font-size: 20pt; font-weight: bold;" << QString("%1 %2 %3 %4").arg(1).arg(2*em).arg(3).arg(4*ex); + + QTest::newRow("crap") << "margin: crap" << "0 0 0 0"; +} + +void tst_QCssParser::marginValue() +{ + QFETCH(QString, css); + QFETCH(QString, expectedMargin); + + QDomDocument doc; + QVERIFY(doc.setContent(QLatin1String(" "))); + + css.prepend("dummy {"); + css.append("}"); + + QCss::Parser parser(css); + QCss::StyleSheet sheet; + QVERIFY(parser.parse(&sheet)); + + DomStyleSelector testSelector(doc, sheet); + QDomElement e = doc.documentElement().firstChildElement(); + QCss::StyleSelector::NodePtr n; + n.ptr = &e; + QVector rules = testSelector.styleRulesForNode(n); + QVector decls = rules.at(0).declarations; + QCss::ValueExtractor v(decls); + + { + int m[4]; + int p[4]; + int spacing; + v.extractBox(m, p, &spacing); + QString str = QString("%1 %2 %3 %4").arg(m[0]).arg(m[1]).arg(m[2]).arg(m[3]); + QCOMPARE(str, expectedMargin); + } +} + +void tst_QCssParser::styleSelector_data() +{ + QTest::addColumn("match"); + QTest::addColumn("selector"); + QTest::addColumn("xml"); + QTest::addColumn("elementToCheck"); + + QTest::newRow("plain") << true << QString("p") << QString("

") << QString(); + QTest::newRow("noplain") << false << QString("bar") << QString("

") << QString(); + + QTest::newRow("class") << true << QString(".foo") << QString("

") << QString(); + QTest::newRow("noclass") << false << QString(".bar") << QString("

") << QString(); + + QTest::newRow("attrset") << true << QString("[justset]") << QString("

") << QString(); + QTest::newRow("notattrset") << false << QString("[justset]") << QString("

") << QString(); + + QTest::newRow("attrmatch") << true << QString("[foo=bar]") << QString("

") << QString(); + QTest::newRow("noattrmatch") << false << QString("[foo=bar]") << QString("

") << QString(); + + QTest::newRow("contains") << true << QString("[foo~=bar]") << QString("

") << QString(); + QTest::newRow("notcontains") << false << QString("[foo~=bar]") << QString("

") << QString(); + + QTest::newRow("beingswith") << true << QString("[foo|=bar]") << QString("

") << QString(); + QTest::newRow("notbeingswith") << false << QString("[foo|=bar]") << QString("

") << QString(); + + QTest::newRow("attr2") << true << QString("[bar=foo]") << QString("

") << QString(); + + QTest::newRow("universal1") << true << QString("*") << QString("

") << QString(); + + QTest::newRow("universal3") << false << QString("*[foo=bar]") << QString("

") << QString(); + QTest::newRow("universal4") << true << QString("*[foo=bar]") << QString("

") << QString(); + + QTest::newRow("universal5") << false << QString("[foo=bar]") << QString("

") << QString(); + QTest::newRow("universal6") << true << QString("[foo=bar]") << QString("

") << QString(); + + QTest::newRow("universal7") << true << QString(".charfmt1") << QString("

") << QString(); + + QTest::newRow("id") << true << QString("#blub") << QString("

") << QString(); + QTest::newRow("noid") << false << QString("#blub") << QString("

") << QString(); + + QTest::newRow("childselector") << true << QString("parent > child") + << QString("") + << QString("parent/child"); + + QTest::newRow("nochildselector2") << false << QString("parent > child") + << QString("") + << QString("child/parent"); + + QTest::newRow("nochildselector3") << false << QString("parent > child") + << QString("") + << QString("parent/intermediate/child"); + + QTest::newRow("childselector2") << true << QString("parent[foo=bar] > child") + << QString("") + << QString("parent/child"); + + QTest::newRow("nochildselector4") << false << QString("parent[foo=bar] > child") + << QString("") + << QString("parent/child"); + + QTest::newRow("nochildselector5") << false << QString("parent[foo=bar] > child") + << QString("") + << QString("parent/parent/child"); + + QTest::newRow("childselectors") << true << QString("grandparent > parent > child") + << QString("") + << QString("grandparent/parent/child"); + + QTest::newRow("descendant") << true << QString("grandparent child") + << QString("") + << QString("grandparent/parent/child"); + + QTest::newRow("nodescendant") << false << QString("grandparent child") + << QString("") + << QString("other/parent/child"); + + QTest::newRow("descendant2") << true << QString("grandgrandparent grandparent child") + << QString("") + << QString("grandgrandparent/inbetween/grandparent/parent/child"); + + QTest::newRow("combined") << true << QString("grandparent parent > child") + << QString("") + << QString("grandparent/inbetween/parent/child"); + + QTest::newRow("combined2") << true << QString("grandparent > parent child") + << QString("") + << QString("grandparent/parent/inbetween/child"); + + QTest::newRow("combined3") << true << QString("grandparent > parent child") + << QString("") + << QString("grandparent/parent/inbetween/child"); + + QTest::newRow("nocombined") << false << QString("grandparent parent > child") + << QString("") + << QString("inbetween/parent/child"); + + QTest::newRow("nocombined2") << false << QString("grandparent parent > child") + << QString("") + << QString("parent/child"); + + QTest::newRow("previoussibling") << true << QString("p1 + p2") + << QString("") + << QString("p2"); + + QTest::newRow("noprevioussibling") << false << QString("p2 + p1") + << QString("") + << QString("p2"); + + QTest::newRow("ancestry_firstmismatch") << false << QString("parent child[foo=bar]") + << QString("") + << QString("parent/child"); + + QTest::newRow("unknown-pseudo") << false << QString("p:enabled:foobar") << QString("

") << QString(); +} + +void tst_QCssParser::styleSelector() +{ + QFETCH(bool, match); + QFETCH(QString, selector); + QFETCH(QString, xml); + QFETCH(QString, elementToCheck); + + QString css = QString("%1 { background-color: green }").arg(selector); + QCss::Parser parser(css); + QCss::StyleSheet sheet; + QVERIFY(parser.parse(&sheet)); + + QDomDocument doc; + xml.prepend(""); + xml.append(""); + QVERIFY(doc.setContent(xml)); + + DomStyleSelector testSelector(doc, sheet); + + QDomElement e = doc.documentElement(); + if (elementToCheck.isEmpty()) { + e = e.firstChildElement(); + } else { + QStringList path = elementToCheck.split(QLatin1Char('/')); + do { + e = e.namedItem(path.takeFirst()).toElement(); + } while (!path.isEmpty()); + } + QVERIFY(!e.isNull()); + QCss::StyleSelector::NodePtr n; + n.ptr = &e; + QVector decls = testSelector.declarationsForNode(n); + + if (match) { + QCOMPARE(decls.count(), 1); + QCOMPARE(int(decls.at(0).d->propertyId), int(QCss::BackgroundColor)); + QCOMPARE(decls.at(0).d->values.count(), 1); + QCOMPARE(int(decls.at(0).d->values.at(0).type), int(QCss::Value::Identifier)); + QCOMPARE(decls.at(0).d->values.at(0).variant.toString(), QString("green")); + } else { + QVERIFY(decls.isEmpty()); + } +} + +void tst_QCssParser::specificity_data() +{ + QTest::addColumn("selector"); + QTest::addColumn("specificity"); + + QTest::newRow("universal") << QString("*") << 0; + + QTest::newRow("elements+pseudos1") << QString("foo") << 1; + QTest::newRow("elements+pseudos2") << QString("foo *[blah]") << 1 + (1 * 0x10); + + // should strictly speaking be '2', but we don't support pseudo-elements yet, + // only pseudo-classes + QTest::newRow("elements+pseudos3") << QString("li:first-line") << 1 + (1 * 0x10); + + QTest::newRow("elements+pseudos4") << QString("ul li") << 2; + QTest::newRow("elements+pseudos5") << QString("ul ol+li") << 3; + QTest::newRow("elements+pseudos6") << QString("h1 + *[rel=up]") << 1 + (1 * 0x10); + + QTest::newRow("elements+pseudos7") << QString("ul ol li.red") << 3 + (1 * 0x10); + QTest::newRow("elements+pseudos8") << QString("li.red.level") << 1 + (2 * 0x10); + QTest::newRow("id") << QString("#x34y") << 1 * 0x100; +} + +void tst_QCssParser::specificity() +{ + QFETCH(QString, selector); + + QString css = QString("%1 { }").arg(selector); + QCss::Parser parser(css); + QCss::StyleSheet sheet; + QVERIFY(parser.parse(&sheet)); + + QCOMPARE(sheet.styleRules.count() + sheet.nameIndex.count() + sheet.idIndex.count() , 1); + QCss::StyleRule rule = (!sheet.styleRules.isEmpty()) ? sheet.styleRules.at(0) + : (!sheet.nameIndex.isEmpty()) ? *sheet.nameIndex.begin() + : *sheet.idIndex.begin(); + QCOMPARE(rule.selectors.count(), 1); + QTEST(rule.selectors.at(0).specificity(), "specificity"); +} + +void tst_QCssParser::specificitySort_data() +{ + QTest::addColumn("firstSelector"); + QTest::addColumn("secondSelector"); + QTest::addColumn("xml"); + + QTest::newRow("universal1") << QString("*") << QString("p") << QString("

"); + QTest::newRow("attr") << QString("p") << QString("p[foo=bar]") << QString("

"); + QTest::newRow("id") << QString("p") << QString("#hey") << QString("

"); + QTest::newRow("id2") << QString("[id=hey]") << QString("#hey") << QString("

"); + QTest::newRow("class") << QString("p") << QString(".hey") << QString("

"); +} + +void tst_QCssParser::specificitySort() +{ + QFETCH(QString, firstSelector); + QFETCH(QString, secondSelector); + QFETCH(QString, xml); + + firstSelector.append(" { color: green; }"); + secondSelector.append(" { color: red; }"); + + QDomDocument doc; + xml.prepend(""); + xml.append(""); + QVERIFY(doc.setContent(xml)); + + for (int i = 0; i < 2; ++i) { + QString css; + if (i == 0) + css = firstSelector + secondSelector; + else + css = secondSelector + firstSelector; + + QCss::Parser parser(css); + QCss::StyleSheet sheet; + QVERIFY(parser.parse(&sheet)); + + DomStyleSelector testSelector(doc, sheet); + + QDomElement e = doc.documentElement().firstChildElement(); + QCss::StyleSelector::NodePtr n; + n.ptr = &e; + QVector decls = testSelector.declarationsForNode(n); + + QCOMPARE(decls.count(), 2); + + QCOMPARE(int(decls.at(0).d->propertyId), int(QCss::Color)); + QCOMPARE(decls.at(0).d->values.count(), 1); + QCOMPARE(int(decls.at(0).d->values.at(0).type), int(QCss::Value::Identifier)); + QCOMPARE(decls.at(0).d->values.at(0).variant.toString(), QString("green")); + + QCOMPARE(int(decls.at(1).d->propertyId), int(QCss::Color)); + QCOMPARE(decls.at(1).d->values.count(), 1); + QCOMPARE(int(decls.at(1).d->values.at(0).type), int(QCss::Value::Identifier)); + QCOMPARE(decls.at(1).d->values.at(0).variant.toString(), QString("red")); + } +} + +void tst_QCssParser::rulesForNode_data() +{ + QTest::addColumn("xml"); + QTest::addColumn("css"); + QTest::addColumn("pseudoClass"); + QTest::addColumn("declCount"); + QTest::addColumn("value0"); + QTest::addColumn("value1"); + + QTest::newRow("universal1") << QString("

") << QString("* { color: red }") + << (quint64)QCss::PseudoClass_Unspecified << 1 << "red" << ""; + + QTest::newRow("basic") << QString("

") << QString("p:enabled { color: red; bg:blue; }") + << (quint64)QCss::PseudoClass_Enabled << 2 << "red" << "blue"; + + QTest::newRow("single") << QString("

") + << QString("p:enabled { color: red; } *:hover { color: white }") + << (quint64)QCss::PseudoClass_Hover << 1 << "white" << ""; + + QTest::newRow("multisel") << QString("

") + << QString("p:enabled { color: red; } p:hover { color: gray } *:hover { color: white } ") + << (quint64)QCss::PseudoClass_Hover << 2 << "white" << "gray"; + + QTest::newRow("multisel2") << QString("

") + << QString("p:enabled { color: red; } p:hover:focus { color: gray } *:hover { color: white } ") + << quint64(QCss::PseudoClass_Hover|QCss::PseudoClass_Focus) << 2 << "white" << "gray"; + + QTest::newRow("multisel3-diffspec") << QString("

") + << QString("p:enabled { color: red; } p:hover:focus { color: gray } *:hover { color: white } ") + << quint64(QCss::PseudoClass_Hover) << 1 << "white" << ""; + + QTest::newRow("!-1") << QString("

") + << QString("p:checked:!hover { color: red; } p:checked:hover { color: gray } p:checked { color: white }") + << quint64(QCss::PseudoClass_Hover|QCss::PseudoClass_Checked) << 2 << "white" << "gray"; + + QTest::newRow("!-2") << QString("

") + << QString("p:checked:!hover:!pressed { color: red; } p:!checked:hover { color: gray } p:!focus { color: blue }") + << quint64(QCss::PseudoClass_Focus) << 0 << "" << ""; + + QTest::newRow("!-3") << QString("

") + << QString("p:checked:!hover:!pressed { color: red; } p:!checked:hover { color: gray } p:!focus { color: blue; }") + << quint64(QCss::PseudoClass_Pressed) << 1 << "blue" << ""; +} + +void tst_QCssParser::rulesForNode() +{ + QFETCH(QString, xml); + QFETCH(QString, css); + QFETCH(quint64, pseudoClass); + QFETCH(int, declCount); + QFETCH(QString, value0); + QFETCH(QString, value1); + + QDomDocument doc; + xml.prepend(""); + xml.append(""); + QVERIFY(doc.setContent(xml)); + + QCss::Parser parser(css); + QCss::StyleSheet sheet; + QVERIFY(parser.parse(&sheet)); + + DomStyleSelector testSelector(doc, sheet); + QDomElement e = doc.documentElement().firstChildElement(); + QCss::StyleSelector::NodePtr n; + n.ptr = &e; + QVector rules = testSelector.styleRulesForNode(n); + + QVector decls; + for (int i = 0; i < rules.count(); i++) { + const QCss::Selector &selector = rules.at(i).selectors.at(0); + quint64 negated = 0; + quint64 cssClass = selector.pseudoClass(&negated); + if ((cssClass == QCss::PseudoClass_Unspecified) + || ((((cssClass & pseudoClass) == cssClass)) && ((negated & pseudoClass) == 0))) + decls += rules.at(i).declarations; + } + + QVERIFY(decls.count() == declCount); + + if (declCount > 0) + QCOMPARE(decls.at(0).d->values.at(0).variant.toString(), value0); + if (declCount > 1) + QCOMPARE(decls.at(1).d->values.at(0).variant.toString(), value1); +} + +void tst_QCssParser::shorthandBackgroundProperty_data() +{ + QTest::addColumn("css"); + QTest::addColumn("expectedBrush"); + QTest::addColumn("expectedImage"); + QTest::addColumn("expectedRepeatValue"); + QTest::addColumn("expectedAlignment"); + + QTest::newRow("simple color") << "background: red" << QBrush(QColor("red")) << QString() << int(QCss::Repeat_XY) << int(Qt::AlignLeft | Qt::AlignTop); + QTest::newRow("plain color") << "background-color: red" << QBrush(QColor("red")) << QString() << int(QCss::Repeat_XY) << int(Qt::AlignLeft | Qt::AlignTop); + QTest::newRow("palette color") << "background-color: palette(mid)" << qApp->palette().mid() << QString() << int(QCss::Repeat_XY) << int(Qt::AlignLeft | Qt::AlignTop); + QTest::newRow("multiple") << "background: url(chess.png) blue repeat-y" << QBrush(QColor("blue")) << QString("chess.png") << int(QCss::Repeat_Y) << int(Qt::AlignLeft | Qt::AlignTop); + QTest::newRow("plain alignment") << "background-position: center" << QBrush() << QString() << int(QCss::Repeat_XY) << int(Qt::AlignCenter); + QTest::newRow("plain alignment2") << "background-position: left top" << QBrush() << QString() << int(QCss::Repeat_XY) << int(Qt::AlignLeft | Qt::AlignTop); + QTest::newRow("plain alignment3") << "background-position: left" << QBrush() << QString() << int(QCss::Repeat_XY) << int(Qt::AlignLeft | Qt::AlignVCenter); + QTest::newRow("multi") << "background: left url(blah.png) repeat-x" << QBrush() << QString("blah.png") << int(QCss::Repeat_X) << int(Qt::AlignLeft | Qt::AlignVCenter); + QTest::newRow("multi2") << "background: url(blah.png) repeat-x top" << QBrush() << QString("blah.png") << int(QCss::Repeat_X) << int(Qt::AlignTop | Qt::AlignHCenter); + QTest::newRow("multi3") << "background: url(blah.png) top right" << QBrush() << QString("blah.png") << int(QCss::Repeat_XY) << int(Qt::AlignTop | Qt::AlignRight); +} + +void tst_QCssParser::shorthandBackgroundProperty() +{ + QFETCH(QString, css); + + QDomDocument doc; + QVERIFY(doc.setContent(QLatin1String(" "))); + + css.prepend("dummy {"); + css.append("}"); + + QCss::Parser parser(css); + QCss::StyleSheet sheet; + QVERIFY(parser.parse(&sheet)); + + DomStyleSelector testSelector(doc, sheet); + QDomElement e = doc.documentElement().firstChildElement(); + QCss::StyleSelector::NodePtr n; + n.ptr = &e; + QVector rules = testSelector.styleRulesForNode(n); + QVector decls = rules.at(0).declarations; + QCss::ValueExtractor v(decls); + + QBrush brush; + QString image; + QCss::Repeat repeat = QCss::Repeat_XY; + Qt::Alignment alignment = Qt::AlignTop | Qt::AlignLeft; + QCss::Origin origin = QCss::Origin_Padding; + QCss::Attachment attachment; + QCss::Origin ignoredOrigin; + v.extractBackground(&brush, &image, &repeat, &alignment, &origin, &attachment, &ignoredOrigin); + + QFETCH(QBrush, expectedBrush); + QVERIFY(expectedBrush.color() == brush.color()); + + QTEST(image, "expectedImage"); + QTEST(int(repeat), "expectedRepeatValue"); + QTEST(int(alignment), "expectedAlignment"); +} + +void tst_QCssParser::pseudoElement_data() +{ + QTest::addColumn("css"); + QTest::addColumn("pseudoElement"); + QTest::addColumn("declCount"); + + // QComboBox::dropDown { border-image: blah; } + QTest::newRow("no pseudo-elements") << QString("dummy:hover { color: red }") << "" << 1; + QTest::newRow("no pseudo-elements") << QString("dummy:hover { color: red }") << "pe" << 0; + + QTest::newRow("1 pseudo-element (1)") << QString("dummy::pe:hover { color: red }") << "pe" << 1; + QTest::newRow("1 pseudo-element (2)") << QString("dummy::pe:hover { color: red }") << "x" << 0; + QTest::newRow("1 pseudo-element (2)") << QString("whatever::pe:hover { color: red }") << "pe" << 0; + + QTest::newRow("1 pseudo-element (3)") + << QString("dummy { color: white; } dummy::pe:hover { color: red }") << "x" << 0; + QTest::newRow("1 pseudo-element (4)") + << QString("dummy { color: white; } dummy::pe:hover { color: red } dummy { x:y }") << "" << 2; + QTest::newRow("1 pseudo-element (5)") + << QString("dummy { color: white; } dummy::pe:hover { color: red }") << "pe" << 1; + QTest::newRow("1 pseudo-element (6)") + << QString("dummy { color: white; } dummy::pe:hover { color: red } dummy::pe:checked { x: y} ") << "pe" << 2; + + QTest::newRow("2 pseudo-elements (1)") + << QString("dummy { color: white; } dummy::pe1:hover { color: red } dummy::pe2:checked { x: y} ") + << "" << 1; + QTest::newRow("2 pseudo-elements (1)") + << QString("dummy { color: white; } dummy::pe1:hover { color: red } dummy::pe2:checked { x: y} ") + << "pe1" << 1; + QTest::newRow("2 pseudo-elements (2)") + << QString("dummy { color: white; } dummy::pe1:hover { color: red } dummy::pe2:checked { x: y} ") + << "pe2" << 1; +} + +void tst_QCssParser::pseudoElement() +{ + QFETCH(QString, css); + QFETCH(QString, pseudoElement); + QFETCH(int, declCount); + + QDomDocument doc; + QVERIFY(doc.setContent(QLatin1String(" "))); + + QCss::Parser parser(css); + QCss::StyleSheet sheet; + QVERIFY(parser.parse(&sheet)); + + DomStyleSelector testSelector(doc, sheet); + QDomElement e = doc.documentElement().firstChildElement(); + QCss::StyleSelector::NodePtr n; + n.ptr = &e; + QVector rules = testSelector.styleRulesForNode(n); + QVector decls; + for (int i = 0; i < rules.count(); i++) { + const QCss::Selector& selector = rules.at(i).selectors.at(0); + if (pseudoElement.compare(selector.pseudoElement(), Qt::CaseInsensitive) != 0) + continue; + decls += rules.at(i).declarations; + + } + QVERIFY(decls.count() == declCount); +} + +void tst_QCssParser::gradient_data() +{ + QTest::addColumn("css"); + QTest::addColumn("type"); + QTest::addColumn("start"); + QTest::addColumn("finalStop"); + QTest::addColumn("spread"); + QTest::addColumn("stop0"); + QTest::addColumn("color0"); + QTest::addColumn("stop1"); + QTest::addColumn("color1"); + + QTest::newRow("color-string") << + "selection-background-color: qlineargradient(x1:1, y1:2, x2:3, y2:4, " + "stop:0.2 red, stop:0.5 green)" << "linear" << QPointF(1, 2) << QPointF(3, 4) + << 0 << qreal(0.2) << QColor("red") << qreal(0.5) << QColor("green"); + + QTest::newRow("color-#") << + "selection-background-color: qlineargradient(x1:0, y1:0, x2:0, y2:1, " + "spread: reflect, stop:0.2 #123, stop:0.5 #456)" << "linear" << QPointF(0, 0) << QPointF(0, 1) + << 1 << qreal(0.2) << QColor("#123") << qreal(0.5) << QColor("#456"); + + QTest::newRow("color-rgb") << + "selection-background-color: qlineargradient(x1:0, y1:0, x2:0, y2:1, " + "spread: reflect, stop:0.2 rgb(1, 2, 3), stop:0.5 rgba(1, 2, 3, 4))" << "linear" << QPointF(0, 0) << QPointF(0, 1) + << 1 << qreal(0.2) << QColor(1, 2, 3) << qreal(0.5) << QColor(1, 2, 3, 4); + + QTest::newRow("color-spaces") << + "selection-background-color: qlineargradient(x1: 0, y1 :0,x2:0, y2 : 1 , " + "spread: reflect, stop:0.2 rgb(1, 2, 3), stop: 0.5 rgba(1, 2, 3, 4))" << "linear" << QPointF(0, 0) << QPointF(0, 1) + << 1 << qreal(0.2) << QColor(1, 2, 3) << qreal(0.5) << QColor(1, 2, 3, 4); + + QTest::newRow("conical gradient") << + "selection-background-color: qconicalgradient(cx: 4, cy : 2, angle: 23, " + "spread: repeat, stop:0.2 rgb(1, 2, 3), stop:0.5 rgba(1, 2, 3, 4))" << "conical" << QPointF(4, 2) << QPointF() + << 2 << qreal(0.2) << QColor(1, 2, 3) << qreal(0.5) << QColor(1, 2, 3, 4); + + /* wont pass: stop values are expected to be sorted + QTest::newRow("unsorted-stop") << + "selection-background: lineargradient(x1:0, y1:0, x2:0, y2:1, " + "stop:0.5 green, stop:0.2 red)" << QPointF(0, 0) << QPointF(0, 1) + 0 << 0.2 << QColor("red") << 0.5 << QColor("green"); + */ +} + +void tst_QCssParser::gradient() +{ + QFETCH(QString, css); + QFETCH(QString, type); + QFETCH(QPointF, finalStop); + QFETCH(QPointF, start); + QFETCH(int, spread); + QFETCH(qreal, stop0); QFETCH(QColor, color0); + QFETCH(qreal, stop1); QFETCH(QColor, color1); + + QDomDocument doc; + QVERIFY(doc.setContent(QLatin1String(" "))); + + css.prepend("dummy {"); + css.append("}"); + + QCss::Parser parser(css); + QCss::StyleSheet sheet; + QVERIFY(parser.parse(&sheet)); + + DomStyleSelector testSelector(doc, sheet); + QDomElement e = doc.documentElement().firstChildElement(); + QCss::StyleSelector::NodePtr n; + n.ptr = &e; + QVector rules = testSelector.styleRulesForNode(n); + QVector decls = rules.at(0).declarations; + QCss::ValueExtractor ve(decls); + QBrush fg, sfg; + QBrush sbg, abg; + QVERIFY(ve.extractPalette(&fg, &sfg, &sbg, &abg)); + if (type == "linear") { + QVERIFY(sbg.style() == Qt::LinearGradientPattern); + const QLinearGradient *lg = static_cast(sbg.gradient()); + QCOMPARE(lg->start(), start); + QCOMPARE(lg->finalStop(), finalStop); + } else if (type == "conical") { + QVERIFY(sbg.style() == Qt::ConicalGradientPattern); + const QConicalGradient *cg = static_cast(sbg.gradient()); + QCOMPARE(cg->center(), start); + } + const QGradient *g = sbg.gradient(); + QCOMPARE(g->spread(), QGradient::Spread(spread)); + QVERIFY(g->stops().at(0).first == stop0); + QVERIFY(g->stops().at(0).second == color0); + QVERIFY(g->stops().at(1).first == stop1); + QVERIFY(g->stops().at(1).second == color1); +} + +void tst_QCssParser::extractFontFamily_data() +{ + QTest::addColumn("css"); + QTest::addColumn("expectedFamily"); + + QTest::newRow("quoted-family-name") << "font-family: 'Times New Roman'" << QString("Times New Roman"); + QTest::newRow("unquoted-family-name") << "font-family: Times New Roman" << QString("Times New Roman"); + QTest::newRow("unquoted-family-name2") << "font-family: Times New Roman" << QString("Times New Roman"); + QTest::newRow("multiple") << "font-family: Times New Roman , foobar, 'baz'" << QString("Times New Roman"); + QTest::newRow("multiple2") << "font-family: invalid, Times New Roman " << QString("Times New Roman"); + QTest::newRow("invalid") << "font-family: invalid" << QFontInfo(QFont("invalid font")).family(); + QTest::newRow("shorthand") << "font: 12pt Times New Roman" << QString("Times New Roman"); + QTest::newRow("shorthand multiple quote") << "font: 12pt invalid, \"Times New Roman\" " << QString("Times New Roman"); + QTest::newRow("shorthand multiple") << "font: 12pt invalid, Times New Roman " << QString("Times New Roman"); +} + +void tst_QCssParser::extractFontFamily() +{ + QFETCH(QString, css); + css.prepend("dummy {"); + css.append("}"); + + QCss::Parser parser(css); + QCss::StyleSheet sheet; + QVERIFY(parser.parse(&sheet)); + + QCOMPARE(sheet.styleRules.count() + sheet.nameIndex.count(), 1); + QCss::StyleRule rule = (!sheet.styleRules.isEmpty()) ? + sheet.styleRules.at(0) : *sheet.nameIndex.begin(); + + const QVector decls = rule.declarations; + QVERIFY(!decls.isEmpty()); + QCss::ValueExtractor extractor(decls); + + int adjustment = 0; + QFont fnt; + extractor.extractFont(&fnt, &adjustment); + QFontInfo info(fnt); + QTEST(info.family(), "expectedFamily"); +} + +void tst_QCssParser::extractBorder_data() +{ + QTest::addColumn("css"); + QTest::addColumn("expectedTopWidth"); + QTest::addColumn("expectedTopStyle"); + QTest::addColumn("expectedTopColor"); + + QTest::newRow("all values") << "border: 2px solid green" << 2 << (int)QCss::BorderStyle_Solid << QColor("green"); + QTest::newRow("palette") << "border: 2px solid palette(highlight)" << 2 << (int)QCss::BorderStyle_Solid << qApp->palette().color(QPalette::Highlight); + QTest::newRow("just width") << "border: 2px" << 2 << (int)QCss::BorderStyle_None << QColor(); + QTest::newRow("just style") << "border: solid" << 0 << (int)QCss::BorderStyle_Solid << QColor(); + QTest::newRow("just color") << "border: green" << 0 << (int)QCss::BorderStyle_None << QColor("green"); + QTest::newRow("width+style") << "border: 2px solid" << 2 << (int)QCss::BorderStyle_Solid << QColor(); + QTest::newRow("style+color") << "border: solid green" << 0 << (int)QCss::BorderStyle_Solid << QColor("green"); + QTest::newRow("width+color") << "border: 3px green" << 3 << (int)QCss::BorderStyle_None << QColor("green"); + QTest::newRow("groove style") << "border: groove" << 0 << (int)QCss::BorderStyle_Groove << QColor(); + QTest::newRow("ridge style") << "border: ridge" << 0 << (int)QCss::BorderStyle_Ridge << QColor(); + QTest::newRow("double style") << "border: double" << 0 << (int)QCss::BorderStyle_Double << QColor(); + QTest::newRow("inset style") << "border: inset" << 0 << (int)QCss::BorderStyle_Inset << QColor(); + QTest::newRow("outset style") << "border: outset" << 0 << (int)QCss::BorderStyle_Outset << QColor(); + QTest::newRow("dashed style") << "border: dashed" << 0 << (int)QCss::BorderStyle_Dashed << QColor(); + QTest::newRow("dotted style") << "border: dotted" << 0 << (int)QCss::BorderStyle_Dotted << QColor(); + QTest::newRow("dot-dash style") << "border: dot-dash" << 0 << (int)QCss::BorderStyle_DotDash << QColor(); + QTest::newRow("dot-dot-dash style") << "border: dot-dot-dash" << 0 << (int)QCss::BorderStyle_DotDotDash << QColor(); + + QTest::newRow("top-width+color") << "border-top: 3px green" << 3 << (int)QCss::BorderStyle_None << QColor("green"); +} + +void tst_QCssParser::extractBorder() +{ + QFETCH(QString, css); + QFETCH(int, expectedTopWidth); + QFETCH(int, expectedTopStyle); + QFETCH(QColor, expectedTopColor); + + css.prepend("dummy {"); + css.append("}"); + + QCss::Parser parser(css); + QCss::StyleSheet sheet; + QVERIFY(parser.parse(&sheet)); + + QCOMPARE(sheet.styleRules.count() + sheet.nameIndex.count(), 1); + QCss::StyleRule rule = (!sheet.styleRules.isEmpty()) ? + sheet.styleRules.at(0) : *sheet.nameIndex.begin(); + const QVector decls = rule.declarations; + QVERIFY(!decls.isEmpty()); + QCss::ValueExtractor extractor(decls); + + int widths[4]; + QBrush colors[4]; + QCss::BorderStyle styles[4]; + QSize radii[4]; + + extractor.extractBorder(widths, colors, styles, radii); + QVERIFY(widths[QCss::TopEdge] == expectedTopWidth); + QVERIFY(styles[QCss::TopEdge] == expectedTopStyle); + QVERIFY(colors[QCss::TopEdge] == expectedTopColor); +} + +void tst_QCssParser::noTextDecoration() +{ + QCss::Parser parser("dummy { text-decoration: none; }"); + QCss::StyleSheet sheet; + QVERIFY(parser.parse(&sheet)); + + QCOMPARE(sheet.styleRules.count() + sheet.nameIndex.count(), 1); + QCss::StyleRule rule = (!sheet.styleRules.isEmpty()) ? + sheet.styleRules.at(0) : *sheet.nameIndex.begin(); + const QVector decls = rule.declarations; + QVERIFY(!decls.isEmpty()); + QCss::ValueExtractor extractor(decls); + + int adjustment = 0; + QFont f; + f.setUnderline(true); + f.setOverline(true); + f.setStrikeOut(true); + QVERIFY(extractor.extractFont(&f, &adjustment)); + + QVERIFY(!f.underline()); + QVERIFY(!f.overline()); + QVERIFY(!f.strikeOut()); +} + +void tst_QCssParser::quotedAndUnquotedIdentifiers() +{ + QCss::Parser parser("foo { font-style: \"italic\"; font-weight: bold }"); + QCss::StyleSheet sheet; + QVERIFY(parser.parse(&sheet)); + + QCOMPARE(sheet.styleRules.count() + sheet.nameIndex.count(), 1); + QCss::StyleRule rule = (!sheet.styleRules.isEmpty()) ? + sheet.styleRules.at(0) : *sheet.nameIndex.begin(); + const QVector decls = rule.declarations; + QCOMPARE(decls.size(), 2); + + QCOMPARE(decls.at(0).d->values.first().type, QCss::Value::String); + QCOMPARE(decls.at(0).d->property, QLatin1String("font-style")); + QCOMPARE(decls.at(0).d->values.first().toString(), QLatin1String("italic")); + + QCOMPARE(decls.at(1).d->values.first().type, QCss::Value::KnownIdentifier); + QCOMPARE(decls.at(1).d->property, QLatin1String("font-weight")); + QCOMPARE(decls.at(1).d->values.first().toString(), QLatin1String("bold")); +} + +QTEST_MAIN(tst_QCssParser) +#include "tst_qcssparser.moc" + diff --git a/tests/auto/qdbuspendingcall/qdbuspendingcall.pro b/tests/auto/qdbuspendingcall/qdbuspendingcall.pro index 65e8f13..dd8f141 100644 --- a/tests/auto/qdbuspendingcall/qdbuspendingcall.pro +++ b/tests/auto/qdbuspendingcall/qdbuspendingcall.pro @@ -1,4 +1,5 @@ load(qttest_p4) -QT = core -contains(QT_CONFIG, dbus):QT += dbus +requires(contains(QT_CONFIG, dbus)) +QT = core dbus SOURCES += tst_qdbuspendingcall.cpp + diff --git a/tests/auto/qdbuspendingreply/qdbuspendingreply.pro b/tests/auto/qdbuspendingreply/qdbuspendingreply.pro index 94e7acf..c649e4a 100644 --- a/tests/auto/qdbuspendingreply/qdbuspendingreply.pro +++ b/tests/auto/qdbuspendingreply/qdbuspendingreply.pro @@ -1,4 +1,4 @@ load(qttest_p4) -QT = core -contains(QT_CONFIG, dbus):QT += dbus +requires(contains(QT_CONFIG, dbus)) +QT = core dbus SOURCES += tst_qdbuspendingreply.cpp diff --git a/tests/auto/qdirectpainter/qdirectpainter.pro b/tests/auto/qdirectpainter/qdirectpainter.pro index 8967194..e86b342 100644 --- a/tests/auto/qdirectpainter/qdirectpainter.pro +++ b/tests/auto/qdirectpainter/qdirectpainter.pro @@ -1,7 +1,5 @@ -load(qttest_p4) -SOURCES += tst_qdirectpainter.cpp - TEMPLATE = subdirs SUBDIRS = test runDirectPainter +requires(embedded) diff --git a/tests/auto/qdirectpainter/runDirectPainter/runDirectPainter.pro b/tests/auto/qdirectpainter/runDirectPainter/runDirectPainter.pro index 9e5131c..09524e9 100644 --- a/tests/auto/qdirectpainter/runDirectPainter/runDirectPainter.pro +++ b/tests/auto/qdirectpainter/runDirectPainter/runDirectPainter.pro @@ -2,4 +2,5 @@ load(qttest_p4) SOURCES = main.cpp TARGET = runDirectPainter +requires(embedded) diff --git a/tests/auto/qdirectpainter/test/test.pro b/tests/auto/qdirectpainter/test/test.pro index 98c74e4..6d820b1 100644 --- a/tests/auto/qdirectpainter/test/test.pro +++ b/tests/auto/qdirectpainter/test/test.pro @@ -3,12 +3,5 @@ load(qttest_p4) SOURCES += ../tst_qdirectpainter.cpp TARGET = ../tst_qdirectpainter -win32 { - CONFIG(debug, debug|release) { - TARGET = ../../debug/tst_qdirectpainter -} else { - TARGET = ../../release/tst_qdirectpainter - } -} - +requires(embedded) diff --git a/tests/auto/qicoimageformat/qicoimageformat.pro b/tests/auto/qicoimageformat/qicoimageformat.pro index 19c13b7..9a347d7 100644 --- a/tests/auto/qicoimageformat/qicoimageformat.pro +++ b/tests/auto/qicoimageformat/qicoimageformat.pro @@ -1,5 +1,5 @@ load(qttest_p4) -SOURCES+= tst_qticoimageformat.cpp +SOURCES+= tst_qicoimageformat.cpp wince*: { DEFINES += SRCDIR=\\\".\\\" diff --git a/tests/auto/qicoimageformat/tst_qicoimageformat.cpp b/tests/auto/qicoimageformat/tst_qicoimageformat.cpp new file mode 100644 index 0000000..799a20b --- /dev/null +++ b/tests/auto/qicoimageformat/tst_qicoimageformat.cpp @@ -0,0 +1,299 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include +#include +#include + +class tst_QIcoImageFormat : public QObject +{ + Q_OBJECT + +public: + tst_QIcoImageFormat(); + virtual ~tst_QIcoImageFormat(); + + +public slots: + void initTestCase(); + void cleanupTestCase(); + void init(); + void cleanup(); +private slots: + void format(); + void canRead_data(); + void canRead(); + void SequentialFile_data(); + void SequentialFile(); + void imageCount_data(); + void imageCount(); + void jumpToNextImage_data(); + void jumpToNextImage(); + void loopCount_data(); + void loopCount(); + void nextImageDelay_data(); + void nextImageDelay(); + +private: + QString m_IconPath; +}; + + +tst_QIcoImageFormat::tst_QIcoImageFormat() +{ + m_IconPath = QLatin1String(SRCDIR) + "/icons"; + qDebug() << m_IconPath; +} + +tst_QIcoImageFormat::~tst_QIcoImageFormat() +{ + +} + +void tst_QIcoImageFormat::init() +{ + +} + +void tst_QIcoImageFormat::cleanup() +{ + +} + +void tst_QIcoImageFormat::initTestCase() +{ + +} + +void tst_QIcoImageFormat::cleanupTestCase() +{ + +} + +void tst_QIcoImageFormat::format() +{ + QImageReader reader(m_IconPath + "/valid/35FLOPPY.ICO", "ico"); + QByteArray fmt = reader.format(); + QCOMPARE(const_cast(fmt.data()), "ico" ); +} + +void tst_QIcoImageFormat::canRead_data() +{ + QTest::addColumn("fileName"); + QTest::addColumn("isValid"); + + QTest::newRow("floppy (16px,32px - 16 colors)") << "valid/35FLOPPY.ICO" << 1; + QTest::newRow("16px,32px,48px - 256,16M colors") << "valid/abcardWindow.ico" << 1; + QTest::newRow("16px - 16 colors") << "valid/App.ico" << 1; + QTest::newRow("16px,32px,48px - 16,256,16M colors") << "valid/Obj_N2_Internal_Mem.ico" << 1; + QTest::newRow("16px - 16,256,16M colors") << "valid/Status_Play.ico" << 1; + QTest::newRow("16px,32px - 16 colors") << "valid/TIMER01.ICO" << 1; + QTest::newRow("16px16c, 32px32c, 32px256c") << "valid/WORLD.ico" << 1; + QTest::newRow("16px16c, 32px32c, 32px256c") << "valid/WORLDH.ico" << 1; + QTest::newRow("invalid floppy (first 8 bytes = 0xff)") << "invalid/35floppy.ico" << 0; + QTest::newRow("103x16px, 24BPP") << "valid/trolltechlogo_tiny.ico" << 1; + QTest::newRow("includes 32BPP w/alpha") << "valid/semitransparent.ico" << 1; +} + +void tst_QIcoImageFormat::canRead() +{ + QFETCH(QString, fileName); + QFETCH(int, isValid); + + QImageReader reader(m_IconPath + "/" + fileName); + QCOMPARE(reader.canRead(), (isValid == 0 ? false : true)); +} + +class QSequentialFile : public QFile +{ +public: + QSequentialFile(const QString &name) : QFile(name) {} + + virtual ~QSequentialFile() {} + + virtual bool isSequential() const { + return true; + } + +}; + +void tst_QIcoImageFormat::SequentialFile_data() +{ + QTest::addColumn("fileName"); + QTest::addColumn("isValid"); + + QTest::newRow("floppy (16,32 pixels - 16 colors)") << "valid/35FLOPPY.ICO" << 1; + + QTest::newRow("invalid floppy (first 8 bytes = 0xff)") << "invalid/35floppy.ico" << 0; + + +} + +void tst_QIcoImageFormat::SequentialFile() +{ + QFETCH(QString, fileName); + QFETCH(int, isValid); + + QSequentialFile *file = new QSequentialFile(m_IconPath + "/" + fileName); + QVERIFY(file); + QVERIFY(file->open(QFile::ReadOnly)); + QImageReader reader(file); + + // Perform the check twice. If canRead() does not restore the sequential device back to its original state, + // it will fail on the second try. + QCOMPARE(reader.canRead(), (isValid == 0 ? false : true)); + QCOMPARE(reader.canRead(), (isValid == 0 ? false : true)); + file->close(); +} + + +void tst_QIcoImageFormat::imageCount_data() +{ + QTest::addColumn("fileName"); + QTest::addColumn("count"); + + QTest::newRow("floppy (16px,32px - 16 colors)") << "valid/35FLOPPY.ICO" << 2; + QTest::newRow("16px,32px,48px - 256,16M colors") << "valid/abcardWindow.ico" << 6; + QTest::newRow("16px - 16 colors") << "valid/App.ico" << 1; + QTest::newRow("16px,32px,48px - 16,256,16M colors") << "valid/Obj_N2_Internal_Mem.ico" << 9; + QTest::newRow("16px - 16,256,16M colors") << "valid/Status_Play.ico" << 3; + QTest::newRow("16px,32px - 16 colors") << "valid/TIMER01.ICO" << 2; + QTest::newRow("16px16c, 32px32c, 32px256c") << "valid/WORLD.ico" << 3; + QTest::newRow("16px16c, 32px32c, 32px256c") << "valid/WORLDH.ico" << 3; + QTest::newRow("invalid floppy (first 8 bytes = 0xff)") << "invalid/35floppy.ico" << 0; + QTest::newRow("includes 32BPP w/alpha") << "valid/semitransparent.ico" << 9; + +} + +void tst_QIcoImageFormat::imageCount() +{ + QFETCH(QString, fileName); + QFETCH(int, count); + + QImageReader reader(m_IconPath + "/" + fileName); + QCOMPARE(reader.imageCount(), count); + +} + +void tst_QIcoImageFormat::jumpToNextImage_data() +{ + QTest::addColumn("fileName"); + QTest::addColumn("count"); + + QTest::newRow("floppy (16px,32px - 16 colors)") << "valid/35FLOPPY.ICO" << 2; + QTest::newRow("16px,32px,48px - 256,16M colors") << "valid/abcardWindow.ico" << 6; + QTest::newRow("16px - 16 colors") << "valid/App.ico" << 1; + QTest::newRow("16px,32px,48px - 16,256,16M colors") << "valid/Obj_N2_Internal_Mem.ico" << 9; + QTest::newRow("16px - 16,256,16M colors") << "valid/Status_Play.ico" << 3; + QTest::newRow("16px,32px - 16 colors") << "valid/TIMER01.ICO" << 2; + QTest::newRow("16px16c, 32px32c, 32px256c") << "valid/WORLD.ico" << 3; + QTest::newRow("16px16c, 32px32c, 32px256c") << "valid/WORLDH.ico" << 3; + QTest::newRow("includes 32BPP w/alpha") << "valid/semitransparent.ico" << 9; +} + +void tst_QIcoImageFormat::jumpToNextImage() +{ + QFETCH(QString, fileName); + QFETCH(int, count); + + QImageReader reader(m_IconPath + "/" + fileName); + bool bJumped = reader.jumpToImage(0); + while (bJumped) { + count--; + bJumped = reader.jumpToNextImage(); + } + QCOMPARE(count, 0); +} + +void tst_QIcoImageFormat::loopCount_data() +{ + QTest::addColumn("fileName"); + QTest::addColumn("count"); + + QTest::newRow("floppy (16px,32px - 16 colors)") << "valid/35FLOPPY.ICO" << 0; + QTest::newRow("invalid floppy (first 8 bytes = 0xff)") << "invalid/35floppy.ico" << 0; +} + +void tst_QIcoImageFormat::loopCount() +{ + QFETCH(QString, fileName); + QFETCH(int, count); + + QImageReader reader(m_IconPath + "/" + fileName); + QCOMPARE(reader.loopCount(), count); +} + +void tst_QIcoImageFormat::nextImageDelay_data() +{ + QTest::addColumn("fileName"); + QTest::addColumn("count"); + + QTest::newRow("floppy (16px,32px - 16 colors)") << "valid/35FLOPPY.ICO" << 2; + QTest::newRow("16px,32px,48px - 256,16M colors") << "valid/abcardWindow.ico" << 6; + QTest::newRow("16px - 16 colors") << "valid/App.ico" << 1; + QTest::newRow("16px,32px,48px - 16,256,16M colors") << "valid/Obj_N2_Internal_Mem.ico" << 9; + QTest::newRow("16px - 16,256,16M colors") << "valid/Status_Play.ico" << 3; + QTest::newRow("16px,32px - 16 colors") << "valid/TIMER01.ICO" << 2; + QTest::newRow("16px16c, 32px32c, 32px256c") << "valid/WORLD.ico" << 3; + QTest::newRow("16px16c, 32px32c, 32px256c") << "valid/WORLDH.ico" << 3; + QTest::newRow("invalid floppy (first 8 bytes = 0xff)") << "invalid/35floppy.ico" << -1; + QTest::newRow("includes 32BPP w/alpha") << "valid/semitransparent.ico" << 9; +} + +void tst_QIcoImageFormat::nextImageDelay() +{ + QFETCH(QString, fileName); + QFETCH(int, count); + + QImageReader reader(m_IconPath + "/" + fileName); + if (count == -1) { + QCOMPARE(reader.nextImageDelay(), 0); + } else { + int i; + for (i = 0; i < count; i++) { + QVERIFY(reader.jumpToImage(i)); + QCOMPARE(reader.nextImageDelay(), 0); + } + } +} + +QTEST_MAIN(tst_QIcoImageFormat) +#include "tst_qicoimageformat.moc" + diff --git a/tests/auto/qicoimageformat/tst_qticoimageformat.cpp b/tests/auto/qicoimageformat/tst_qticoimageformat.cpp deleted file mode 100644 index 51ee4aa..0000000 --- a/tests/auto/qicoimageformat/tst_qticoimageformat.cpp +++ /dev/null @@ -1,298 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** 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 either Technology Preview License Agreement or the -** Beta Release License Agreement. -** -** 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.0, included in the file LGPL_EXCEPTION.txt in this -** package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** If you are unsure which license is appropriate for your use, please -** contact the sales department at http://www.qtsoftware.com/contact. -** $QT_END_LICENSE$ -** -****************************************************************************/ -#include -#include -#include - -class tst_QtIcoImageFormat : public QObject -{ - Q_OBJECT - -public: - tst_QtIcoImageFormat(); - virtual ~tst_QtIcoImageFormat(); - - -public slots: - void initTestCase(); - void cleanupTestCase(); - void init(); - void cleanup(); -private slots: - void format(); - void canRead_data(); - void canRead(); - void SequentialFile_data(); - void SequentialFile(); - void imageCount_data(); - void imageCount(); - void jumpToNextImage_data(); - void jumpToNextImage(); - void loopCount_data(); - void loopCount(); - void nextImageDelay_data(); - void nextImageDelay(); - -private: - QString m_IconPath; -}; - - -tst_QtIcoImageFormat::tst_QtIcoImageFormat() -{ - m_IconPath = QLatin1String(SRCDIR) + "/icons"; - qDebug() << m_IconPath; -} - -tst_QtIcoImageFormat::~tst_QtIcoImageFormat() -{ - -} - -void tst_QtIcoImageFormat::init() -{ - -} - -void tst_QtIcoImageFormat::cleanup() -{ - -} - -void tst_QtIcoImageFormat::initTestCase() -{ - -} - -void tst_QtIcoImageFormat::cleanupTestCase() -{ - -} - -void tst_QtIcoImageFormat::format() -{ - QImageReader reader(m_IconPath + "/valid/35FLOPPY.ICO", "ico"); - QByteArray fmt = reader.format(); - QCOMPARE(const_cast(fmt.data()), "ico" ); -} - -void tst_QtIcoImageFormat::canRead_data() -{ - QTest::addColumn("fileName"); - QTest::addColumn("isValid"); - - QTest::newRow("floppy (16px,32px - 16 colors)") << "valid/35FLOPPY.ICO" << 1; - QTest::newRow("16px,32px,48px - 256,16M colors") << "valid/abcardWindow.ico" << 1; - QTest::newRow("16px - 16 colors") << "valid/App.ico" << 1; - QTest::newRow("16px,32px,48px - 16,256,16M colors") << "valid/Obj_N2_Internal_Mem.ico" << 1; - QTest::newRow("16px - 16,256,16M colors") << "valid/Status_Play.ico" << 1; - QTest::newRow("16px,32px - 16 colors") << "valid/TIMER01.ICO" << 1; - QTest::newRow("16px16c, 32px32c, 32px256c") << "valid/WORLD.ico" << 1; - QTest::newRow("16px16c, 32px32c, 32px256c") << "valid/WORLDH.ico" << 1; - QTest::newRow("invalid floppy (first 8 bytes = 0xff)") << "invalid/35floppy.ico" << 0; - QTest::newRow("103x16px, 24BPP") << "valid/trolltechlogo_tiny.ico" << 1; - QTest::newRow("includes 32BPP w/alpha") << "valid/semitransparent.ico" << 1; -} - -void tst_QtIcoImageFormat::canRead() -{ - QFETCH(QString, fileName); - QFETCH(int, isValid); - - QImageReader reader(m_IconPath + "/" + fileName); - QCOMPARE(reader.canRead(), (isValid == 0 ? false : true)); -} - -class QSequentialFile : public QFile -{ -public: - QSequentialFile(const QString &name) : QFile(name) {} - - virtual ~QSequentialFile() {} - - virtual bool isSequential() const { - return true; - } - -}; - -void tst_QtIcoImageFormat::SequentialFile_data() -{ - QTest::addColumn("fileName"); - QTest::addColumn("isValid"); - - QTest::newRow("floppy (16,32 pixels - 16 colors)") << "valid/35FLOPPY.ICO" << 1; - - QTest::newRow("invalid floppy (first 8 bytes = 0xff)") << "invalid/35floppy.ico" << 0; - - -} - -void tst_QtIcoImageFormat::SequentialFile() -{ - QFETCH(QString, fileName); - QFETCH(int, isValid); - - QSequentialFile *file = new QSequentialFile(m_IconPath + "/" + fileName); - QVERIFY(file); - QVERIFY(file->open(QFile::ReadOnly)); - QImageReader reader(file); - - // Perform the check twice. If canRead() does not restore the sequential device back to its original state, - // it will fail on the second try. - QCOMPARE(reader.canRead(), (isValid == 0 ? false : true)); - QCOMPARE(reader.canRead(), (isValid == 0 ? false : true)); - file->close(); -} - - -void tst_QtIcoImageFormat::imageCount_data() -{ - QTest::addColumn("fileName"); - QTest::addColumn("count"); - - QTest::newRow("floppy (16px,32px - 16 colors)") << "valid/35FLOPPY.ICO" << 2; - QTest::newRow("16px,32px,48px - 256,16M colors") << "valid/abcardWindow.ico" << 6; - QTest::newRow("16px - 16 colors") << "valid/App.ico" << 1; - QTest::newRow("16px,32px,48px - 16,256,16M colors") << "valid/Obj_N2_Internal_Mem.ico" << 9; - QTest::newRow("16px - 16,256,16M colors") << "valid/Status_Play.ico" << 3; - QTest::newRow("16px,32px - 16 colors") << "valid/TIMER01.ICO" << 2; - QTest::newRow("16px16c, 32px32c, 32px256c") << "valid/WORLD.ico" << 3; - QTest::newRow("16px16c, 32px32c, 32px256c") << "valid/WORLDH.ico" << 3; - QTest::newRow("invalid floppy (first 8 bytes = 0xff)") << "invalid/35floppy.ico" << 0; - QTest::newRow("includes 32BPP w/alpha") << "valid/semitransparent.ico" << 9; - -} - -void tst_QtIcoImageFormat::imageCount() -{ - QFETCH(QString, fileName); - QFETCH(int, count); - - QImageReader reader(m_IconPath + "/" + fileName); - QCOMPARE(reader.imageCount(), count); - -} - -void tst_QtIcoImageFormat::jumpToNextImage_data() -{ - QTest::addColumn("fileName"); - QTest::addColumn("count"); - - QTest::newRow("floppy (16px,32px - 16 colors)") << "valid/35FLOPPY.ICO" << 2; - QTest::newRow("16px,32px,48px - 256,16M colors") << "valid/abcardWindow.ico" << 6; - QTest::newRow("16px - 16 colors") << "valid/App.ico" << 1; - QTest::newRow("16px,32px,48px - 16,256,16M colors") << "valid/Obj_N2_Internal_Mem.ico" << 9; - QTest::newRow("16px - 16,256,16M colors") << "valid/Status_Play.ico" << 3; - QTest::newRow("16px,32px - 16 colors") << "valid/TIMER01.ICO" << 2; - QTest::newRow("16px16c, 32px32c, 32px256c") << "valid/WORLD.ico" << 3; - QTest::newRow("16px16c, 32px32c, 32px256c") << "valid/WORLDH.ico" << 3; - QTest::newRow("includes 32BPP w/alpha") << "valid/semitransparent.ico" << 9; -} - -void tst_QtIcoImageFormat::jumpToNextImage() -{ - QFETCH(QString, fileName); - QFETCH(int, count); - - QImageReader reader(m_IconPath + "/" + fileName); - bool bJumped = reader.jumpToImage(0); - while (bJumped) { - count--; - bJumped = reader.jumpToNextImage(); - } - QCOMPARE(count, 0); -} - -void tst_QtIcoImageFormat::loopCount_data() -{ - QTest::addColumn("fileName"); - QTest::addColumn("count"); - - QTest::newRow("floppy (16px,32px - 16 colors)") << "valid/35FLOPPY.ICO" << 0; - QTest::newRow("invalid floppy (first 8 bytes = 0xff)") << "invalid/35floppy.ico" << 0; -} - -void tst_QtIcoImageFormat::loopCount() -{ - QFETCH(QString, fileName); - QFETCH(int, count); - - QImageReader reader(m_IconPath + "/" + fileName); - QCOMPARE(reader.loopCount(), count); -} - -void tst_QtIcoImageFormat::nextImageDelay_data() -{ - QTest::addColumn("fileName"); - QTest::addColumn("count"); - - QTest::newRow("floppy (16px,32px - 16 colors)") << "valid/35FLOPPY.ICO" << 2; - QTest::newRow("16px,32px,48px - 256,16M colors") << "valid/abcardWindow.ico" << 6; - QTest::newRow("16px - 16 colors") << "valid/App.ico" << 1; - QTest::newRow("16px,32px,48px - 16,256,16M colors") << "valid/Obj_N2_Internal_Mem.ico" << 9; - QTest::newRow("16px - 16,256,16M colors") << "valid/Status_Play.ico" << 3; - QTest::newRow("16px,32px - 16 colors") << "valid/TIMER01.ICO" << 2; - QTest::newRow("16px16c, 32px32c, 32px256c") << "valid/WORLD.ico" << 3; - QTest::newRow("16px16c, 32px32c, 32px256c") << "valid/WORLDH.ico" << 3; - QTest::newRow("invalid floppy (first 8 bytes = 0xff)") << "invalid/35floppy.ico" << -1; - QTest::newRow("includes 32BPP w/alpha") << "valid/semitransparent.ico" << 9; -} - -void tst_QtIcoImageFormat::nextImageDelay() -{ - QFETCH(QString, fileName); - QFETCH(int, count); - - QImageReader reader(m_IconPath + "/" + fileName); - if (count == -1) { - QCOMPARE(reader.nextImageDelay(), 0); - } else { - int i; - for (i = 0; i < count; i++) { - QVERIFY(reader.jumpToImage(i)); - QCOMPARE(reader.nextImageDelay(), 0); - } - } -} - -QTEST_MAIN(tst_QtIcoImageFormat) -#include "tst_qticoimageformat.moc" diff --git a/tests/auto/qmultiscreen/qmultiscreen.pro b/tests/auto/qmultiscreen/qmultiscreen.pro index 810c05f..30666d7 100644 --- a/tests/auto/qmultiscreen/qmultiscreen.pro +++ b/tests/auto/qmultiscreen/qmultiscreen.pro @@ -1,5 +1,5 @@ load(qttest_p4) SOURCES += tst_qmultiscreen.cpp - +requires(embedded) diff --git a/tests/auto/qpointarray/.gitignore b/tests/auto/qpointarray/.gitignore deleted file mode 100644 index 7c9d48c..0000000 --- a/tests/auto/qpointarray/.gitignore +++ /dev/null @@ -1 +0,0 @@ -tst_qpointarray diff --git a/tests/auto/qpointarray/qpointarray.pro b/tests/auto/qpointarray/qpointarray.pro deleted file mode 100644 index d864337..0000000 --- a/tests/auto/qpointarray/qpointarray.pro +++ /dev/null @@ -1,6 +0,0 @@ -load(qttest_p4) -SOURCES += tst_qpointarray.cpp - -unix:!mac:LIBS+=-lm - - diff --git a/tests/auto/qpointarray/tst_qpointarray.cpp b/tests/auto/qpointarray/tst_qpointarray.cpp deleted file mode 100644 index f46c96d..0000000 --- a/tests/auto/qpointarray/tst_qpointarray.cpp +++ /dev/null @@ -1,95 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** 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 either Technology Preview License Agreement or the -** Beta Release License Agreement. -** -** 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.0, included in the file LGPL_EXCEPTION.txt in this -** package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** If you are unsure which license is appropriate for your use, please -** contact the sales department at http://www.qtsoftware.com/contact. -** $QT_END_LICENSE$ -** -****************************************************************************/ - - -#include - -#include -#include -#include - -#include -#include - - - -//TESTED_CLASS= -//TESTED_FILES=gui/painting/qpolygon.h gui/painting/qpolygon.cpp - -class tst_QPolygon : public QObject -{ - Q_OBJECT - -public: - tst_QPolygon(); - -private slots: - void makeEllipse(); -}; - -tst_QPolygon::tst_QPolygon() -{ -} - -void tst_QPolygon::makeEllipse() -{ - // create an ellipse with R1 = R2 = R, i.e. a circle - QPolygon pa; - const int R = 50; // radius - QPainterPath path; - path.addEllipse(0, 0, 2*R, 2*R); - pa = path.toSubpathPolygons().at(0).toPolygon(); - - int i; - // make sure that all points are R+-1 away from the center - bool err = FALSE; - for (i = 1; i < pa.size(); i++) { - QPoint p = pa.at( i ); - double r = sqrt( pow( double(p.x() - R), 2.0 ) + pow( double(p.y() - R), 2.0 ) ); - // ### too strict ? at least from visual inspection it looks - // quite odd around the main axes. 2.0 passes easily. - err |= ( qAbs( r - double(R) ) > 2.0 ); - } - QVERIFY( !err ); -} - -QTEST_APPLESS_MAIN(tst_QPolygon) -#include "tst_qpointarray.moc" diff --git a/tests/auto/qpolygon/.gitignore b/tests/auto/qpolygon/.gitignore new file mode 100644 index 0000000..7c9d48c --- /dev/null +++ b/tests/auto/qpolygon/.gitignore @@ -0,0 +1 @@ +tst_qpointarray diff --git a/tests/auto/qpolygon/qpolygon.pro b/tests/auto/qpolygon/qpolygon.pro new file mode 100644 index 0000000..311958d --- /dev/null +++ b/tests/auto/qpolygon/qpolygon.pro @@ -0,0 +1,6 @@ +load(qttest_p4) +SOURCES += tst_qpolygon.cpp + +unix:!mac:LIBS+=-lm + + diff --git a/tests/auto/qpolygon/tst_qpolygon.cpp b/tests/auto/qpolygon/tst_qpolygon.cpp new file mode 100644 index 0000000..6b20dae --- /dev/null +++ b/tests/auto/qpolygon/tst_qpolygon.cpp @@ -0,0 +1,95 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include + +#include +#include +#include + +#include +#include + + + +//TESTED_CLASS= +//TESTED_FILES=gui/painting/qpolygon.h gui/painting/qpolygon.cpp + +class tst_QPolygon : public QObject +{ + Q_OBJECT + +public: + tst_QPolygon(); + +private slots: + void makeEllipse(); +}; + +tst_QPolygon::tst_QPolygon() +{ +} + +void tst_QPolygon::makeEllipse() +{ + // create an ellipse with R1 = R2 = R, i.e. a circle + QPolygon pa; + const int R = 50; // radius + QPainterPath path; + path.addEllipse(0, 0, 2*R, 2*R); + pa = path.toSubpathPolygons().at(0).toPolygon(); + + int i; + // make sure that all points are R+-1 away from the center + bool err = FALSE; + for (i = 1; i < pa.size(); i++) { + QPoint p = pa.at( i ); + double r = sqrt( pow( double(p.x() - R), 2.0 ) + pow( double(p.y() - R), 2.0 ) ); + // ### too strict ? at least from visual inspection it looks + // quite odd around the main axes. 2.0 passes easily. + err |= ( qAbs( r - double(R) ) > 2.0 ); + } + QVERIFY( !err ); +} + +QTEST_APPLESS_MAIN(tst_QPolygon) +#include "tst_qpolygon.moc" diff --git a/tests/auto/qresourceengine/qresourceengine.pro b/tests/auto/qresourceengine/qresourceengine.pro index cdbbbd2..f897d60 100644 --- a/tests/auto/qresourceengine/qresourceengine.pro +++ b/tests/auto/qresourceengine/qresourceengine.pro @@ -6,7 +6,7 @@ load(qttest_p4) load(resources) # Input -SOURCES += tst_resourceengine.cpp +SOURCES += tst_qresourceengine.cpp RESOURCES += testqrc/test.qrc runtime_resource.target = runtime_resource.rcc diff --git a/tests/auto/qresourceengine/tst_qresourceengine.cpp b/tests/auto/qresourceengine/tst_qresourceengine.cpp new file mode 100644 index 0000000..d446562 --- /dev/null +++ b/tests/auto/qresourceengine/tst_qresourceengine.cpp @@ -0,0 +1,462 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include +#include + +class tst_QResourceEngine: public QObject +{ + Q_OBJECT + +private slots: + void initTestCase(); + void cleanupTestCase(); + + void checkUnregisterResource_data(); + void checkUnregisterResource(); + void checkStructure_data(); + void checkStructure(); + void searchPath_data(); + void searchPath(); + void doubleSlashInRoot(); + +private: + QString builddir; +}; + +Q_DECLARE_METATYPE(QLocale) +Q_DECLARE_METATYPE(qlonglong) + +void tst_QResourceEngine::initTestCase() +{ + QVERIFY(QResource::registerResource("runtime_resource.rcc")); + QVERIFY(QResource::registerResource("runtime_resource.rcc", "/secondary_root/")); + QString srcdir(QLatin1String(SRCDIR)); + if (!srcdir.isEmpty()) { + builddir = QDir::current().absolutePath(); + if (!builddir.endsWith(QDir::separator())) + builddir.append(QDir::separator()); + QDir::setCurrent(srcdir); + } +} + +void tst_QResourceEngine::cleanupTestCase() +{ + if (!builddir.isEmpty()) { + QDir::setCurrent(builddir); + } + + // make sure we don't leak memory + QVERIFY(QResource::unregisterResource("runtime_resource.rcc")); + QVERIFY(QResource::unregisterResource("runtime_resource.rcc", "/secondary_root/")); +} + +void tst_QResourceEngine::checkStructure_data() +{ + QTest::addColumn("pathName"); + QTest::addColumn("contents"); + QTest::addColumn("containedFiles"); + QTest::addColumn("containedDirs"); + QTest::addColumn("locale"); + QTest::addColumn("contentsSize"); + + QFileInfo info; + + QTest::newRow("root dir") << QString(":/") + << QString() + << (QStringList() << "search_file.txt") + << (QStringList() << QLatin1String("aliasdir") << QLatin1String("otherdir") + << QLatin1String("runtime_resource") + << QLatin1String("searchpath1") << QLatin1String("searchpath2") + << QLatin1String("secondary_root") + << QLatin1String("test") << QLatin1String("trolltech") + << QLatin1String("withoutslashes")) + << QLocale::c() + << qlonglong(0); + + QTest::newRow("secondary root") << QString(":/secondary_root/") + << QString() + << QStringList() + << (QStringList() << QLatin1String("runtime_resource")) + << QLocale::c() + << qlonglong(0); + + QStringList roots; + roots << QString(":/") << QString(":/runtime_resource/") << QString(":/secondary_root/runtime_resource/"); + for(int i = 0; i < roots.size(); ++i) { + const QString root = roots.at(i); + + QTest::newRow(QString(root + "prefix dir").toLatin1().constData()) << QString(root + "test/abc/123/+++") + << QString() + << (QStringList() << QLatin1String("currentdir.txt") << QLatin1String("currentdir2.txt") << QLatin1String("parentdir.txt")) + << (QStringList() << QLatin1String("subdir")) + << QLocale::c() + << qlonglong(0); + + QTest::newRow(QString(root + "parent to prefix").toLatin1().constData()) << QString(root + "test/abc/123") + << QString() + << QStringList() + << (QStringList() << QLatin1String("+++")) + << QLocale::c() + << qlonglong(0); + + QTest::newRow(QString(root + "two parents prefix").toLatin1().constData()) << QString(root + "test/abc") + << QString() + << QStringList() + << QStringList(QLatin1String("123")) + << QLocale::c() + << qlonglong(0); + + QTest::newRow(QString(root + "test dir ").toLatin1().constData()) << QString(root + "test") + << QString() + << (QStringList() << QLatin1String("testdir.txt")) + << (QStringList() << QLatin1String("abc") << QLatin1String("test")) + << QLocale::c() + << qlonglong(0); + + QTest::newRow(QString(root + "prefix no slashes").toLatin1().constData()) << QString(root + "withoutslashes") + << QString() + << QStringList("blahblah.txt") + << QStringList() + << QLocale::c() + << qlonglong(0); + + QTest::newRow(QString(root + "other dir").toLatin1().constData()) << QString(root + "otherdir") + << QString() + << QStringList(QLatin1String("otherdir.txt")) + << QStringList() + << QLocale::c() + << qlonglong(0); + + QTest::newRow(QString(root + "alias dir").toLatin1().constData()) << QString(root + "aliasdir") + << QString() + << QStringList(QLatin1String("aliasdir.txt")) + << QStringList() + << QLocale::c() + << qlonglong(0); + + QTest::newRow(QString(root + "second test dir").toLatin1().constData()) << QString(root + "test/test") + << QString() + << (QStringList() << QLatin1String("test1.txt") << QLatin1String("test2.txt")) + << QStringList() + << QLocale::c() + << qlonglong(0); + + info = QFileInfo("testqrc/test/test/test1.txt"); + QTest::newRow(QString(root + "test1 text").toLatin1().constData()) << QString(root + "test/test/test1.txt") + << QString("abc") + << QStringList() + << QStringList() + << QLocale::c() + << qlonglong(info.size()); + + info = QFileInfo("testqrc/blahblah.txt"); + QTest::newRow(QString(root + "text no slashes").toLatin1().constData()) << QString(root + "withoutslashes/blahblah.txt") + << QString("qwerty") + << QStringList() + << QStringList() + << QLocale::c() + << qlonglong(info.size()); + + + info = QFileInfo("testqrc/test/test/test2.txt"); + QTest::newRow(QString(root + "test1 text").toLatin1().constData()) << QString(root + "test/test/test2.txt") + << QString("def") + << QStringList() + << QStringList() + << QLocale::c() + << qlonglong(info.size()); + + info = QFileInfo("testqrc/currentdir.txt"); + QTest::newRow(QString(root + "currentdir text").toLatin1().constData()) << QString(root + "test/abc/123/+++/currentdir.txt") + << QString("\"This is the current dir\" ") + << QStringList() + << QStringList() + << QLocale::c() + << qlonglong(info.size()); + + info = QFileInfo("testqrc/currentdir2.txt"); + QTest::newRow(QString(root + "currentdir text2").toLatin1().constData()) << QString(root + "test/abc/123/+++/currentdir2.txt") + << QString("\"This is also the current dir\" ") + << QStringList() + << QStringList() + << QLocale::c() + << qlonglong(info.size()); + + info = QFileInfo("parentdir.txt"); + QTest::newRow(QString(root + "parentdir text").toLatin1().constData()) << QString(root + "test/abc/123/+++/parentdir.txt") + << QString("abcdefgihklmnopqrstuvwxyz ") + << QStringList() + << QStringList() + << QLocale::c() + << qlonglong(info.size()); + + info = QFileInfo("testqrc/subdir/subdir.txt"); + QTest::newRow(QString(root + "subdir text").toLatin1().constData()) << QString(root + "test/abc/123/+++/subdir/subdir.txt") + << QString("\"This is in the sub directory\" ") + << QStringList() + << QStringList() + << QLocale::c() + << qlonglong(info.size()); + + info = QFileInfo("testqrc/test/testdir.txt"); + QTest::newRow(QString(root + "testdir text").toLatin1().constData()) << QString(root + "test/testdir.txt") + << QString("\"This is in the test directory\" ") + << QStringList() + << QStringList() + << QLocale::c() + << qlonglong(info.size()); + + info = QFileInfo("testqrc/otherdir/otherdir.txt"); + QTest::newRow(QString(root + "otherdir text").toLatin1().constData()) << QString(root + "otherdir/otherdir.txt") + << QString("\"This is the other dir\" ") + << QStringList() + << QStringList() + << QLocale::c() + << qlonglong(info.size()); + + info = QFileInfo("testqrc/test/testdir2.txt"); + QTest::newRow(QString(root + "alias text").toLatin1().constData()) << QString(root + "aliasdir/aliasdir.txt") + << QString("\"This is another file in this directory\" ") + << QStringList() + << QStringList() + << QLocale::c() + << qlonglong(info.size()); + + info = QFileInfo("testqrc/aliasdir/aliasdir.txt"); + QTest::newRow(QString(root + "korean text").toLatin1().constData()) << QString(root + "aliasdir/aliasdir.txt") + << QString("\"This is a korean text file\" ") + << QStringList() + << QStringList() + << QLocale("ko") + << qlonglong(info.size()); + + info = QFileInfo("testqrc/aliasdir/aliasdir.txt"); + QTest::newRow(QString(root + "korean text 2").toLatin1().constData()) << QString(root + "aliasdir/aliasdir.txt") + << QString("\"This is a korean text file\" ") + << QStringList() + << QStringList() + << QLocale("ko_KR") + << qlonglong(info.size()); + + info = QFileInfo("testqrc/test/german.txt"); + QTest::newRow(QString(root + "german text").toLatin1().constData()) << QString(root + "aliasdir/aliasdir.txt") + << QString("Deutsch") + << QStringList() + << QStringList() + << QLocale("de") + << qlonglong(info.size()); + + info = QFileInfo("testqrc/test/german.txt"); + QTest::newRow(QString(root + "german text 2").toLatin1().constData()) << QString(root + "aliasdir/aliasdir.txt") + << QString("Deutsch") + << QStringList() + << QStringList() + << QLocale("de_DE") + << qlonglong(info.size()); + + QFile file("testqrc/aliasdir/compressme.txt"); + file.open(QFile::ReadOnly); + info = QFileInfo("testqrc/aliasdir/compressme.txt"); + QTest::newRow(QString(root + "compressed text").toLatin1().constData()) << QString(root + "aliasdir/aliasdir.txt") + << QString(file.readAll()) + << QStringList() + << QStringList() + << QLocale("de_CH") + << qlonglong(info.size()); + } +} + +void tst_QResourceEngine::checkStructure() +{ + QFETCH(QString, pathName); + QFETCH(QString, contents); + QFETCH(QStringList, containedFiles); + QFETCH(QStringList, containedDirs); + QFETCH(QLocale, locale); + QFETCH(qlonglong, contentsSize); + + bool directory = (containedDirs.size() + containedFiles.size() > 0); + QLocale::setDefault(locale); + + QFileInfo fileInfo(pathName); + + QVERIFY(fileInfo.exists()); + QCOMPARE(fileInfo.isDir(), directory); + QCOMPARE(fileInfo.size(), contentsSize); + //QVERIFY(fileInfo.isReadable()); + QVERIFY(!fileInfo.isWritable()); + QVERIFY(!fileInfo.isExecutable()); + + if (directory) { + QDir dir(pathName); + + // Test the Dir filter + QFileInfoList list = dir.entryInfoList(QDir::Dirs, QDir::Name); +// for(int i = 0; i < list.size(); ++i) +// qDebug() << "one" << i << list.at(i).fileName(); +// for(int i = 0; i < containedDirs.size(); ++i) +// qDebug() << "two" << i << containedDirs.at(i); +// qDebug() << "one" << list.size() << containedDirs.size(); + QCOMPARE(list.size(), containedDirs.size()); +// qDebug() << "two"; + + int i; + for (i=0; i("searchPath"); + QTest::addColumn("file"); + QTest::addColumn("expected"); + + QTest::newRow("no_search_path") << QString() + << ":search_file.txt" + << QByteArray("root\n"); + QTest::newRow("path1") << "/searchpath1" + << ":search_file.txt" + << QByteArray("path1\n"); + QTest::newRow("no_search_path2") << QString() + << ":/search_file.txt" + << QByteArray("root\n"); + QTest::newRow("path2") << "/searchpath2" + << ":search_file.txt" + << QByteArray("path2\n"); +} + +void tst_QResourceEngine::searchPath() +{ + QFETCH(QString, searchPath); + QFETCH(QString, file); + QFETCH(QByteArray, expected); + + if(!searchPath.isEmpty()) + QDir::addResourceSearchPath(searchPath); + QFile qf(file); + QVERIFY(qf.open(QFile::ReadOnly)); + QByteArray actual = qf.readAll(); + + actual.replace('\r', ""); + + QCOMPARE(actual, expected); + qf.close(); +} + +void tst_QResourceEngine::checkUnregisterResource_data() +{ + QTest::addColumn("rcc_file"); + QTest::addColumn("root"); + QTest::addColumn("file_check"); + QTest::addColumn("size"); + + QTest::newRow("currentdir.txt") << builddir + QString("runtime_resource.rcc") << QString("/check_unregister/") + << QString(":/check_unregister/runtime_resource/test/abc/123/+++/currentdir.txt") + << (int)QFileInfo("testqrc/currentdir.txt").size(); +} + +void tst_QResourceEngine::checkUnregisterResource() +{ + QFETCH(QString, rcc_file); + QFETCH(QString, root); + QFETCH(QString, file_check); + QFETCH(int, size); + + + + QVERIFY(!QFile::exists(file_check)); + QVERIFY(QResource::registerResource(rcc_file, root)); + QVERIFY(QFile::exists(file_check)); + QVERIFY(QResource::unregisterResource(rcc_file, root)); + QVERIFY(!QFile::exists(file_check)); + QVERIFY(QResource::registerResource(rcc_file, root)); + QVERIFY(QFile::exists(file_check)); + QFileInfo fileInfo(file_check); + fileInfo.setCaching(false); + QVERIFY(fileInfo.exists()); + QVERIFY(!QResource::unregisterResource(rcc_file, root)); + QVERIFY(!QFile::exists(file_check)); + QCOMPARE((int)fileInfo.size(), size); +} + +void tst_QResourceEngine::doubleSlashInRoot() +{ + QVERIFY(QFile::exists(":/secondary_root/runtime_resource/search_file.txt")); + QVERIFY(QFile::exists("://secondary_root/runtime_resource/search_file.txt")); +} + +QTEST_MAIN(tst_QResourceEngine) + +#include "tst_qresourceengine.moc" + diff --git a/tests/auto/qresourceengine/tst_resourceengine.cpp b/tests/auto/qresourceengine/tst_resourceengine.cpp deleted file mode 100644 index a5e701a..0000000 --- a/tests/auto/qresourceengine/tst_resourceengine.cpp +++ /dev/null @@ -1,461 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** 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 either Technology Preview License Agreement or the -** Beta Release License Agreement. -** -** 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.0, included in the file LGPL_EXCEPTION.txt in this -** package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** If you are unsure which license is appropriate for your use, please -** contact the sales department at http://www.qtsoftware.com/contact. -** $QT_END_LICENSE$ -** -****************************************************************************/ - - -#include -#include - -class tst_ResourceEngine: public QObject -{ - Q_OBJECT - -private slots: - void initTestCase(); - void cleanupTestCase(); - - void checkUnregisterResource_data(); - void checkUnregisterResource(); - void checkStructure_data(); - void checkStructure(); - void searchPath_data(); - void searchPath(); - void doubleSlashInRoot(); - -private: - QString builddir; -}; - -Q_DECLARE_METATYPE(QLocale) -Q_DECLARE_METATYPE(qlonglong) - -void tst_ResourceEngine::initTestCase() -{ - QVERIFY(QResource::registerResource("runtime_resource.rcc")); - QVERIFY(QResource::registerResource("runtime_resource.rcc", "/secondary_root/")); - QString srcdir(QLatin1String(SRCDIR)); - if (!srcdir.isEmpty()) { - builddir = QDir::current().absolutePath(); - if (!builddir.endsWith(QDir::separator())) - builddir.append(QDir::separator()); - QDir::setCurrent(srcdir); - } -} - -void tst_ResourceEngine::cleanupTestCase() -{ - if (!builddir.isEmpty()) { - QDir::setCurrent(builddir); - } - - // make sure we don't leak memory - QVERIFY(QResource::unregisterResource("runtime_resource.rcc")); - QVERIFY(QResource::unregisterResource("runtime_resource.rcc", "/secondary_root/")); -} - -void tst_ResourceEngine::checkStructure_data() -{ - QTest::addColumn("pathName"); - QTest::addColumn("contents"); - QTest::addColumn("containedFiles"); - QTest::addColumn("containedDirs"); - QTest::addColumn("locale"); - QTest::addColumn("contentsSize"); - - QFileInfo info; - - QTest::newRow("root dir") << QString(":/") - << QString() - << (QStringList() << "search_file.txt") - << (QStringList() << QLatin1String("aliasdir") << QLatin1String("otherdir") - << QLatin1String("runtime_resource") - << QLatin1String("searchpath1") << QLatin1String("searchpath2") - << QLatin1String("secondary_root") - << QLatin1String("test") << QLatin1String("trolltech") - << QLatin1String("withoutslashes")) - << QLocale::c() - << qlonglong(0); - - QTest::newRow("secondary root") << QString(":/secondary_root/") - << QString() - << QStringList() - << (QStringList() << QLatin1String("runtime_resource")) - << QLocale::c() - << qlonglong(0); - - QStringList roots; - roots << QString(":/") << QString(":/runtime_resource/") << QString(":/secondary_root/runtime_resource/"); - for(int i = 0; i < roots.size(); ++i) { - const QString root = roots.at(i); - - QTest::newRow(QString(root + "prefix dir").toLatin1().constData()) << QString(root + "test/abc/123/+++") - << QString() - << (QStringList() << QLatin1String("currentdir.txt") << QLatin1String("currentdir2.txt") << QLatin1String("parentdir.txt")) - << (QStringList() << QLatin1String("subdir")) - << QLocale::c() - << qlonglong(0); - - QTest::newRow(QString(root + "parent to prefix").toLatin1().constData()) << QString(root + "test/abc/123") - << QString() - << QStringList() - << (QStringList() << QLatin1String("+++")) - << QLocale::c() - << qlonglong(0); - - QTest::newRow(QString(root + "two parents prefix").toLatin1().constData()) << QString(root + "test/abc") - << QString() - << QStringList() - << QStringList(QLatin1String("123")) - << QLocale::c() - << qlonglong(0); - - QTest::newRow(QString(root + "test dir ").toLatin1().constData()) << QString(root + "test") - << QString() - << (QStringList() << QLatin1String("testdir.txt")) - << (QStringList() << QLatin1String("abc") << QLatin1String("test")) - << QLocale::c() - << qlonglong(0); - - QTest::newRow(QString(root + "prefix no slashes").toLatin1().constData()) << QString(root + "withoutslashes") - << QString() - << QStringList("blahblah.txt") - << QStringList() - << QLocale::c() - << qlonglong(0); - - QTest::newRow(QString(root + "other dir").toLatin1().constData()) << QString(root + "otherdir") - << QString() - << QStringList(QLatin1String("otherdir.txt")) - << QStringList() - << QLocale::c() - << qlonglong(0); - - QTest::newRow(QString(root + "alias dir").toLatin1().constData()) << QString(root + "aliasdir") - << QString() - << QStringList(QLatin1String("aliasdir.txt")) - << QStringList() - << QLocale::c() - << qlonglong(0); - - QTest::newRow(QString(root + "second test dir").toLatin1().constData()) << QString(root + "test/test") - << QString() - << (QStringList() << QLatin1String("test1.txt") << QLatin1String("test2.txt")) - << QStringList() - << QLocale::c() - << qlonglong(0); - - info = QFileInfo("testqrc/test/test/test1.txt"); - QTest::newRow(QString(root + "test1 text").toLatin1().constData()) << QString(root + "test/test/test1.txt") - << QString("abc") - << QStringList() - << QStringList() - << QLocale::c() - << qlonglong(info.size()); - - info = QFileInfo("testqrc/blahblah.txt"); - QTest::newRow(QString(root + "text no slashes").toLatin1().constData()) << QString(root + "withoutslashes/blahblah.txt") - << QString("qwerty") - << QStringList() - << QStringList() - << QLocale::c() - << qlonglong(info.size()); - - - info = QFileInfo("testqrc/test/test/test2.txt"); - QTest::newRow(QString(root + "test1 text").toLatin1().constData()) << QString(root + "test/test/test2.txt") - << QString("def") - << QStringList() - << QStringList() - << QLocale::c() - << qlonglong(info.size()); - - info = QFileInfo("testqrc/currentdir.txt"); - QTest::newRow(QString(root + "currentdir text").toLatin1().constData()) << QString(root + "test/abc/123/+++/currentdir.txt") - << QString("\"This is the current dir\" ") - << QStringList() - << QStringList() - << QLocale::c() - << qlonglong(info.size()); - - info = QFileInfo("testqrc/currentdir2.txt"); - QTest::newRow(QString(root + "currentdir text2").toLatin1().constData()) << QString(root + "test/abc/123/+++/currentdir2.txt") - << QString("\"This is also the current dir\" ") - << QStringList() - << QStringList() - << QLocale::c() - << qlonglong(info.size()); - - info = QFileInfo("parentdir.txt"); - QTest::newRow(QString(root + "parentdir text").toLatin1().constData()) << QString(root + "test/abc/123/+++/parentdir.txt") - << QString("abcdefgihklmnopqrstuvwxyz ") - << QStringList() - << QStringList() - << QLocale::c() - << qlonglong(info.size()); - - info = QFileInfo("testqrc/subdir/subdir.txt"); - QTest::newRow(QString(root + "subdir text").toLatin1().constData()) << QString(root + "test/abc/123/+++/subdir/subdir.txt") - << QString("\"This is in the sub directory\" ") - << QStringList() - << QStringList() - << QLocale::c() - << qlonglong(info.size()); - - info = QFileInfo("testqrc/test/testdir.txt"); - QTest::newRow(QString(root + "testdir text").toLatin1().constData()) << QString(root + "test/testdir.txt") - << QString("\"This is in the test directory\" ") - << QStringList() - << QStringList() - << QLocale::c() - << qlonglong(info.size()); - - info = QFileInfo("testqrc/otherdir/otherdir.txt"); - QTest::newRow(QString(root + "otherdir text").toLatin1().constData()) << QString(root + "otherdir/otherdir.txt") - << QString("\"This is the other dir\" ") - << QStringList() - << QStringList() - << QLocale::c() - << qlonglong(info.size()); - - info = QFileInfo("testqrc/test/testdir2.txt"); - QTest::newRow(QString(root + "alias text").toLatin1().constData()) << QString(root + "aliasdir/aliasdir.txt") - << QString("\"This is another file in this directory\" ") - << QStringList() - << QStringList() - << QLocale::c() - << qlonglong(info.size()); - - info = QFileInfo("testqrc/aliasdir/aliasdir.txt"); - QTest::newRow(QString(root + "korean text").toLatin1().constData()) << QString(root + "aliasdir/aliasdir.txt") - << QString("\"This is a korean text file\" ") - << QStringList() - << QStringList() - << QLocale("ko") - << qlonglong(info.size()); - - info = QFileInfo("testqrc/aliasdir/aliasdir.txt"); - QTest::newRow(QString(root + "korean text 2").toLatin1().constData()) << QString(root + "aliasdir/aliasdir.txt") - << QString("\"This is a korean text file\" ") - << QStringList() - << QStringList() - << QLocale("ko_KR") - << qlonglong(info.size()); - - info = QFileInfo("testqrc/test/german.txt"); - QTest::newRow(QString(root + "german text").toLatin1().constData()) << QString(root + "aliasdir/aliasdir.txt") - << QString("Deutsch") - << QStringList() - << QStringList() - << QLocale("de") - << qlonglong(info.size()); - - info = QFileInfo("testqrc/test/german.txt"); - QTest::newRow(QString(root + "german text 2").toLatin1().constData()) << QString(root + "aliasdir/aliasdir.txt") - << QString("Deutsch") - << QStringList() - << QStringList() - << QLocale("de_DE") - << qlonglong(info.size()); - - QFile file("testqrc/aliasdir/compressme.txt"); - file.open(QFile::ReadOnly); - info = QFileInfo("testqrc/aliasdir/compressme.txt"); - QTest::newRow(QString(root + "compressed text").toLatin1().constData()) << QString(root + "aliasdir/aliasdir.txt") - << QString(file.readAll()) - << QStringList() - << QStringList() - << QLocale("de_CH") - << qlonglong(info.size()); - } -} - -void tst_ResourceEngine::checkStructure() -{ - QFETCH(QString, pathName); - QFETCH(QString, contents); - QFETCH(QStringList, containedFiles); - QFETCH(QStringList, containedDirs); - QFETCH(QLocale, locale); - QFETCH(qlonglong, contentsSize); - - bool directory = (containedDirs.size() + containedFiles.size() > 0); - QLocale::setDefault(locale); - - QFileInfo fileInfo(pathName); - - QVERIFY(fileInfo.exists()); - QCOMPARE(fileInfo.isDir(), directory); - QCOMPARE(fileInfo.size(), contentsSize); - //QVERIFY(fileInfo.isReadable()); - QVERIFY(!fileInfo.isWritable()); - QVERIFY(!fileInfo.isExecutable()); - - if (directory) { - QDir dir(pathName); - - // Test the Dir filter - QFileInfoList list = dir.entryInfoList(QDir::Dirs, QDir::Name); -// for(int i = 0; i < list.size(); ++i) -// qDebug() << "one" << i << list.at(i).fileName(); -// for(int i = 0; i < containedDirs.size(); ++i) -// qDebug() << "two" << i << containedDirs.at(i); -// qDebug() << "one" << list.size() << containedDirs.size(); - QCOMPARE(list.size(), containedDirs.size()); -// qDebug() << "two"; - - int i; - for (i=0; i("searchPath"); - QTest::addColumn("file"); - QTest::addColumn("expected"); - - QTest::newRow("no_search_path") << QString() - << ":search_file.txt" - << QByteArray("root\n"); - QTest::newRow("path1") << "/searchpath1" - << ":search_file.txt" - << QByteArray("path1\n"); - QTest::newRow("no_search_path2") << QString() - << ":/search_file.txt" - << QByteArray("root\n"); - QTest::newRow("path2") << "/searchpath2" - << ":search_file.txt" - << QByteArray("path2\n"); -} - -void tst_ResourceEngine::searchPath() -{ - QFETCH(QString, searchPath); - QFETCH(QString, file); - QFETCH(QByteArray, expected); - - if(!searchPath.isEmpty()) - QDir::addResourceSearchPath(searchPath); - QFile qf(file); - QVERIFY(qf.open(QFile::ReadOnly)); - QByteArray actual = qf.readAll(); - - actual.replace('\r', ""); - - QCOMPARE(actual, expected); - qf.close(); -} - -void tst_ResourceEngine::checkUnregisterResource_data() -{ - QTest::addColumn("rcc_file"); - QTest::addColumn("root"); - QTest::addColumn("file_check"); - QTest::addColumn("size"); - - QTest::newRow("currentdir.txt") << builddir + QString("runtime_resource.rcc") << QString("/check_unregister/") - << QString(":/check_unregister/runtime_resource/test/abc/123/+++/currentdir.txt") - << (int)QFileInfo("testqrc/currentdir.txt").size(); -} - -void tst_ResourceEngine::checkUnregisterResource() -{ - QFETCH(QString, rcc_file); - QFETCH(QString, root); - QFETCH(QString, file_check); - QFETCH(int, size); - - - - QVERIFY(!QFile::exists(file_check)); - QVERIFY(QResource::registerResource(rcc_file, root)); - QVERIFY(QFile::exists(file_check)); - QVERIFY(QResource::unregisterResource(rcc_file, root)); - QVERIFY(!QFile::exists(file_check)); - QVERIFY(QResource::registerResource(rcc_file, root)); - QVERIFY(QFile::exists(file_check)); - QFileInfo fileInfo(file_check); - fileInfo.setCaching(false); - QVERIFY(fileInfo.exists()); - QVERIFY(!QResource::unregisterResource(rcc_file, root)); - QVERIFY(!QFile::exists(file_check)); - QCOMPARE((int)fileInfo.size(), size); -} - -void tst_ResourceEngine::doubleSlashInRoot() -{ - QVERIFY(QFile::exists(":/secondary_root/runtime_resource/search_file.txt")); - QVERIFY(QFile::exists("://secondary_root/runtime_resource/search_file.txt")); -} - -QTEST_MAIN(tst_ResourceEngine) - -#include "tst_resourceengine.moc" diff --git a/tests/auto/qscriptextqobject/.gitignore b/tests/auto/qscriptextqobject/.gitignore new file mode 100644 index 0000000..bff799f --- /dev/null +++ b/tests/auto/qscriptextqobject/.gitignore @@ -0,0 +1 @@ +tst_qscriptqobject diff --git a/tests/auto/qscriptextqobject/qscriptextqobject.pro b/tests/auto/qscriptextqobject/qscriptextqobject.pro new file mode 100644 index 0000000..a5e9cab --- /dev/null +++ b/tests/auto/qscriptextqobject/qscriptextqobject.pro @@ -0,0 +1,5 @@ +load(qttest_p4) +QT += script +SOURCES += tst_qscriptextqobject.cpp + + diff --git a/tests/auto/qscriptextqobject/tst_qscriptextqobject.cpp b/tests/auto/qscriptextqobject/tst_qscriptextqobject.cpp new file mode 100644 index 0000000..0d0f927 --- /dev/null +++ b/tests/auto/qscriptextqobject/tst_qscriptextqobject.cpp @@ -0,0 +1,2734 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include + +#include +#include +#include +#include +#include +#include + +//TESTED_CLASS= +//TESTED_FILES=script/qscriptextqobject_p.h script/qscriptextqobject.cpp + +struct CustomType +{ + QString string; +}; +Q_DECLARE_METATYPE(CustomType) + +Q_DECLARE_METATYPE(QBrush*) +Q_DECLARE_METATYPE(QObjectList) +Q_DECLARE_METATYPE(QList) +Q_DECLARE_METATYPE(Qt::BrushStyle) +Q_DECLARE_METATYPE(QDir) + +static void dirFromScript(const QScriptValue &in, QDir &out) +{ + QScriptValue path = in.property("path"); + if (!path.isValid()) + in.engine()->currentContext()->throwError("No path"); + else + out.setPath(path.toString()); +} + +namespace MyNS +{ + class A : public QObject + { + Q_OBJECT + public: + enum Type { + Foo, + Bar + }; + Q_ENUMS(Type) + public Q_SLOTS: + int slotTakingScopedEnumArg(MyNS::A::Type t) { + return t; + } + }; +} + +class MyQObject : public QObject +{ + Q_OBJECT + + Q_PROPERTY(int intProperty READ intProperty WRITE setIntProperty) + Q_PROPERTY(QVariant variantProperty READ variantProperty WRITE setVariantProperty) + Q_PROPERTY(QVariantList variantListProperty READ variantListProperty WRITE setVariantListProperty) + Q_PROPERTY(QString stringProperty READ stringProperty WRITE setStringProperty) + Q_PROPERTY(QStringList stringListProperty READ stringListProperty WRITE setStringListProperty) + Q_PROPERTY(QByteArray byteArrayProperty READ byteArrayProperty WRITE setByteArrayProperty) + Q_PROPERTY(QBrush brushProperty READ brushProperty WRITE setBrushProperty) + Q_PROPERTY(double hiddenProperty READ hiddenProperty WRITE setHiddenProperty SCRIPTABLE false) + Q_PROPERTY(int writeOnlyProperty WRITE setWriteOnlyProperty) + Q_PROPERTY(int readOnlyProperty READ readOnlyProperty) + Q_PROPERTY(QKeySequence shortcut READ shortcut WRITE setShortcut) + Q_PROPERTY(CustomType propWithCustomType READ propWithCustomType WRITE setPropWithCustomType) + Q_ENUMS(Policy Strategy) + Q_FLAGS(Ability) + +public: + enum Policy { + FooPolicy = 0, + BarPolicy, + BazPolicy + }; + + enum Strategy { + FooStrategy = 10, + BarStrategy, + BazStrategy + }; + + enum AbilityFlag { + NoAbility = 0x000, + FooAbility = 0x001, + BarAbility = 0x080, + BazAbility = 0x200, + AllAbility = FooAbility | BarAbility | BazAbility + }; + + Q_DECLARE_FLAGS(Ability, AbilityFlag) + + MyQObject(QObject *parent = 0) + : QObject(parent), + m_intValue(123), + m_variantValue(QLatin1String("foo")), + m_variantListValue(QVariantList() << QVariant(123) << QVariant(QLatin1String("foo"))), + m_stringValue(QLatin1String("bar")), + m_stringListValue(QStringList() << QLatin1String("zig") << QLatin1String("zag")), + m_brushValue(QColor(10, 20, 30, 40)), + m_hiddenValue(456.0), + m_writeOnlyValue(789), + m_readOnlyValue(987), + m_qtFunctionInvoked(-1) + { } + + int intProperty() const + { return m_intValue; } + void setIntProperty(int value) + { m_intValue = value; } + + QVariant variantProperty() const + { return m_variantValue; } + void setVariantProperty(const QVariant &value) + { m_variantValue = value; } + + QVariantList variantListProperty() const + { return m_variantListValue; } + void setVariantListProperty(const QVariantList &value) + { m_variantListValue = value; } + + QString stringProperty() const + { return m_stringValue; } + void setStringProperty(const QString &value) + { m_stringValue = value; } + + QStringList stringListProperty() const + { return m_stringListValue; } + void setStringListProperty(const QStringList &value) + { m_stringListValue = value; } + + QByteArray byteArrayProperty() const + { return m_byteArrayValue; } + void setByteArrayProperty(const QByteArray &value) + { m_byteArrayValue = value; } + + QBrush brushProperty() const + { return m_brushValue; } + Q_INVOKABLE void setBrushProperty(const QBrush &value) + { m_brushValue = value; } + + double hiddenProperty() const + { return m_hiddenValue; } + void setHiddenProperty(double value) + { m_hiddenValue = value; } + + int writeOnlyProperty() const + { return m_writeOnlyValue; } + void setWriteOnlyProperty(int value) + { m_writeOnlyValue = value; } + + int readOnlyProperty() const + { return m_readOnlyValue; } + + QKeySequence shortcut() const + { return m_shortcut; } + void setShortcut(const QKeySequence &seq) + { m_shortcut = seq; } + + CustomType propWithCustomType() const + { return m_customType; } + void setPropWithCustomType(const CustomType &c) + { m_customType = c; } + + int qtFunctionInvoked() const + { return m_qtFunctionInvoked; } + + QVariantList qtFunctionActuals() const + { return m_actuals; } + + void resetQtFunctionInvoked() + { m_qtFunctionInvoked = -1; m_actuals.clear(); } + + void clearConnectedSignal() + { m_connectedSignal = QByteArray(); } + void clearDisconnectedSignal() + { m_disconnectedSignal = QByteArray(); } + QByteArray connectedSignal() const + { return m_connectedSignal; } + QByteArray disconnectedSignal() const + { return m_disconnectedSignal; } + + Q_INVOKABLE void myInvokable() + { m_qtFunctionInvoked = 0; } + Q_INVOKABLE void myInvokableWithIntArg(int arg) + { m_qtFunctionInvoked = 1; m_actuals << arg; } + Q_INVOKABLE void myInvokableWithLonglongArg(qlonglong arg) + { m_qtFunctionInvoked = 2; m_actuals << arg; } + Q_INVOKABLE void myInvokableWithFloatArg(float arg) + { m_qtFunctionInvoked = 3; m_actuals << arg; } + Q_INVOKABLE void myInvokableWithDoubleArg(double arg) + { m_qtFunctionInvoked = 4; m_actuals << arg; } + Q_INVOKABLE void myInvokableWithStringArg(const QString &arg) + { m_qtFunctionInvoked = 5; m_actuals << arg; } + Q_INVOKABLE void myInvokableWithIntArgs(int arg1, int arg2) + { m_qtFunctionInvoked = 6; m_actuals << arg1 << arg2; } + Q_INVOKABLE int myInvokableReturningInt() + { m_qtFunctionInvoked = 7; return 123; } + Q_INVOKABLE qlonglong myInvokableReturningLongLong() + { m_qtFunctionInvoked = 39; return 456; } + Q_INVOKABLE QString myInvokableReturningString() + { m_qtFunctionInvoked = 8; return QLatin1String("ciao"); } + Q_INVOKABLE QVariant myInvokableReturningVariant() + { m_qtFunctionInvoked = 60; return 123; } + Q_INVOKABLE QScriptValue myInvokableReturningScriptValue() + { m_qtFunctionInvoked = 61; return 456; } + Q_INVOKABLE void myInvokableWithIntArg(int arg1, int arg2) // overload + { m_qtFunctionInvoked = 9; m_actuals << arg1 << arg2; } + Q_INVOKABLE void myInvokableWithEnumArg(Policy policy) + { m_qtFunctionInvoked = 10; m_actuals << policy; } + Q_INVOKABLE void myInvokableWithQualifiedEnumArg(MyQObject::Policy policy) + { m_qtFunctionInvoked = 36; m_actuals << policy; } + Q_INVOKABLE Policy myInvokableReturningEnum() + { m_qtFunctionInvoked = 37; return BazPolicy; } + Q_INVOKABLE MyQObject::Policy myInvokableReturningQualifiedEnum() + { m_qtFunctionInvoked = 38; return BazPolicy; } + Q_INVOKABLE QVector myInvokableReturningVectorOfInt() + { m_qtFunctionInvoked = 11; return QVector(); } + Q_INVOKABLE void myInvokableWithVectorOfIntArg(const QVector &) + { m_qtFunctionInvoked = 12; } + Q_INVOKABLE QObject *myInvokableReturningQObjectStar() + { m_qtFunctionInvoked = 13; return this; } + Q_INVOKABLE QObjectList myInvokableWithQObjectListArg(const QObjectList &lst) + { m_qtFunctionInvoked = 14; m_actuals << qVariantFromValue(lst); return lst; } + Q_INVOKABLE QVariant myInvokableWithVariantArg(const QVariant &v) + { m_qtFunctionInvoked = 15; m_actuals << v; return v; } + Q_INVOKABLE QVariantMap myInvokableWithVariantMapArg(const QVariantMap &vm) + { m_qtFunctionInvoked = 16; m_actuals << vm; return vm; } + Q_INVOKABLE QList myInvokableWithListOfIntArg(const QList &lst) + { m_qtFunctionInvoked = 17; m_actuals << qVariantFromValue(lst); return lst; } + Q_INVOKABLE QObject* myInvokableWithQObjectStarArg(QObject *obj) + { m_qtFunctionInvoked = 18; m_actuals << qVariantFromValue(obj); return obj; } + Q_INVOKABLE QBrush myInvokableWithQBrushArg(const QBrush &brush) + { m_qtFunctionInvoked = 19; m_actuals << qVariantFromValue(brush); return brush; } + Q_INVOKABLE void myInvokableWithBrushStyleArg(Qt::BrushStyle style) + { m_qtFunctionInvoked = 43; m_actuals << qVariantFromValue(style); } + Q_INVOKABLE void myInvokableWithVoidStarArg(void *arg) + { m_qtFunctionInvoked = 44; m_actuals << qVariantFromValue(arg); } + Q_INVOKABLE void myInvokableWithAmbiguousArg(int arg) + { m_qtFunctionInvoked = 45; m_actuals << qVariantFromValue(arg); } + Q_INVOKABLE void myInvokableWithAmbiguousArg(uint arg) + { m_qtFunctionInvoked = 46; m_actuals << qVariantFromValue(arg); } + Q_INVOKABLE void myInvokableWithDefaultArgs(int arg1, const QString &arg2 = "") + { m_qtFunctionInvoked = 47; m_actuals << qVariantFromValue(arg1) << qVariantFromValue(arg2); } + Q_INVOKABLE QObject& myInvokableReturningRef() + { m_qtFunctionInvoked = 48; return *this; } + Q_INVOKABLE const QObject& myInvokableReturningConstRef() const + { const_cast(this)->m_qtFunctionInvoked = 49; return *this; } + Q_INVOKABLE void myInvokableWithPointArg(const QPoint &arg) + { const_cast(this)->m_qtFunctionInvoked = 50; m_actuals << qVariantFromValue(arg); } + Q_INVOKABLE void myInvokableWithPointArg(const QPointF &arg) + { const_cast(this)->m_qtFunctionInvoked = 51; m_actuals << qVariantFromValue(arg); } + Q_INVOKABLE void myInvokableWithMyQObjectArg(MyQObject *arg) + { m_qtFunctionInvoked = 52; m_actuals << qVariantFromValue((QObject*)arg); } + Q_INVOKABLE MyQObject* myInvokableReturningMyQObject() + { m_qtFunctionInvoked = 53; return this; } + Q_INVOKABLE void myInvokableWithConstMyQObjectArg(const MyQObject *arg) + { m_qtFunctionInvoked = 54; m_actuals << qVariantFromValue((QObject*)arg); } + Q_INVOKABLE void myInvokableWithQDirArg(const QDir &arg) + { m_qtFunctionInvoked = 55; m_actuals << qVariantFromValue(arg); } + Q_INVOKABLE QScriptValue myInvokableWithScriptValueArg(const QScriptValue &arg) + { m_qtFunctionInvoked = 56; return arg; } + Q_INVOKABLE QObject* myInvokableReturningMyQObjectAsQObject() + { m_qtFunctionInvoked = 57; return this; } + + void emitMySignal() + { emit mySignal(); } + void emitMySignalWithIntArg(int arg) + { emit mySignalWithIntArg(arg); } + void emitMySignal2(bool arg) + { emit mySignal2(arg); } + void emitMySignal2() + { emit mySignal2(); } + void emitMyOverloadedSignal(int arg) + { emit myOverloadedSignal(arg); } + void emitMyOverloadedSignal(const QString &arg) + { emit myOverloadedSignal(arg); } + void emitMyOtherOverloadedSignal(const QString &arg) + { emit myOtherOverloadedSignal(arg); } + void emitMyOtherOverloadedSignal(int arg) + { emit myOtherOverloadedSignal(arg); } + void emitMySignalWithDefaultArgWithArg(int arg) + { emit mySignalWithDefaultArg(arg); } + void emitMySignalWithDefaultArg() + { emit mySignalWithDefaultArg(); } + +public Q_SLOTS: + void mySlot() + { m_qtFunctionInvoked = 20; } + void mySlotWithIntArg(int arg) + { m_qtFunctionInvoked = 21; m_actuals << arg; } + void mySlotWithDoubleArg(double arg) + { m_qtFunctionInvoked = 22; m_actuals << arg; } + void mySlotWithStringArg(const QString &arg) + { m_qtFunctionInvoked = 23; m_actuals << arg; } + + void myOverloadedSlot() + { m_qtFunctionInvoked = 24; } + void myOverloadedSlot(QObject *arg) + { m_qtFunctionInvoked = 41; m_actuals << qVariantFromValue(arg); } + void myOverloadedSlot(bool arg) + { m_qtFunctionInvoked = 25; m_actuals << arg; } + void myOverloadedSlot(const QStringList &arg) + { m_qtFunctionInvoked = 42; m_actuals << arg; } + void myOverloadedSlot(double arg) + { m_qtFunctionInvoked = 26; m_actuals << arg; } + void myOverloadedSlot(float arg) + { m_qtFunctionInvoked = 27; m_actuals << arg; } + void myOverloadedSlot(int arg) + { m_qtFunctionInvoked = 28; m_actuals << arg; } + void myOverloadedSlot(const QString &arg) + { m_qtFunctionInvoked = 29; m_actuals << arg; } + void myOverloadedSlot(const QColor &arg) + { m_qtFunctionInvoked = 30; m_actuals << arg; } + void myOverloadedSlot(const QBrush &arg) + { m_qtFunctionInvoked = 31; m_actuals << arg; } + void myOverloadedSlot(const QDateTime &arg) + { m_qtFunctionInvoked = 32; m_actuals << arg; } + void myOverloadedSlot(const QDate &arg) + { m_qtFunctionInvoked = 33; m_actuals << arg; } + void myOverloadedSlot(const QRegExp &arg) + { m_qtFunctionInvoked = 34; m_actuals << arg; } + void myOverloadedSlot(const QVariant &arg) + { m_qtFunctionInvoked = 35; m_actuals << arg; } + + virtual int myVirtualSlot(int arg) + { m_qtFunctionInvoked = 58; return arg; } + + void qscript_call(int arg) + { m_qtFunctionInvoked = 40; m_actuals << arg; } + +protected Q_SLOTS: + void myProtectedSlot() { m_qtFunctionInvoked = 36; } + +private Q_SLOTS: + void myPrivateSlot() { } + +Q_SIGNALS: + void mySignal(); + void mySignalWithIntArg(int arg); + void mySignalWithDoubleArg(double arg); + void mySignal2(bool arg = false); + void myOverloadedSignal(int arg); + void myOverloadedSignal(const QString &arg); + void myOtherOverloadedSignal(const QString &arg); + void myOtherOverloadedSignal(int arg); + void mySignalWithDefaultArg(int arg = 123); + +protected: + void connectNotify(const char *signal) { + m_connectedSignal = signal; + } + void disconnectNotify(const char *signal) { + m_disconnectedSignal = signal; + } + +protected: + int m_intValue; + QVariant m_variantValue; + QVariantList m_variantListValue; + QString m_stringValue; + QStringList m_stringListValue; + QByteArray m_byteArrayValue; + QBrush m_brushValue; + double m_hiddenValue; + int m_writeOnlyValue; + int m_readOnlyValue; + QKeySequence m_shortcut; + CustomType m_customType; + int m_qtFunctionInvoked; + QVariantList m_actuals; + QByteArray m_connectedSignal; + QByteArray m_disconnectedSignal; +}; + +Q_DECLARE_METATYPE(MyQObject*) + +class MyOtherQObject : public MyQObject +{ + Q_OBJECT +public: + MyOtherQObject(QObject *parent = 0) + : MyQObject(parent) + { } +public Q_SLOTS: + virtual int myVirtualSlot(int arg) + { m_qtFunctionInvoked = 59; return arg; } +}; + +class MyEnumTestQObject : public QObject +{ + Q_OBJECT + Q_PROPERTY(QString p1 READ p1) + Q_PROPERTY(QString p2 READ p2) + Q_PROPERTY(QString p3 READ p3 SCRIPTABLE false) + Q_PROPERTY(QString p4 READ p4) + Q_PROPERTY(QString p5 READ p5 SCRIPTABLE false) + Q_PROPERTY(QString p6 READ p6) +public: + MyEnumTestQObject(QObject *parent = 0) + : QObject(parent) { } + QString p1() const { return QLatin1String("p1"); } + QString p2() const { return QLatin1String("p2"); } + QString p3() const { return QLatin1String("p3"); } + QString p4() const { return QLatin1String("p4"); } + QString p5() const { return QLatin1String("p5"); } + QString p6() const { return QLatin1String("p5"); } +public Q_SLOTS: + void mySlot() { } + void myOtherSlot() { } +Q_SIGNALS: + void mySignal(); +}; + +class tst_QScriptExtQObject : public QObject +{ + Q_OBJECT + +public: + tst_QScriptExtQObject(); + virtual ~tst_QScriptExtQObject(); + +public slots: + void init(); + void cleanup(); + +protected slots: + void onSignalHandlerException(const QScriptValue &exception) + { + m_signalHandlerException = exception; + } + +private slots: + void getSetStaticProperty(); + void getSetDynamicProperty(); + void getSetChildren(); + void callQtInvokable(); + void connectAndDisconnect(); + void cppConnectAndDisconnect(); + void classEnums(); + void classConstructor(); + void overrideInvokable(); + void transferInvokable(); + void findChild(); + void findChildren(); + void overloadedSlots(); + void enumerate_data(); + void enumerate(); + void enumerateSpecial(); + void wrapOptions(); + void prototypes(); + void objectDeleted(); + void connectToDestroyedSignal(); + +private: + QScriptEngine *m_engine; + MyQObject *m_myObject; + QScriptValue m_signalHandlerException; +}; + +tst_QScriptExtQObject::tst_QScriptExtQObject() +{ +} + +tst_QScriptExtQObject::~tst_QScriptExtQObject() +{ +} + +void tst_QScriptExtQObject::init() +{ + m_engine = new QScriptEngine(); + m_myObject = new MyQObject(); + m_engine->globalObject().setProperty("myObject", m_engine->newQObject(m_myObject)); + m_engine->globalObject().setProperty("global", m_engine->globalObject()); +} + +void tst_QScriptExtQObject::cleanup() +{ + delete m_engine; + delete m_myObject; +} + +static QScriptValue getSetProperty(QScriptContext *ctx, QScriptEngine *) +{ + if (ctx->argumentCount() != 0) + ctx->callee().setProperty("value", ctx->argument(0)); + return ctx->callee().property("value"); +} + +void tst_QScriptExtQObject::getSetStaticProperty() +{ + QCOMPARE(m_engine->evaluate("myObject.noSuchProperty").isUndefined(), true); + + // initial value (set in MyQObject constructor) + QCOMPARE(m_engine->evaluate("myObject.intProperty") + .strictlyEquals(QScriptValue(m_engine, 123.0)), true); + QCOMPARE(m_engine->evaluate("myObject.variantProperty") + .toVariant(), QVariant(QLatin1String("foo"))); + QCOMPARE(m_engine->evaluate("myObject.stringProperty") + .strictlyEquals(QScriptValue(m_engine, QLatin1String("bar"))), true); + QCOMPARE(m_engine->evaluate("myObject.variantListProperty").isArray(), true); + QCOMPARE(m_engine->evaluate("myObject.variantListProperty.length") + .strictlyEquals(QScriptValue(m_engine, 2)), true); + QCOMPARE(m_engine->evaluate("myObject.variantListProperty[0]") + .strictlyEquals(QScriptValue(m_engine, 123)), true); + QCOMPARE(m_engine->evaluate("myObject.variantListProperty[1]") + .strictlyEquals(QScriptValue(m_engine, QLatin1String("foo"))), true); + QCOMPARE(m_engine->evaluate("myObject.stringListProperty").isArray(), true); + QCOMPARE(m_engine->evaluate("myObject.stringListProperty.length") + .strictlyEquals(QScriptValue(m_engine, 2)), true); + QCOMPARE(m_engine->evaluate("myObject.stringListProperty[0]").isString(), true); + QCOMPARE(m_engine->evaluate("myObject.stringListProperty[0]").toString(), + QLatin1String("zig")); + QCOMPARE(m_engine->evaluate("myObject.stringListProperty[1]").isString(), true); + QCOMPARE(m_engine->evaluate("myObject.stringListProperty[1]").toString(), + QLatin1String("zag")); + + // default flags for "normal" properties + { + QScriptValue mobj = m_engine->globalObject().property("myObject"); + QVERIFY(!(mobj.propertyFlags("intProperty") & QScriptValue::ReadOnly)); + QVERIFY(mobj.propertyFlags("intProperty") & QScriptValue::Undeletable); + QVERIFY(mobj.propertyFlags("intProperty") & QScriptValue::PropertyGetter); + QVERIFY(mobj.propertyFlags("intProperty") & QScriptValue::PropertySetter); + QVERIFY(!(mobj.propertyFlags("intProperty") & QScriptValue::SkipInEnumeration)); + QVERIFY(mobj.propertyFlags("intProperty") & QScriptValue::QObjectMember); + + QVERIFY(!(mobj.propertyFlags("mySlot") & QScriptValue::ReadOnly)); + QVERIFY(!(mobj.propertyFlags("mySlot") & QScriptValue::Undeletable)); + QVERIFY(!(mobj.propertyFlags("mySlot") & QScriptValue::SkipInEnumeration)); + QVERIFY(mobj.propertyFlags("mySlot") & QScriptValue::QObjectMember); + } + + // property change in C++ should be reflected in script + m_myObject->setIntProperty(456); + QCOMPARE(m_engine->evaluate("myObject.intProperty") + .strictlyEquals(QScriptValue(m_engine, 456)), true); + m_myObject->setIntProperty(789); + QCOMPARE(m_engine->evaluate("myObject.intProperty") + .strictlyEquals(QScriptValue(m_engine, 789)), true); + + m_myObject->setVariantProperty(QLatin1String("bar")); + QVERIFY(m_engine->evaluate("myObject.variantProperty") + .strictlyEquals(QScriptValue(m_engine, QLatin1String("bar")))); + m_myObject->setVariantProperty(42); + QCOMPARE(m_engine->evaluate("myObject.variantProperty") + .toVariant(), QVariant(42)); + m_myObject->setVariantProperty(qVariantFromValue(QBrush())); + QVERIFY(m_engine->evaluate("myObject.variantProperty").isVariant()); + + m_myObject->setStringProperty(QLatin1String("baz")); + QCOMPARE(m_engine->evaluate("myObject.stringProperty") + .equals(QScriptValue(m_engine, QLatin1String("baz"))), true); + m_myObject->setStringProperty(QLatin1String("zab")); + QCOMPARE(m_engine->evaluate("myObject.stringProperty") + .equals(QScriptValue(m_engine, QLatin1String("zab"))), true); + + // property change in script should be reflected in C++ + QCOMPARE(m_engine->evaluate("myObject.intProperty = 123") + .strictlyEquals(QScriptValue(m_engine, 123)), true); + QCOMPARE(m_engine->evaluate("myObject.intProperty") + .strictlyEquals(QScriptValue(m_engine, 123)), true); + QCOMPARE(m_myObject->intProperty(), 123); + QCOMPARE(m_engine->evaluate("myObject.intProperty = 'ciao!';" + "myObject.intProperty") + .strictlyEquals(QScriptValue(m_engine, 0)), true); + QCOMPARE(m_myObject->intProperty(), 0); + QCOMPARE(m_engine->evaluate("myObject.intProperty = '123';" + "myObject.intProperty") + .strictlyEquals(QScriptValue(m_engine, 123)), true); + QCOMPARE(m_myObject->intProperty(), 123); + + QCOMPARE(m_engine->evaluate("myObject.stringProperty = 'ciao'") + .strictlyEquals(QScriptValue(m_engine, QLatin1String("ciao"))), true); + QCOMPARE(m_engine->evaluate("myObject.stringProperty") + .strictlyEquals(QScriptValue(m_engine, QLatin1String("ciao"))), true); + QCOMPARE(m_myObject->stringProperty(), QLatin1String("ciao")); + QCOMPARE(m_engine->evaluate("myObject.stringProperty = 123;" + "myObject.stringProperty") + .strictlyEquals(QScriptValue(m_engine, QLatin1String("123"))), true); + QCOMPARE(m_myObject->stringProperty(), QLatin1String("123")); + QVERIFY(m_engine->evaluate("myObject.stringProperty = null;" + "myObject.stringProperty") + .strictlyEquals(QScriptValue(m_engine, QString()))); + QCOMPARE(m_myObject->stringProperty(), QString()); + QVERIFY(m_engine->evaluate("myObject.stringProperty = undefined;" + "myObject.stringProperty") + .strictlyEquals(QScriptValue(m_engine, QString()))); + QCOMPARE(m_myObject->stringProperty(), QString()); + + QCOMPARE(m_engine->evaluate("myObject.variantProperty = 'foo';" + "myObject.variantProperty.valueOf()").toString(), QLatin1String("foo")); + QCOMPARE(m_myObject->variantProperty(), QVariant(QLatin1String("foo"))); + QVERIFY(m_engine->evaluate("myObject.variantProperty = undefined;" + "myObject.variantProperty").isUndefined()); + QVERIFY(!m_myObject->variantProperty().isValid()); + QVERIFY(m_engine->evaluate("myObject.variantProperty = null;" + "myObject.variantProperty").isUndefined()); + QVERIFY(!m_myObject->variantProperty().isValid()); + QCOMPARE(m_engine->evaluate("myObject.variantProperty = 42;" + "myObject.variantProperty").toNumber(), 42.0); + QCOMPARE(m_myObject->variantProperty().toDouble(), 42.0); + + QCOMPARE(m_engine->evaluate("myObject.variantListProperty = [1, 'two', true];" + "myObject.variantListProperty.length") + .strictlyEquals(QScriptValue(m_engine, 3)), true); + QCOMPARE(m_engine->evaluate("myObject.variantListProperty[0]") + .strictlyEquals(QScriptValue(m_engine, 1)), true); + QCOMPARE(m_engine->evaluate("myObject.variantListProperty[1]") + .strictlyEquals(QScriptValue(m_engine, QLatin1String("two"))), true); + QCOMPARE(m_engine->evaluate("myObject.variantListProperty[2]") + .strictlyEquals(QScriptValue(m_engine, true)), true); + { + QVariantList vl = qscriptvalue_cast(m_engine->evaluate("myObject.variantListProperty")); + QCOMPARE(vl, QVariantList() + << QVariant(1) + << QVariant(QLatin1String("two")) + << QVariant(true)); + } + + QCOMPARE(m_engine->evaluate("myObject.stringListProperty = [1, 'two', true];" + "myObject.stringListProperty.length") + .strictlyEquals(QScriptValue(m_engine, 3)), true); + QCOMPARE(m_engine->evaluate("myObject.stringListProperty[0]").isString(), true); + QCOMPARE(m_engine->evaluate("myObject.stringListProperty[0]").toString(), + QLatin1String("1")); + QCOMPARE(m_engine->evaluate("myObject.stringListProperty[1]").isString(), true); + QCOMPARE(m_engine->evaluate("myObject.stringListProperty[1]").toString(), + QLatin1String("two")); + QCOMPARE(m_engine->evaluate("myObject.stringListProperty[2]").isString(), true); + QCOMPARE(m_engine->evaluate("myObject.stringListProperty[2]").toString(), + QLatin1String("true")); + { + QStringList sl = qscriptvalue_cast(m_engine->evaluate("myObject.stringListProperty")); + QCOMPARE(sl, QStringList() + << QLatin1String("1") + << QLatin1String("two") + << QLatin1String("true")); + } + + // test setting properties where we can't convert the type natively but where the + // types happen to be compatible variant types already + { + QKeySequence sequence(Qt::ControlModifier + Qt::AltModifier + Qt::Key_Delete); + QScriptValue mobj = m_engine->globalObject().property("myObject"); + + QVERIFY(m_myObject->shortcut().isEmpty()); + mobj.setProperty("shortcut", m_engine->newVariant(sequence)); + QVERIFY(m_myObject->shortcut() == sequence); + } + { + CustomType t; t.string = "hello"; + QScriptValue mobj = m_engine->globalObject().property("myObject"); + + QVERIFY(m_myObject->propWithCustomType().string.isEmpty()); + mobj.setProperty("propWithCustomType", m_engine->newVariant(qVariantFromValue(t))); + QVERIFY(m_myObject->propWithCustomType().string == t.string); + } + + // test that we do value conversion if necessary when setting properties + { + QScriptValue br = m_engine->evaluate("myObject.brushProperty"); + QCOMPARE(qscriptvalue_cast(br), m_myObject->brushProperty()); + QCOMPARE(qscriptvalue_cast(br), m_myObject->brushProperty().color()); + + QColor newColor(40, 30, 20, 10); + QScriptValue val = qScriptValueFromValue(m_engine, newColor); + m_engine->globalObject().setProperty("myColor", val); + QScriptValue ret = m_engine->evaluate("myObject.brushProperty = myColor"); + QCOMPARE(ret.strictlyEquals(val), true); + br = m_engine->evaluate("myObject.brushProperty"); + QCOMPARE(qscriptvalue_cast(br), QBrush(newColor)); + QCOMPARE(qscriptvalue_cast(br), newColor); + + m_engine->globalObject().setProperty("myColor", QScriptValue()); + } + + // try to delete + QCOMPARE(m_engine->evaluate("delete myObject.intProperty").toBoolean(), false); + QCOMPARE(m_engine->evaluate("myObject.intProperty").toNumber(), 123.0); + + QCOMPARE(m_engine->evaluate("delete myObject.variantProperty").toBoolean(), false); + QCOMPARE(m_engine->evaluate("myObject.variantProperty").toNumber(), 42.0); + + // non-scriptable property + QCOMPARE(m_myObject->hiddenProperty(), 456.0); + QCOMPARE(m_engine->evaluate("myObject.hiddenProperty").isUndefined(), true); + QCOMPARE(m_engine->evaluate("myObject.hiddenProperty = 123;" + "myObject.hiddenProperty").toInt32(), 123); + QCOMPARE(m_myObject->hiddenProperty(), 456.0); + + // write-only property + QCOMPARE(m_myObject->writeOnlyProperty(), 789); + QCOMPARE(m_engine->evaluate("myObject.writeOnlyProperty").isUndefined(), true); + QCOMPARE(m_engine->evaluate("myObject.writeOnlyProperty = 123;" + "myObject.writeOnlyProperty").isUndefined(), true); + QCOMPARE(m_myObject->writeOnlyProperty(), 123); + + // read-only property + QCOMPARE(m_myObject->readOnlyProperty(), 987); + QCOMPARE(m_engine->evaluate("myObject.readOnlyProperty").toInt32(), 987); + QCOMPARE(m_engine->evaluate("myObject.readOnlyProperty = 654;" + "myObject.readOnlyProperty").toInt32(), 987); + QCOMPARE(m_myObject->readOnlyProperty(), 987); + { + QScriptValue mobj = m_engine->globalObject().property("myObject"); + QCOMPARE(mobj.propertyFlags("readOnlyProperty") & QScriptValue::ReadOnly, + QScriptValue::ReadOnly); + } + + // auto-dereferencing of pointers + { + QBrush b = QColor(0xCA, 0xFE, 0xBA, 0xBE); + QBrush *bp = &b; + QScriptValue bpValue = m_engine->newVariant(qVariantFromValue(bp)); + m_engine->globalObject().setProperty("brushPointer", bpValue); + { + QScriptValue ret = m_engine->evaluate("myObject.setBrushProperty(brushPointer)"); + QCOMPARE(ret.isUndefined(), true); + QCOMPARE(qscriptvalue_cast(m_engine->evaluate("myObject.brushProperty")), b); + } + { + b = QColor(0xDE, 0xAD, 0xBE, 0xEF); + QScriptValue ret = m_engine->evaluate("myObject.brushProperty = brushPointer"); + QCOMPARE(ret.strictlyEquals(bpValue), true); + QCOMPARE(qscriptvalue_cast(m_engine->evaluate("myObject.brushProperty")), b); + } + m_engine->globalObject().setProperty("brushPointer", QScriptValue()); + } + + // try to install custom property getter+setter + { + QScriptValue mobj = m_engine->globalObject().property("myObject"); + QTest::ignoreMessage(QtWarningMsg, "QScriptValue::setProperty() failed: " + "cannot set getter or setter of native property " + "`intProperty'"); + mobj.setProperty("intProperty", m_engine->newFunction(getSetProperty), + QScriptValue::PropertyGetter | QScriptValue::PropertySetter); + } +} + +void tst_QScriptExtQObject::getSetDynamicProperty() +{ + // initially the object does not have the property + QCOMPARE(m_engine->evaluate("myObject.hasOwnProperty('dynamicProperty')") + .strictlyEquals(QScriptValue(m_engine, false)), true); + + // add a dynamic property in C++ + QCOMPARE(m_myObject->setProperty("dynamicProperty", 123), false); + QCOMPARE(m_engine->evaluate("myObject.hasOwnProperty('dynamicProperty')") + .strictlyEquals(QScriptValue(m_engine, true)), true); + QCOMPARE(m_engine->evaluate("myObject.dynamicProperty") + .strictlyEquals(QScriptValue(m_engine, 123)), true); + + // check the flags + { + QScriptValue mobj = m_engine->globalObject().property("myObject"); + QVERIFY(!(mobj.propertyFlags("dynamicProperty") & QScriptValue::ReadOnly)); + QVERIFY(!(mobj.propertyFlags("dynamicProperty") & QScriptValue::Undeletable)); + QVERIFY(!(mobj.propertyFlags("dynamicProperty") & QScriptValue::SkipInEnumeration)); + QVERIFY(mobj.propertyFlags("dynamicProperty") & QScriptValue::QObjectMember); + } + + // property change in script should be reflected in C++ + QCOMPARE(m_engine->evaluate("myObject.dynamicProperty = 'foo';" + "myObject.dynamicProperty") + .strictlyEquals(QScriptValue(m_engine, QLatin1String("foo"))), true); + QCOMPARE(m_myObject->property("dynamicProperty").toString(), QLatin1String("foo")); + + // delete the property + QCOMPARE(m_engine->evaluate("delete myObject.dynamicProperty").toBoolean(), true); + QCOMPARE(m_myObject->property("dynamicProperty").isValid(), false); + QCOMPARE(m_engine->evaluate("myObject.dynamicProperty").isUndefined(), true); + QCOMPARE(m_engine->evaluate("myObject.hasOwnProperty('dynamicProperty')").toBoolean(), false); +} + +void tst_QScriptExtQObject::getSetChildren() +{ + // initially the object does not have the child + QCOMPARE(m_engine->evaluate("myObject.hasOwnProperty('child')") + .strictlyEquals(QScriptValue(m_engine, false)), true); + + // add a child + MyQObject *child = new MyQObject(m_myObject); + child->setObjectName("child"); + QCOMPARE(m_engine->evaluate("myObject.hasOwnProperty('child')") + .strictlyEquals(QScriptValue(m_engine, true)), true); + + // add a grandchild + MyQObject *grandChild = new MyQObject(child); + grandChild->setObjectName("grandChild"); + QCOMPARE(m_engine->evaluate("myObject.child.hasOwnProperty('grandChild')") + .strictlyEquals(QScriptValue(m_engine, true)), true); + + // delete grandchild + delete grandChild; + QCOMPARE(m_engine->evaluate("myObject.child.hasOwnProperty('grandChild')") + .strictlyEquals(QScriptValue(m_engine, false)), true); + + // delete child + delete child; + QCOMPARE(m_engine->evaluate("myObject.hasOwnProperty('child')") + .strictlyEquals(QScriptValue(m_engine, false)), true); + +} + +Q_DECLARE_METATYPE(QVector) +Q_DECLARE_METATYPE(QVector) +Q_DECLARE_METATYPE(QVector) + +template +static QScriptValue qobjectToScriptValue(QScriptEngine *engine, T* const &in) +{ return engine->newQObject(in); } + +template +static void qobjectFromScriptValue(const QScriptValue &object, T* &out) +{ out = qobject_cast(object.toQObject()); } + +void tst_QScriptExtQObject::callQtInvokable() +{ + m_myObject->resetQtFunctionInvoked(); + QCOMPARE(m_engine->evaluate("myObject.myInvokable()").isUndefined(), true); + QCOMPARE(m_myObject->qtFunctionInvoked(), 0); + QCOMPARE(m_myObject->qtFunctionActuals(), QVariantList()); + + // extra arguments should silently be ignored + m_myObject->resetQtFunctionInvoked(); + QCOMPARE(m_engine->evaluate("myObject.myInvokable(10, 20, 30)").isUndefined(), true); + QCOMPARE(m_myObject->qtFunctionInvoked(), 0); + QCOMPARE(m_myObject->qtFunctionActuals(), QVariantList()); + + m_myObject->resetQtFunctionInvoked(); + QCOMPARE(m_engine->evaluate("myObject.myInvokableWithIntArg(123)").isUndefined(), true); + QCOMPARE(m_myObject->qtFunctionInvoked(), 1); + QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); + QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 123); + + m_myObject->resetQtFunctionInvoked(); + QCOMPARE(m_engine->evaluate("myObject.myInvokableWithIntArg('123')").isUndefined(), true); + QCOMPARE(m_myObject->qtFunctionInvoked(), 1); + QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); + QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 123); + + m_myObject->resetQtFunctionInvoked(); + QCOMPARE(m_engine->evaluate("myObject.myInvokableWithLonglongArg(123)").isUndefined(), true); + QCOMPARE(m_myObject->qtFunctionInvoked(), 2); + QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); + QCOMPARE(m_myObject->qtFunctionActuals().at(0).toLongLong(), qlonglong(123)); + + m_myObject->resetQtFunctionInvoked(); + QCOMPARE(m_engine->evaluate("myObject.myInvokableWithFloatArg(123.5)").isUndefined(), true); + QCOMPARE(m_myObject->qtFunctionInvoked(), 3); + QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); + QCOMPARE(m_myObject->qtFunctionActuals().at(0).toDouble(), 123.5); + + m_myObject->resetQtFunctionInvoked(); + QCOMPARE(m_engine->evaluate("myObject.myInvokableWithDoubleArg(123.5)").isUndefined(), true); + QCOMPARE(m_myObject->qtFunctionInvoked(), 4); + QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); + QCOMPARE(m_myObject->qtFunctionActuals().at(0).toDouble(), 123.5); + + m_myObject->resetQtFunctionInvoked(); + QCOMPARE(m_engine->evaluate("myObject.myInvokableWithStringArg('ciao')").isUndefined(), true); + QCOMPARE(m_myObject->qtFunctionInvoked(), 5); + QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); + QCOMPARE(m_myObject->qtFunctionActuals().at(0).toString(), QLatin1String("ciao")); + + m_myObject->resetQtFunctionInvoked(); + QCOMPARE(m_engine->evaluate("myObject.myInvokableWithStringArg(123)").isUndefined(), true); + QCOMPARE(m_myObject->qtFunctionInvoked(), 5); + QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); + QCOMPARE(m_myObject->qtFunctionActuals().at(0).toString(), QLatin1String("123")); + + m_myObject->resetQtFunctionInvoked(); + QVERIFY(m_engine->evaluate("myObject.myInvokableWithStringArg(null)").isUndefined()); + QCOMPARE(m_myObject->qtFunctionInvoked(), 5); + QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); + QCOMPARE(m_myObject->qtFunctionActuals().at(0).type(), QVariant::String); + QCOMPARE(m_myObject->qtFunctionActuals().at(0).toString(), QString()); + + m_myObject->resetQtFunctionInvoked(); + QVERIFY(m_engine->evaluate("myObject.myInvokableWithStringArg(undefined)").isUndefined()); + QCOMPARE(m_myObject->qtFunctionInvoked(), 5); + QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); + QCOMPARE(m_myObject->qtFunctionActuals().at(0).type(), QVariant::String); + QCOMPARE(m_myObject->qtFunctionActuals().at(0).toString(), QString()); + + m_myObject->resetQtFunctionInvoked(); + QCOMPARE(m_engine->evaluate("myObject.myInvokableWithIntArgs(123, 456)").isUndefined(), true); + QCOMPARE(m_myObject->qtFunctionInvoked(), 6); + QCOMPARE(m_myObject->qtFunctionActuals().size(), 2); + QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 123); + QCOMPARE(m_myObject->qtFunctionActuals().at(1).toInt(), 456); + + m_myObject->resetQtFunctionInvoked(); + QCOMPARE(m_engine->evaluate("myObject.myInvokableReturningInt()") + .strictlyEquals(QScriptValue(m_engine, 123)), true); + QCOMPARE(m_myObject->qtFunctionInvoked(), 7); + QCOMPARE(m_myObject->qtFunctionActuals(), QVariantList()); + + m_myObject->resetQtFunctionInvoked(); + QCOMPARE(m_engine->evaluate("myObject.myInvokableReturningLongLong()") + .strictlyEquals(QScriptValue(m_engine, 456)), true); + QCOMPARE(m_myObject->qtFunctionInvoked(), 39); + QCOMPARE(m_myObject->qtFunctionActuals(), QVariantList()); + + m_myObject->resetQtFunctionInvoked(); + QCOMPARE(m_engine->evaluate("myObject.myInvokableReturningString()") + .strictlyEquals(QScriptValue(m_engine, QLatin1String("ciao"))), true); + QCOMPARE(m_myObject->qtFunctionInvoked(), 8); + QCOMPARE(m_myObject->qtFunctionActuals(), QVariantList()); + + m_myObject->resetQtFunctionInvoked(); + QVERIFY(m_engine->evaluate("myObject.myInvokableReturningVariant()") + .strictlyEquals(QScriptValue(m_engine, 123))); + QCOMPARE(m_myObject->qtFunctionInvoked(), 60); + + m_myObject->resetQtFunctionInvoked(); + QVERIFY(m_engine->evaluate("myObject.myInvokableReturningScriptValue()") + .strictlyEquals(QScriptValue(m_engine, 456))); + QCOMPARE(m_myObject->qtFunctionInvoked(), 61); + + m_myObject->resetQtFunctionInvoked(); + QCOMPARE(m_engine->evaluate("myObject.myInvokableWithIntArg(123, 456)").isUndefined(), true); + QCOMPARE(m_myObject->qtFunctionInvoked(), 9); + QCOMPARE(m_myObject->qtFunctionActuals().size(), 2); + QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 123); + QCOMPARE(m_myObject->qtFunctionActuals().at(1).toInt(), 456); + + m_myObject->resetQtFunctionInvoked(); + QVERIFY(m_engine->evaluate("myObject.myInvokableWithVoidStarArg(null)").isUndefined()); + QCOMPARE(m_myObject->qtFunctionInvoked(), 44); + m_myObject->resetQtFunctionInvoked(); + QVERIFY(m_engine->evaluate("myObject.myInvokableWithVoidStarArg(123)").isError()); + QCOMPARE(m_myObject->qtFunctionInvoked(), -1); + + m_myObject->resetQtFunctionInvoked(); + { + QScriptValue ret = m_engine->evaluate("myObject.myInvokableWithAmbiguousArg(123)"); + QVERIFY(ret.isError()); + QCOMPARE(ret.toString(), QLatin1String("TypeError: ambiguous call of overloaded function myInvokableWithAmbiguousArg(); candidates were\n myInvokableWithAmbiguousArg(int)\n myInvokableWithAmbiguousArg(uint)")); + } + + m_myObject->resetQtFunctionInvoked(); + { + QScriptValue ret = m_engine->evaluate("myObject.myInvokableWithDefaultArgs(123, 'hello')"); + QVERIFY(ret.isUndefined()); + QCOMPARE(m_myObject->qtFunctionInvoked(), 47); + QCOMPARE(m_myObject->qtFunctionActuals().size(), 2); + QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 123); + QCOMPARE(m_myObject->qtFunctionActuals().at(1).toString(), QLatin1String("hello")); + } + + m_myObject->resetQtFunctionInvoked(); + { + QScriptValue ret = m_engine->evaluate("myObject.myInvokableWithDefaultArgs(456)"); + QVERIFY(ret.isUndefined()); + QCOMPARE(m_myObject->qtFunctionInvoked(), 47); + QCOMPARE(m_myObject->qtFunctionActuals().size(), 2); + QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 456); + QCOMPARE(m_myObject->qtFunctionActuals().at(1).toString(), QString()); + } + + { + QScriptValue fun = m_engine->evaluate("myObject.myInvokableWithPointArg"); + QVERIFY(fun.isFunction()); + m_myObject->resetQtFunctionInvoked(); + { + QScriptValue ret = fun.call(m_engine->evaluate("myObject"), + QScriptValueList() << qScriptValueFromValue(m_engine, QPoint(10, 20))); + QVERIFY(ret.isUndefined()); + QCOMPARE(m_myObject->qtFunctionInvoked(), 50); + QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); + QCOMPARE(m_myObject->qtFunctionActuals().at(0).toPoint(), QPoint(10, 20)); + } + m_myObject->resetQtFunctionInvoked(); + { + QScriptValue ret = fun.call(m_engine->evaluate("myObject"), + QScriptValueList() << qScriptValueFromValue(m_engine, QPointF(30, 40))); + QVERIFY(ret.isUndefined()); + QCOMPARE(m_myObject->qtFunctionInvoked(), 51); + QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); + QCOMPARE(m_myObject->qtFunctionActuals().at(0).toPointF(), QPointF(30, 40)); + } + } + + // calling function that returns (const)ref + m_myObject->resetQtFunctionInvoked(); + { + QScriptValue ret = m_engine->evaluate("myObject.myInvokableReturningRef()"); + QVERIFY(ret.isUndefined()); + QVERIFY(!m_engine->hasUncaughtException()); + QCOMPARE(m_myObject->qtFunctionInvoked(), 48); + } + m_myObject->resetQtFunctionInvoked(); + { + QScriptValue ret = m_engine->evaluate("myObject.myInvokableReturningConstRef()"); + QVERIFY(ret.isUndefined()); + QVERIFY(!m_engine->hasUncaughtException()); + QCOMPARE(m_myObject->qtFunctionInvoked(), 49); + } + + // first time we expect failure because the metatype is not registered + m_myObject->resetQtFunctionInvoked(); + QCOMPARE(m_engine->evaluate("myObject.myInvokableReturningVectorOfInt()").isError(), true); + QCOMPARE(m_myObject->qtFunctionInvoked(), -1); + + QCOMPARE(m_engine->evaluate("myObject.myInvokableWithVectorOfIntArg(0)").isError(), true); + QCOMPARE(m_myObject->qtFunctionInvoked(), -1); + + // now we register it, and it should work + qScriptRegisterSequenceMetaType >(m_engine); + { + QScriptValue ret = m_engine->evaluate("myObject.myInvokableReturningVectorOfInt()"); + QCOMPARE(ret.isArray(), true); + QCOMPARE(m_myObject->qtFunctionInvoked(), 11); + } + + { + QScriptValue ret = m_engine->evaluate("myObject.myInvokableWithVectorOfIntArg(myObject.myInvokableReturningVectorOfInt())"); + QCOMPARE(ret.isUndefined(), true); + QCOMPARE(m_myObject->qtFunctionInvoked(), 12); + } + + m_myObject->resetQtFunctionInvoked(); + { + QScriptValue ret = m_engine->evaluate("myObject.myInvokableReturningQObjectStar()"); + QCOMPARE(m_myObject->qtFunctionInvoked(), 13); + QCOMPARE(m_myObject->qtFunctionActuals().size(), 0); + QCOMPARE(ret.isQObject(), true); + QCOMPARE(ret.toQObject(), (QObject *)m_myObject); + } + + m_myObject->resetQtFunctionInvoked(); + { + QScriptValue ret = m_engine->evaluate("myObject.myInvokableWithQObjectListArg([myObject])"); + QCOMPARE(m_myObject->qtFunctionInvoked(), 14); + QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); + QCOMPARE(ret.isArray(), true); + QCOMPARE(ret.property(QLatin1String("length")) + .strictlyEquals(QScriptValue(m_engine, 1)), true); + QCOMPARE(ret.property(QLatin1String("0")).isQObject(), true); + QCOMPARE(ret.property(QLatin1String("0")).toQObject(), (QObject *)m_myObject); + } + + m_myObject->resetQtFunctionInvoked(); + { + m_myObject->setVariantProperty(QVariant(123)); + QScriptValue ret = m_engine->evaluate("myObject.myInvokableWithVariantArg(myObject.variantProperty)"); + QVERIFY(ret.isNumber()); + QCOMPARE(m_myObject->qtFunctionInvoked(), 15); + QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); + QCOMPARE(m_myObject->qtFunctionActuals().at(0), m_myObject->variantProperty()); + QVERIFY(ret.strictlyEquals(QScriptValue(m_engine, 123))); + } + + m_myObject->resetQtFunctionInvoked(); + { + m_myObject->setVariantProperty(qVariantFromValue(QBrush())); + QScriptValue ret = m_engine->evaluate("myObject.myInvokableWithVariantArg(myObject.variantProperty)"); + QVERIFY(ret.isVariant()); + QCOMPARE(m_myObject->qtFunctionInvoked(), 15); + QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); + QCOMPARE(ret.toVariant(), m_myObject->qtFunctionActuals().at(0)); + QCOMPARE(ret.toVariant(), m_myObject->variantProperty()); + } + + m_myObject->resetQtFunctionInvoked(); + { + QScriptValue ret = m_engine->evaluate("myObject.myInvokableWithVariantArg(123)"); + QVERIFY(ret.isNumber()); + QCOMPARE(m_myObject->qtFunctionInvoked(), 15); + QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); + QCOMPARE(m_myObject->qtFunctionActuals().at(0), QVariant(123)); + QVERIFY(ret.strictlyEquals(QScriptValue(m_engine, 123))); + } + + m_myObject->resetQtFunctionInvoked(); + { + QScriptValue ret = m_engine->evaluate("myObject.myInvokableWithVariantArg('ciao')"); + QVERIFY(ret.isString()); + QCOMPARE(m_myObject->qtFunctionInvoked(), 15); + QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); + QCOMPARE(m_myObject->qtFunctionActuals().at(0), QVariant(QString::fromLatin1("ciao"))); + QVERIFY(ret.strictlyEquals(QScriptValue(m_engine, QString::fromLatin1("ciao")))); + } + + m_myObject->resetQtFunctionInvoked(); + { + QScriptValue ret = m_engine->evaluate("myObject.myInvokableWithVariantArg(null)"); + QVERIFY(ret.isUndefined()); // invalid QVariant is converted to Undefined + QCOMPARE(m_myObject->qtFunctionInvoked(), 15); + QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); + QCOMPARE(m_myObject->qtFunctionActuals().at(0), QVariant()); + } + + m_myObject->resetQtFunctionInvoked(); + { + QScriptValue ret = m_engine->evaluate("myObject.myInvokableWithVariantArg(undefined)"); + QVERIFY(ret.isUndefined()); + QCOMPARE(m_myObject->qtFunctionInvoked(), 15); + QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); + QCOMPARE(m_myObject->qtFunctionActuals().at(0), QVariant()); + } + + m_engine->globalObject().setProperty("fishy", m_engine->newVariant(123)); + m_engine->evaluate("myObject.myInvokableWithStringArg(fishy)"); + + m_myObject->resetQtFunctionInvoked(); + { + QScriptValue ret = m_engine->evaluate("myObject.myInvokableWithVariantMapArg({ a:123, b:'ciao' })"); + QCOMPARE(m_myObject->qtFunctionInvoked(), 16); + QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); + QVariant v = m_myObject->qtFunctionActuals().at(0); + QCOMPARE(v.userType(), int(QMetaType::QVariantMap)); + QVariantMap vmap = qvariant_cast(v); + QCOMPARE(vmap.keys().size(), 2); + QCOMPARE(vmap.keys().at(0), QLatin1String("a")); + QCOMPARE(vmap.value("a"), QVariant(123)); + QCOMPARE(vmap.keys().at(1), QLatin1String("b")); + QCOMPARE(vmap.value("b"), QVariant("ciao")); + + QCOMPARE(ret.isObject(), true); + QCOMPARE(ret.property("a").strictlyEquals(QScriptValue(m_engine, 123)), true); + QCOMPARE(ret.property("b").strictlyEquals(QScriptValue(m_engine, "ciao")), true); + } + + m_myObject->resetQtFunctionInvoked(); + { + QScriptValue ret = m_engine->evaluate("myObject.myInvokableWithListOfIntArg([1, 5])"); + QCOMPARE(m_myObject->qtFunctionInvoked(), 17); + QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); + QVariant v = m_myObject->qtFunctionActuals().at(0); + QCOMPARE(v.userType(), qMetaTypeId >()); + QList ilst = qvariant_cast >(v); + QCOMPARE(ilst.size(), 2); + QCOMPARE(ilst.at(0), 1); + QCOMPARE(ilst.at(1), 5); + + QCOMPARE(ret.isArray(), true); + QCOMPARE(ret.property("0").strictlyEquals(QScriptValue(m_engine, 1)), true); + QCOMPARE(ret.property("1").strictlyEquals(QScriptValue(m_engine, 5)), true); + } + + m_myObject->resetQtFunctionInvoked(); + { + QScriptValue ret = m_engine->evaluate("myObject.myInvokableWithQObjectStarArg(myObject)"); + QCOMPARE(m_myObject->qtFunctionInvoked(), 18); + QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); + QVariant v = m_myObject->qtFunctionActuals().at(0); + QCOMPARE(v.userType(), int(QMetaType::QObjectStar)); + QCOMPARE(qvariant_cast(v), (QObject *)m_myObject); + + QCOMPARE(ret.isQObject(), true); + QCOMPARE(qscriptvalue_cast(ret), (QObject *)m_myObject); + } + + m_myObject->resetQtFunctionInvoked(); + { + // no implicit conversion from integer to QObject* + QScriptValue ret = m_engine->evaluate("myObject.myInvokableWithQObjectStarArg(123)"); + QCOMPARE(ret.isError(), true); + } + + m_myObject->resetQtFunctionInvoked(); + { + QScriptValue fun = m_engine->evaluate("myObject.myInvokableWithQBrushArg"); + QVERIFY(fun.isFunction()); + QColor color(10, 20, 30, 40); + // QColor should be converted to a QBrush + QScriptValue ret = fun.call(QScriptValue(), QScriptValueList() + << qScriptValueFromValue(m_engine, color)); + QCOMPARE(m_myObject->qtFunctionInvoked(), 19); + QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); + QVariant v = m_myObject->qtFunctionActuals().at(0); + QCOMPARE(v.userType(), int(QMetaType::QBrush)); + QCOMPARE(qvariant_cast(v), color); + + QCOMPARE(qscriptvalue_cast(ret), color); + } + + // private slots should not be part of the QObject binding + QCOMPARE(m_engine->evaluate("myObject.myPrivateSlot").isUndefined(), true); + + // protected slots should be fine + m_myObject->resetQtFunctionInvoked(); + m_engine->evaluate("myObject.myProtectedSlot()"); + QCOMPARE(m_myObject->qtFunctionInvoked(), 36); + + // call with too few arguments + { + QScriptValue ret = m_engine->evaluate("myObject.myInvokableWithIntArg()"); + QVERIFY(ret.isError()); + QCOMPARE(ret.toString(), QLatin1String("SyntaxError: too few arguments in call to myInvokableWithIntArg(); candidates are\n myInvokableWithIntArg(int,int)\n myInvokableWithIntArg(int)")); + } + + // call function where not all types have been registered + m_myObject->resetQtFunctionInvoked(); + { + QScriptValue ret = m_engine->evaluate("myObject.myInvokableWithBrushStyleArg(0)"); + QVERIFY(ret.isError()); + QCOMPARE(ret.toString(), QLatin1String("TypeError: cannot call myInvokableWithBrushStyleArg(): argument 1 has unknown type `Qt::BrushStyle' (register the type with qScriptRegisterMetaType())")); + QCOMPARE(m_myObject->qtFunctionInvoked(), -1); + } + + // call function with incompatible argument type + m_myObject->resetQtFunctionInvoked(); + { + QScriptValue ret = m_engine->evaluate("myObject.myInvokableWithQBrushArg(null)"); + QVERIFY(ret.isError()); + QCOMPARE(ret.toString(), QLatin1String("TypeError: incompatible type of argument(s) in call to myInvokableWithQBrushArg(); candidates were\n myInvokableWithQBrushArg(QBrush)")); + QCOMPARE(m_myObject->qtFunctionInvoked(), -1); + } + + // ability to call a slot with QObject-based arguments, even if those types haven't been registered + m_myObject->resetQtFunctionInvoked(); + { + QScriptValue ret = m_engine->evaluate("myObject.myInvokableWithMyQObjectArg(myObject)"); + QCOMPARE(m_myObject->qtFunctionInvoked(), 52); + QVERIFY(ret.isUndefined()); + QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); + QCOMPARE(qvariant_cast(m_myObject->qtFunctionActuals().at(0)), (QObject*)m_myObject); + } + + // inability to call a slot returning QObject-based type, when that type hasn't been registered + m_myObject->resetQtFunctionInvoked(); + { + QScriptValue ret = m_engine->evaluate("myObject.myInvokableReturningMyQObject()"); + QVERIFY(ret.isError()); + QCOMPARE(ret.toString(), QString::fromLatin1("TypeError: cannot call myInvokableReturningMyQObject(): unknown return type `MyQObject*' (register the type with qScriptRegisterMetaType())")); + } + + // ability to call a slot returning QObject-based type when that type has been registered + qRegisterMetaType("MyQObject*"); + m_myObject->resetQtFunctionInvoked(); + { + QScriptValue ret = m_engine->evaluate("myObject.myInvokableReturningMyQObject()"); + QCOMPARE(m_myObject->qtFunctionInvoked(), 53); + QVERIFY(ret.isVariant()); + QCOMPARE(*reinterpret_cast(ret.toVariant().constData()), m_myObject); + } + + // ability to call a slot with QObject-based argument, when the argument is const + m_myObject->resetQtFunctionInvoked(); + { + QScriptValue ret = m_engine->evaluate("myObject.myInvokableWithConstMyQObjectArg(myObject)"); + QCOMPARE(m_myObject->qtFunctionInvoked(), 54); + QVERIFY(ret.isUndefined()); + QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); + QCOMPARE(qvariant_cast(m_myObject->qtFunctionActuals().at(0)), (QObject*)m_myObject); + } + + // QScriptValue arguments should be passed on without conversion + m_myObject->resetQtFunctionInvoked(); + { + QScriptValue ret = m_engine->evaluate("myObject.myInvokableWithScriptValueArg(123)"); + QCOMPARE(m_myObject->qtFunctionInvoked(), 56); + QVERIFY(ret.isNumber()); + QCOMPARE(ret.toInt32(), 123); + } + m_myObject->resetQtFunctionInvoked(); + { + QScriptValue ret = m_engine->evaluate("myObject.myInvokableWithScriptValueArg('ciao')"); + QCOMPARE(m_myObject->qtFunctionInvoked(), 56); + QVERIFY(ret.isString()); + QCOMPARE(ret.toString(), QString::fromLatin1("ciao")); + } + m_myObject->resetQtFunctionInvoked(); + { + QScriptValue ret = m_engine->evaluate("myObject.myInvokableWithScriptValueArg(this)"); + QCOMPARE(m_myObject->qtFunctionInvoked(), 56); + QVERIFY(ret.isObject()); + QVERIFY(ret.strictlyEquals(m_engine->globalObject())); + } + + // the prototype specified by a conversion function should not be "down-graded" + m_myObject->resetQtFunctionInvoked(); + { + QScriptValue qobjectProto = m_engine->newObject(); + qScriptRegisterMetaType(m_engine, qobjectToScriptValue, + qobjectFromScriptValue, qobjectProto); + QScriptValue myQObjectProto = m_engine->newObject(); + myQObjectProto.setPrototype(qobjectProto); + qScriptRegisterMetaType(m_engine, qobjectToScriptValue, + qobjectFromScriptValue, myQObjectProto); + QScriptValue ret = m_engine->evaluate("myObject.myInvokableReturningMyQObjectAsQObject()"); + QCOMPARE(m_myObject->qtFunctionInvoked(), 57); + QVERIFY(ret.isQObject()); + QVERIFY(ret.prototype().strictlyEquals(myQObjectProto)); + + qScriptRegisterMetaType(m_engine, 0, 0, QScriptValue()); + qScriptRegisterMetaType(m_engine, 0, 0, QScriptValue()); + } + + // detect exceptions during argument conversion + m_myObject->resetQtFunctionInvoked(); + { + QScriptValue (*dummy)(QScriptEngine *, const QDir &) = 0; + qScriptRegisterMetaType(m_engine, dummy, dirFromScript); + { + QVERIFY(!m_engine->hasUncaughtException()); + QScriptValue ret = m_engine->evaluate("myObject.myInvokableWithQDirArg({})"); + QVERIFY(m_engine->hasUncaughtException()); + QVERIFY(ret.isError()); + QCOMPARE(ret.toString(), QString::fromLatin1("Error: No path")); + QCOMPARE(m_myObject->qtFunctionInvoked(), -1); + } + m_engine->clearExceptions(); + { + QScriptValue ret = m_engine->evaluate("myObject.myInvokableWithQDirArg({path:'.'})"); + QVERIFY(!m_engine->hasUncaughtException()); + QVERIFY(ret.isUndefined()); + QCOMPARE(m_myObject->qtFunctionInvoked(), 55); + } + } + + // qscript_call() + { + m_myObject->resetQtFunctionInvoked(); + QScriptValue ret = m_engine->evaluate("new myObject(123)"); + QVERIFY(ret.isError()); + QCOMPARE(ret.toString(), QString::fromLatin1("TypeError: myObject is not a constructor")); + } + { + m_myObject->resetQtFunctionInvoked(); + QScriptValue ret = m_engine->evaluate("myObject(123)"); + QCOMPARE(ret.toString(), QString::fromLatin1("TypeError: myObject is not a function")); + } + + // task 233624 + { + MyNS::A a; + m_engine->globalObject().setProperty("anObject", m_engine->newQObject(&a)); + QScriptValue ret = m_engine->evaluate("anObject.slotTakingScopedEnumArg(1)"); + QVERIFY(!ret.isError()); + QVERIFY(ret.isNumber()); + QCOMPARE(ret.toInt32(), 1); + m_engine->globalObject().setProperty("anObject", QScriptValue()); + } + + // virtual slot redeclared in subclass (task 236467) + { + MyOtherQObject moq; + m_engine->globalObject().setProperty("myOtherQObject", m_engine->newQObject(&moq)); + moq.resetQtFunctionInvoked(); + QScriptValue ret = m_engine->evaluate("myOtherQObject.myVirtualSlot(123)"); + QCOMPARE(moq.qtFunctionInvoked(), 59); + QVERIFY(!ret.isError()); + QVERIFY(ret.isNumber()); + QCOMPARE(ret.toInt32(), 123); + } +} + +void tst_QScriptExtQObject::connectAndDisconnect() +{ + // connect(function) + QCOMPARE(m_engine->evaluate("myObject.mySignal.connect(123)").isError(), true); + + m_engine->evaluate("myHandler = function() { global.gotSignal = true; global.signalArgs = arguments; global.slotThisObject = this; global.signalSender = __qt_sender__; }"); + + m_myObject->clearConnectedSignal(); + QVERIFY(m_engine->evaluate("myObject.mySignal.connect(myHandler)").isUndefined()); + QCOMPARE(m_myObject->connectedSignal().constData(), SIGNAL(mySignal())); + + m_engine->evaluate("gotSignal = false"); + m_engine->evaluate("myObject.mySignal()"); + QCOMPARE(m_engine->evaluate("gotSignal").toBoolean(), true); + QCOMPARE(m_engine->evaluate("signalArgs.length").toNumber(), 0.0); + QCOMPARE(m_engine->evaluate("signalSender").toQObject(), (QObject *)m_myObject); + QVERIFY(m_engine->evaluate("slotThisObject").strictlyEquals(m_engine->globalObject())); + + m_engine->evaluate("gotSignal = false"); + m_myObject->emitMySignal(); + QCOMPARE(m_engine->evaluate("gotSignal").toBoolean(), true); + QCOMPARE(m_engine->evaluate("signalArgs.length").toNumber(), 0.0); + + QVERIFY(m_engine->evaluate("myObject.mySignalWithIntArg.connect(myHandler)").isUndefined()); + + m_engine->evaluate("gotSignal = false"); + m_myObject->emitMySignalWithIntArg(123); + QCOMPARE(m_engine->evaluate("gotSignal").toBoolean(), true); + QCOMPARE(m_engine->evaluate("signalArgs.length").toNumber(), 1.0); + QCOMPARE(m_engine->evaluate("signalArgs[0]").toNumber(), 123.0); + + m_myObject->clearDisconnectedSignal(); + QVERIFY(m_engine->evaluate("myObject.mySignal.disconnect(myHandler)").isUndefined()); + QCOMPARE(m_myObject->disconnectedSignal().constData(), SIGNAL(mySignal())); + + QVERIFY(m_engine->evaluate("myObject.mySignal.disconnect(myHandler)").isError()); + + QVERIFY(m_engine->evaluate("myObject.mySignal2.connect(myHandler)").isUndefined()); + + m_engine->evaluate("gotSignal = false"); + m_myObject->emitMySignal2(false); + QCOMPARE(m_engine->evaluate("gotSignal").toBoolean(), true); + QCOMPARE(m_engine->evaluate("signalArgs.length").toNumber(), 1.0); + QCOMPARE(m_engine->evaluate("signalArgs[0]").toBoolean(), false); + + m_engine->evaluate("gotSignal = false"); + QVERIFY(m_engine->evaluate("myObject.mySignal2.connect(myHandler)").isUndefined()); + m_myObject->emitMySignal2(true); + QCOMPARE(m_engine->evaluate("gotSignal").toBoolean(), true); + QCOMPARE(m_engine->evaluate("signalArgs.length").toNumber(), 1.0); + QCOMPARE(m_engine->evaluate("signalArgs[0]").toBoolean(), true); + + QVERIFY(m_engine->evaluate("myObject.mySignal2.disconnect(myHandler)").isUndefined()); + + QVERIFY(m_engine->evaluate("myObject['mySignal2()'].connect(myHandler)").isUndefined()); + + m_engine->evaluate("gotSignal = false"); + m_myObject->emitMySignal2(); + QCOMPARE(m_engine->evaluate("gotSignal").toBoolean(), true); + + QVERIFY(m_engine->evaluate("myObject['mySignal2()'].disconnect(myHandler)").isUndefined()); + + // connecting to signal with default args should pick the most generic version (i.e. with all args) + QVERIFY(m_engine->evaluate("myObject.mySignalWithDefaultArg.connect(myHandler)").isUndefined()); + m_engine->evaluate("gotSignal = false"); + m_myObject->emitMySignalWithDefaultArgWithArg(456); + QVERIFY(m_engine->evaluate("gotSignal").toBoolean()); + QCOMPARE(m_engine->evaluate("signalArgs.length").toInt32(), 1); + QCOMPARE(m_engine->evaluate("signalArgs[0]").toInt32(), 456); + + m_engine->evaluate("gotSignal = false"); + m_myObject->emitMySignalWithDefaultArg(); + QVERIFY(m_engine->evaluate("gotSignal").toBoolean()); + QCOMPARE(m_engine->evaluate("signalArgs.length").toInt32(), 1); + QCOMPARE(m_engine->evaluate("signalArgs[0]").toInt32(), 123); + + QVERIFY(m_engine->evaluate("myObject.mySignalWithDefaultArg.disconnect(myHandler)").isUndefined()); + + m_engine->evaluate("gotSignal = false"); + // connecting to overloaded signal should throw an error + { + QScriptValue ret = m_engine->evaluate("myObject.myOverloadedSignal.connect(myHandler)"); + QVERIFY(ret.isError()); + QCOMPARE(ret.toString(), QString::fromLatin1("Error: Function.prototype.connect: ambiguous connect to MyQObject::myOverloadedSignal(); candidates are\n" + " myOverloadedSignal(int)\n" + " myOverloadedSignal(QString)\n" + "Use e.g. object['myOverloadedSignal(QString)'].connect() to connect to a particular overload")); + } + m_myObject->emitMyOverloadedSignal(123); + QVERIFY(!m_engine->evaluate("gotSignal").toBoolean()); + m_myObject->emitMyOverloadedSignal("ciao"); + QVERIFY(!m_engine->evaluate("gotSignal").toBoolean()); + + m_engine->evaluate("gotSignal = false"); + { + QScriptValue ret = m_engine->evaluate("myObject.myOtherOverloadedSignal.connect(myHandler)"); + QVERIFY(ret.isError()); + QCOMPARE(ret.toString(), QString::fromLatin1("Error: Function.prototype.connect: ambiguous connect to MyQObject::myOtherOverloadedSignal(); candidates are\n" + " myOtherOverloadedSignal(QString)\n" + " myOtherOverloadedSignal(int)\n" + "Use e.g. object['myOtherOverloadedSignal(int)'].connect() to connect to a particular overload")); + } + m_myObject->emitMyOtherOverloadedSignal("ciao"); + QVERIFY(!m_engine->evaluate("gotSignal").toBoolean()); + m_myObject->emitMyOtherOverloadedSignal(123); + QVERIFY(!m_engine->evaluate("gotSignal").toBoolean()); + + // connect(object, function) + m_engine->evaluate("otherObject = { name:'foo' }"); + QVERIFY(m_engine->evaluate("myObject.mySignal.connect(otherObject, myHandler)").isUndefined()); + QVERIFY(m_engine->evaluate("myObject.mySignal.disconnect(otherObject, myHandler)").isUndefined()); + m_engine->evaluate("gotSignal = false"); + m_myObject->emitMySignal(); + QCOMPARE(m_engine->evaluate("gotSignal").toBoolean(), false); + + QVERIFY(m_engine->evaluate("myObject.mySignal.disconnect(otherObject, myHandler)").isError()); + + QVERIFY(m_engine->evaluate("myObject.mySignal.connect(otherObject, myHandler)").isUndefined()); + m_engine->evaluate("gotSignal = false"); + m_myObject->emitMySignal(); + QCOMPARE(m_engine->evaluate("gotSignal").toBoolean(), true); + QCOMPARE(m_engine->evaluate("signalArgs.length").toNumber(), 0.0); + QVERIFY(m_engine->evaluate("slotThisObject").strictlyEquals(m_engine->evaluate("otherObject"))); + QVERIFY(m_engine->evaluate("signalSender").strictlyEquals(m_engine->evaluate("myObject"))); + QCOMPARE(m_engine->evaluate("slotThisObject").property("name").toString(), QLatin1String("foo")); + QVERIFY(m_engine->evaluate("myObject.mySignal.disconnect(otherObject, myHandler)").isUndefined()); + + m_engine->evaluate("yetAnotherObject = { name:'bar', func : function() { } }"); + QVERIFY(m_engine->evaluate("myObject.mySignal2.connect(yetAnotherObject, myHandler)").isUndefined()); + m_engine->evaluate("gotSignal = false"); + m_myObject->emitMySignal2(true); + QCOMPARE(m_engine->evaluate("gotSignal").toBoolean(), true); + QCOMPARE(m_engine->evaluate("signalArgs.length").toNumber(), 1.0); + QVERIFY(m_engine->evaluate("slotThisObject").strictlyEquals(m_engine->evaluate("yetAnotherObject"))); + QVERIFY(m_engine->evaluate("signalSender").strictlyEquals(m_engine->evaluate("myObject"))); + QCOMPARE(m_engine->evaluate("slotThisObject").property("name").toString(), QLatin1String("bar")); + QVERIFY(m_engine->evaluate("myObject.mySignal2.disconnect(yetAnotherObject, myHandler)").isUndefined()); + + QVERIFY(m_engine->evaluate("myObject.mySignal2.connect(myObject, myHandler)").isUndefined()); + m_engine->evaluate("gotSignal = false"); + m_myObject->emitMySignal2(true); + QCOMPARE(m_engine->evaluate("gotSignal").toBoolean(), true); + QCOMPARE(m_engine->evaluate("signalArgs.length").toNumber(), 1.0); + QCOMPARE(m_engine->evaluate("slotThisObject").toQObject(), (QObject *)m_myObject); + QVERIFY(m_engine->evaluate("signalSender").strictlyEquals(m_engine->evaluate("myObject"))); + QVERIFY(m_engine->evaluate("myObject.mySignal2.disconnect(myObject, myHandler)").isUndefined()); + + // connect(obj, string) + QVERIFY(m_engine->evaluate("myObject.mySignal.connect(yetAnotherObject, 'func')").isUndefined()); + QVERIFY(m_engine->evaluate("myObject.mySignal.connect(myObject, 'mySlot')").isUndefined()); + QVERIFY(m_engine->evaluate("myObject.mySignal.disconnect(yetAnotherObject, 'func')").isUndefined()); + QVERIFY(m_engine->evaluate("myObject.mySignal.disconnect(myObject, 'mySlot')").isUndefined()); + + // check that emitting signals from script works + + // no arguments + QVERIFY(m_engine->evaluate("myObject.mySignal.connect(myObject.mySlot)").isUndefined()); + m_myObject->resetQtFunctionInvoked(); + QCOMPARE(m_engine->evaluate("myObject.mySignal()").isUndefined(), true); + QCOMPARE(m_myObject->qtFunctionInvoked(), 20); + QVERIFY(m_engine->evaluate("myObject.mySignal.disconnect(myObject.mySlot)").isUndefined()); + + // one argument + QVERIFY(m_engine->evaluate("myObject.mySignalWithIntArg.connect(myObject.mySlotWithIntArg)").isUndefined()); + m_myObject->resetQtFunctionInvoked(); + QCOMPARE(m_engine->evaluate("myObject.mySignalWithIntArg(123)").isUndefined(), true); + QCOMPARE(m_myObject->qtFunctionInvoked(), 21); + QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); + QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 123); + QVERIFY(m_engine->evaluate("myObject.mySignalWithIntArg.disconnect(myObject.mySlotWithIntArg)").isUndefined()); + + QVERIFY(m_engine->evaluate("myObject.mySignalWithIntArg.connect(myObject.mySlotWithDoubleArg)").isUndefined()); + m_myObject->resetQtFunctionInvoked(); + QCOMPARE(m_engine->evaluate("myObject.mySignalWithIntArg(123)").isUndefined(), true); + QCOMPARE(m_myObject->qtFunctionInvoked(), 22); + QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); + QCOMPARE(m_myObject->qtFunctionActuals().at(0).toDouble(), 123.0); + QVERIFY(m_engine->evaluate("myObject.mySignalWithIntArg.disconnect(myObject.mySlotWithDoubleArg)").isUndefined()); + + QVERIFY(m_engine->evaluate("myObject.mySignalWithIntArg.connect(myObject.mySlotWithStringArg)").isUndefined()); + m_myObject->resetQtFunctionInvoked(); + QCOMPARE(m_engine->evaluate("myObject.mySignalWithIntArg(123)").isUndefined(), true); + QCOMPARE(m_myObject->qtFunctionInvoked(), 23); + QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); + QCOMPARE(m_myObject->qtFunctionActuals().at(0).toString(), QLatin1String("123")); + QVERIFY(m_engine->evaluate("myObject.mySignalWithIntArg.disconnect(myObject.mySlotWithStringArg)").isUndefined()); + + // connecting to overloaded slot + QVERIFY(m_engine->evaluate("myObject.mySignalWithIntArg.connect(myObject.myOverloadedSlot)").isUndefined()); + m_myObject->resetQtFunctionInvoked(); + QCOMPARE(m_engine->evaluate("myObject.mySignalWithIntArg(123)").isUndefined(), true); + QCOMPARE(m_myObject->qtFunctionInvoked(), 26); // double overload + QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); + QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 123); + QVERIFY(m_engine->evaluate("myObject.mySignalWithIntArg.disconnect(myObject.myOverloadedSlot)").isUndefined()); + + QVERIFY(m_engine->evaluate("myObject.mySignalWithIntArg.connect(myObject['myOverloadedSlot(int)'])").isUndefined()); + m_myObject->resetQtFunctionInvoked(); + QCOMPARE(m_engine->evaluate("myObject.mySignalWithIntArg(456)").isUndefined(), true); + QCOMPARE(m_myObject->qtFunctionInvoked(), 28); // int overload + QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); + QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 456); + QVERIFY(m_engine->evaluate("myObject.mySignalWithIntArg.disconnect(myObject['myOverloadedSlot(int)'])").isUndefined()); + + // erroneous input + { + QScriptValue ret = m_engine->evaluate("(function() { }).connect()"); + QVERIFY(ret.isError()); + QCOMPARE(ret.toString(), QLatin1String("Error: Function.prototype.connect: no arguments given")); + } + { + QScriptValue ret = m_engine->evaluate("var o = { }; o.connect = Function.prototype.connect; o.connect()"); + QVERIFY(ret.isError()); + QCOMPARE(ret.toString(), QLatin1String("Error: Function.prototype.connect: no arguments given")); + } + + { + QScriptValue ret = m_engine->evaluate("(function() { }).connect(123)"); + QVERIFY(ret.isError()); + QCOMPARE(ret.toString(), QLatin1String("TypeError: Function.prototype.connect: this object is not a signal")); + } + { + QScriptValue ret = m_engine->evaluate("var o = { }; o.connect = Function.prototype.connect; o.connect(123)"); + QVERIFY(ret.isError()); + QCOMPARE(ret.toString(), QLatin1String("TypeError: Function.prototype.connect: this object is not a signal")); + } + + { + QScriptValue ret = m_engine->evaluate("myObject.myInvokable.connect(123)"); + QVERIFY(ret.isError()); + QCOMPARE(ret.toString(), QLatin1String("TypeError: Function.prototype.connect: MyQObject::myInvokable() is not a signal")); + } + { + QScriptValue ret = m_engine->evaluate("myObject.myInvokable.connect(function() { })"); + QVERIFY(ret.isError()); + QCOMPARE(ret.toString(), QLatin1String("TypeError: Function.prototype.connect: MyQObject::myInvokable() is not a signal")); + } + + { + QScriptValue ret = m_engine->evaluate("myObject.mySignal.connect(123)"); + QVERIFY(ret.isError()); + QCOMPARE(ret.toString(), QLatin1String("TypeError: Function.prototype.connect: target is not a function")); + } + + { + QScriptValue ret = m_engine->evaluate("(function() { }).disconnect()"); + QVERIFY(ret.isError()); + QCOMPARE(ret.toString(), QLatin1String("Error: Function.prototype.disconnect: no arguments given")); + } + { + QScriptValue ret = m_engine->evaluate("var o = { }; o.disconnect = Function.prototype.disconnect; o.disconnect()"); + QVERIFY(ret.isError()); + QCOMPARE(ret.toString(), QLatin1String("Error: Function.prototype.disconnect: no arguments given")); + } + + { + QScriptValue ret = m_engine->evaluate("(function() { }).disconnect(123)"); + QVERIFY(ret.isError()); + QCOMPARE(ret.toString(), QLatin1String("TypeError: Function.prototype.disconnect: this object is not a signal")); + } + { + QScriptValue ret = m_engine->evaluate("var o = { }; o.disconnect = Function.prototype.disconnect; o.disconnect(123)"); + QVERIFY(ret.isError()); + QCOMPARE(ret.toString(), QLatin1String("TypeError: Function.prototype.disconnect: this object is not a signal")); + } + + { + QScriptValue ret = m_engine->evaluate("myObject.myInvokable.disconnect(123)"); + QVERIFY(ret.isError()); + QCOMPARE(ret.toString(), QLatin1String("TypeError: Function.prototype.disconnect: MyQObject::myInvokable() is not a signal")); + } + { + QScriptValue ret = m_engine->evaluate("myObject.myInvokable.disconnect(function() { })"); + QVERIFY(ret.isError()); + QCOMPARE(ret.toString(), QLatin1String("TypeError: Function.prototype.disconnect: MyQObject::myInvokable() is not a signal")); + } + + { + QScriptValue ret = m_engine->evaluate("myObject.mySignal.disconnect(123)"); + QVERIFY(ret.isError()); + QCOMPARE(ret.toString(), QLatin1String("TypeError: Function.prototype.disconnect: target is not a function")); + } + + { + QScriptValue ret = m_engine->evaluate("myObject.mySignal.disconnect(function() { })"); + QVERIFY(ret.isError()); + QCOMPARE(ret.toString(), QLatin1String("Error: Function.prototype.disconnect: failed to disconnect from MyQObject::mySignal()")); + } + + // when the wrapper dies, the connection stays alive + QVERIFY(m_engine->evaluate("myObject.mySignal.connect(myObject.mySlot)").isUndefined()); + m_myObject->resetQtFunctionInvoked(); + m_myObject->emitMySignal(); + QCOMPARE(m_myObject->qtFunctionInvoked(), 20); + m_engine->evaluate("myObject = null"); + m_engine->collectGarbage(); + m_myObject->resetQtFunctionInvoked(); + m_myObject->emitMySignal(); + QCOMPARE(m_myObject->qtFunctionInvoked(), 20); +} + +void tst_QScriptExtQObject::cppConnectAndDisconnect() +{ + QScriptEngine eng; + QLineEdit edit; + QLineEdit edit2; + QScriptValue fun = eng.evaluate("function fun(text) { signalObject = this; signalArg = text; }; fun"); + QVERIFY(fun.isFunction()); + for (int z = 0; z < 2; ++z) { + QScriptValue receiver; + if (z == 0) + receiver = QScriptValue(); + else + receiver = eng.newObject(); + for (int y = 0; y < 2; ++y) { + QVERIFY(qScriptConnect(&edit, SIGNAL(textChanged(const QString &)), receiver, fun)); + QVERIFY(qScriptConnect(&edit2, SIGNAL(textChanged(const QString &)), receiver, fun)); + // check signal emission + for (int x = 0; x < 4; ++x) { + QLineEdit *ed = (x < 2) ? &edit : &edit2; + ed->setText((x % 2) ? "foo" : "bar"); + { + QScriptValue ret = eng.globalObject().property("signalObject"); + if (receiver.isObject()) + QVERIFY(ret.strictlyEquals(receiver)); + else + QVERIFY(ret.strictlyEquals(eng.globalObject())); + } + { + QScriptValue ret = eng.globalObject().property("signalArg"); + QVERIFY(ret.isString()); + QCOMPARE(ret.toString(), ed->text()); + } + eng.collectGarbage(); + } + + // check disconnect + QVERIFY(qScriptDisconnect(&edit, SIGNAL(textChanged(const QString &)), receiver, fun)); + eng.globalObject().setProperty("signalObject", QScriptValue()); + eng.globalObject().setProperty("signalArg", QScriptValue()); + edit.setText("something else"); + QVERIFY(!eng.globalObject().property("signalObject").isValid()); + QVERIFY(!eng.globalObject().property("signalArg").isValid()); + QVERIFY(!qScriptDisconnect(&edit, SIGNAL(textChanged(const QString &)), receiver, fun)); + + // other object's connection should remain + edit2.setText(edit.text()); + { + QScriptValue ret = eng.globalObject().property("signalObject"); + if (receiver.isObject()) + QVERIFY(ret.strictlyEquals(receiver)); + else + QVERIFY(ret.strictlyEquals(eng.globalObject())); + } + { + QScriptValue ret = eng.globalObject().property("signalArg"); + QVERIFY(ret.isString()); + QCOMPARE(ret.toString(), edit2.text()); + } + + // disconnect other object too + QVERIFY(qScriptDisconnect(&edit2, SIGNAL(textChanged(const QString &)), receiver, fun)); + eng.globalObject().setProperty("signalObject", QScriptValue()); + eng.globalObject().setProperty("signalArg", QScriptValue()); + edit2.setText("even more different"); + QVERIFY(!eng.globalObject().property("signalObject").isValid()); + QVERIFY(!eng.globalObject().property("signalArg").isValid()); + QVERIFY(!qScriptDisconnect(&edit2, SIGNAL(textChanged(const QString &)), receiver, fun)); + } + } + + // make sure we don't crash when engine is deleted + { + QScriptEngine *eng2 = new QScriptEngine; + QScriptValue fun2 = eng2->evaluate("function(text) { signalObject = this; signalArg = text; }"); + QVERIFY(qScriptConnect(&edit, SIGNAL(textChanged(const QString &)), QScriptValue(), fun2)); + delete eng2; + edit.setText("ciao"); + QVERIFY(!qScriptDisconnect(&edit, SIGNAL(textChanged(const QString &)), QScriptValue(), fun2)); + } + + // mixing script-side and C++-side connect + { + eng.globalObject().setProperty("edit", eng.newQObject(&edit)); + QVERIFY(eng.evaluate("edit.textChanged.connect(fun)").isUndefined()); + QVERIFY(qScriptDisconnect(&edit, SIGNAL(textChanged(const QString &)), QScriptValue(), fun)); + + QVERIFY(qScriptConnect(&edit, SIGNAL(textChanged(const QString &)), QScriptValue(), fun)); + QVERIFY(eng.evaluate("edit.textChanged.disconnect(fun)").isUndefined()); + } + + // signalHandlerException() + { + connect(&eng, SIGNAL(signalHandlerException(QScriptValue)), + this, SLOT(onSignalHandlerException(QScriptValue))); + + eng.globalObject().setProperty("edit", eng.newQObject(&edit)); + QScriptValue fun = eng.evaluate("function() { nonExistingFunction(); }"); + QVERIFY(qScriptConnect(&edit, SIGNAL(textChanged(const QString &)), QScriptValue(), fun)); + + m_signalHandlerException = QScriptValue(); + QScriptValue ret = eng.evaluate("edit.text = 'trigger a signal handler exception from script'"); + QVERIFY(ret.isError()); + QVERIFY(m_signalHandlerException.strictlyEquals(ret)); + + m_signalHandlerException = QScriptValue(); + edit.setText("trigger a signal handler exception from C++"); + QVERIFY(m_signalHandlerException.isError()); + + QVERIFY(qScriptDisconnect(&edit, SIGNAL(textChanged(const QString &)), QScriptValue(), fun)); + + m_signalHandlerException = QScriptValue(); + eng.evaluate("edit.text = 'no more exception from script'"); + QVERIFY(!m_signalHandlerException.isValid()); + edit.setText("no more exception from C++"); + QVERIFY(!m_signalHandlerException.isValid()); + + disconnect(&eng, SIGNAL(signalHandlerException(QScriptValue)), + this, SLOT(onSignalHandlerException(QScriptValue))); + } + + // check that connectNotify() and disconnectNotify() are called (task 232987) + { + m_myObject->clearConnectedSignal(); + QVERIFY(qScriptConnect(m_myObject, SIGNAL(mySignal()), QScriptValue(), fun)); + QCOMPARE(m_myObject->connectedSignal().constData(), SIGNAL(mySignal())); + + m_myObject->clearDisconnectedSignal(); + QVERIFY(qScriptDisconnect(m_myObject, SIGNAL(mySignal()), QScriptValue(), fun)); + QCOMPARE(m_myObject->disconnectedSignal().constData(), SIGNAL(mySignal())); + } +} + +void tst_QScriptExtQObject::classEnums() +{ + QScriptValue myClass = m_engine->newQMetaObject(m_myObject->metaObject(), m_engine->undefinedValue()); + m_engine->globalObject().setProperty("MyQObject", myClass); + + QCOMPARE(static_cast(m_engine->evaluate("MyQObject.FooPolicy").toInt32()), + MyQObject::FooPolicy); + QCOMPARE(static_cast(m_engine->evaluate("MyQObject.BarPolicy").toInt32()), + MyQObject::BarPolicy); + QCOMPARE(static_cast(m_engine->evaluate("MyQObject.BazPolicy").toInt32()), + MyQObject::BazPolicy); + + QCOMPARE(static_cast(m_engine->evaluate("MyQObject.FooStrategy").toInt32()), + MyQObject::FooStrategy); + QCOMPARE(static_cast(m_engine->evaluate("MyQObject.BarStrategy").toInt32()), + MyQObject::BarStrategy); + QCOMPARE(static_cast(m_engine->evaluate("MyQObject.BazStrategy").toInt32()), + MyQObject::BazStrategy); + + QCOMPARE(MyQObject::Ability(m_engine->evaluate("MyQObject.NoAbility").toInt32()), + MyQObject::NoAbility); + QCOMPARE(MyQObject::Ability(m_engine->evaluate("MyQObject.FooAbility").toInt32()), + MyQObject::FooAbility); + QCOMPARE(MyQObject::Ability(m_engine->evaluate("MyQObject.BarAbility").toInt32()), + MyQObject::BarAbility); + QCOMPARE(MyQObject::Ability(m_engine->evaluate("MyQObject.BazAbility").toInt32()), + MyQObject::BazAbility); + QCOMPARE(MyQObject::Ability(m_engine->evaluate("MyQObject.AllAbility").toInt32()), + MyQObject::AllAbility); + + QScriptValue::PropertyFlags expectedEnumFlags = QScriptValue::ReadOnly; + QCOMPARE(myClass.propertyFlags("FooPolicy"), expectedEnumFlags); + QCOMPARE(myClass.propertyFlags("BarPolicy"), expectedEnumFlags); + QCOMPARE(myClass.propertyFlags("BazPolicy"), expectedEnumFlags); + + // enums from Qt are inherited through prototype + QCOMPARE(static_cast(m_engine->evaluate("MyQObject.StrongFocus").toInt32()), + Qt::StrongFocus); + QCOMPARE(static_cast(m_engine->evaluate("MyQObject.Key_Left").toInt32()), + Qt::Key_Left); + + QCOMPARE(m_engine->evaluate("MyQObject.className()").toString(), QLatin1String("MyQObject")); + + qRegisterMetaType("Policy"); + + m_myObject->resetQtFunctionInvoked(); + QCOMPARE(m_engine->evaluate("myObject.myInvokableWithEnumArg(MyQObject.BazPolicy)").isUndefined(), true); + QCOMPARE(m_myObject->qtFunctionInvoked(), 10); + QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); + QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), int(MyQObject::BazPolicy)); + + m_myObject->resetQtFunctionInvoked(); + QCOMPARE(m_engine->evaluate("myObject.myInvokableWithQualifiedEnumArg(MyQObject.BazPolicy)").isUndefined(), true); + QCOMPARE(m_myObject->qtFunctionInvoked(), 36); + QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); + QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), int(MyQObject::BazPolicy)); + + m_myObject->resetQtFunctionInvoked(); + { + QScriptValue ret = m_engine->evaluate("myObject.myInvokableReturningEnum()"); + QCOMPARE(m_myObject->qtFunctionInvoked(), 37); + QCOMPARE(m_myObject->qtFunctionActuals().size(), 0); + QCOMPARE(ret.isVariant(), true); + } + m_myObject->resetQtFunctionInvoked(); + { + QScriptValue ret = m_engine->evaluate("myObject.myInvokableReturningQualifiedEnum()"); + QCOMPARE(m_myObject->qtFunctionInvoked(), 38); + QCOMPARE(m_myObject->qtFunctionActuals().size(), 0); + QCOMPARE(ret.isNumber(), true); + } +} + +QT_BEGIN_NAMESPACE +Q_SCRIPT_DECLARE_QMETAOBJECT(MyQObject, QObject*) +Q_SCRIPT_DECLARE_QMETAOBJECT(QObject, QObject*) +QT_END_NAMESPACE + +class ConstructorTest : public QObject +{ + Q_OBJECT +public: + Q_INVOKABLE ConstructorTest(QObject *parent) + : QObject(parent) + { + setProperty("ctorIndex", 0); + } + Q_INVOKABLE ConstructorTest(int arg, QObject *parent = 0) + : QObject(parent) + { + setProperty("ctorIndex", 1); + setProperty("arg", arg); + } + Q_INVOKABLE ConstructorTest(const QString &arg, QObject *parent = 0) + : QObject(parent) + { + setProperty("ctorIndex", 2); + setProperty("arg", arg); + } + Q_INVOKABLE ConstructorTest(int arg, const QString &arg2, QObject *parent = 0) + : QObject(parent) + { + setProperty("ctorIndex", 3); + setProperty("arg", arg); + setProperty("arg2", arg2); + } + Q_INVOKABLE ConstructorTest(const QBrush &arg, QObject *parent = 0) + : QObject(parent) + { + setProperty("ctorIndex", 4); + setProperty("arg", arg); + } +}; + +void tst_QScriptExtQObject::classConstructor() +{ + QScriptValue myClass = qScriptValueFromQMetaObject(m_engine); + m_engine->globalObject().setProperty("MyQObject", myClass); + + QScriptValue myObj = m_engine->evaluate("myObj = MyQObject()"); + QObject *qobj = myObj.toQObject(); + QVERIFY(qobj != 0); + QCOMPARE(qobj->metaObject()->className(), "MyQObject"); + QCOMPARE(qobj->parent(), (QObject *)0); + + QScriptValue qobjectClass = qScriptValueFromQMetaObject(m_engine); + m_engine->globalObject().setProperty("QObject", qobjectClass); + + QScriptValue otherObj = m_engine->evaluate("otherObj = QObject(myObj)"); + QObject *qqobj = otherObj.toQObject(); + QVERIFY(qqobj != 0); + QCOMPARE(qqobj->metaObject()->className(), "QObject"); + QCOMPARE(qqobj->parent(), qobj); + + delete qobj; + + // Q_INVOKABLE constructors + { + QScriptValue klazz = m_engine->newQMetaObject(&ConstructorTest::staticMetaObject); + { + QScriptValue obj = klazz.construct(); + QVERIFY(obj.isError()); + QCOMPARE(obj.toString(), QString::fromLatin1("SyntaxError: too few arguments in call to ConstructorTest(); candidates are\n" + " ConstructorTest(QBrush)\n" + " ConstructorTest(QBrush,QObject*)\n" + " ConstructorTest(int,QString)\n" + " ConstructorTest(int,QString,QObject*)\n" + " ConstructorTest(QString)\n" + " ConstructorTest(QString,QObject*)\n" + " ConstructorTest(int)\n" + " ConstructorTest(int,QObject*)\n" + " ConstructorTest(QObject*)")); + } + { + QObject objobj; + QScriptValue arg = m_engine->newQObject(&objobj); + QScriptValue obj = klazz.construct(QScriptValueList() << arg); + QVERIFY(!obj.isError()); + QVERIFY(obj.instanceOf(klazz)); + QVERIFY(obj.property("ctorIndex").isNumber()); + QCOMPARE(obj.property("ctorIndex").toInt32(), 0); + } + { + int arg = 123; + QScriptValue obj = klazz.construct(QScriptValueList() << arg); + QVERIFY(!obj.isError()); + QVERIFY(obj.instanceOf(klazz)); + QVERIFY(obj.property("ctorIndex").isNumber()); + QCOMPARE(obj.property("ctorIndex").toInt32(), 1); + QVERIFY(obj.property("arg").isNumber()); + QCOMPARE(obj.property("arg").toInt32(), arg); + } + { + QString arg = "foo"; + QScriptValue obj = klazz.construct(QScriptValueList() << arg); + QVERIFY(!obj.isError()); + QVERIFY(obj.instanceOf(klazz)); + QVERIFY(obj.property("ctorIndex").isNumber()); + QCOMPARE(obj.property("ctorIndex").toInt32(), 2); + QVERIFY(obj.property("arg").isString()); + QCOMPARE(obj.property("arg").toString(), arg); + } + { + int arg = 123; + QString arg2 = "foo"; + QScriptValue obj = klazz.construct(QScriptValueList() << arg << arg2); + QVERIFY(!obj.isError()); + QVERIFY(obj.instanceOf(klazz)); + QVERIFY(obj.property("ctorIndex").isNumber()); + QCOMPARE(obj.property("ctorIndex").toInt32(), 3); + QVERIFY(obj.property("arg").isNumber()); + QCOMPARE(obj.property("arg").toInt32(), arg); + QVERIFY(obj.property("arg2").isString()); + QCOMPARE(obj.property("arg2").toString(), arg2); + } + { + QBrush arg(Qt::red); + QScriptValue obj = klazz.construct(QScriptValueList() << qScriptValueFromValue(m_engine, arg)); + QVERIFY(!obj.isError()); + QVERIFY(obj.instanceOf(klazz)); + QVERIFY(obj.property("ctorIndex").isNumber()); + QCOMPARE(obj.property("ctorIndex").toInt32(), 4); + QVERIFY(obj.property("arg").isVariant()); + QCOMPARE(qvariant_cast(obj.property("arg").toVariant()), arg); + } + { + QDir arg; + QScriptValue obj = klazz.construct(QScriptValueList() + << qScriptValueFromValue(m_engine, arg)); + QVERIFY(obj.isError()); + QCOMPARE(obj.toString(), QString::fromLatin1("TypeError: ambiguous call of overloaded function ConstructorTest(); candidates were\n" + " ConstructorTest(int)\n" + " ConstructorTest(QString)")); + } + } +} + +void tst_QScriptExtQObject::overrideInvokable() +{ + m_myObject->resetQtFunctionInvoked(); + m_engine->evaluate("myObject.myInvokable()"); + QCOMPARE(m_myObject->qtFunctionInvoked(), 0); + + m_myObject->resetQtFunctionInvoked(); + m_engine->evaluate("myObject.myInvokable = function() { global.a = 123; }"); + m_engine->evaluate("myObject.myInvokable()"); + QCOMPARE(m_myObject->qtFunctionInvoked(), -1); + QCOMPARE(m_engine->evaluate("global.a").toNumber(), 123.0); + + m_engine->evaluate("myObject.myInvokable = function() { global.a = 456; }"); + m_engine->evaluate("myObject.myInvokable()"); + QCOMPARE(m_myObject->qtFunctionInvoked(), -1); + QCOMPARE(m_engine->evaluate("global.a").toNumber(), 456.0); + + m_engine->evaluate("delete myObject.myInvokable"); + m_engine->evaluate("myObject.myInvokable()"); + QCOMPARE(m_myObject->qtFunctionInvoked(), 0); + + m_myObject->resetQtFunctionInvoked(); + m_engine->evaluate("myObject.myInvokable = myObject.myInvokableWithIntArg"); + m_engine->evaluate("myObject.myInvokable(123)"); + QCOMPARE(m_myObject->qtFunctionInvoked(), 1); + + m_engine->evaluate("delete myObject.myInvokable"); + m_myObject->resetQtFunctionInvoked(); + // this form (with the '()') is read-only + m_engine->evaluate("myObject['myInvokable()'] = function() { global.a = 123; }"); + m_engine->evaluate("myObject.myInvokable()"); + QCOMPARE(m_myObject->qtFunctionInvoked(), 0); +} + +void tst_QScriptExtQObject::transferInvokable() +{ + m_myObject->resetQtFunctionInvoked(); + m_engine->evaluate("myObject.foozball = myObject.myInvokable"); + m_engine->evaluate("myObject.foozball()"); + QCOMPARE(m_myObject->qtFunctionInvoked(), 0); + m_myObject->resetQtFunctionInvoked(); + m_engine->evaluate("myObject.foozball = myObject.myInvokableWithIntArg"); + m_engine->evaluate("myObject.foozball(123)"); + QCOMPARE(m_myObject->qtFunctionInvoked(), 1); + m_myObject->resetQtFunctionInvoked(); + m_engine->evaluate("myObject.myInvokable = myObject.myInvokableWithIntArg"); + m_engine->evaluate("myObject.myInvokable(123)"); + QCOMPARE(m_myObject->qtFunctionInvoked(), 1); + + MyOtherQObject other; + m_engine->globalObject().setProperty( + "myOtherObject", m_engine->newQObject(&other)); + m_engine->evaluate("myOtherObject.foo = myObject.foozball"); + other.resetQtFunctionInvoked(); + m_engine->evaluate("myOtherObject.foo(456)"); + QCOMPARE(other.qtFunctionInvoked(), 1); +} + +void tst_QScriptExtQObject::findChild() +{ + QObject *child = new QObject(m_myObject); + child->setObjectName(QLatin1String("myChildObject")); + + { + QScriptValue result = m_engine->evaluate("myObject.findChild('noSuchChild')"); + QCOMPARE(result.isNull(), true); + } + + { + QScriptValue result = m_engine->evaluate("myObject.findChild('myChildObject')"); + QCOMPARE(result.isQObject(), true); + QCOMPARE(result.toQObject(), child); + } + + delete child; +} + +void tst_QScriptExtQObject::findChildren() +{ + QObject *child = new QObject(m_myObject); + child->setObjectName(QLatin1String("myChildObject")); + + { + QScriptValue result = m_engine->evaluate("myObject.findChildren('noSuchChild')"); + QCOMPARE(result.isArray(), true); + QCOMPARE(result.property(QLatin1String("length")).toNumber(), 0.0); + } + + { + QScriptValue result = m_engine->evaluate("myObject.findChildren('myChildObject')"); + QCOMPARE(result.isArray(), true); + QCOMPARE(result.property(QLatin1String("length")).toNumber(), 1.0); + QCOMPARE(result.property(QLatin1String("0")).toQObject(), child); + } + + QObject *namelessChild = new QObject(m_myObject); + + { + QScriptValue result = m_engine->evaluate("myObject.findChildren('myChildObject')"); + QCOMPARE(result.isArray(), true); + QCOMPARE(result.property(QLatin1String("length")).toNumber(), 1.0); + QCOMPARE(result.property(QLatin1String("0")).toQObject(), child); + } + + QObject *anotherChild = new QObject(m_myObject); + anotherChild->setObjectName(QLatin1String("anotherChildObject")); + + { + QScriptValue result = m_engine->evaluate("myObject.findChildren('anotherChildObject')"); + QCOMPARE(result.isArray(), true); + QCOMPARE(result.property(QLatin1String("length")).toNumber(), 1.0); + QCOMPARE(result.property(QLatin1String("0")).toQObject(), anotherChild); + } + + anotherChild->setObjectName(QLatin1String("myChildObject")); + { + QScriptValue result = m_engine->evaluate("myObject.findChildren('myChildObject')"); + QCOMPARE(result.isArray(), true); + QCOMPARE(result.property(QLatin1String("length")).toNumber(), 2.0); + QObject *o1 = result.property(QLatin1String("0")).toQObject(); + QObject *o2 = result.property(QLatin1String("1")).toQObject(); + if (o1 != child) { + QCOMPARE(o1, anotherChild); + QCOMPARE(o2, child); + } else { + QCOMPARE(o1, child); + QCOMPARE(o2, anotherChild); + } + } + + // find all + { + QScriptValue result = m_engine->evaluate("myObject.findChildren()"); + QVERIFY(result.isArray()); + int count = 3; + QCOMPARE(result.property("length").toInt32(), count); + for (int i = 0; i < 3; ++i) { + QObject *o = result.property(i).toQObject(); + if (o == namelessChild || o == child || o == anotherChild) + --count; + } + QVERIFY(count == 0); + } + + delete anotherChild; + delete namelessChild; + delete child; +} + +void tst_QScriptExtQObject::overloadedSlots() +{ + // should pick myOverloadedSlot(double) + m_myObject->resetQtFunctionInvoked(); + m_engine->evaluate("myObject.myOverloadedSlot(10)"); + QCOMPARE(m_myObject->qtFunctionInvoked(), 26); + + // should pick myOverloadedSlot(double) + m_myObject->resetQtFunctionInvoked(); + m_engine->evaluate("myObject.myOverloadedSlot(10.0)"); + QCOMPARE(m_myObject->qtFunctionInvoked(), 26); + + // should pick myOverloadedSlot(QString) + m_myObject->resetQtFunctionInvoked(); + m_engine->evaluate("myObject.myOverloadedSlot('10')"); + QCOMPARE(m_myObject->qtFunctionInvoked(), 29); + + // should pick myOverloadedSlot(bool) + m_myObject->resetQtFunctionInvoked(); + m_engine->evaluate("myObject.myOverloadedSlot(true)"); + QCOMPARE(m_myObject->qtFunctionInvoked(), 25); + + // should pick myOverloadedSlot(QDateTime) + m_myObject->resetQtFunctionInvoked(); + m_engine->evaluate("myObject.myOverloadedSlot(new Date())"); + QCOMPARE(m_myObject->qtFunctionInvoked(), 32); + + // should pick myOverloadedSlot(QRegExp) + m_myObject->resetQtFunctionInvoked(); + m_engine->evaluate("myObject.myOverloadedSlot(new RegExp())"); + QCOMPARE(m_myObject->qtFunctionInvoked(), 34); + + // should pick myOverloadedSlot(QVariant) + m_myObject->resetQtFunctionInvoked(); + QScriptValue f = m_engine->evaluate("myObject.myOverloadedSlot"); + f.call(QScriptValue(), QScriptValueList() << m_engine->newVariant(QVariant("ciao"))); + QCOMPARE(m_myObject->qtFunctionInvoked(), 35); + + // should pick myOverloadedSlot(QObject*) + m_myObject->resetQtFunctionInvoked(); + m_engine->evaluate("myObject.myOverloadedSlot(myObject)"); + QCOMPARE(m_myObject->qtFunctionInvoked(), 41); + + // should pick myOverloadedSlot(QObject*) + m_myObject->resetQtFunctionInvoked(); + m_engine->evaluate("myObject.myOverloadedSlot(null)"); + QCOMPARE(m_myObject->qtFunctionInvoked(), 41); + + // should pick myOverloadedSlot(QStringList) + m_myObject->resetQtFunctionInvoked(); + m_engine->evaluate("myObject.myOverloadedSlot(['hello'])"); + QCOMPARE(m_myObject->qtFunctionInvoked(), 42); +} + +void tst_QScriptExtQObject::enumerate_data() +{ + QTest::addColumn("wrapOptions"); + QTest::addColumn("expectedNames"); + + QTest::newRow( "enumerate all" ) + << 0 + << (QStringList() + // meta-object-defined properties: + // inherited + << "objectName" + // non-inherited + << "p1" << "p2" << "p4" << "p6" + // dynamic properties + << "dp1" << "dp2" << "dp3" + // inherited slots + << "destroyed(QObject*)" << "destroyed()" + << "deleteLater()" + // not included because it's private: + // << "_q_reregisterTimers(void*)" + // signals + << "mySignal()" + // slots + << "mySlot()" << "myOtherSlot()"); + + QTest::newRow( "don't enumerate inherited properties" ) + << int(QScriptEngine::ExcludeSuperClassProperties) + << (QStringList() + // meta-object-defined properties: + // non-inherited + << "p1" << "p2" << "p4" << "p6" + // dynamic properties + << "dp1" << "dp2" << "dp3" + // inherited slots + << "destroyed(QObject*)" << "destroyed()" + << "deleteLater()" + // not included because it's private: + // << "_q_reregisterTimers(void*)" + // signals + << "mySignal()" + // slots + << "mySlot()" << "myOtherSlot()"); + + QTest::newRow( "don't enumerate inherited methods" ) + << int(QScriptEngine::ExcludeSuperClassMethods) + << (QStringList() + // meta-object-defined properties: + // inherited + << "objectName" + // non-inherited + << "p1" << "p2" << "p4" << "p6" + // dynamic properties + << "dp1" << "dp2" << "dp3" + // signals + << "mySignal()" + // slots + << "mySlot()" << "myOtherSlot()"); + + QTest::newRow( "don't enumerate inherited members" ) + << int(QScriptEngine::ExcludeSuperClassMethods + | QScriptEngine::ExcludeSuperClassProperties) + << (QStringList() + // meta-object-defined properties + << "p1" << "p2" << "p4" << "p6" + // dynamic properties + << "dp1" << "dp2" << "dp3" + // signals + << "mySignal()" + // slots + << "mySlot()" << "myOtherSlot()"); + + QTest::newRow( "enumerate properties, not methods" ) + << int(QScriptEngine::SkipMethodsInEnumeration) + << (QStringList() + // meta-object-defined properties: + // inherited + << "objectName" + // non-inherited + << "p1" << "p2" << "p4" << "p6" + // dynamic properties + << "dp1" << "dp2" << "dp3"); + + QTest::newRow( "don't enumerate inherited properties + methods" ) + << int(QScriptEngine::ExcludeSuperClassProperties + | QScriptEngine::SkipMethodsInEnumeration) + << (QStringList() + // meta-object-defined properties: + // non-inherited + << "p1" << "p2" << "p4" << "p6" + // dynamic properties + << "dp1" << "dp2" << "dp3"); + + QTest::newRow( "don't enumerate inherited members" ) + << int(QScriptEngine::ExcludeSuperClassContents) + << (QStringList() + // meta-object-defined properties + << "p1" << "p2" << "p4" << "p6" + // dynamic properties + << "dp1" << "dp2" << "dp3" + // signals + << "mySignal()" + // slots + << "mySlot()" << "myOtherSlot()"); + + QTest::newRow( "don't enumerate deleteLater()" ) + << int(QScriptEngine::ExcludeDeleteLater) + << (QStringList() + // meta-object-defined properties: + // inherited + << "objectName" + // non-inherited + << "p1" << "p2" << "p4" << "p6" + // dynamic properties + << "dp1" << "dp2" << "dp3" + // inherited slots + << "destroyed(QObject*)" << "destroyed()" + // not included because it's private: + // << "_q_reregisterTimers(void*)" + // signals + << "mySignal()" + // slots + << "mySlot()" << "myOtherSlot()"); +} + +void tst_QScriptExtQObject::enumerate() +{ + QFETCH( int, wrapOptions ); + QFETCH( QStringList, expectedNames ); + + QScriptEngine eng; + MyEnumTestQObject enumQObject; + // give it some dynamic properties + enumQObject.setProperty("dp1", "dp1"); + enumQObject.setProperty("dp2", "dp2"); + enumQObject.setProperty("dp3", "dp3"); + QScriptValue obj = eng.newQObject(&enumQObject, QScriptEngine::QtOwnership, + QScriptEngine::QObjectWrapOptions(wrapOptions)); + + // enumerate in script + { + eng.globalObject().setProperty("myEnumObject", obj); + eng.evaluate("var enumeratedProperties = []"); + eng.evaluate("for (var p in myEnumObject) { enumeratedProperties.push(p); }"); + QStringList result = qscriptvalue_cast(eng.evaluate("enumeratedProperties")); + QCOMPARE(result.size(), expectedNames.size()); + for (int i = 0; i < expectedNames.size(); ++i) + QCOMPARE(result.at(i), expectedNames.at(i)); + } + // enumerate in C++ + { + QScriptValueIterator it(obj); + QStringList result; + while (it.hasNext()) { + it.next(); + QCOMPARE(it.flags(), obj.propertyFlags(it.name())); + result.append(it.name()); + } + QCOMPARE(result.size(), expectedNames.size()); + for (int i = 0; i < expectedNames.size(); ++i) + QCOMPARE(result.at(i), expectedNames.at(i)); + } +} + +class SpecialEnumTestObject : public QObject +{ + Q_OBJECT + // overriding a property in the super-class to make it non-scriptable + Q_PROPERTY(QString objectName READ objectName SCRIPTABLE false) +public: + SpecialEnumTestObject(QObject *parent = 0) + : QObject(parent) {} +}; + +class SpecialEnumTestObject2 : public QObject +{ + Q_OBJECT + // overriding a property in the super-class to make it non-designable (but still scriptable) + Q_PROPERTY(QString objectName READ objectName DESIGNABLE false) +public: + SpecialEnumTestObject2(QObject *parent = 0) + : QObject(parent) {} +}; + +void tst_QScriptExtQObject::enumerateSpecial() +{ + QScriptEngine eng; + { + SpecialEnumTestObject testObj; + QScriptValueIterator it(eng.newQObject(&testObj)); + bool objectNameEncountered = false; + while (it.hasNext()) { + it.next(); + if (it.name() == QLatin1String("objectName")) { + objectNameEncountered = true; + break; + } + } + QVERIFY(!objectNameEncountered); + } + { + SpecialEnumTestObject2 testObj; + testObj.setObjectName("foo"); + QScriptValueList values; + QScriptValueIterator it(eng.newQObject(&testObj)); + while (it.hasNext()) { + it.next(); + if (it.name() == "objectName") + values.append(it.value()); + } + QCOMPARE(values.size(), 1); + QCOMPARE(values.at(0).toString(), QString::fromLatin1("foo")); + } +} + +void tst_QScriptExtQObject::wrapOptions() +{ + QCOMPARE(m_myObject->setProperty("dynamicProperty", 123), false); + MyQObject *child = new MyQObject(m_myObject); + child->setObjectName("child"); + // exclude child objects + { + QScriptValue obj = m_engine->newQObject(m_myObject, QScriptEngine::QtOwnership, + QScriptEngine::ExcludeChildObjects); + QCOMPARE(obj.property("child").isValid(), false); + obj.setProperty("child", QScriptValue(m_engine, 123)); + QCOMPARE(obj.property("child") + .strictlyEquals(QScriptValue(m_engine, 123)), true); + } + // don't auto-create dynamic properties + { + QScriptValue obj = m_engine->newQObject(m_myObject); + QVERIFY(!m_myObject->dynamicPropertyNames().contains("anotherDynamicProperty")); + obj.setProperty("anotherDynamicProperty", QScriptValue(m_engine, 123)); + QVERIFY(!m_myObject->dynamicPropertyNames().contains("anotherDynamicProperty")); + QCOMPARE(obj.property("anotherDynamicProperty") + .strictlyEquals(QScriptValue(m_engine, 123)), true); + } + // auto-create dynamic properties + { + QScriptValue obj = m_engine->newQObject(m_myObject, QScriptEngine::QtOwnership, + QScriptEngine::AutoCreateDynamicProperties); + QVERIFY(!m_myObject->dynamicPropertyNames().contains("anotherDynamicProperty")); + obj.setProperty("anotherDynamicProperty", QScriptValue(m_engine, 123)); + QVERIFY(m_myObject->dynamicPropertyNames().contains("anotherDynamicProperty")); + QCOMPARE(obj.property("anotherDynamicProperty") + .strictlyEquals(QScriptValue(m_engine, 123)), true); + // task 236685 + { + QScriptValue obj2 = m_engine->newObject(); + obj2.setProperty("notADynamicProperty", 456); + obj.setPrototype(obj2); + QScriptValue ret = obj.property("notADynamicProperty"); + QVERIFY(ret.isNumber()); + QVERIFY(ret.strictlyEquals(obj2.property("notADynamicProperty"))); + } + } + // don't exclude super-class properties + { + QScriptValue obj = m_engine->newQObject(m_myObject); + QVERIFY(obj.property("objectName").isValid()); + QVERIFY(obj.propertyFlags("objectName") & QScriptValue::QObjectMember); + } + // exclude super-class properties + { + QScriptValue obj = m_engine->newQObject(m_myObject, QScriptEngine::QtOwnership, + QScriptEngine::ExcludeSuperClassProperties); + QVERIFY(!obj.property("objectName").isValid()); + QVERIFY(!(obj.propertyFlags("objectName") & QScriptValue::QObjectMember)); + QVERIFY(obj.property("intProperty").isValid()); + QVERIFY(obj.propertyFlags("intProperty") & QScriptValue::QObjectMember); + } + // don't exclude super-class methods + { + QScriptValue obj = m_engine->newQObject(m_myObject); + QVERIFY(obj.property("deleteLater").isValid()); + QVERIFY(obj.propertyFlags("deleteLater") & QScriptValue::QObjectMember); + } + // exclude super-class methods + { + QScriptValue obj = m_engine->newQObject(m_myObject, QScriptEngine::QtOwnership, + QScriptEngine::ExcludeSuperClassMethods); + QVERIFY(!obj.property("deleteLater").isValid()); + QVERIFY(!(obj.propertyFlags("deleteLater") & QScriptValue::QObjectMember)); + QVERIFY(obj.property("mySlot").isValid()); + QVERIFY(obj.propertyFlags("mySlot") & QScriptValue::QObjectMember); + } + // exclude all super-class contents + { + QScriptValue obj = m_engine->newQObject(m_myObject, QScriptEngine::QtOwnership, + QScriptEngine::ExcludeSuperClassContents); + QVERIFY(!obj.property("deleteLater").isValid()); + QVERIFY(!(obj.propertyFlags("deleteLater") & QScriptValue::QObjectMember)); + QVERIFY(obj.property("mySlot").isValid()); + QVERIFY(obj.propertyFlags("mySlot") & QScriptValue::QObjectMember); + + QVERIFY(!obj.property("objectName").isValid()); + QVERIFY(!(obj.propertyFlags("objectName") & QScriptValue::QObjectMember)); + QVERIFY(obj.property("intProperty").isValid()); + QVERIFY(obj.propertyFlags("intProperty") & QScriptValue::QObjectMember); + } + // exclude deleteLater() + { + QScriptValue obj = m_engine->newQObject(m_myObject, QScriptEngine::QtOwnership, + QScriptEngine::ExcludeDeleteLater); + QVERIFY(!obj.property("deleteLater").isValid()); + QVERIFY(!(obj.propertyFlags("deleteLater") & QScriptValue::QObjectMember)); + QVERIFY(obj.property("mySlot").isValid()); + QVERIFY(obj.propertyFlags("mySlot") & QScriptValue::QObjectMember); + + QVERIFY(obj.property("objectName").isValid()); + QVERIFY(obj.propertyFlags("objectName") & QScriptValue::QObjectMember); + QVERIFY(obj.property("intProperty").isValid()); + QVERIFY(obj.propertyFlags("intProperty") & QScriptValue::QObjectMember); + } + // exclude all that we can + { + QScriptValue obj = m_engine->newQObject(m_myObject, QScriptEngine::QtOwnership, + QScriptEngine::ExcludeSuperClassMethods + | QScriptEngine::ExcludeSuperClassProperties + | QScriptEngine::ExcludeChildObjects); + QVERIFY(!obj.property("deleteLater").isValid()); + QVERIFY(!(obj.propertyFlags("deleteLater") & QScriptValue::QObjectMember)); + QVERIFY(obj.property("mySlot").isValid()); + QVERIFY(obj.propertyFlags("mySlot") & QScriptValue::QObjectMember); + + QVERIFY(!obj.property("objectName").isValid()); + QVERIFY(!(obj.propertyFlags("objectName") & QScriptValue::QObjectMember)); + QVERIFY(obj.property("intProperty").isValid()); + QVERIFY(obj.propertyFlags("intProperty") & QScriptValue::QObjectMember); + + QCOMPARE(obj.property("child").isValid(), false); + obj.setProperty("child", QScriptValue(m_engine, 123)); + QCOMPARE(obj.property("child") + .strictlyEquals(QScriptValue(m_engine, 123)), true); + } + + delete child; +} + +Q_DECLARE_METATYPE(QWidget*) +Q_DECLARE_METATYPE(QPushButton*) + +void tst_QScriptExtQObject::prototypes() +{ + QScriptEngine eng; + QScriptValue widgetProto = eng.newQObject(new QWidget(), QScriptEngine::ScriptOwnership); + eng.setDefaultPrototype(qMetaTypeId(), widgetProto); + QPushButton *pbp = new QPushButton(); + QScriptValue buttonProto = eng.newQObject(pbp, QScriptEngine::ScriptOwnership); + buttonProto.setPrototype(widgetProto); + eng.setDefaultPrototype(qMetaTypeId(), buttonProto); + QPushButton *pb = new QPushButton(); + QScriptValue button = eng.newQObject(pb, QScriptEngine::ScriptOwnership); + QVERIFY(button.prototype().strictlyEquals(buttonProto)); + + buttonProto.setProperty("text", QScriptValue(&eng, "prototype button")); + QCOMPARE(pbp->text(), QLatin1String("prototype button")); + button.setProperty("text", QScriptValue(&eng, "not the prototype button")); + QCOMPARE(pb->text(), QLatin1String("not the prototype button")); + QCOMPARE(pbp->text(), QLatin1String("prototype button")); + + buttonProto.setProperty("objectName", QScriptValue(&eng, "prototype button")); + QCOMPARE(pbp->objectName(), QLatin1String("prototype button")); + button.setProperty("objectName", QScriptValue(&eng, "not the prototype button")); + QCOMPARE(pb->objectName(), QLatin1String("not the prototype button")); + QCOMPARE(pbp->objectName(), QLatin1String("prototype button")); +} + +void tst_QScriptExtQObject::objectDeleted() +{ + QScriptEngine eng; + MyQObject *qobj = new MyQObject(); + QScriptValue v = eng.newQObject(qobj); + v.setProperty("objectName", QScriptValue(&eng, "foo")); + QCOMPARE(qobj->objectName(), QLatin1String("foo")); + v.setProperty("intProperty", QScriptValue(&eng, 123)); + QCOMPARE(qobj->intProperty(), 123); + qobj->resetQtFunctionInvoked(); + v.property("myInvokable").call(v); + QCOMPARE(qobj->qtFunctionInvoked(), 0); + + // now delete the object + delete qobj; + + // the documented behavior is: isQObject() should still return true, + // but toQObject() should return 0 + QVERIFY(v.isQObject()); + QCOMPARE(v.toQObject(), (QObject *)0); + + // any attempt to access properties of the object should result in an exception + { + QScriptValue ret = v.property("objectName"); + QVERIFY(ret.isError()); + QCOMPARE(ret.toString(), QLatin1String("Error: cannot access member `objectName' of deleted QObject")); + } + { + eng.evaluate("Object"); + QVERIFY(!eng.hasUncaughtException()); + v.setProperty("objectName", QScriptValue(&eng, "foo")); + QVERIFY(eng.hasUncaughtException()); + QVERIFY(eng.uncaughtException().isError()); + QCOMPARE(eng.uncaughtException().toString(), QLatin1String("Error: cannot access member `objectName' of deleted QObject")); + } + + { + QScriptValue ret = v.call(); + QVERIFY(!ret.isValid()); + } + + // myInvokable is stored in member table (since we've accessed it before deletion) + QVERIFY(v.property("myInvokable").isFunction()); + { + QScriptValue ret = v.property("myInvokable").call(v); + QVERIFY(ret.isError()); + QCOMPARE(ret.toString(), QLatin1String("Error: cannot call function of deleted QObject")); + } + // myInvokableWithIntArg is not stored in member table (since we've not accessed it) + { + QScriptValue ret = v.property("myInvokableWithIntArg"); + QVERIFY(ret.isError()); + QCOMPARE(ret.toString(), QLatin1String("Error: cannot access member `myInvokableWithIntArg' of deleted QObject")); + } + + // access from script + eng.globalObject().setProperty("o", v); + { + QScriptValue ret = eng.evaluate("o()"); + QVERIFY(ret.isError()); + QCOMPARE(ret.toString(), QLatin1String("TypeError: o is not a function")); + } + { + QScriptValue ret = eng.evaluate("o.objectName"); + QVERIFY(ret.isError()); + QCOMPARE(ret.toString(), QLatin1String("Error: cannot access member `objectName' of deleted QObject")); + } + { + QScriptValue ret = eng.evaluate("o.myInvokable()"); + QVERIFY(ret.isError()); + QCOMPARE(ret.toString(), QLatin1String("Error: cannot call function of deleted QObject")); + } + { + QScriptValue ret = eng.evaluate("o.myInvokableWithIntArg(10)"); + QVERIFY(ret.isError()); + QCOMPARE(ret.toString(), QLatin1String("Error: cannot access member `myInvokableWithIntArg' of deleted QObject")); + } +} + +void tst_QScriptExtQObject::connectToDestroyedSignal() +{ + // ### the following test currently depends on signal emission order +#if 0 + { + // case 1: deleted when the engine is not doing GC + QScriptEngine eng; + QObject *obj = new QObject(); + eng.globalObject().setProperty("o", eng.newQObject(obj, QScriptEngine::QtOwnership)); + eng.evaluate("o.destroyed.connect(function() { wasDestroyed = true; })"); + eng.evaluate("wasDestroyed = false"); + delete obj; + QVERIFY(eng.evaluate("wasDestroyed").toBoolean()); + } + { + // case 2: deleted when the engine is doing GC + QScriptEngine eng; + QObject *obj = new QObject(); + eng.globalObject().setProperty("o", eng.newQObject(obj, QScriptEngine::ScriptOwnership)); + eng.evaluate("o.destroyed.connect(function() { wasDestroyed = true; })"); + eng.evaluate("wasDestroyed = false"); + eng.evaluate("o = null"); + eng.collectGarbage(); + QVERIFY(eng.evaluate("wasDestroyed").toBoolean()); + } + { + // case 3: deleted when the engine is destroyed + QScriptEngine eng; + QObject *obj = new QObject(); + eng.globalObject().setProperty("o", eng.newQObject(obj, QScriptEngine::ScriptOwnership)); + eng.evaluate("o.destroyed.connect(function() { })"); + // the signal handler won't get called -- we don't want to crash + } +#endif +} + +QTEST_MAIN(tst_QScriptExtQObject) +#include "tst_qscriptextqobject.moc" diff --git a/tests/auto/qscriptjstestsuite/tst_qscriptjstestsuite.cpp b/tests/auto/qscriptjstestsuite/tst_qscriptjstestsuite.cpp index 66004f8..4f6f38e 100644 --- a/tests/auto/qscriptjstestsuite/tst_qscriptjstestsuite.cpp +++ b/tests/auto/qscriptjstestsuite/tst_qscriptjstestsuite.cpp @@ -785,6 +785,8 @@ tst_Suite::tst_Suite() addFileExclusion("regress-322135-04.js", "takes forever"); addFileExclusion("ecma_3/RegExp/regress-375715-04.js", "bug"); + static const char klass[] = "tst_QScriptJsTestSuite"; + QVector *data = qt_meta_data_tst_Suite(); // content: *data << 1 // revision @@ -796,7 +798,7 @@ tst_Suite::tst_Suite() ; QVector *stringdata = qt_meta_stringdata_tst_Suite(); - appendCString(stringdata, "tst_Suite"); + appendCString(stringdata, klass); appendCString(stringdata, ""); // don't execute any tests on slow machines @@ -814,11 +816,12 @@ tst_Suite::tst_Suite() // slot: signature, parameters, type, tag, flags QString data_slot = QString::fromLatin1("%0/%1_data()") .arg(testSuiteDir.dirName()).arg(ssdi.fileName()); - *data << stringdata->size() << 10 << 10 << 10 << 0x08; + static const int nullbyte = sizeof(klass); + *data << stringdata->size() << nullbyte << nullbyte << nullbyte << 0x08; appendCString(stringdata, data_slot.toLatin1()); QString slot = QString::fromLatin1("%0/%1()") .arg(testSuiteDir.dirName()).arg(ssdi.fileName()); - *data << stringdata->size() << 10 << 10 << 10 << 0x08; + *data << stringdata->size() << nullbyte << nullbyte << nullbyte << 0x08; appendCString(stringdata, slot.toLatin1()); } } diff --git a/tests/auto/qscriptqobject/.gitignore b/tests/auto/qscriptqobject/.gitignore deleted file mode 100644 index bff799f..0000000 --- a/tests/auto/qscriptqobject/.gitignore +++ /dev/null @@ -1 +0,0 @@ -tst_qscriptqobject diff --git a/tests/auto/qscriptqobject/qscriptqobject.pro b/tests/auto/qscriptqobject/qscriptqobject.pro deleted file mode 100644 index e4e2b56..0000000 --- a/tests/auto/qscriptqobject/qscriptqobject.pro +++ /dev/null @@ -1,5 +0,0 @@ -load(qttest_p4) -QT += script -SOURCES += tst_qscriptqobject.cpp - - diff --git a/tests/auto/qscriptqobject/tst_qscriptqobject.cpp b/tests/auto/qscriptqobject/tst_qscriptqobject.cpp deleted file mode 100644 index 73400b2..0000000 --- a/tests/auto/qscriptqobject/tst_qscriptqobject.cpp +++ /dev/null @@ -1,2734 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** 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 either Technology Preview License Agreement or the -** Beta Release License Agreement. -** -** 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.0, included in the file LGPL_EXCEPTION.txt in this -** package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** If you are unsure which license is appropriate for your use, please -** contact the sales department at http://www.qtsoftware.com/contact. -** $QT_END_LICENSE$ -** -****************************************************************************/ - - -#include - -#include -#include -#include -#include -#include -#include - -//TESTED_CLASS= -//TESTED_FILES=script/qscriptextqobject_p.h script/qscriptextqobject.cpp - -struct CustomType -{ - QString string; -}; -Q_DECLARE_METATYPE(CustomType) - -Q_DECLARE_METATYPE(QBrush*) -Q_DECLARE_METATYPE(QObjectList) -Q_DECLARE_METATYPE(QList) -Q_DECLARE_METATYPE(Qt::BrushStyle) -Q_DECLARE_METATYPE(QDir) - -static void dirFromScript(const QScriptValue &in, QDir &out) -{ - QScriptValue path = in.property("path"); - if (!path.isValid()) - in.engine()->currentContext()->throwError("No path"); - else - out.setPath(path.toString()); -} - -namespace MyNS -{ - class A : public QObject - { - Q_OBJECT - public: - enum Type { - Foo, - Bar - }; - Q_ENUMS(Type) - public Q_SLOTS: - int slotTakingScopedEnumArg(MyNS::A::Type t) { - return t; - } - }; -} - -class MyQObject : public QObject -{ - Q_OBJECT - - Q_PROPERTY(int intProperty READ intProperty WRITE setIntProperty) - Q_PROPERTY(QVariant variantProperty READ variantProperty WRITE setVariantProperty) - Q_PROPERTY(QVariantList variantListProperty READ variantListProperty WRITE setVariantListProperty) - Q_PROPERTY(QString stringProperty READ stringProperty WRITE setStringProperty) - Q_PROPERTY(QStringList stringListProperty READ stringListProperty WRITE setStringListProperty) - Q_PROPERTY(QByteArray byteArrayProperty READ byteArrayProperty WRITE setByteArrayProperty) - Q_PROPERTY(QBrush brushProperty READ brushProperty WRITE setBrushProperty) - Q_PROPERTY(double hiddenProperty READ hiddenProperty WRITE setHiddenProperty SCRIPTABLE false) - Q_PROPERTY(int writeOnlyProperty WRITE setWriteOnlyProperty) - Q_PROPERTY(int readOnlyProperty READ readOnlyProperty) - Q_PROPERTY(QKeySequence shortcut READ shortcut WRITE setShortcut) - Q_PROPERTY(CustomType propWithCustomType READ propWithCustomType WRITE setPropWithCustomType) - Q_ENUMS(Policy Strategy) - Q_FLAGS(Ability) - -public: - enum Policy { - FooPolicy = 0, - BarPolicy, - BazPolicy - }; - - enum Strategy { - FooStrategy = 10, - BarStrategy, - BazStrategy - }; - - enum AbilityFlag { - NoAbility = 0x000, - FooAbility = 0x001, - BarAbility = 0x080, - BazAbility = 0x200, - AllAbility = FooAbility | BarAbility | BazAbility - }; - - Q_DECLARE_FLAGS(Ability, AbilityFlag) - - MyQObject(QObject *parent = 0) - : QObject(parent), - m_intValue(123), - m_variantValue(QLatin1String("foo")), - m_variantListValue(QVariantList() << QVariant(123) << QVariant(QLatin1String("foo"))), - m_stringValue(QLatin1String("bar")), - m_stringListValue(QStringList() << QLatin1String("zig") << QLatin1String("zag")), - m_brushValue(QColor(10, 20, 30, 40)), - m_hiddenValue(456.0), - m_writeOnlyValue(789), - m_readOnlyValue(987), - m_qtFunctionInvoked(-1) - { } - - int intProperty() const - { return m_intValue; } - void setIntProperty(int value) - { m_intValue = value; } - - QVariant variantProperty() const - { return m_variantValue; } - void setVariantProperty(const QVariant &value) - { m_variantValue = value; } - - QVariantList variantListProperty() const - { return m_variantListValue; } - void setVariantListProperty(const QVariantList &value) - { m_variantListValue = value; } - - QString stringProperty() const - { return m_stringValue; } - void setStringProperty(const QString &value) - { m_stringValue = value; } - - QStringList stringListProperty() const - { return m_stringListValue; } - void setStringListProperty(const QStringList &value) - { m_stringListValue = value; } - - QByteArray byteArrayProperty() const - { return m_byteArrayValue; } - void setByteArrayProperty(const QByteArray &value) - { m_byteArrayValue = value; } - - QBrush brushProperty() const - { return m_brushValue; } - Q_INVOKABLE void setBrushProperty(const QBrush &value) - { m_brushValue = value; } - - double hiddenProperty() const - { return m_hiddenValue; } - void setHiddenProperty(double value) - { m_hiddenValue = value; } - - int writeOnlyProperty() const - { return m_writeOnlyValue; } - void setWriteOnlyProperty(int value) - { m_writeOnlyValue = value; } - - int readOnlyProperty() const - { return m_readOnlyValue; } - - QKeySequence shortcut() const - { return m_shortcut; } - void setShortcut(const QKeySequence &seq) - { m_shortcut = seq; } - - CustomType propWithCustomType() const - { return m_customType; } - void setPropWithCustomType(const CustomType &c) - { m_customType = c; } - - int qtFunctionInvoked() const - { return m_qtFunctionInvoked; } - - QVariantList qtFunctionActuals() const - { return m_actuals; } - - void resetQtFunctionInvoked() - { m_qtFunctionInvoked = -1; m_actuals.clear(); } - - void clearConnectedSignal() - { m_connectedSignal = QByteArray(); } - void clearDisconnectedSignal() - { m_disconnectedSignal = QByteArray(); } - QByteArray connectedSignal() const - { return m_connectedSignal; } - QByteArray disconnectedSignal() const - { return m_disconnectedSignal; } - - Q_INVOKABLE void myInvokable() - { m_qtFunctionInvoked = 0; } - Q_INVOKABLE void myInvokableWithIntArg(int arg) - { m_qtFunctionInvoked = 1; m_actuals << arg; } - Q_INVOKABLE void myInvokableWithLonglongArg(qlonglong arg) - { m_qtFunctionInvoked = 2; m_actuals << arg; } - Q_INVOKABLE void myInvokableWithFloatArg(float arg) - { m_qtFunctionInvoked = 3; m_actuals << arg; } - Q_INVOKABLE void myInvokableWithDoubleArg(double arg) - { m_qtFunctionInvoked = 4; m_actuals << arg; } - Q_INVOKABLE void myInvokableWithStringArg(const QString &arg) - { m_qtFunctionInvoked = 5; m_actuals << arg; } - Q_INVOKABLE void myInvokableWithIntArgs(int arg1, int arg2) - { m_qtFunctionInvoked = 6; m_actuals << arg1 << arg2; } - Q_INVOKABLE int myInvokableReturningInt() - { m_qtFunctionInvoked = 7; return 123; } - Q_INVOKABLE qlonglong myInvokableReturningLongLong() - { m_qtFunctionInvoked = 39; return 456; } - Q_INVOKABLE QString myInvokableReturningString() - { m_qtFunctionInvoked = 8; return QLatin1String("ciao"); } - Q_INVOKABLE QVariant myInvokableReturningVariant() - { m_qtFunctionInvoked = 60; return 123; } - Q_INVOKABLE QScriptValue myInvokableReturningScriptValue() - { m_qtFunctionInvoked = 61; return 456; } - Q_INVOKABLE void myInvokableWithIntArg(int arg1, int arg2) // overload - { m_qtFunctionInvoked = 9; m_actuals << arg1 << arg2; } - Q_INVOKABLE void myInvokableWithEnumArg(Policy policy) - { m_qtFunctionInvoked = 10; m_actuals << policy; } - Q_INVOKABLE void myInvokableWithQualifiedEnumArg(MyQObject::Policy policy) - { m_qtFunctionInvoked = 36; m_actuals << policy; } - Q_INVOKABLE Policy myInvokableReturningEnum() - { m_qtFunctionInvoked = 37; return BazPolicy; } - Q_INVOKABLE MyQObject::Policy myInvokableReturningQualifiedEnum() - { m_qtFunctionInvoked = 38; return BazPolicy; } - Q_INVOKABLE QVector myInvokableReturningVectorOfInt() - { m_qtFunctionInvoked = 11; return QVector(); } - Q_INVOKABLE void myInvokableWithVectorOfIntArg(const QVector &) - { m_qtFunctionInvoked = 12; } - Q_INVOKABLE QObject *myInvokableReturningQObjectStar() - { m_qtFunctionInvoked = 13; return this; } - Q_INVOKABLE QObjectList myInvokableWithQObjectListArg(const QObjectList &lst) - { m_qtFunctionInvoked = 14; m_actuals << qVariantFromValue(lst); return lst; } - Q_INVOKABLE QVariant myInvokableWithVariantArg(const QVariant &v) - { m_qtFunctionInvoked = 15; m_actuals << v; return v; } - Q_INVOKABLE QVariantMap myInvokableWithVariantMapArg(const QVariantMap &vm) - { m_qtFunctionInvoked = 16; m_actuals << vm; return vm; } - Q_INVOKABLE QList myInvokableWithListOfIntArg(const QList &lst) - { m_qtFunctionInvoked = 17; m_actuals << qVariantFromValue(lst); return lst; } - Q_INVOKABLE QObject* myInvokableWithQObjectStarArg(QObject *obj) - { m_qtFunctionInvoked = 18; m_actuals << qVariantFromValue(obj); return obj; } - Q_INVOKABLE QBrush myInvokableWithQBrushArg(const QBrush &brush) - { m_qtFunctionInvoked = 19; m_actuals << qVariantFromValue(brush); return brush; } - Q_INVOKABLE void myInvokableWithBrushStyleArg(Qt::BrushStyle style) - { m_qtFunctionInvoked = 43; m_actuals << qVariantFromValue(style); } - Q_INVOKABLE void myInvokableWithVoidStarArg(void *arg) - { m_qtFunctionInvoked = 44; m_actuals << qVariantFromValue(arg); } - Q_INVOKABLE void myInvokableWithAmbiguousArg(int arg) - { m_qtFunctionInvoked = 45; m_actuals << qVariantFromValue(arg); } - Q_INVOKABLE void myInvokableWithAmbiguousArg(uint arg) - { m_qtFunctionInvoked = 46; m_actuals << qVariantFromValue(arg); } - Q_INVOKABLE void myInvokableWithDefaultArgs(int arg1, const QString &arg2 = "") - { m_qtFunctionInvoked = 47; m_actuals << qVariantFromValue(arg1) << qVariantFromValue(arg2); } - Q_INVOKABLE QObject& myInvokableReturningRef() - { m_qtFunctionInvoked = 48; return *this; } - Q_INVOKABLE const QObject& myInvokableReturningConstRef() const - { const_cast(this)->m_qtFunctionInvoked = 49; return *this; } - Q_INVOKABLE void myInvokableWithPointArg(const QPoint &arg) - { const_cast(this)->m_qtFunctionInvoked = 50; m_actuals << qVariantFromValue(arg); } - Q_INVOKABLE void myInvokableWithPointArg(const QPointF &arg) - { const_cast(this)->m_qtFunctionInvoked = 51; m_actuals << qVariantFromValue(arg); } - Q_INVOKABLE void myInvokableWithMyQObjectArg(MyQObject *arg) - { m_qtFunctionInvoked = 52; m_actuals << qVariantFromValue((QObject*)arg); } - Q_INVOKABLE MyQObject* myInvokableReturningMyQObject() - { m_qtFunctionInvoked = 53; return this; } - Q_INVOKABLE void myInvokableWithConstMyQObjectArg(const MyQObject *arg) - { m_qtFunctionInvoked = 54; m_actuals << qVariantFromValue((QObject*)arg); } - Q_INVOKABLE void myInvokableWithQDirArg(const QDir &arg) - { m_qtFunctionInvoked = 55; m_actuals << qVariantFromValue(arg); } - Q_INVOKABLE QScriptValue myInvokableWithScriptValueArg(const QScriptValue &arg) - { m_qtFunctionInvoked = 56; return arg; } - Q_INVOKABLE QObject* myInvokableReturningMyQObjectAsQObject() - { m_qtFunctionInvoked = 57; return this; } - - void emitMySignal() - { emit mySignal(); } - void emitMySignalWithIntArg(int arg) - { emit mySignalWithIntArg(arg); } - void emitMySignal2(bool arg) - { emit mySignal2(arg); } - void emitMySignal2() - { emit mySignal2(); } - void emitMyOverloadedSignal(int arg) - { emit myOverloadedSignal(arg); } - void emitMyOverloadedSignal(const QString &arg) - { emit myOverloadedSignal(arg); } - void emitMyOtherOverloadedSignal(const QString &arg) - { emit myOtherOverloadedSignal(arg); } - void emitMyOtherOverloadedSignal(int arg) - { emit myOtherOverloadedSignal(arg); } - void emitMySignalWithDefaultArgWithArg(int arg) - { emit mySignalWithDefaultArg(arg); } - void emitMySignalWithDefaultArg() - { emit mySignalWithDefaultArg(); } - -public Q_SLOTS: - void mySlot() - { m_qtFunctionInvoked = 20; } - void mySlotWithIntArg(int arg) - { m_qtFunctionInvoked = 21; m_actuals << arg; } - void mySlotWithDoubleArg(double arg) - { m_qtFunctionInvoked = 22; m_actuals << arg; } - void mySlotWithStringArg(const QString &arg) - { m_qtFunctionInvoked = 23; m_actuals << arg; } - - void myOverloadedSlot() - { m_qtFunctionInvoked = 24; } - void myOverloadedSlot(QObject *arg) - { m_qtFunctionInvoked = 41; m_actuals << qVariantFromValue(arg); } - void myOverloadedSlot(bool arg) - { m_qtFunctionInvoked = 25; m_actuals << arg; } - void myOverloadedSlot(const QStringList &arg) - { m_qtFunctionInvoked = 42; m_actuals << arg; } - void myOverloadedSlot(double arg) - { m_qtFunctionInvoked = 26; m_actuals << arg; } - void myOverloadedSlot(float arg) - { m_qtFunctionInvoked = 27; m_actuals << arg; } - void myOverloadedSlot(int arg) - { m_qtFunctionInvoked = 28; m_actuals << arg; } - void myOverloadedSlot(const QString &arg) - { m_qtFunctionInvoked = 29; m_actuals << arg; } - void myOverloadedSlot(const QColor &arg) - { m_qtFunctionInvoked = 30; m_actuals << arg; } - void myOverloadedSlot(const QBrush &arg) - { m_qtFunctionInvoked = 31; m_actuals << arg; } - void myOverloadedSlot(const QDateTime &arg) - { m_qtFunctionInvoked = 32; m_actuals << arg; } - void myOverloadedSlot(const QDate &arg) - { m_qtFunctionInvoked = 33; m_actuals << arg; } - void myOverloadedSlot(const QRegExp &arg) - { m_qtFunctionInvoked = 34; m_actuals << arg; } - void myOverloadedSlot(const QVariant &arg) - { m_qtFunctionInvoked = 35; m_actuals << arg; } - - virtual int myVirtualSlot(int arg) - { m_qtFunctionInvoked = 58; return arg; } - - void qscript_call(int arg) - { m_qtFunctionInvoked = 40; m_actuals << arg; } - -protected Q_SLOTS: - void myProtectedSlot() { m_qtFunctionInvoked = 36; } - -private Q_SLOTS: - void myPrivateSlot() { } - -Q_SIGNALS: - void mySignal(); - void mySignalWithIntArg(int arg); - void mySignalWithDoubleArg(double arg); - void mySignal2(bool arg = false); - void myOverloadedSignal(int arg); - void myOverloadedSignal(const QString &arg); - void myOtherOverloadedSignal(const QString &arg); - void myOtherOverloadedSignal(int arg); - void mySignalWithDefaultArg(int arg = 123); - -protected: - void connectNotify(const char *signal) { - m_connectedSignal = signal; - } - void disconnectNotify(const char *signal) { - m_disconnectedSignal = signal; - } - -protected: - int m_intValue; - QVariant m_variantValue; - QVariantList m_variantListValue; - QString m_stringValue; - QStringList m_stringListValue; - QByteArray m_byteArrayValue; - QBrush m_brushValue; - double m_hiddenValue; - int m_writeOnlyValue; - int m_readOnlyValue; - QKeySequence m_shortcut; - CustomType m_customType; - int m_qtFunctionInvoked; - QVariantList m_actuals; - QByteArray m_connectedSignal; - QByteArray m_disconnectedSignal; -}; - -Q_DECLARE_METATYPE(MyQObject*) - -class MyOtherQObject : public MyQObject -{ - Q_OBJECT -public: - MyOtherQObject(QObject *parent = 0) - : MyQObject(parent) - { } -public Q_SLOTS: - virtual int myVirtualSlot(int arg) - { m_qtFunctionInvoked = 59; return arg; } -}; - -class MyEnumTestQObject : public QObject -{ - Q_OBJECT - Q_PROPERTY(QString p1 READ p1) - Q_PROPERTY(QString p2 READ p2) - Q_PROPERTY(QString p3 READ p3 SCRIPTABLE false) - Q_PROPERTY(QString p4 READ p4) - Q_PROPERTY(QString p5 READ p5 SCRIPTABLE false) - Q_PROPERTY(QString p6 READ p6) -public: - MyEnumTestQObject(QObject *parent = 0) - : QObject(parent) { } - QString p1() const { return QLatin1String("p1"); } - QString p2() const { return QLatin1String("p2"); } - QString p3() const { return QLatin1String("p3"); } - QString p4() const { return QLatin1String("p4"); } - QString p5() const { return QLatin1String("p5"); } - QString p6() const { return QLatin1String("p5"); } -public Q_SLOTS: - void mySlot() { } - void myOtherSlot() { } -Q_SIGNALS: - void mySignal(); -}; - -class tst_QScriptExtQObject : public QObject -{ - Q_OBJECT - -public: - tst_QScriptExtQObject(); - virtual ~tst_QScriptExtQObject(); - -public slots: - void init(); - void cleanup(); - -protected slots: - void onSignalHandlerException(const QScriptValue &exception) - { - m_signalHandlerException = exception; - } - -private slots: - void getSetStaticProperty(); - void getSetDynamicProperty(); - void getSetChildren(); - void callQtInvokable(); - void connectAndDisconnect(); - void cppConnectAndDisconnect(); - void classEnums(); - void classConstructor(); - void overrideInvokable(); - void transferInvokable(); - void findChild(); - void findChildren(); - void overloadedSlots(); - void enumerate_data(); - void enumerate(); - void enumerateSpecial(); - void wrapOptions(); - void prototypes(); - void objectDeleted(); - void connectToDestroyedSignal(); - -private: - QScriptEngine *m_engine; - MyQObject *m_myObject; - QScriptValue m_signalHandlerException; -}; - -tst_QScriptExtQObject::tst_QScriptExtQObject() -{ -} - -tst_QScriptExtQObject::~tst_QScriptExtQObject() -{ -} - -void tst_QScriptExtQObject::init() -{ - m_engine = new QScriptEngine(); - m_myObject = new MyQObject(); - m_engine->globalObject().setProperty("myObject", m_engine->newQObject(m_myObject)); - m_engine->globalObject().setProperty("global", m_engine->globalObject()); -} - -void tst_QScriptExtQObject::cleanup() -{ - delete m_engine; - delete m_myObject; -} - -static QScriptValue getSetProperty(QScriptContext *ctx, QScriptEngine *) -{ - if (ctx->argumentCount() != 0) - ctx->callee().setProperty("value", ctx->argument(0)); - return ctx->callee().property("value"); -} - -void tst_QScriptExtQObject::getSetStaticProperty() -{ - QCOMPARE(m_engine->evaluate("myObject.noSuchProperty").isUndefined(), true); - - // initial value (set in MyQObject constructor) - QCOMPARE(m_engine->evaluate("myObject.intProperty") - .strictlyEquals(QScriptValue(m_engine, 123.0)), true); - QCOMPARE(m_engine->evaluate("myObject.variantProperty") - .toVariant(), QVariant(QLatin1String("foo"))); - QCOMPARE(m_engine->evaluate("myObject.stringProperty") - .strictlyEquals(QScriptValue(m_engine, QLatin1String("bar"))), true); - QCOMPARE(m_engine->evaluate("myObject.variantListProperty").isArray(), true); - QCOMPARE(m_engine->evaluate("myObject.variantListProperty.length") - .strictlyEquals(QScriptValue(m_engine, 2)), true); - QCOMPARE(m_engine->evaluate("myObject.variantListProperty[0]") - .strictlyEquals(QScriptValue(m_engine, 123)), true); - QCOMPARE(m_engine->evaluate("myObject.variantListProperty[1]") - .strictlyEquals(QScriptValue(m_engine, QLatin1String("foo"))), true); - QCOMPARE(m_engine->evaluate("myObject.stringListProperty").isArray(), true); - QCOMPARE(m_engine->evaluate("myObject.stringListProperty.length") - .strictlyEquals(QScriptValue(m_engine, 2)), true); - QCOMPARE(m_engine->evaluate("myObject.stringListProperty[0]").isString(), true); - QCOMPARE(m_engine->evaluate("myObject.stringListProperty[0]").toString(), - QLatin1String("zig")); - QCOMPARE(m_engine->evaluate("myObject.stringListProperty[1]").isString(), true); - QCOMPARE(m_engine->evaluate("myObject.stringListProperty[1]").toString(), - QLatin1String("zag")); - - // default flags for "normal" properties - { - QScriptValue mobj = m_engine->globalObject().property("myObject"); - QVERIFY(!(mobj.propertyFlags("intProperty") & QScriptValue::ReadOnly)); - QVERIFY(mobj.propertyFlags("intProperty") & QScriptValue::Undeletable); - QVERIFY(mobj.propertyFlags("intProperty") & QScriptValue::PropertyGetter); - QVERIFY(mobj.propertyFlags("intProperty") & QScriptValue::PropertySetter); - QVERIFY(!(mobj.propertyFlags("intProperty") & QScriptValue::SkipInEnumeration)); - QVERIFY(mobj.propertyFlags("intProperty") & QScriptValue::QObjectMember); - - QVERIFY(!(mobj.propertyFlags("mySlot") & QScriptValue::ReadOnly)); - QVERIFY(!(mobj.propertyFlags("mySlot") & QScriptValue::Undeletable)); - QVERIFY(!(mobj.propertyFlags("mySlot") & QScriptValue::SkipInEnumeration)); - QVERIFY(mobj.propertyFlags("mySlot") & QScriptValue::QObjectMember); - } - - // property change in C++ should be reflected in script - m_myObject->setIntProperty(456); - QCOMPARE(m_engine->evaluate("myObject.intProperty") - .strictlyEquals(QScriptValue(m_engine, 456)), true); - m_myObject->setIntProperty(789); - QCOMPARE(m_engine->evaluate("myObject.intProperty") - .strictlyEquals(QScriptValue(m_engine, 789)), true); - - m_myObject->setVariantProperty(QLatin1String("bar")); - QVERIFY(m_engine->evaluate("myObject.variantProperty") - .strictlyEquals(QScriptValue(m_engine, QLatin1String("bar")))); - m_myObject->setVariantProperty(42); - QCOMPARE(m_engine->evaluate("myObject.variantProperty") - .toVariant(), QVariant(42)); - m_myObject->setVariantProperty(qVariantFromValue(QBrush())); - QVERIFY(m_engine->evaluate("myObject.variantProperty").isVariant()); - - m_myObject->setStringProperty(QLatin1String("baz")); - QCOMPARE(m_engine->evaluate("myObject.stringProperty") - .equals(QScriptValue(m_engine, QLatin1String("baz"))), true); - m_myObject->setStringProperty(QLatin1String("zab")); - QCOMPARE(m_engine->evaluate("myObject.stringProperty") - .equals(QScriptValue(m_engine, QLatin1String("zab"))), true); - - // property change in script should be reflected in C++ - QCOMPARE(m_engine->evaluate("myObject.intProperty = 123") - .strictlyEquals(QScriptValue(m_engine, 123)), true); - QCOMPARE(m_engine->evaluate("myObject.intProperty") - .strictlyEquals(QScriptValue(m_engine, 123)), true); - QCOMPARE(m_myObject->intProperty(), 123); - QCOMPARE(m_engine->evaluate("myObject.intProperty = 'ciao!';" - "myObject.intProperty") - .strictlyEquals(QScriptValue(m_engine, 0)), true); - QCOMPARE(m_myObject->intProperty(), 0); - QCOMPARE(m_engine->evaluate("myObject.intProperty = '123';" - "myObject.intProperty") - .strictlyEquals(QScriptValue(m_engine, 123)), true); - QCOMPARE(m_myObject->intProperty(), 123); - - QCOMPARE(m_engine->evaluate("myObject.stringProperty = 'ciao'") - .strictlyEquals(QScriptValue(m_engine, QLatin1String("ciao"))), true); - QCOMPARE(m_engine->evaluate("myObject.stringProperty") - .strictlyEquals(QScriptValue(m_engine, QLatin1String("ciao"))), true); - QCOMPARE(m_myObject->stringProperty(), QLatin1String("ciao")); - QCOMPARE(m_engine->evaluate("myObject.stringProperty = 123;" - "myObject.stringProperty") - .strictlyEquals(QScriptValue(m_engine, QLatin1String("123"))), true); - QCOMPARE(m_myObject->stringProperty(), QLatin1String("123")); - QVERIFY(m_engine->evaluate("myObject.stringProperty = null;" - "myObject.stringProperty") - .strictlyEquals(QScriptValue(m_engine, QString()))); - QCOMPARE(m_myObject->stringProperty(), QString()); - QVERIFY(m_engine->evaluate("myObject.stringProperty = undefined;" - "myObject.stringProperty") - .strictlyEquals(QScriptValue(m_engine, QString()))); - QCOMPARE(m_myObject->stringProperty(), QString()); - - QCOMPARE(m_engine->evaluate("myObject.variantProperty = 'foo';" - "myObject.variantProperty.valueOf()").toString(), QLatin1String("foo")); - QCOMPARE(m_myObject->variantProperty(), QVariant(QLatin1String("foo"))); - QVERIFY(m_engine->evaluate("myObject.variantProperty = undefined;" - "myObject.variantProperty").isUndefined()); - QVERIFY(!m_myObject->variantProperty().isValid()); - QVERIFY(m_engine->evaluate("myObject.variantProperty = null;" - "myObject.variantProperty").isUndefined()); - QVERIFY(!m_myObject->variantProperty().isValid()); - QCOMPARE(m_engine->evaluate("myObject.variantProperty = 42;" - "myObject.variantProperty").toNumber(), 42.0); - QCOMPARE(m_myObject->variantProperty().toDouble(), 42.0); - - QCOMPARE(m_engine->evaluate("myObject.variantListProperty = [1, 'two', true];" - "myObject.variantListProperty.length") - .strictlyEquals(QScriptValue(m_engine, 3)), true); - QCOMPARE(m_engine->evaluate("myObject.variantListProperty[0]") - .strictlyEquals(QScriptValue(m_engine, 1)), true); - QCOMPARE(m_engine->evaluate("myObject.variantListProperty[1]") - .strictlyEquals(QScriptValue(m_engine, QLatin1String("two"))), true); - QCOMPARE(m_engine->evaluate("myObject.variantListProperty[2]") - .strictlyEquals(QScriptValue(m_engine, true)), true); - { - QVariantList vl = qscriptvalue_cast(m_engine->evaluate("myObject.variantListProperty")); - QCOMPARE(vl, QVariantList() - << QVariant(1) - << QVariant(QLatin1String("two")) - << QVariant(true)); - } - - QCOMPARE(m_engine->evaluate("myObject.stringListProperty = [1, 'two', true];" - "myObject.stringListProperty.length") - .strictlyEquals(QScriptValue(m_engine, 3)), true); - QCOMPARE(m_engine->evaluate("myObject.stringListProperty[0]").isString(), true); - QCOMPARE(m_engine->evaluate("myObject.stringListProperty[0]").toString(), - QLatin1String("1")); - QCOMPARE(m_engine->evaluate("myObject.stringListProperty[1]").isString(), true); - QCOMPARE(m_engine->evaluate("myObject.stringListProperty[1]").toString(), - QLatin1String("two")); - QCOMPARE(m_engine->evaluate("myObject.stringListProperty[2]").isString(), true); - QCOMPARE(m_engine->evaluate("myObject.stringListProperty[2]").toString(), - QLatin1String("true")); - { - QStringList sl = qscriptvalue_cast(m_engine->evaluate("myObject.stringListProperty")); - QCOMPARE(sl, QStringList() - << QLatin1String("1") - << QLatin1String("two") - << QLatin1String("true")); - } - - // test setting properties where we can't convert the type natively but where the - // types happen to be compatible variant types already - { - QKeySequence sequence(Qt::ControlModifier + Qt::AltModifier + Qt::Key_Delete); - QScriptValue mobj = m_engine->globalObject().property("myObject"); - - QVERIFY(m_myObject->shortcut().isEmpty()); - mobj.setProperty("shortcut", m_engine->newVariant(sequence)); - QVERIFY(m_myObject->shortcut() == sequence); - } - { - CustomType t; t.string = "hello"; - QScriptValue mobj = m_engine->globalObject().property("myObject"); - - QVERIFY(m_myObject->propWithCustomType().string.isEmpty()); - mobj.setProperty("propWithCustomType", m_engine->newVariant(qVariantFromValue(t))); - QVERIFY(m_myObject->propWithCustomType().string == t.string); - } - - // test that we do value conversion if necessary when setting properties - { - QScriptValue br = m_engine->evaluate("myObject.brushProperty"); - QCOMPARE(qscriptvalue_cast(br), m_myObject->brushProperty()); - QCOMPARE(qscriptvalue_cast(br), m_myObject->brushProperty().color()); - - QColor newColor(40, 30, 20, 10); - QScriptValue val = qScriptValueFromValue(m_engine, newColor); - m_engine->globalObject().setProperty("myColor", val); - QScriptValue ret = m_engine->evaluate("myObject.brushProperty = myColor"); - QCOMPARE(ret.strictlyEquals(val), true); - br = m_engine->evaluate("myObject.brushProperty"); - QCOMPARE(qscriptvalue_cast(br), QBrush(newColor)); - QCOMPARE(qscriptvalue_cast(br), newColor); - - m_engine->globalObject().setProperty("myColor", QScriptValue()); - } - - // try to delete - QCOMPARE(m_engine->evaluate("delete myObject.intProperty").toBoolean(), false); - QCOMPARE(m_engine->evaluate("myObject.intProperty").toNumber(), 123.0); - - QCOMPARE(m_engine->evaluate("delete myObject.variantProperty").toBoolean(), false); - QCOMPARE(m_engine->evaluate("myObject.variantProperty").toNumber(), 42.0); - - // non-scriptable property - QCOMPARE(m_myObject->hiddenProperty(), 456.0); - QCOMPARE(m_engine->evaluate("myObject.hiddenProperty").isUndefined(), true); - QCOMPARE(m_engine->evaluate("myObject.hiddenProperty = 123;" - "myObject.hiddenProperty").toInt32(), 123); - QCOMPARE(m_myObject->hiddenProperty(), 456.0); - - // write-only property - QCOMPARE(m_myObject->writeOnlyProperty(), 789); - QCOMPARE(m_engine->evaluate("myObject.writeOnlyProperty").isUndefined(), true); - QCOMPARE(m_engine->evaluate("myObject.writeOnlyProperty = 123;" - "myObject.writeOnlyProperty").isUndefined(), true); - QCOMPARE(m_myObject->writeOnlyProperty(), 123); - - // read-only property - QCOMPARE(m_myObject->readOnlyProperty(), 987); - QCOMPARE(m_engine->evaluate("myObject.readOnlyProperty").toInt32(), 987); - QCOMPARE(m_engine->evaluate("myObject.readOnlyProperty = 654;" - "myObject.readOnlyProperty").toInt32(), 987); - QCOMPARE(m_myObject->readOnlyProperty(), 987); - { - QScriptValue mobj = m_engine->globalObject().property("myObject"); - QCOMPARE(mobj.propertyFlags("readOnlyProperty") & QScriptValue::ReadOnly, - QScriptValue::ReadOnly); - } - - // auto-dereferencing of pointers - { - QBrush b = QColor(0xCA, 0xFE, 0xBA, 0xBE); - QBrush *bp = &b; - QScriptValue bpValue = m_engine->newVariant(qVariantFromValue(bp)); - m_engine->globalObject().setProperty("brushPointer", bpValue); - { - QScriptValue ret = m_engine->evaluate("myObject.setBrushProperty(brushPointer)"); - QCOMPARE(ret.isUndefined(), true); - QCOMPARE(qscriptvalue_cast(m_engine->evaluate("myObject.brushProperty")), b); - } - { - b = QColor(0xDE, 0xAD, 0xBE, 0xEF); - QScriptValue ret = m_engine->evaluate("myObject.brushProperty = brushPointer"); - QCOMPARE(ret.strictlyEquals(bpValue), true); - QCOMPARE(qscriptvalue_cast(m_engine->evaluate("myObject.brushProperty")), b); - } - m_engine->globalObject().setProperty("brushPointer", QScriptValue()); - } - - // try to install custom property getter+setter - { - QScriptValue mobj = m_engine->globalObject().property("myObject"); - QTest::ignoreMessage(QtWarningMsg, "QScriptValue::setProperty() failed: " - "cannot set getter or setter of native property " - "`intProperty'"); - mobj.setProperty("intProperty", m_engine->newFunction(getSetProperty), - QScriptValue::PropertyGetter | QScriptValue::PropertySetter); - } -} - -void tst_QScriptExtQObject::getSetDynamicProperty() -{ - // initially the object does not have the property - QCOMPARE(m_engine->evaluate("myObject.hasOwnProperty('dynamicProperty')") - .strictlyEquals(QScriptValue(m_engine, false)), true); - - // add a dynamic property in C++ - QCOMPARE(m_myObject->setProperty("dynamicProperty", 123), false); - QCOMPARE(m_engine->evaluate("myObject.hasOwnProperty('dynamicProperty')") - .strictlyEquals(QScriptValue(m_engine, true)), true); - QCOMPARE(m_engine->evaluate("myObject.dynamicProperty") - .strictlyEquals(QScriptValue(m_engine, 123)), true); - - // check the flags - { - QScriptValue mobj = m_engine->globalObject().property("myObject"); - QVERIFY(!(mobj.propertyFlags("dynamicProperty") & QScriptValue::ReadOnly)); - QVERIFY(!(mobj.propertyFlags("dynamicProperty") & QScriptValue::Undeletable)); - QVERIFY(!(mobj.propertyFlags("dynamicProperty") & QScriptValue::SkipInEnumeration)); - QVERIFY(mobj.propertyFlags("dynamicProperty") & QScriptValue::QObjectMember); - } - - // property change in script should be reflected in C++ - QCOMPARE(m_engine->evaluate("myObject.dynamicProperty = 'foo';" - "myObject.dynamicProperty") - .strictlyEquals(QScriptValue(m_engine, QLatin1String("foo"))), true); - QCOMPARE(m_myObject->property("dynamicProperty").toString(), QLatin1String("foo")); - - // delete the property - QCOMPARE(m_engine->evaluate("delete myObject.dynamicProperty").toBoolean(), true); - QCOMPARE(m_myObject->property("dynamicProperty").isValid(), false); - QCOMPARE(m_engine->evaluate("myObject.dynamicProperty").isUndefined(), true); - QCOMPARE(m_engine->evaluate("myObject.hasOwnProperty('dynamicProperty')").toBoolean(), false); -} - -void tst_QScriptExtQObject::getSetChildren() -{ - // initially the object does not have the child - QCOMPARE(m_engine->evaluate("myObject.hasOwnProperty('child')") - .strictlyEquals(QScriptValue(m_engine, false)), true); - - // add a child - MyQObject *child = new MyQObject(m_myObject); - child->setObjectName("child"); - QCOMPARE(m_engine->evaluate("myObject.hasOwnProperty('child')") - .strictlyEquals(QScriptValue(m_engine, true)), true); - - // add a grandchild - MyQObject *grandChild = new MyQObject(child); - grandChild->setObjectName("grandChild"); - QCOMPARE(m_engine->evaluate("myObject.child.hasOwnProperty('grandChild')") - .strictlyEquals(QScriptValue(m_engine, true)), true); - - // delete grandchild - delete grandChild; - QCOMPARE(m_engine->evaluate("myObject.child.hasOwnProperty('grandChild')") - .strictlyEquals(QScriptValue(m_engine, false)), true); - - // delete child - delete child; - QCOMPARE(m_engine->evaluate("myObject.hasOwnProperty('child')") - .strictlyEquals(QScriptValue(m_engine, false)), true); - -} - -Q_DECLARE_METATYPE(QVector) -Q_DECLARE_METATYPE(QVector) -Q_DECLARE_METATYPE(QVector) - -template -static QScriptValue qobjectToScriptValue(QScriptEngine *engine, T* const &in) -{ return engine->newQObject(in); } - -template -static void qobjectFromScriptValue(const QScriptValue &object, T* &out) -{ out = qobject_cast(object.toQObject()); } - -void tst_QScriptExtQObject::callQtInvokable() -{ - m_myObject->resetQtFunctionInvoked(); - QCOMPARE(m_engine->evaluate("myObject.myInvokable()").isUndefined(), true); - QCOMPARE(m_myObject->qtFunctionInvoked(), 0); - QCOMPARE(m_myObject->qtFunctionActuals(), QVariantList()); - - // extra arguments should silently be ignored - m_myObject->resetQtFunctionInvoked(); - QCOMPARE(m_engine->evaluate("myObject.myInvokable(10, 20, 30)").isUndefined(), true); - QCOMPARE(m_myObject->qtFunctionInvoked(), 0); - QCOMPARE(m_myObject->qtFunctionActuals(), QVariantList()); - - m_myObject->resetQtFunctionInvoked(); - QCOMPARE(m_engine->evaluate("myObject.myInvokableWithIntArg(123)").isUndefined(), true); - QCOMPARE(m_myObject->qtFunctionInvoked(), 1); - QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); - QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 123); - - m_myObject->resetQtFunctionInvoked(); - QCOMPARE(m_engine->evaluate("myObject.myInvokableWithIntArg('123')").isUndefined(), true); - QCOMPARE(m_myObject->qtFunctionInvoked(), 1); - QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); - QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 123); - - m_myObject->resetQtFunctionInvoked(); - QCOMPARE(m_engine->evaluate("myObject.myInvokableWithLonglongArg(123)").isUndefined(), true); - QCOMPARE(m_myObject->qtFunctionInvoked(), 2); - QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); - QCOMPARE(m_myObject->qtFunctionActuals().at(0).toLongLong(), qlonglong(123)); - - m_myObject->resetQtFunctionInvoked(); - QCOMPARE(m_engine->evaluate("myObject.myInvokableWithFloatArg(123.5)").isUndefined(), true); - QCOMPARE(m_myObject->qtFunctionInvoked(), 3); - QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); - QCOMPARE(m_myObject->qtFunctionActuals().at(0).toDouble(), 123.5); - - m_myObject->resetQtFunctionInvoked(); - QCOMPARE(m_engine->evaluate("myObject.myInvokableWithDoubleArg(123.5)").isUndefined(), true); - QCOMPARE(m_myObject->qtFunctionInvoked(), 4); - QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); - QCOMPARE(m_myObject->qtFunctionActuals().at(0).toDouble(), 123.5); - - m_myObject->resetQtFunctionInvoked(); - QCOMPARE(m_engine->evaluate("myObject.myInvokableWithStringArg('ciao')").isUndefined(), true); - QCOMPARE(m_myObject->qtFunctionInvoked(), 5); - QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); - QCOMPARE(m_myObject->qtFunctionActuals().at(0).toString(), QLatin1String("ciao")); - - m_myObject->resetQtFunctionInvoked(); - QCOMPARE(m_engine->evaluate("myObject.myInvokableWithStringArg(123)").isUndefined(), true); - QCOMPARE(m_myObject->qtFunctionInvoked(), 5); - QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); - QCOMPARE(m_myObject->qtFunctionActuals().at(0).toString(), QLatin1String("123")); - - m_myObject->resetQtFunctionInvoked(); - QVERIFY(m_engine->evaluate("myObject.myInvokableWithStringArg(null)").isUndefined()); - QCOMPARE(m_myObject->qtFunctionInvoked(), 5); - QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); - QCOMPARE(m_myObject->qtFunctionActuals().at(0).type(), QVariant::String); - QCOMPARE(m_myObject->qtFunctionActuals().at(0).toString(), QString()); - - m_myObject->resetQtFunctionInvoked(); - QVERIFY(m_engine->evaluate("myObject.myInvokableWithStringArg(undefined)").isUndefined()); - QCOMPARE(m_myObject->qtFunctionInvoked(), 5); - QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); - QCOMPARE(m_myObject->qtFunctionActuals().at(0).type(), QVariant::String); - QCOMPARE(m_myObject->qtFunctionActuals().at(0).toString(), QString()); - - m_myObject->resetQtFunctionInvoked(); - QCOMPARE(m_engine->evaluate("myObject.myInvokableWithIntArgs(123, 456)").isUndefined(), true); - QCOMPARE(m_myObject->qtFunctionInvoked(), 6); - QCOMPARE(m_myObject->qtFunctionActuals().size(), 2); - QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 123); - QCOMPARE(m_myObject->qtFunctionActuals().at(1).toInt(), 456); - - m_myObject->resetQtFunctionInvoked(); - QCOMPARE(m_engine->evaluate("myObject.myInvokableReturningInt()") - .strictlyEquals(QScriptValue(m_engine, 123)), true); - QCOMPARE(m_myObject->qtFunctionInvoked(), 7); - QCOMPARE(m_myObject->qtFunctionActuals(), QVariantList()); - - m_myObject->resetQtFunctionInvoked(); - QCOMPARE(m_engine->evaluate("myObject.myInvokableReturningLongLong()") - .strictlyEquals(QScriptValue(m_engine, 456)), true); - QCOMPARE(m_myObject->qtFunctionInvoked(), 39); - QCOMPARE(m_myObject->qtFunctionActuals(), QVariantList()); - - m_myObject->resetQtFunctionInvoked(); - QCOMPARE(m_engine->evaluate("myObject.myInvokableReturningString()") - .strictlyEquals(QScriptValue(m_engine, QLatin1String("ciao"))), true); - QCOMPARE(m_myObject->qtFunctionInvoked(), 8); - QCOMPARE(m_myObject->qtFunctionActuals(), QVariantList()); - - m_myObject->resetQtFunctionInvoked(); - QVERIFY(m_engine->evaluate("myObject.myInvokableReturningVariant()") - .strictlyEquals(QScriptValue(m_engine, 123))); - QCOMPARE(m_myObject->qtFunctionInvoked(), 60); - - m_myObject->resetQtFunctionInvoked(); - QVERIFY(m_engine->evaluate("myObject.myInvokableReturningScriptValue()") - .strictlyEquals(QScriptValue(m_engine, 456))); - QCOMPARE(m_myObject->qtFunctionInvoked(), 61); - - m_myObject->resetQtFunctionInvoked(); - QCOMPARE(m_engine->evaluate("myObject.myInvokableWithIntArg(123, 456)").isUndefined(), true); - QCOMPARE(m_myObject->qtFunctionInvoked(), 9); - QCOMPARE(m_myObject->qtFunctionActuals().size(), 2); - QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 123); - QCOMPARE(m_myObject->qtFunctionActuals().at(1).toInt(), 456); - - m_myObject->resetQtFunctionInvoked(); - QVERIFY(m_engine->evaluate("myObject.myInvokableWithVoidStarArg(null)").isUndefined()); - QCOMPARE(m_myObject->qtFunctionInvoked(), 44); - m_myObject->resetQtFunctionInvoked(); - QVERIFY(m_engine->evaluate("myObject.myInvokableWithVoidStarArg(123)").isError()); - QCOMPARE(m_myObject->qtFunctionInvoked(), -1); - - m_myObject->resetQtFunctionInvoked(); - { - QScriptValue ret = m_engine->evaluate("myObject.myInvokableWithAmbiguousArg(123)"); - QVERIFY(ret.isError()); - QCOMPARE(ret.toString(), QLatin1String("TypeError: ambiguous call of overloaded function myInvokableWithAmbiguousArg(); candidates were\n myInvokableWithAmbiguousArg(int)\n myInvokableWithAmbiguousArg(uint)")); - } - - m_myObject->resetQtFunctionInvoked(); - { - QScriptValue ret = m_engine->evaluate("myObject.myInvokableWithDefaultArgs(123, 'hello')"); - QVERIFY(ret.isUndefined()); - QCOMPARE(m_myObject->qtFunctionInvoked(), 47); - QCOMPARE(m_myObject->qtFunctionActuals().size(), 2); - QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 123); - QCOMPARE(m_myObject->qtFunctionActuals().at(1).toString(), QLatin1String("hello")); - } - - m_myObject->resetQtFunctionInvoked(); - { - QScriptValue ret = m_engine->evaluate("myObject.myInvokableWithDefaultArgs(456)"); - QVERIFY(ret.isUndefined()); - QCOMPARE(m_myObject->qtFunctionInvoked(), 47); - QCOMPARE(m_myObject->qtFunctionActuals().size(), 2); - QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 456); - QCOMPARE(m_myObject->qtFunctionActuals().at(1).toString(), QString()); - } - - { - QScriptValue fun = m_engine->evaluate("myObject.myInvokableWithPointArg"); - QVERIFY(fun.isFunction()); - m_myObject->resetQtFunctionInvoked(); - { - QScriptValue ret = fun.call(m_engine->evaluate("myObject"), - QScriptValueList() << qScriptValueFromValue(m_engine, QPoint(10, 20))); - QVERIFY(ret.isUndefined()); - QCOMPARE(m_myObject->qtFunctionInvoked(), 50); - QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); - QCOMPARE(m_myObject->qtFunctionActuals().at(0).toPoint(), QPoint(10, 20)); - } - m_myObject->resetQtFunctionInvoked(); - { - QScriptValue ret = fun.call(m_engine->evaluate("myObject"), - QScriptValueList() << qScriptValueFromValue(m_engine, QPointF(30, 40))); - QVERIFY(ret.isUndefined()); - QCOMPARE(m_myObject->qtFunctionInvoked(), 51); - QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); - QCOMPARE(m_myObject->qtFunctionActuals().at(0).toPointF(), QPointF(30, 40)); - } - } - - // calling function that returns (const)ref - m_myObject->resetQtFunctionInvoked(); - { - QScriptValue ret = m_engine->evaluate("myObject.myInvokableReturningRef()"); - QVERIFY(ret.isUndefined()); - QVERIFY(!m_engine->hasUncaughtException()); - QCOMPARE(m_myObject->qtFunctionInvoked(), 48); - } - m_myObject->resetQtFunctionInvoked(); - { - QScriptValue ret = m_engine->evaluate("myObject.myInvokableReturningConstRef()"); - QVERIFY(ret.isUndefined()); - QVERIFY(!m_engine->hasUncaughtException()); - QCOMPARE(m_myObject->qtFunctionInvoked(), 49); - } - - // first time we expect failure because the metatype is not registered - m_myObject->resetQtFunctionInvoked(); - QCOMPARE(m_engine->evaluate("myObject.myInvokableReturningVectorOfInt()").isError(), true); - QCOMPARE(m_myObject->qtFunctionInvoked(), -1); - - QCOMPARE(m_engine->evaluate("myObject.myInvokableWithVectorOfIntArg(0)").isError(), true); - QCOMPARE(m_myObject->qtFunctionInvoked(), -1); - - // now we register it, and it should work - qScriptRegisterSequenceMetaType >(m_engine); - { - QScriptValue ret = m_engine->evaluate("myObject.myInvokableReturningVectorOfInt()"); - QCOMPARE(ret.isArray(), true); - QCOMPARE(m_myObject->qtFunctionInvoked(), 11); - } - - { - QScriptValue ret = m_engine->evaluate("myObject.myInvokableWithVectorOfIntArg(myObject.myInvokableReturningVectorOfInt())"); - QCOMPARE(ret.isUndefined(), true); - QCOMPARE(m_myObject->qtFunctionInvoked(), 12); - } - - m_myObject->resetQtFunctionInvoked(); - { - QScriptValue ret = m_engine->evaluate("myObject.myInvokableReturningQObjectStar()"); - QCOMPARE(m_myObject->qtFunctionInvoked(), 13); - QCOMPARE(m_myObject->qtFunctionActuals().size(), 0); - QCOMPARE(ret.isQObject(), true); - QCOMPARE(ret.toQObject(), (QObject *)m_myObject); - } - - m_myObject->resetQtFunctionInvoked(); - { - QScriptValue ret = m_engine->evaluate("myObject.myInvokableWithQObjectListArg([myObject])"); - QCOMPARE(m_myObject->qtFunctionInvoked(), 14); - QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); - QCOMPARE(ret.isArray(), true); - QCOMPARE(ret.property(QLatin1String("length")) - .strictlyEquals(QScriptValue(m_engine, 1)), true); - QCOMPARE(ret.property(QLatin1String("0")).isQObject(), true); - QCOMPARE(ret.property(QLatin1String("0")).toQObject(), (QObject *)m_myObject); - } - - m_myObject->resetQtFunctionInvoked(); - { - m_myObject->setVariantProperty(QVariant(123)); - QScriptValue ret = m_engine->evaluate("myObject.myInvokableWithVariantArg(myObject.variantProperty)"); - QVERIFY(ret.isNumber()); - QCOMPARE(m_myObject->qtFunctionInvoked(), 15); - QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); - QCOMPARE(m_myObject->qtFunctionActuals().at(0), m_myObject->variantProperty()); - QVERIFY(ret.strictlyEquals(QScriptValue(m_engine, 123))); - } - - m_myObject->resetQtFunctionInvoked(); - { - m_myObject->setVariantProperty(qVariantFromValue(QBrush())); - QScriptValue ret = m_engine->evaluate("myObject.myInvokableWithVariantArg(myObject.variantProperty)"); - QVERIFY(ret.isVariant()); - QCOMPARE(m_myObject->qtFunctionInvoked(), 15); - QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); - QCOMPARE(ret.toVariant(), m_myObject->qtFunctionActuals().at(0)); - QCOMPARE(ret.toVariant(), m_myObject->variantProperty()); - } - - m_myObject->resetQtFunctionInvoked(); - { - QScriptValue ret = m_engine->evaluate("myObject.myInvokableWithVariantArg(123)"); - QVERIFY(ret.isNumber()); - QCOMPARE(m_myObject->qtFunctionInvoked(), 15); - QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); - QCOMPARE(m_myObject->qtFunctionActuals().at(0), QVariant(123)); - QVERIFY(ret.strictlyEquals(QScriptValue(m_engine, 123))); - } - - m_myObject->resetQtFunctionInvoked(); - { - QScriptValue ret = m_engine->evaluate("myObject.myInvokableWithVariantArg('ciao')"); - QVERIFY(ret.isString()); - QCOMPARE(m_myObject->qtFunctionInvoked(), 15); - QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); - QCOMPARE(m_myObject->qtFunctionActuals().at(0), QVariant(QString::fromLatin1("ciao"))); - QVERIFY(ret.strictlyEquals(QScriptValue(m_engine, QString::fromLatin1("ciao")))); - } - - m_myObject->resetQtFunctionInvoked(); - { - QScriptValue ret = m_engine->evaluate("myObject.myInvokableWithVariantArg(null)"); - QVERIFY(ret.isUndefined()); // invalid QVariant is converted to Undefined - QCOMPARE(m_myObject->qtFunctionInvoked(), 15); - QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); - QCOMPARE(m_myObject->qtFunctionActuals().at(0), QVariant()); - } - - m_myObject->resetQtFunctionInvoked(); - { - QScriptValue ret = m_engine->evaluate("myObject.myInvokableWithVariantArg(undefined)"); - QVERIFY(ret.isUndefined()); - QCOMPARE(m_myObject->qtFunctionInvoked(), 15); - QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); - QCOMPARE(m_myObject->qtFunctionActuals().at(0), QVariant()); - } - - m_engine->globalObject().setProperty("fishy", m_engine->newVariant(123)); - m_engine->evaluate("myObject.myInvokableWithStringArg(fishy)"); - - m_myObject->resetQtFunctionInvoked(); - { - QScriptValue ret = m_engine->evaluate("myObject.myInvokableWithVariantMapArg({ a:123, b:'ciao' })"); - QCOMPARE(m_myObject->qtFunctionInvoked(), 16); - QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); - QVariant v = m_myObject->qtFunctionActuals().at(0); - QCOMPARE(v.userType(), int(QMetaType::QVariantMap)); - QVariantMap vmap = qvariant_cast(v); - QCOMPARE(vmap.keys().size(), 2); - QCOMPARE(vmap.keys().at(0), QLatin1String("a")); - QCOMPARE(vmap.value("a"), QVariant(123)); - QCOMPARE(vmap.keys().at(1), QLatin1String("b")); - QCOMPARE(vmap.value("b"), QVariant("ciao")); - - QCOMPARE(ret.isObject(), true); - QCOMPARE(ret.property("a").strictlyEquals(QScriptValue(m_engine, 123)), true); - QCOMPARE(ret.property("b").strictlyEquals(QScriptValue(m_engine, "ciao")), true); - } - - m_myObject->resetQtFunctionInvoked(); - { - QScriptValue ret = m_engine->evaluate("myObject.myInvokableWithListOfIntArg([1, 5])"); - QCOMPARE(m_myObject->qtFunctionInvoked(), 17); - QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); - QVariant v = m_myObject->qtFunctionActuals().at(0); - QCOMPARE(v.userType(), qMetaTypeId >()); - QList ilst = qvariant_cast >(v); - QCOMPARE(ilst.size(), 2); - QCOMPARE(ilst.at(0), 1); - QCOMPARE(ilst.at(1), 5); - - QCOMPARE(ret.isArray(), true); - QCOMPARE(ret.property("0").strictlyEquals(QScriptValue(m_engine, 1)), true); - QCOMPARE(ret.property("1").strictlyEquals(QScriptValue(m_engine, 5)), true); - } - - m_myObject->resetQtFunctionInvoked(); - { - QScriptValue ret = m_engine->evaluate("myObject.myInvokableWithQObjectStarArg(myObject)"); - QCOMPARE(m_myObject->qtFunctionInvoked(), 18); - QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); - QVariant v = m_myObject->qtFunctionActuals().at(0); - QCOMPARE(v.userType(), int(QMetaType::QObjectStar)); - QCOMPARE(qvariant_cast(v), (QObject *)m_myObject); - - QCOMPARE(ret.isQObject(), true); - QCOMPARE(qscriptvalue_cast(ret), (QObject *)m_myObject); - } - - m_myObject->resetQtFunctionInvoked(); - { - // no implicit conversion from integer to QObject* - QScriptValue ret = m_engine->evaluate("myObject.myInvokableWithQObjectStarArg(123)"); - QCOMPARE(ret.isError(), true); - } - - m_myObject->resetQtFunctionInvoked(); - { - QScriptValue fun = m_engine->evaluate("myObject.myInvokableWithQBrushArg"); - QVERIFY(fun.isFunction()); - QColor color(10, 20, 30, 40); - // QColor should be converted to a QBrush - QScriptValue ret = fun.call(QScriptValue(), QScriptValueList() - << qScriptValueFromValue(m_engine, color)); - QCOMPARE(m_myObject->qtFunctionInvoked(), 19); - QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); - QVariant v = m_myObject->qtFunctionActuals().at(0); - QCOMPARE(v.userType(), int(QMetaType::QBrush)); - QCOMPARE(qvariant_cast(v), color); - - QCOMPARE(qscriptvalue_cast(ret), color); - } - - // private slots should not be part of the QObject binding - QCOMPARE(m_engine->evaluate("myObject.myPrivateSlot").isUndefined(), true); - - // protected slots should be fine - m_myObject->resetQtFunctionInvoked(); - m_engine->evaluate("myObject.myProtectedSlot()"); - QCOMPARE(m_myObject->qtFunctionInvoked(), 36); - - // call with too few arguments - { - QScriptValue ret = m_engine->evaluate("myObject.myInvokableWithIntArg()"); - QVERIFY(ret.isError()); - QCOMPARE(ret.toString(), QLatin1String("SyntaxError: too few arguments in call to myInvokableWithIntArg(); candidates are\n myInvokableWithIntArg(int,int)\n myInvokableWithIntArg(int)")); - } - - // call function where not all types have been registered - m_myObject->resetQtFunctionInvoked(); - { - QScriptValue ret = m_engine->evaluate("myObject.myInvokableWithBrushStyleArg(0)"); - QVERIFY(ret.isError()); - QCOMPARE(ret.toString(), QLatin1String("TypeError: cannot call myInvokableWithBrushStyleArg(): argument 1 has unknown type `Qt::BrushStyle' (register the type with qScriptRegisterMetaType())")); - QCOMPARE(m_myObject->qtFunctionInvoked(), -1); - } - - // call function with incompatible argument type - m_myObject->resetQtFunctionInvoked(); - { - QScriptValue ret = m_engine->evaluate("myObject.myInvokableWithQBrushArg(null)"); - QVERIFY(ret.isError()); - QCOMPARE(ret.toString(), QLatin1String("TypeError: incompatible type of argument(s) in call to myInvokableWithQBrushArg(); candidates were\n myInvokableWithQBrushArg(QBrush)")); - QCOMPARE(m_myObject->qtFunctionInvoked(), -1); - } - - // ability to call a slot with QObject-based arguments, even if those types haven't been registered - m_myObject->resetQtFunctionInvoked(); - { - QScriptValue ret = m_engine->evaluate("myObject.myInvokableWithMyQObjectArg(myObject)"); - QCOMPARE(m_myObject->qtFunctionInvoked(), 52); - QVERIFY(ret.isUndefined()); - QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); - QCOMPARE(qvariant_cast(m_myObject->qtFunctionActuals().at(0)), (QObject*)m_myObject); - } - - // inability to call a slot returning QObject-based type, when that type hasn't been registered - m_myObject->resetQtFunctionInvoked(); - { - QScriptValue ret = m_engine->evaluate("myObject.myInvokableReturningMyQObject()"); - QVERIFY(ret.isError()); - QCOMPARE(ret.toString(), QString::fromLatin1("TypeError: cannot call myInvokableReturningMyQObject(): unknown return type `MyQObject*' (register the type with qScriptRegisterMetaType())")); - } - - // ability to call a slot returning QObject-based type when that type has been registered - qRegisterMetaType("MyQObject*"); - m_myObject->resetQtFunctionInvoked(); - { - QScriptValue ret = m_engine->evaluate("myObject.myInvokableReturningMyQObject()"); - QCOMPARE(m_myObject->qtFunctionInvoked(), 53); - QVERIFY(ret.isVariant()); - QCOMPARE(*reinterpret_cast(ret.toVariant().constData()), m_myObject); - } - - // ability to call a slot with QObject-based argument, when the argument is const - m_myObject->resetQtFunctionInvoked(); - { - QScriptValue ret = m_engine->evaluate("myObject.myInvokableWithConstMyQObjectArg(myObject)"); - QCOMPARE(m_myObject->qtFunctionInvoked(), 54); - QVERIFY(ret.isUndefined()); - QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); - QCOMPARE(qvariant_cast(m_myObject->qtFunctionActuals().at(0)), (QObject*)m_myObject); - } - - // QScriptValue arguments should be passed on without conversion - m_myObject->resetQtFunctionInvoked(); - { - QScriptValue ret = m_engine->evaluate("myObject.myInvokableWithScriptValueArg(123)"); - QCOMPARE(m_myObject->qtFunctionInvoked(), 56); - QVERIFY(ret.isNumber()); - QCOMPARE(ret.toInt32(), 123); - } - m_myObject->resetQtFunctionInvoked(); - { - QScriptValue ret = m_engine->evaluate("myObject.myInvokableWithScriptValueArg('ciao')"); - QCOMPARE(m_myObject->qtFunctionInvoked(), 56); - QVERIFY(ret.isString()); - QCOMPARE(ret.toString(), QString::fromLatin1("ciao")); - } - m_myObject->resetQtFunctionInvoked(); - { - QScriptValue ret = m_engine->evaluate("myObject.myInvokableWithScriptValueArg(this)"); - QCOMPARE(m_myObject->qtFunctionInvoked(), 56); - QVERIFY(ret.isObject()); - QVERIFY(ret.strictlyEquals(m_engine->globalObject())); - } - - // the prototype specified by a conversion function should not be "down-graded" - m_myObject->resetQtFunctionInvoked(); - { - QScriptValue qobjectProto = m_engine->newObject(); - qScriptRegisterMetaType(m_engine, qobjectToScriptValue, - qobjectFromScriptValue, qobjectProto); - QScriptValue myQObjectProto = m_engine->newObject(); - myQObjectProto.setPrototype(qobjectProto); - qScriptRegisterMetaType(m_engine, qobjectToScriptValue, - qobjectFromScriptValue, myQObjectProto); - QScriptValue ret = m_engine->evaluate("myObject.myInvokableReturningMyQObjectAsQObject()"); - QCOMPARE(m_myObject->qtFunctionInvoked(), 57); - QVERIFY(ret.isQObject()); - QVERIFY(ret.prototype().strictlyEquals(myQObjectProto)); - - qScriptRegisterMetaType(m_engine, 0, 0, QScriptValue()); - qScriptRegisterMetaType(m_engine, 0, 0, QScriptValue()); - } - - // detect exceptions during argument conversion - m_myObject->resetQtFunctionInvoked(); - { - QScriptValue (*dummy)(QScriptEngine *, const QDir &) = 0; - qScriptRegisterMetaType(m_engine, dummy, dirFromScript); - { - QVERIFY(!m_engine->hasUncaughtException()); - QScriptValue ret = m_engine->evaluate("myObject.myInvokableWithQDirArg({})"); - QVERIFY(m_engine->hasUncaughtException()); - QVERIFY(ret.isError()); - QCOMPARE(ret.toString(), QString::fromLatin1("Error: No path")); - QCOMPARE(m_myObject->qtFunctionInvoked(), -1); - } - m_engine->clearExceptions(); - { - QScriptValue ret = m_engine->evaluate("myObject.myInvokableWithQDirArg({path:'.'})"); - QVERIFY(!m_engine->hasUncaughtException()); - QVERIFY(ret.isUndefined()); - QCOMPARE(m_myObject->qtFunctionInvoked(), 55); - } - } - - // qscript_call() - { - m_myObject->resetQtFunctionInvoked(); - QScriptValue ret = m_engine->evaluate("new myObject(123)"); - QVERIFY(ret.isError()); - QCOMPARE(ret.toString(), QString::fromLatin1("TypeError: myObject is not a constructor")); - } - { - m_myObject->resetQtFunctionInvoked(); - QScriptValue ret = m_engine->evaluate("myObject(123)"); - QCOMPARE(ret.toString(), QString::fromLatin1("TypeError: myObject is not a function")); - } - - // task 233624 - { - MyNS::A a; - m_engine->globalObject().setProperty("anObject", m_engine->newQObject(&a)); - QScriptValue ret = m_engine->evaluate("anObject.slotTakingScopedEnumArg(1)"); - QVERIFY(!ret.isError()); - QVERIFY(ret.isNumber()); - QCOMPARE(ret.toInt32(), 1); - m_engine->globalObject().setProperty("anObject", QScriptValue()); - } - - // virtual slot redeclared in subclass (task 236467) - { - MyOtherQObject moq; - m_engine->globalObject().setProperty("myOtherQObject", m_engine->newQObject(&moq)); - moq.resetQtFunctionInvoked(); - QScriptValue ret = m_engine->evaluate("myOtherQObject.myVirtualSlot(123)"); - QCOMPARE(moq.qtFunctionInvoked(), 59); - QVERIFY(!ret.isError()); - QVERIFY(ret.isNumber()); - QCOMPARE(ret.toInt32(), 123); - } -} - -void tst_QScriptExtQObject::connectAndDisconnect() -{ - // connect(function) - QCOMPARE(m_engine->evaluate("myObject.mySignal.connect(123)").isError(), true); - - m_engine->evaluate("myHandler = function() { global.gotSignal = true; global.signalArgs = arguments; global.slotThisObject = this; global.signalSender = __qt_sender__; }"); - - m_myObject->clearConnectedSignal(); - QVERIFY(m_engine->evaluate("myObject.mySignal.connect(myHandler)").isUndefined()); - QCOMPARE(m_myObject->connectedSignal().constData(), SIGNAL(mySignal())); - - m_engine->evaluate("gotSignal = false"); - m_engine->evaluate("myObject.mySignal()"); - QCOMPARE(m_engine->evaluate("gotSignal").toBoolean(), true); - QCOMPARE(m_engine->evaluate("signalArgs.length").toNumber(), 0.0); - QCOMPARE(m_engine->evaluate("signalSender").toQObject(), (QObject *)m_myObject); - QVERIFY(m_engine->evaluate("slotThisObject").strictlyEquals(m_engine->globalObject())); - - m_engine->evaluate("gotSignal = false"); - m_myObject->emitMySignal(); - QCOMPARE(m_engine->evaluate("gotSignal").toBoolean(), true); - QCOMPARE(m_engine->evaluate("signalArgs.length").toNumber(), 0.0); - - QVERIFY(m_engine->evaluate("myObject.mySignalWithIntArg.connect(myHandler)").isUndefined()); - - m_engine->evaluate("gotSignal = false"); - m_myObject->emitMySignalWithIntArg(123); - QCOMPARE(m_engine->evaluate("gotSignal").toBoolean(), true); - QCOMPARE(m_engine->evaluate("signalArgs.length").toNumber(), 1.0); - QCOMPARE(m_engine->evaluate("signalArgs[0]").toNumber(), 123.0); - - m_myObject->clearDisconnectedSignal(); - QVERIFY(m_engine->evaluate("myObject.mySignal.disconnect(myHandler)").isUndefined()); - QCOMPARE(m_myObject->disconnectedSignal().constData(), SIGNAL(mySignal())); - - QVERIFY(m_engine->evaluate("myObject.mySignal.disconnect(myHandler)").isError()); - - QVERIFY(m_engine->evaluate("myObject.mySignal2.connect(myHandler)").isUndefined()); - - m_engine->evaluate("gotSignal = false"); - m_myObject->emitMySignal2(false); - QCOMPARE(m_engine->evaluate("gotSignal").toBoolean(), true); - QCOMPARE(m_engine->evaluate("signalArgs.length").toNumber(), 1.0); - QCOMPARE(m_engine->evaluate("signalArgs[0]").toBoolean(), false); - - m_engine->evaluate("gotSignal = false"); - QVERIFY(m_engine->evaluate("myObject.mySignal2.connect(myHandler)").isUndefined()); - m_myObject->emitMySignal2(true); - QCOMPARE(m_engine->evaluate("gotSignal").toBoolean(), true); - QCOMPARE(m_engine->evaluate("signalArgs.length").toNumber(), 1.0); - QCOMPARE(m_engine->evaluate("signalArgs[0]").toBoolean(), true); - - QVERIFY(m_engine->evaluate("myObject.mySignal2.disconnect(myHandler)").isUndefined()); - - QVERIFY(m_engine->evaluate("myObject['mySignal2()'].connect(myHandler)").isUndefined()); - - m_engine->evaluate("gotSignal = false"); - m_myObject->emitMySignal2(); - QCOMPARE(m_engine->evaluate("gotSignal").toBoolean(), true); - - QVERIFY(m_engine->evaluate("myObject['mySignal2()'].disconnect(myHandler)").isUndefined()); - - // connecting to signal with default args should pick the most generic version (i.e. with all args) - QVERIFY(m_engine->evaluate("myObject.mySignalWithDefaultArg.connect(myHandler)").isUndefined()); - m_engine->evaluate("gotSignal = false"); - m_myObject->emitMySignalWithDefaultArgWithArg(456); - QVERIFY(m_engine->evaluate("gotSignal").toBoolean()); - QCOMPARE(m_engine->evaluate("signalArgs.length").toInt32(), 1); - QCOMPARE(m_engine->evaluate("signalArgs[0]").toInt32(), 456); - - m_engine->evaluate("gotSignal = false"); - m_myObject->emitMySignalWithDefaultArg(); - QVERIFY(m_engine->evaluate("gotSignal").toBoolean()); - QCOMPARE(m_engine->evaluate("signalArgs.length").toInt32(), 1); - QCOMPARE(m_engine->evaluate("signalArgs[0]").toInt32(), 123); - - QVERIFY(m_engine->evaluate("myObject.mySignalWithDefaultArg.disconnect(myHandler)").isUndefined()); - - m_engine->evaluate("gotSignal = false"); - // connecting to overloaded signal should throw an error - { - QScriptValue ret = m_engine->evaluate("myObject.myOverloadedSignal.connect(myHandler)"); - QVERIFY(ret.isError()); - QCOMPARE(ret.toString(), QString::fromLatin1("Error: Function.prototype.connect: ambiguous connect to MyQObject::myOverloadedSignal(); candidates are\n" - " myOverloadedSignal(int)\n" - " myOverloadedSignal(QString)\n" - "Use e.g. object['myOverloadedSignal(QString)'].connect() to connect to a particular overload")); - } - m_myObject->emitMyOverloadedSignal(123); - QVERIFY(!m_engine->evaluate("gotSignal").toBoolean()); - m_myObject->emitMyOverloadedSignal("ciao"); - QVERIFY(!m_engine->evaluate("gotSignal").toBoolean()); - - m_engine->evaluate("gotSignal = false"); - { - QScriptValue ret = m_engine->evaluate("myObject.myOtherOverloadedSignal.connect(myHandler)"); - QVERIFY(ret.isError()); - QCOMPARE(ret.toString(), QString::fromLatin1("Error: Function.prototype.connect: ambiguous connect to MyQObject::myOtherOverloadedSignal(); candidates are\n" - " myOtherOverloadedSignal(QString)\n" - " myOtherOverloadedSignal(int)\n" - "Use e.g. object['myOtherOverloadedSignal(int)'].connect() to connect to a particular overload")); - } - m_myObject->emitMyOtherOverloadedSignal("ciao"); - QVERIFY(!m_engine->evaluate("gotSignal").toBoolean()); - m_myObject->emitMyOtherOverloadedSignal(123); - QVERIFY(!m_engine->evaluate("gotSignal").toBoolean()); - - // connect(object, function) - m_engine->evaluate("otherObject = { name:'foo' }"); - QVERIFY(m_engine->evaluate("myObject.mySignal.connect(otherObject, myHandler)").isUndefined()); - QVERIFY(m_engine->evaluate("myObject.mySignal.disconnect(otherObject, myHandler)").isUndefined()); - m_engine->evaluate("gotSignal = false"); - m_myObject->emitMySignal(); - QCOMPARE(m_engine->evaluate("gotSignal").toBoolean(), false); - - QVERIFY(m_engine->evaluate("myObject.mySignal.disconnect(otherObject, myHandler)").isError()); - - QVERIFY(m_engine->evaluate("myObject.mySignal.connect(otherObject, myHandler)").isUndefined()); - m_engine->evaluate("gotSignal = false"); - m_myObject->emitMySignal(); - QCOMPARE(m_engine->evaluate("gotSignal").toBoolean(), true); - QCOMPARE(m_engine->evaluate("signalArgs.length").toNumber(), 0.0); - QVERIFY(m_engine->evaluate("slotThisObject").strictlyEquals(m_engine->evaluate("otherObject"))); - QVERIFY(m_engine->evaluate("signalSender").strictlyEquals(m_engine->evaluate("myObject"))); - QCOMPARE(m_engine->evaluate("slotThisObject").property("name").toString(), QLatin1String("foo")); - QVERIFY(m_engine->evaluate("myObject.mySignal.disconnect(otherObject, myHandler)").isUndefined()); - - m_engine->evaluate("yetAnotherObject = { name:'bar', func : function() { } }"); - QVERIFY(m_engine->evaluate("myObject.mySignal2.connect(yetAnotherObject, myHandler)").isUndefined()); - m_engine->evaluate("gotSignal = false"); - m_myObject->emitMySignal2(true); - QCOMPARE(m_engine->evaluate("gotSignal").toBoolean(), true); - QCOMPARE(m_engine->evaluate("signalArgs.length").toNumber(), 1.0); - QVERIFY(m_engine->evaluate("slotThisObject").strictlyEquals(m_engine->evaluate("yetAnotherObject"))); - QVERIFY(m_engine->evaluate("signalSender").strictlyEquals(m_engine->evaluate("myObject"))); - QCOMPARE(m_engine->evaluate("slotThisObject").property("name").toString(), QLatin1String("bar")); - QVERIFY(m_engine->evaluate("myObject.mySignal2.disconnect(yetAnotherObject, myHandler)").isUndefined()); - - QVERIFY(m_engine->evaluate("myObject.mySignal2.connect(myObject, myHandler)").isUndefined()); - m_engine->evaluate("gotSignal = false"); - m_myObject->emitMySignal2(true); - QCOMPARE(m_engine->evaluate("gotSignal").toBoolean(), true); - QCOMPARE(m_engine->evaluate("signalArgs.length").toNumber(), 1.0); - QCOMPARE(m_engine->evaluate("slotThisObject").toQObject(), (QObject *)m_myObject); - QVERIFY(m_engine->evaluate("signalSender").strictlyEquals(m_engine->evaluate("myObject"))); - QVERIFY(m_engine->evaluate("myObject.mySignal2.disconnect(myObject, myHandler)").isUndefined()); - - // connect(obj, string) - QVERIFY(m_engine->evaluate("myObject.mySignal.connect(yetAnotherObject, 'func')").isUndefined()); - QVERIFY(m_engine->evaluate("myObject.mySignal.connect(myObject, 'mySlot')").isUndefined()); - QVERIFY(m_engine->evaluate("myObject.mySignal.disconnect(yetAnotherObject, 'func')").isUndefined()); - QVERIFY(m_engine->evaluate("myObject.mySignal.disconnect(myObject, 'mySlot')").isUndefined()); - - // check that emitting signals from script works - - // no arguments - QVERIFY(m_engine->evaluate("myObject.mySignal.connect(myObject.mySlot)").isUndefined()); - m_myObject->resetQtFunctionInvoked(); - QCOMPARE(m_engine->evaluate("myObject.mySignal()").isUndefined(), true); - QCOMPARE(m_myObject->qtFunctionInvoked(), 20); - QVERIFY(m_engine->evaluate("myObject.mySignal.disconnect(myObject.mySlot)").isUndefined()); - - // one argument - QVERIFY(m_engine->evaluate("myObject.mySignalWithIntArg.connect(myObject.mySlotWithIntArg)").isUndefined()); - m_myObject->resetQtFunctionInvoked(); - QCOMPARE(m_engine->evaluate("myObject.mySignalWithIntArg(123)").isUndefined(), true); - QCOMPARE(m_myObject->qtFunctionInvoked(), 21); - QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); - QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 123); - QVERIFY(m_engine->evaluate("myObject.mySignalWithIntArg.disconnect(myObject.mySlotWithIntArg)").isUndefined()); - - QVERIFY(m_engine->evaluate("myObject.mySignalWithIntArg.connect(myObject.mySlotWithDoubleArg)").isUndefined()); - m_myObject->resetQtFunctionInvoked(); - QCOMPARE(m_engine->evaluate("myObject.mySignalWithIntArg(123)").isUndefined(), true); - QCOMPARE(m_myObject->qtFunctionInvoked(), 22); - QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); - QCOMPARE(m_myObject->qtFunctionActuals().at(0).toDouble(), 123.0); - QVERIFY(m_engine->evaluate("myObject.mySignalWithIntArg.disconnect(myObject.mySlotWithDoubleArg)").isUndefined()); - - QVERIFY(m_engine->evaluate("myObject.mySignalWithIntArg.connect(myObject.mySlotWithStringArg)").isUndefined()); - m_myObject->resetQtFunctionInvoked(); - QCOMPARE(m_engine->evaluate("myObject.mySignalWithIntArg(123)").isUndefined(), true); - QCOMPARE(m_myObject->qtFunctionInvoked(), 23); - QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); - QCOMPARE(m_myObject->qtFunctionActuals().at(0).toString(), QLatin1String("123")); - QVERIFY(m_engine->evaluate("myObject.mySignalWithIntArg.disconnect(myObject.mySlotWithStringArg)").isUndefined()); - - // connecting to overloaded slot - QVERIFY(m_engine->evaluate("myObject.mySignalWithIntArg.connect(myObject.myOverloadedSlot)").isUndefined()); - m_myObject->resetQtFunctionInvoked(); - QCOMPARE(m_engine->evaluate("myObject.mySignalWithIntArg(123)").isUndefined(), true); - QCOMPARE(m_myObject->qtFunctionInvoked(), 26); // double overload - QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); - QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 123); - QVERIFY(m_engine->evaluate("myObject.mySignalWithIntArg.disconnect(myObject.myOverloadedSlot)").isUndefined()); - - QVERIFY(m_engine->evaluate("myObject.mySignalWithIntArg.connect(myObject['myOverloadedSlot(int)'])").isUndefined()); - m_myObject->resetQtFunctionInvoked(); - QCOMPARE(m_engine->evaluate("myObject.mySignalWithIntArg(456)").isUndefined(), true); - QCOMPARE(m_myObject->qtFunctionInvoked(), 28); // int overload - QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); - QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 456); - QVERIFY(m_engine->evaluate("myObject.mySignalWithIntArg.disconnect(myObject['myOverloadedSlot(int)'])").isUndefined()); - - // erroneous input - { - QScriptValue ret = m_engine->evaluate("(function() { }).connect()"); - QVERIFY(ret.isError()); - QCOMPARE(ret.toString(), QLatin1String("Error: Function.prototype.connect: no arguments given")); - } - { - QScriptValue ret = m_engine->evaluate("var o = { }; o.connect = Function.prototype.connect; o.connect()"); - QVERIFY(ret.isError()); - QCOMPARE(ret.toString(), QLatin1String("Error: Function.prototype.connect: no arguments given")); - } - - { - QScriptValue ret = m_engine->evaluate("(function() { }).connect(123)"); - QVERIFY(ret.isError()); - QCOMPARE(ret.toString(), QLatin1String("TypeError: Function.prototype.connect: this object is not a signal")); - } - { - QScriptValue ret = m_engine->evaluate("var o = { }; o.connect = Function.prototype.connect; o.connect(123)"); - QVERIFY(ret.isError()); - QCOMPARE(ret.toString(), QLatin1String("TypeError: Function.prototype.connect: this object is not a signal")); - } - - { - QScriptValue ret = m_engine->evaluate("myObject.myInvokable.connect(123)"); - QVERIFY(ret.isError()); - QCOMPARE(ret.toString(), QLatin1String("TypeError: Function.prototype.connect: MyQObject::myInvokable() is not a signal")); - } - { - QScriptValue ret = m_engine->evaluate("myObject.myInvokable.connect(function() { })"); - QVERIFY(ret.isError()); - QCOMPARE(ret.toString(), QLatin1String("TypeError: Function.prototype.connect: MyQObject::myInvokable() is not a signal")); - } - - { - QScriptValue ret = m_engine->evaluate("myObject.mySignal.connect(123)"); - QVERIFY(ret.isError()); - QCOMPARE(ret.toString(), QLatin1String("TypeError: Function.prototype.connect: target is not a function")); - } - - { - QScriptValue ret = m_engine->evaluate("(function() { }).disconnect()"); - QVERIFY(ret.isError()); - QCOMPARE(ret.toString(), QLatin1String("Error: Function.prototype.disconnect: no arguments given")); - } - { - QScriptValue ret = m_engine->evaluate("var o = { }; o.disconnect = Function.prototype.disconnect; o.disconnect()"); - QVERIFY(ret.isError()); - QCOMPARE(ret.toString(), QLatin1String("Error: Function.prototype.disconnect: no arguments given")); - } - - { - QScriptValue ret = m_engine->evaluate("(function() { }).disconnect(123)"); - QVERIFY(ret.isError()); - QCOMPARE(ret.toString(), QLatin1String("TypeError: Function.prototype.disconnect: this object is not a signal")); - } - { - QScriptValue ret = m_engine->evaluate("var o = { }; o.disconnect = Function.prototype.disconnect; o.disconnect(123)"); - QVERIFY(ret.isError()); - QCOMPARE(ret.toString(), QLatin1String("TypeError: Function.prototype.disconnect: this object is not a signal")); - } - - { - QScriptValue ret = m_engine->evaluate("myObject.myInvokable.disconnect(123)"); - QVERIFY(ret.isError()); - QCOMPARE(ret.toString(), QLatin1String("TypeError: Function.prototype.disconnect: MyQObject::myInvokable() is not a signal")); - } - { - QScriptValue ret = m_engine->evaluate("myObject.myInvokable.disconnect(function() { })"); - QVERIFY(ret.isError()); - QCOMPARE(ret.toString(), QLatin1String("TypeError: Function.prototype.disconnect: MyQObject::myInvokable() is not a signal")); - } - - { - QScriptValue ret = m_engine->evaluate("myObject.mySignal.disconnect(123)"); - QVERIFY(ret.isError()); - QCOMPARE(ret.toString(), QLatin1String("TypeError: Function.prototype.disconnect: target is not a function")); - } - - { - QScriptValue ret = m_engine->evaluate("myObject.mySignal.disconnect(function() { })"); - QVERIFY(ret.isError()); - QCOMPARE(ret.toString(), QLatin1String("Error: Function.prototype.disconnect: failed to disconnect from MyQObject::mySignal()")); - } - - // when the wrapper dies, the connection stays alive - QVERIFY(m_engine->evaluate("myObject.mySignal.connect(myObject.mySlot)").isUndefined()); - m_myObject->resetQtFunctionInvoked(); - m_myObject->emitMySignal(); - QCOMPARE(m_myObject->qtFunctionInvoked(), 20); - m_engine->evaluate("myObject = null"); - m_engine->collectGarbage(); - m_myObject->resetQtFunctionInvoked(); - m_myObject->emitMySignal(); - QCOMPARE(m_myObject->qtFunctionInvoked(), 20); -} - -void tst_QScriptExtQObject::cppConnectAndDisconnect() -{ - QScriptEngine eng; - QLineEdit edit; - QLineEdit edit2; - QScriptValue fun = eng.evaluate("function fun(text) { signalObject = this; signalArg = text; }; fun"); - QVERIFY(fun.isFunction()); - for (int z = 0; z < 2; ++z) { - QScriptValue receiver; - if (z == 0) - receiver = QScriptValue(); - else - receiver = eng.newObject(); - for (int y = 0; y < 2; ++y) { - QVERIFY(qScriptConnect(&edit, SIGNAL(textChanged(const QString &)), receiver, fun)); - QVERIFY(qScriptConnect(&edit2, SIGNAL(textChanged(const QString &)), receiver, fun)); - // check signal emission - for (int x = 0; x < 4; ++x) { - QLineEdit *ed = (x < 2) ? &edit : &edit2; - ed->setText((x % 2) ? "foo" : "bar"); - { - QScriptValue ret = eng.globalObject().property("signalObject"); - if (receiver.isObject()) - QVERIFY(ret.strictlyEquals(receiver)); - else - QVERIFY(ret.strictlyEquals(eng.globalObject())); - } - { - QScriptValue ret = eng.globalObject().property("signalArg"); - QVERIFY(ret.isString()); - QCOMPARE(ret.toString(), ed->text()); - } - eng.collectGarbage(); - } - - // check disconnect - QVERIFY(qScriptDisconnect(&edit, SIGNAL(textChanged(const QString &)), receiver, fun)); - eng.globalObject().setProperty("signalObject", QScriptValue()); - eng.globalObject().setProperty("signalArg", QScriptValue()); - edit.setText("something else"); - QVERIFY(!eng.globalObject().property("signalObject").isValid()); - QVERIFY(!eng.globalObject().property("signalArg").isValid()); - QVERIFY(!qScriptDisconnect(&edit, SIGNAL(textChanged(const QString &)), receiver, fun)); - - // other object's connection should remain - edit2.setText(edit.text()); - { - QScriptValue ret = eng.globalObject().property("signalObject"); - if (receiver.isObject()) - QVERIFY(ret.strictlyEquals(receiver)); - else - QVERIFY(ret.strictlyEquals(eng.globalObject())); - } - { - QScriptValue ret = eng.globalObject().property("signalArg"); - QVERIFY(ret.isString()); - QCOMPARE(ret.toString(), edit2.text()); - } - - // disconnect other object too - QVERIFY(qScriptDisconnect(&edit2, SIGNAL(textChanged(const QString &)), receiver, fun)); - eng.globalObject().setProperty("signalObject", QScriptValue()); - eng.globalObject().setProperty("signalArg", QScriptValue()); - edit2.setText("even more different"); - QVERIFY(!eng.globalObject().property("signalObject").isValid()); - QVERIFY(!eng.globalObject().property("signalArg").isValid()); - QVERIFY(!qScriptDisconnect(&edit2, SIGNAL(textChanged(const QString &)), receiver, fun)); - } - } - - // make sure we don't crash when engine is deleted - { - QScriptEngine *eng2 = new QScriptEngine; - QScriptValue fun2 = eng2->evaluate("function(text) { signalObject = this; signalArg = text; }"); - QVERIFY(qScriptConnect(&edit, SIGNAL(textChanged(const QString &)), QScriptValue(), fun2)); - delete eng2; - edit.setText("ciao"); - QVERIFY(!qScriptDisconnect(&edit, SIGNAL(textChanged(const QString &)), QScriptValue(), fun2)); - } - - // mixing script-side and C++-side connect - { - eng.globalObject().setProperty("edit", eng.newQObject(&edit)); - QVERIFY(eng.evaluate("edit.textChanged.connect(fun)").isUndefined()); - QVERIFY(qScriptDisconnect(&edit, SIGNAL(textChanged(const QString &)), QScriptValue(), fun)); - - QVERIFY(qScriptConnect(&edit, SIGNAL(textChanged(const QString &)), QScriptValue(), fun)); - QVERIFY(eng.evaluate("edit.textChanged.disconnect(fun)").isUndefined()); - } - - // signalHandlerException() - { - connect(&eng, SIGNAL(signalHandlerException(QScriptValue)), - this, SLOT(onSignalHandlerException(QScriptValue))); - - eng.globalObject().setProperty("edit", eng.newQObject(&edit)); - QScriptValue fun = eng.evaluate("function() { nonExistingFunction(); }"); - QVERIFY(qScriptConnect(&edit, SIGNAL(textChanged(const QString &)), QScriptValue(), fun)); - - m_signalHandlerException = QScriptValue(); - QScriptValue ret = eng.evaluate("edit.text = 'trigger a signal handler exception from script'"); - QVERIFY(ret.isError()); - QVERIFY(m_signalHandlerException.strictlyEquals(ret)); - - m_signalHandlerException = QScriptValue(); - edit.setText("trigger a signal handler exception from C++"); - QVERIFY(m_signalHandlerException.isError()); - - QVERIFY(qScriptDisconnect(&edit, SIGNAL(textChanged(const QString &)), QScriptValue(), fun)); - - m_signalHandlerException = QScriptValue(); - eng.evaluate("edit.text = 'no more exception from script'"); - QVERIFY(!m_signalHandlerException.isValid()); - edit.setText("no more exception from C++"); - QVERIFY(!m_signalHandlerException.isValid()); - - disconnect(&eng, SIGNAL(signalHandlerException(QScriptValue)), - this, SLOT(onSignalHandlerException(QScriptValue))); - } - - // check that connectNotify() and disconnectNotify() are called (task 232987) - { - m_myObject->clearConnectedSignal(); - QVERIFY(qScriptConnect(m_myObject, SIGNAL(mySignal()), QScriptValue(), fun)); - QCOMPARE(m_myObject->connectedSignal().constData(), SIGNAL(mySignal())); - - m_myObject->clearDisconnectedSignal(); - QVERIFY(qScriptDisconnect(m_myObject, SIGNAL(mySignal()), QScriptValue(), fun)); - QCOMPARE(m_myObject->disconnectedSignal().constData(), SIGNAL(mySignal())); - } -} - -void tst_QScriptExtQObject::classEnums() -{ - QScriptValue myClass = m_engine->newQMetaObject(m_myObject->metaObject(), m_engine->undefinedValue()); - m_engine->globalObject().setProperty("MyQObject", myClass); - - QCOMPARE(static_cast(m_engine->evaluate("MyQObject.FooPolicy").toInt32()), - MyQObject::FooPolicy); - QCOMPARE(static_cast(m_engine->evaluate("MyQObject.BarPolicy").toInt32()), - MyQObject::BarPolicy); - QCOMPARE(static_cast(m_engine->evaluate("MyQObject.BazPolicy").toInt32()), - MyQObject::BazPolicy); - - QCOMPARE(static_cast(m_engine->evaluate("MyQObject.FooStrategy").toInt32()), - MyQObject::FooStrategy); - QCOMPARE(static_cast(m_engine->evaluate("MyQObject.BarStrategy").toInt32()), - MyQObject::BarStrategy); - QCOMPARE(static_cast(m_engine->evaluate("MyQObject.BazStrategy").toInt32()), - MyQObject::BazStrategy); - - QCOMPARE(MyQObject::Ability(m_engine->evaluate("MyQObject.NoAbility").toInt32()), - MyQObject::NoAbility); - QCOMPARE(MyQObject::Ability(m_engine->evaluate("MyQObject.FooAbility").toInt32()), - MyQObject::FooAbility); - QCOMPARE(MyQObject::Ability(m_engine->evaluate("MyQObject.BarAbility").toInt32()), - MyQObject::BarAbility); - QCOMPARE(MyQObject::Ability(m_engine->evaluate("MyQObject.BazAbility").toInt32()), - MyQObject::BazAbility); - QCOMPARE(MyQObject::Ability(m_engine->evaluate("MyQObject.AllAbility").toInt32()), - MyQObject::AllAbility); - - QScriptValue::PropertyFlags expectedEnumFlags = QScriptValue::ReadOnly; - QCOMPARE(myClass.propertyFlags("FooPolicy"), expectedEnumFlags); - QCOMPARE(myClass.propertyFlags("BarPolicy"), expectedEnumFlags); - QCOMPARE(myClass.propertyFlags("BazPolicy"), expectedEnumFlags); - - // enums from Qt are inherited through prototype - QCOMPARE(static_cast(m_engine->evaluate("MyQObject.StrongFocus").toInt32()), - Qt::StrongFocus); - QCOMPARE(static_cast(m_engine->evaluate("MyQObject.Key_Left").toInt32()), - Qt::Key_Left); - - QCOMPARE(m_engine->evaluate("MyQObject.className()").toString(), QLatin1String("MyQObject")); - - qRegisterMetaType("Policy"); - - m_myObject->resetQtFunctionInvoked(); - QCOMPARE(m_engine->evaluate("myObject.myInvokableWithEnumArg(MyQObject.BazPolicy)").isUndefined(), true); - QCOMPARE(m_myObject->qtFunctionInvoked(), 10); - QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); - QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), int(MyQObject::BazPolicy)); - - m_myObject->resetQtFunctionInvoked(); - QCOMPARE(m_engine->evaluate("myObject.myInvokableWithQualifiedEnumArg(MyQObject.BazPolicy)").isUndefined(), true); - QCOMPARE(m_myObject->qtFunctionInvoked(), 36); - QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); - QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), int(MyQObject::BazPolicy)); - - m_myObject->resetQtFunctionInvoked(); - { - QScriptValue ret = m_engine->evaluate("myObject.myInvokableReturningEnum()"); - QCOMPARE(m_myObject->qtFunctionInvoked(), 37); - QCOMPARE(m_myObject->qtFunctionActuals().size(), 0); - QCOMPARE(ret.isVariant(), true); - } - m_myObject->resetQtFunctionInvoked(); - { - QScriptValue ret = m_engine->evaluate("myObject.myInvokableReturningQualifiedEnum()"); - QCOMPARE(m_myObject->qtFunctionInvoked(), 38); - QCOMPARE(m_myObject->qtFunctionActuals().size(), 0); - QCOMPARE(ret.isNumber(), true); - } -} - -QT_BEGIN_NAMESPACE -Q_SCRIPT_DECLARE_QMETAOBJECT(MyQObject, QObject*) -Q_SCRIPT_DECLARE_QMETAOBJECT(QObject, QObject*) -QT_END_NAMESPACE - -class ConstructorTest : public QObject -{ - Q_OBJECT -public: - Q_INVOKABLE ConstructorTest(QObject *parent) - : QObject(parent) - { - setProperty("ctorIndex", 0); - } - Q_INVOKABLE ConstructorTest(int arg, QObject *parent = 0) - : QObject(parent) - { - setProperty("ctorIndex", 1); - setProperty("arg", arg); - } - Q_INVOKABLE ConstructorTest(const QString &arg, QObject *parent = 0) - : QObject(parent) - { - setProperty("ctorIndex", 2); - setProperty("arg", arg); - } - Q_INVOKABLE ConstructorTest(int arg, const QString &arg2, QObject *parent = 0) - : QObject(parent) - { - setProperty("ctorIndex", 3); - setProperty("arg", arg); - setProperty("arg2", arg2); - } - Q_INVOKABLE ConstructorTest(const QBrush &arg, QObject *parent = 0) - : QObject(parent) - { - setProperty("ctorIndex", 4); - setProperty("arg", arg); - } -}; - -void tst_QScriptExtQObject::classConstructor() -{ - QScriptValue myClass = qScriptValueFromQMetaObject(m_engine); - m_engine->globalObject().setProperty("MyQObject", myClass); - - QScriptValue myObj = m_engine->evaluate("myObj = MyQObject()"); - QObject *qobj = myObj.toQObject(); - QVERIFY(qobj != 0); - QCOMPARE(qobj->metaObject()->className(), "MyQObject"); - QCOMPARE(qobj->parent(), (QObject *)0); - - QScriptValue qobjectClass = qScriptValueFromQMetaObject(m_engine); - m_engine->globalObject().setProperty("QObject", qobjectClass); - - QScriptValue otherObj = m_engine->evaluate("otherObj = QObject(myObj)"); - QObject *qqobj = otherObj.toQObject(); - QVERIFY(qqobj != 0); - QCOMPARE(qqobj->metaObject()->className(), "QObject"); - QCOMPARE(qqobj->parent(), qobj); - - delete qobj; - - // Q_INVOKABLE constructors - { - QScriptValue klazz = m_engine->newQMetaObject(&ConstructorTest::staticMetaObject); - { - QScriptValue obj = klazz.construct(); - QVERIFY(obj.isError()); - QCOMPARE(obj.toString(), QString::fromLatin1("SyntaxError: too few arguments in call to ConstructorTest(); candidates are\n" - " ConstructorTest(QBrush)\n" - " ConstructorTest(QBrush,QObject*)\n" - " ConstructorTest(int,QString)\n" - " ConstructorTest(int,QString,QObject*)\n" - " ConstructorTest(QString)\n" - " ConstructorTest(QString,QObject*)\n" - " ConstructorTest(int)\n" - " ConstructorTest(int,QObject*)\n" - " ConstructorTest(QObject*)")); - } - { - QObject objobj; - QScriptValue arg = m_engine->newQObject(&objobj); - QScriptValue obj = klazz.construct(QScriptValueList() << arg); - QVERIFY(!obj.isError()); - QVERIFY(obj.instanceOf(klazz)); - QVERIFY(obj.property("ctorIndex").isNumber()); - QCOMPARE(obj.property("ctorIndex").toInt32(), 0); - } - { - int arg = 123; - QScriptValue obj = klazz.construct(QScriptValueList() << arg); - QVERIFY(!obj.isError()); - QVERIFY(obj.instanceOf(klazz)); - QVERIFY(obj.property("ctorIndex").isNumber()); - QCOMPARE(obj.property("ctorIndex").toInt32(), 1); - QVERIFY(obj.property("arg").isNumber()); - QCOMPARE(obj.property("arg").toInt32(), arg); - } - { - QString arg = "foo"; - QScriptValue obj = klazz.construct(QScriptValueList() << arg); - QVERIFY(!obj.isError()); - QVERIFY(obj.instanceOf(klazz)); - QVERIFY(obj.property("ctorIndex").isNumber()); - QCOMPARE(obj.property("ctorIndex").toInt32(), 2); - QVERIFY(obj.property("arg").isString()); - QCOMPARE(obj.property("arg").toString(), arg); - } - { - int arg = 123; - QString arg2 = "foo"; - QScriptValue obj = klazz.construct(QScriptValueList() << arg << arg2); - QVERIFY(!obj.isError()); - QVERIFY(obj.instanceOf(klazz)); - QVERIFY(obj.property("ctorIndex").isNumber()); - QCOMPARE(obj.property("ctorIndex").toInt32(), 3); - QVERIFY(obj.property("arg").isNumber()); - QCOMPARE(obj.property("arg").toInt32(), arg); - QVERIFY(obj.property("arg2").isString()); - QCOMPARE(obj.property("arg2").toString(), arg2); - } - { - QBrush arg(Qt::red); - QScriptValue obj = klazz.construct(QScriptValueList() << qScriptValueFromValue(m_engine, arg)); - QVERIFY(!obj.isError()); - QVERIFY(obj.instanceOf(klazz)); - QVERIFY(obj.property("ctorIndex").isNumber()); - QCOMPARE(obj.property("ctorIndex").toInt32(), 4); - QVERIFY(obj.property("arg").isVariant()); - QCOMPARE(qvariant_cast(obj.property("arg").toVariant()), arg); - } - { - QDir arg; - QScriptValue obj = klazz.construct(QScriptValueList() - << qScriptValueFromValue(m_engine, arg)); - QVERIFY(obj.isError()); - QCOMPARE(obj.toString(), QString::fromLatin1("TypeError: ambiguous call of overloaded function ConstructorTest(); candidates were\n" - " ConstructorTest(int)\n" - " ConstructorTest(QString)")); - } - } -} - -void tst_QScriptExtQObject::overrideInvokable() -{ - m_myObject->resetQtFunctionInvoked(); - m_engine->evaluate("myObject.myInvokable()"); - QCOMPARE(m_myObject->qtFunctionInvoked(), 0); - - m_myObject->resetQtFunctionInvoked(); - m_engine->evaluate("myObject.myInvokable = function() { global.a = 123; }"); - m_engine->evaluate("myObject.myInvokable()"); - QCOMPARE(m_myObject->qtFunctionInvoked(), -1); - QCOMPARE(m_engine->evaluate("global.a").toNumber(), 123.0); - - m_engine->evaluate("myObject.myInvokable = function() { global.a = 456; }"); - m_engine->evaluate("myObject.myInvokable()"); - QCOMPARE(m_myObject->qtFunctionInvoked(), -1); - QCOMPARE(m_engine->evaluate("global.a").toNumber(), 456.0); - - m_engine->evaluate("delete myObject.myInvokable"); - m_engine->evaluate("myObject.myInvokable()"); - QCOMPARE(m_myObject->qtFunctionInvoked(), 0); - - m_myObject->resetQtFunctionInvoked(); - m_engine->evaluate("myObject.myInvokable = myObject.myInvokableWithIntArg"); - m_engine->evaluate("myObject.myInvokable(123)"); - QCOMPARE(m_myObject->qtFunctionInvoked(), 1); - - m_engine->evaluate("delete myObject.myInvokable"); - m_myObject->resetQtFunctionInvoked(); - // this form (with the '()') is read-only - m_engine->evaluate("myObject['myInvokable()'] = function() { global.a = 123; }"); - m_engine->evaluate("myObject.myInvokable()"); - QCOMPARE(m_myObject->qtFunctionInvoked(), 0); -} - -void tst_QScriptExtQObject::transferInvokable() -{ - m_myObject->resetQtFunctionInvoked(); - m_engine->evaluate("myObject.foozball = myObject.myInvokable"); - m_engine->evaluate("myObject.foozball()"); - QCOMPARE(m_myObject->qtFunctionInvoked(), 0); - m_myObject->resetQtFunctionInvoked(); - m_engine->evaluate("myObject.foozball = myObject.myInvokableWithIntArg"); - m_engine->evaluate("myObject.foozball(123)"); - QCOMPARE(m_myObject->qtFunctionInvoked(), 1); - m_myObject->resetQtFunctionInvoked(); - m_engine->evaluate("myObject.myInvokable = myObject.myInvokableWithIntArg"); - m_engine->evaluate("myObject.myInvokable(123)"); - QCOMPARE(m_myObject->qtFunctionInvoked(), 1); - - MyOtherQObject other; - m_engine->globalObject().setProperty( - "myOtherObject", m_engine->newQObject(&other)); - m_engine->evaluate("myOtherObject.foo = myObject.foozball"); - other.resetQtFunctionInvoked(); - m_engine->evaluate("myOtherObject.foo(456)"); - QCOMPARE(other.qtFunctionInvoked(), 1); -} - -void tst_QScriptExtQObject::findChild() -{ - QObject *child = new QObject(m_myObject); - child->setObjectName(QLatin1String("myChildObject")); - - { - QScriptValue result = m_engine->evaluate("myObject.findChild('noSuchChild')"); - QCOMPARE(result.isNull(), true); - } - - { - QScriptValue result = m_engine->evaluate("myObject.findChild('myChildObject')"); - QCOMPARE(result.isQObject(), true); - QCOMPARE(result.toQObject(), child); - } - - delete child; -} - -void tst_QScriptExtQObject::findChildren() -{ - QObject *child = new QObject(m_myObject); - child->setObjectName(QLatin1String("myChildObject")); - - { - QScriptValue result = m_engine->evaluate("myObject.findChildren('noSuchChild')"); - QCOMPARE(result.isArray(), true); - QCOMPARE(result.property(QLatin1String("length")).toNumber(), 0.0); - } - - { - QScriptValue result = m_engine->evaluate("myObject.findChildren('myChildObject')"); - QCOMPARE(result.isArray(), true); - QCOMPARE(result.property(QLatin1String("length")).toNumber(), 1.0); - QCOMPARE(result.property(QLatin1String("0")).toQObject(), child); - } - - QObject *namelessChild = new QObject(m_myObject); - - { - QScriptValue result = m_engine->evaluate("myObject.findChildren('myChildObject')"); - QCOMPARE(result.isArray(), true); - QCOMPARE(result.property(QLatin1String("length")).toNumber(), 1.0); - QCOMPARE(result.property(QLatin1String("0")).toQObject(), child); - } - - QObject *anotherChild = new QObject(m_myObject); - anotherChild->setObjectName(QLatin1String("anotherChildObject")); - - { - QScriptValue result = m_engine->evaluate("myObject.findChildren('anotherChildObject')"); - QCOMPARE(result.isArray(), true); - QCOMPARE(result.property(QLatin1String("length")).toNumber(), 1.0); - QCOMPARE(result.property(QLatin1String("0")).toQObject(), anotherChild); - } - - anotherChild->setObjectName(QLatin1String("myChildObject")); - { - QScriptValue result = m_engine->evaluate("myObject.findChildren('myChildObject')"); - QCOMPARE(result.isArray(), true); - QCOMPARE(result.property(QLatin1String("length")).toNumber(), 2.0); - QObject *o1 = result.property(QLatin1String("0")).toQObject(); - QObject *o2 = result.property(QLatin1String("1")).toQObject(); - if (o1 != child) { - QCOMPARE(o1, anotherChild); - QCOMPARE(o2, child); - } else { - QCOMPARE(o1, child); - QCOMPARE(o2, anotherChild); - } - } - - // find all - { - QScriptValue result = m_engine->evaluate("myObject.findChildren()"); - QVERIFY(result.isArray()); - int count = 3; - QCOMPARE(result.property("length").toInt32(), count); - for (int i = 0; i < 3; ++i) { - QObject *o = result.property(i).toQObject(); - if (o == namelessChild || o == child || o == anotherChild) - --count; - } - QVERIFY(count == 0); - } - - delete anotherChild; - delete namelessChild; - delete child; -} - -void tst_QScriptExtQObject::overloadedSlots() -{ - // should pick myOverloadedSlot(double) - m_myObject->resetQtFunctionInvoked(); - m_engine->evaluate("myObject.myOverloadedSlot(10)"); - QCOMPARE(m_myObject->qtFunctionInvoked(), 26); - - // should pick myOverloadedSlot(double) - m_myObject->resetQtFunctionInvoked(); - m_engine->evaluate("myObject.myOverloadedSlot(10.0)"); - QCOMPARE(m_myObject->qtFunctionInvoked(), 26); - - // should pick myOverloadedSlot(QString) - m_myObject->resetQtFunctionInvoked(); - m_engine->evaluate("myObject.myOverloadedSlot('10')"); - QCOMPARE(m_myObject->qtFunctionInvoked(), 29); - - // should pick myOverloadedSlot(bool) - m_myObject->resetQtFunctionInvoked(); - m_engine->evaluate("myObject.myOverloadedSlot(true)"); - QCOMPARE(m_myObject->qtFunctionInvoked(), 25); - - // should pick myOverloadedSlot(QDateTime) - m_myObject->resetQtFunctionInvoked(); - m_engine->evaluate("myObject.myOverloadedSlot(new Date())"); - QCOMPARE(m_myObject->qtFunctionInvoked(), 32); - - // should pick myOverloadedSlot(QRegExp) - m_myObject->resetQtFunctionInvoked(); - m_engine->evaluate("myObject.myOverloadedSlot(new RegExp())"); - QCOMPARE(m_myObject->qtFunctionInvoked(), 34); - - // should pick myOverloadedSlot(QVariant) - m_myObject->resetQtFunctionInvoked(); - QScriptValue f = m_engine->evaluate("myObject.myOverloadedSlot"); - f.call(QScriptValue(), QScriptValueList() << m_engine->newVariant(QVariant("ciao"))); - QCOMPARE(m_myObject->qtFunctionInvoked(), 35); - - // should pick myOverloadedSlot(QObject*) - m_myObject->resetQtFunctionInvoked(); - m_engine->evaluate("myObject.myOverloadedSlot(myObject)"); - QCOMPARE(m_myObject->qtFunctionInvoked(), 41); - - // should pick myOverloadedSlot(QObject*) - m_myObject->resetQtFunctionInvoked(); - m_engine->evaluate("myObject.myOverloadedSlot(null)"); - QCOMPARE(m_myObject->qtFunctionInvoked(), 41); - - // should pick myOverloadedSlot(QStringList) - m_myObject->resetQtFunctionInvoked(); - m_engine->evaluate("myObject.myOverloadedSlot(['hello'])"); - QCOMPARE(m_myObject->qtFunctionInvoked(), 42); -} - -void tst_QScriptExtQObject::enumerate_data() -{ - QTest::addColumn("wrapOptions"); - QTest::addColumn("expectedNames"); - - QTest::newRow( "enumerate all" ) - << 0 - << (QStringList() - // meta-object-defined properties: - // inherited - << "objectName" - // non-inherited - << "p1" << "p2" << "p4" << "p6" - // dynamic properties - << "dp1" << "dp2" << "dp3" - // inherited slots - << "destroyed(QObject*)" << "destroyed()" - << "deleteLater()" - // not included because it's private: - // << "_q_reregisterTimers(void*)" - // signals - << "mySignal()" - // slots - << "mySlot()" << "myOtherSlot()"); - - QTest::newRow( "don't enumerate inherited properties" ) - << int(QScriptEngine::ExcludeSuperClassProperties) - << (QStringList() - // meta-object-defined properties: - // non-inherited - << "p1" << "p2" << "p4" << "p6" - // dynamic properties - << "dp1" << "dp2" << "dp3" - // inherited slots - << "destroyed(QObject*)" << "destroyed()" - << "deleteLater()" - // not included because it's private: - // << "_q_reregisterTimers(void*)" - // signals - << "mySignal()" - // slots - << "mySlot()" << "myOtherSlot()"); - - QTest::newRow( "don't enumerate inherited methods" ) - << int(QScriptEngine::ExcludeSuperClassMethods) - << (QStringList() - // meta-object-defined properties: - // inherited - << "objectName" - // non-inherited - << "p1" << "p2" << "p4" << "p6" - // dynamic properties - << "dp1" << "dp2" << "dp3" - // signals - << "mySignal()" - // slots - << "mySlot()" << "myOtherSlot()"); - - QTest::newRow( "don't enumerate inherited members" ) - << int(QScriptEngine::ExcludeSuperClassMethods - | QScriptEngine::ExcludeSuperClassProperties) - << (QStringList() - // meta-object-defined properties - << "p1" << "p2" << "p4" << "p6" - // dynamic properties - << "dp1" << "dp2" << "dp3" - // signals - << "mySignal()" - // slots - << "mySlot()" << "myOtherSlot()"); - - QTest::newRow( "enumerate properties, not methods" ) - << int(QScriptEngine::SkipMethodsInEnumeration) - << (QStringList() - // meta-object-defined properties: - // inherited - << "objectName" - // non-inherited - << "p1" << "p2" << "p4" << "p6" - // dynamic properties - << "dp1" << "dp2" << "dp3"); - - QTest::newRow( "don't enumerate inherited properties + methods" ) - << int(QScriptEngine::ExcludeSuperClassProperties - | QScriptEngine::SkipMethodsInEnumeration) - << (QStringList() - // meta-object-defined properties: - // non-inherited - << "p1" << "p2" << "p4" << "p6" - // dynamic properties - << "dp1" << "dp2" << "dp3"); - - QTest::newRow( "don't enumerate inherited members" ) - << int(QScriptEngine::ExcludeSuperClassContents) - << (QStringList() - // meta-object-defined properties - << "p1" << "p2" << "p4" << "p6" - // dynamic properties - << "dp1" << "dp2" << "dp3" - // signals - << "mySignal()" - // slots - << "mySlot()" << "myOtherSlot()"); - - QTest::newRow( "don't enumerate deleteLater()" ) - << int(QScriptEngine::ExcludeDeleteLater) - << (QStringList() - // meta-object-defined properties: - // inherited - << "objectName" - // non-inherited - << "p1" << "p2" << "p4" << "p6" - // dynamic properties - << "dp1" << "dp2" << "dp3" - // inherited slots - << "destroyed(QObject*)" << "destroyed()" - // not included because it's private: - // << "_q_reregisterTimers(void*)" - // signals - << "mySignal()" - // slots - << "mySlot()" << "myOtherSlot()"); -} - -void tst_QScriptExtQObject::enumerate() -{ - QFETCH( int, wrapOptions ); - QFETCH( QStringList, expectedNames ); - - QScriptEngine eng; - MyEnumTestQObject enumQObject; - // give it some dynamic properties - enumQObject.setProperty("dp1", "dp1"); - enumQObject.setProperty("dp2", "dp2"); - enumQObject.setProperty("dp3", "dp3"); - QScriptValue obj = eng.newQObject(&enumQObject, QScriptEngine::QtOwnership, - QScriptEngine::QObjectWrapOptions(wrapOptions)); - - // enumerate in script - { - eng.globalObject().setProperty("myEnumObject", obj); - eng.evaluate("var enumeratedProperties = []"); - eng.evaluate("for (var p in myEnumObject) { enumeratedProperties.push(p); }"); - QStringList result = qscriptvalue_cast(eng.evaluate("enumeratedProperties")); - QCOMPARE(result.size(), expectedNames.size()); - for (int i = 0; i < expectedNames.size(); ++i) - QCOMPARE(result.at(i), expectedNames.at(i)); - } - // enumerate in C++ - { - QScriptValueIterator it(obj); - QStringList result; - while (it.hasNext()) { - it.next(); - QCOMPARE(it.flags(), obj.propertyFlags(it.name())); - result.append(it.name()); - } - QCOMPARE(result.size(), expectedNames.size()); - for (int i = 0; i < expectedNames.size(); ++i) - QCOMPARE(result.at(i), expectedNames.at(i)); - } -} - -class SpecialEnumTestObject : public QObject -{ - Q_OBJECT - // overriding a property in the super-class to make it non-scriptable - Q_PROPERTY(QString objectName READ objectName SCRIPTABLE false) -public: - SpecialEnumTestObject(QObject *parent = 0) - : QObject(parent) {} -}; - -class SpecialEnumTestObject2 : public QObject -{ - Q_OBJECT - // overriding a property in the super-class to make it non-designable (but still scriptable) - Q_PROPERTY(QString objectName READ objectName DESIGNABLE false) -public: - SpecialEnumTestObject2(QObject *parent = 0) - : QObject(parent) {} -}; - -void tst_QScriptExtQObject::enumerateSpecial() -{ - QScriptEngine eng; - { - SpecialEnumTestObject testObj; - QScriptValueIterator it(eng.newQObject(&testObj)); - bool objectNameEncountered = false; - while (it.hasNext()) { - it.next(); - if (it.name() == QLatin1String("objectName")) { - objectNameEncountered = true; - break; - } - } - QVERIFY(!objectNameEncountered); - } - { - SpecialEnumTestObject2 testObj; - testObj.setObjectName("foo"); - QScriptValueList values; - QScriptValueIterator it(eng.newQObject(&testObj)); - while (it.hasNext()) { - it.next(); - if (it.name() == "objectName") - values.append(it.value()); - } - QCOMPARE(values.size(), 1); - QCOMPARE(values.at(0).toString(), QString::fromLatin1("foo")); - } -} - -void tst_QScriptExtQObject::wrapOptions() -{ - QCOMPARE(m_myObject->setProperty("dynamicProperty", 123), false); - MyQObject *child = new MyQObject(m_myObject); - child->setObjectName("child"); - // exclude child objects - { - QScriptValue obj = m_engine->newQObject(m_myObject, QScriptEngine::QtOwnership, - QScriptEngine::ExcludeChildObjects); - QCOMPARE(obj.property("child").isValid(), false); - obj.setProperty("child", QScriptValue(m_engine, 123)); - QCOMPARE(obj.property("child") - .strictlyEquals(QScriptValue(m_engine, 123)), true); - } - // don't auto-create dynamic properties - { - QScriptValue obj = m_engine->newQObject(m_myObject); - QVERIFY(!m_myObject->dynamicPropertyNames().contains("anotherDynamicProperty")); - obj.setProperty("anotherDynamicProperty", QScriptValue(m_engine, 123)); - QVERIFY(!m_myObject->dynamicPropertyNames().contains("anotherDynamicProperty")); - QCOMPARE(obj.property("anotherDynamicProperty") - .strictlyEquals(QScriptValue(m_engine, 123)), true); - } - // auto-create dynamic properties - { - QScriptValue obj = m_engine->newQObject(m_myObject, QScriptEngine::QtOwnership, - QScriptEngine::AutoCreateDynamicProperties); - QVERIFY(!m_myObject->dynamicPropertyNames().contains("anotherDynamicProperty")); - obj.setProperty("anotherDynamicProperty", QScriptValue(m_engine, 123)); - QVERIFY(m_myObject->dynamicPropertyNames().contains("anotherDynamicProperty")); - QCOMPARE(obj.property("anotherDynamicProperty") - .strictlyEquals(QScriptValue(m_engine, 123)), true); - // task 236685 - { - QScriptValue obj2 = m_engine->newObject(); - obj2.setProperty("notADynamicProperty", 456); - obj.setPrototype(obj2); - QScriptValue ret = obj.property("notADynamicProperty"); - QVERIFY(ret.isNumber()); - QVERIFY(ret.strictlyEquals(obj2.property("notADynamicProperty"))); - } - } - // don't exclude super-class properties - { - QScriptValue obj = m_engine->newQObject(m_myObject); - QVERIFY(obj.property("objectName").isValid()); - QVERIFY(obj.propertyFlags("objectName") & QScriptValue::QObjectMember); - } - // exclude super-class properties - { - QScriptValue obj = m_engine->newQObject(m_myObject, QScriptEngine::QtOwnership, - QScriptEngine::ExcludeSuperClassProperties); - QVERIFY(!obj.property("objectName").isValid()); - QVERIFY(!(obj.propertyFlags("objectName") & QScriptValue::QObjectMember)); - QVERIFY(obj.property("intProperty").isValid()); - QVERIFY(obj.propertyFlags("intProperty") & QScriptValue::QObjectMember); - } - // don't exclude super-class methods - { - QScriptValue obj = m_engine->newQObject(m_myObject); - QVERIFY(obj.property("deleteLater").isValid()); - QVERIFY(obj.propertyFlags("deleteLater") & QScriptValue::QObjectMember); - } - // exclude super-class methods - { - QScriptValue obj = m_engine->newQObject(m_myObject, QScriptEngine::QtOwnership, - QScriptEngine::ExcludeSuperClassMethods); - QVERIFY(!obj.property("deleteLater").isValid()); - QVERIFY(!(obj.propertyFlags("deleteLater") & QScriptValue::QObjectMember)); - QVERIFY(obj.property("mySlot").isValid()); - QVERIFY(obj.propertyFlags("mySlot") & QScriptValue::QObjectMember); - } - // exclude all super-class contents - { - QScriptValue obj = m_engine->newQObject(m_myObject, QScriptEngine::QtOwnership, - QScriptEngine::ExcludeSuperClassContents); - QVERIFY(!obj.property("deleteLater").isValid()); - QVERIFY(!(obj.propertyFlags("deleteLater") & QScriptValue::QObjectMember)); - QVERIFY(obj.property("mySlot").isValid()); - QVERIFY(obj.propertyFlags("mySlot") & QScriptValue::QObjectMember); - - QVERIFY(!obj.property("objectName").isValid()); - QVERIFY(!(obj.propertyFlags("objectName") & QScriptValue::QObjectMember)); - QVERIFY(obj.property("intProperty").isValid()); - QVERIFY(obj.propertyFlags("intProperty") & QScriptValue::QObjectMember); - } - // exclude deleteLater() - { - QScriptValue obj = m_engine->newQObject(m_myObject, QScriptEngine::QtOwnership, - QScriptEngine::ExcludeDeleteLater); - QVERIFY(!obj.property("deleteLater").isValid()); - QVERIFY(!(obj.propertyFlags("deleteLater") & QScriptValue::QObjectMember)); - QVERIFY(obj.property("mySlot").isValid()); - QVERIFY(obj.propertyFlags("mySlot") & QScriptValue::QObjectMember); - - QVERIFY(obj.property("objectName").isValid()); - QVERIFY(obj.propertyFlags("objectName") & QScriptValue::QObjectMember); - QVERIFY(obj.property("intProperty").isValid()); - QVERIFY(obj.propertyFlags("intProperty") & QScriptValue::QObjectMember); - } - // exclude all that we can - { - QScriptValue obj = m_engine->newQObject(m_myObject, QScriptEngine::QtOwnership, - QScriptEngine::ExcludeSuperClassMethods - | QScriptEngine::ExcludeSuperClassProperties - | QScriptEngine::ExcludeChildObjects); - QVERIFY(!obj.property("deleteLater").isValid()); - QVERIFY(!(obj.propertyFlags("deleteLater") & QScriptValue::QObjectMember)); - QVERIFY(obj.property("mySlot").isValid()); - QVERIFY(obj.propertyFlags("mySlot") & QScriptValue::QObjectMember); - - QVERIFY(!obj.property("objectName").isValid()); - QVERIFY(!(obj.propertyFlags("objectName") & QScriptValue::QObjectMember)); - QVERIFY(obj.property("intProperty").isValid()); - QVERIFY(obj.propertyFlags("intProperty") & QScriptValue::QObjectMember); - - QCOMPARE(obj.property("child").isValid(), false); - obj.setProperty("child", QScriptValue(m_engine, 123)); - QCOMPARE(obj.property("child") - .strictlyEquals(QScriptValue(m_engine, 123)), true); - } - - delete child; -} - -Q_DECLARE_METATYPE(QWidget*) -Q_DECLARE_METATYPE(QPushButton*) - -void tst_QScriptExtQObject::prototypes() -{ - QScriptEngine eng; - QScriptValue widgetProto = eng.newQObject(new QWidget(), QScriptEngine::ScriptOwnership); - eng.setDefaultPrototype(qMetaTypeId(), widgetProto); - QPushButton *pbp = new QPushButton(); - QScriptValue buttonProto = eng.newQObject(pbp, QScriptEngine::ScriptOwnership); - buttonProto.setPrototype(widgetProto); - eng.setDefaultPrototype(qMetaTypeId(), buttonProto); - QPushButton *pb = new QPushButton(); - QScriptValue button = eng.newQObject(pb, QScriptEngine::ScriptOwnership); - QVERIFY(button.prototype().strictlyEquals(buttonProto)); - - buttonProto.setProperty("text", QScriptValue(&eng, "prototype button")); - QCOMPARE(pbp->text(), QLatin1String("prototype button")); - button.setProperty("text", QScriptValue(&eng, "not the prototype button")); - QCOMPARE(pb->text(), QLatin1String("not the prototype button")); - QCOMPARE(pbp->text(), QLatin1String("prototype button")); - - buttonProto.setProperty("objectName", QScriptValue(&eng, "prototype button")); - QCOMPARE(pbp->objectName(), QLatin1String("prototype button")); - button.setProperty("objectName", QScriptValue(&eng, "not the prototype button")); - QCOMPARE(pb->objectName(), QLatin1String("not the prototype button")); - QCOMPARE(pbp->objectName(), QLatin1String("prototype button")); -} - -void tst_QScriptExtQObject::objectDeleted() -{ - QScriptEngine eng; - MyQObject *qobj = new MyQObject(); - QScriptValue v = eng.newQObject(qobj); - v.setProperty("objectName", QScriptValue(&eng, "foo")); - QCOMPARE(qobj->objectName(), QLatin1String("foo")); - v.setProperty("intProperty", QScriptValue(&eng, 123)); - QCOMPARE(qobj->intProperty(), 123); - qobj->resetQtFunctionInvoked(); - v.property("myInvokable").call(v); - QCOMPARE(qobj->qtFunctionInvoked(), 0); - - // now delete the object - delete qobj; - - // the documented behavior is: isQObject() should still return true, - // but toQObject() should return 0 - QVERIFY(v.isQObject()); - QCOMPARE(v.toQObject(), (QObject *)0); - - // any attempt to access properties of the object should result in an exception - { - QScriptValue ret = v.property("objectName"); - QVERIFY(ret.isError()); - QCOMPARE(ret.toString(), QLatin1String("Error: cannot access member `objectName' of deleted QObject")); - } - { - eng.evaluate("Object"); - QVERIFY(!eng.hasUncaughtException()); - v.setProperty("objectName", QScriptValue(&eng, "foo")); - QVERIFY(eng.hasUncaughtException()); - QVERIFY(eng.uncaughtException().isError()); - QCOMPARE(eng.uncaughtException().toString(), QLatin1String("Error: cannot access member `objectName' of deleted QObject")); - } - - { - QScriptValue ret = v.call(); - QVERIFY(!ret.isValid()); - } - - // myInvokable is stored in member table (since we've accessed it before deletion) - QVERIFY(v.property("myInvokable").isFunction()); - { - QScriptValue ret = v.property("myInvokable").call(v); - QVERIFY(ret.isError()); - QCOMPARE(ret.toString(), QLatin1String("Error: cannot call function of deleted QObject")); - } - // myInvokableWithIntArg is not stored in member table (since we've not accessed it) - { - QScriptValue ret = v.property("myInvokableWithIntArg"); - QVERIFY(ret.isError()); - QCOMPARE(ret.toString(), QLatin1String("Error: cannot access member `myInvokableWithIntArg' of deleted QObject")); - } - - // access from script - eng.globalObject().setProperty("o", v); - { - QScriptValue ret = eng.evaluate("o()"); - QVERIFY(ret.isError()); - QCOMPARE(ret.toString(), QLatin1String("TypeError: o is not a function")); - } - { - QScriptValue ret = eng.evaluate("o.objectName"); - QVERIFY(ret.isError()); - QCOMPARE(ret.toString(), QLatin1String("Error: cannot access member `objectName' of deleted QObject")); - } - { - QScriptValue ret = eng.evaluate("o.myInvokable()"); - QVERIFY(ret.isError()); - QCOMPARE(ret.toString(), QLatin1String("Error: cannot call function of deleted QObject")); - } - { - QScriptValue ret = eng.evaluate("o.myInvokableWithIntArg(10)"); - QVERIFY(ret.isError()); - QCOMPARE(ret.toString(), QLatin1String("Error: cannot access member `myInvokableWithIntArg' of deleted QObject")); - } -} - -void tst_QScriptExtQObject::connectToDestroyedSignal() -{ - // ### the following test currently depends on signal emission order -#if 0 - { - // case 1: deleted when the engine is not doing GC - QScriptEngine eng; - QObject *obj = new QObject(); - eng.globalObject().setProperty("o", eng.newQObject(obj, QScriptEngine::QtOwnership)); - eng.evaluate("o.destroyed.connect(function() { wasDestroyed = true; })"); - eng.evaluate("wasDestroyed = false"); - delete obj; - QVERIFY(eng.evaluate("wasDestroyed").toBoolean()); - } - { - // case 2: deleted when the engine is doing GC - QScriptEngine eng; - QObject *obj = new QObject(); - eng.globalObject().setProperty("o", eng.newQObject(obj, QScriptEngine::ScriptOwnership)); - eng.evaluate("o.destroyed.connect(function() { wasDestroyed = true; })"); - eng.evaluate("wasDestroyed = false"); - eng.evaluate("o = null"); - eng.collectGarbage(); - QVERIFY(eng.evaluate("wasDestroyed").toBoolean()); - } - { - // case 3: deleted when the engine is destroyed - QScriptEngine eng; - QObject *obj = new QObject(); - eng.globalObject().setProperty("o", eng.newQObject(obj, QScriptEngine::ScriptOwnership)); - eng.evaluate("o.destroyed.connect(function() { })"); - // the signal handler won't get called -- we don't want to crash - } -#endif -} - -QTEST_MAIN(tst_QScriptExtQObject) -#include "tst_qscriptqobject.moc" diff --git a/tests/auto/qscriptv8testsuite/tst_qscriptv8testsuite.cpp b/tests/auto/qscriptv8testsuite/tst_qscriptv8testsuite.cpp index 77bfeb5..2dfd157 100644 --- a/tests/auto/qscriptv8testsuite/tst_qscriptv8testsuite.cpp +++ b/tests/auto/qscriptv8testsuite/tst_qscriptv8testsuite.cpp @@ -254,6 +254,8 @@ tst_Suite::tst_Suite() addTestExclusion("mul-exhaustive", "Demands too much memory on WinCE"); #endif + static const char klass[] = "tst_QScriptV8TestSuite"; + QVector *data = qt_meta_data_tst_Suite(); // content: *data << 1 // revision @@ -265,7 +267,7 @@ tst_Suite::tst_Suite() ; QVector *stringdata = qt_meta_stringdata_tst_Suite(); - appendCString(stringdata, "tst_Suite"); + appendCString(stringdata, klass); appendCString(stringdata, ""); QFileInfoList testFileInfos; @@ -275,7 +277,8 @@ tst_Suite::tst_Suite() QString name = tfi.baseName(); // slot: signature, parameters, type, tag, flags QString slot = QString::fromLatin1("%0()").arg(name); - *data << stringdata->size() << 10 << 10 << 10 << 0x08; + static const int nullbyte = sizeof(klass); + *data << stringdata->size() << nullbyte << nullbyte << nullbyte << 0x08; appendCString(stringdata, slot.toLatin1()); testNames.append(name); } diff --git a/tests/auto/qtextscriptengine/tst_qtextscriptengine.cpp b/tests/auto/qtextscriptengine/tst_qtextscriptengine.cpp index 30f97ba..13d0f34 100644 --- a/tests/auto/qtextscriptengine/tst_qtextscriptengine.cpp +++ b/tests/auto/qtextscriptengine/tst_qtextscriptengine.cpp @@ -76,13 +76,13 @@ // This test depends on the fonts in the following package being installed: // http://people.freedesktop.org/~hausmann/harfbuzz-test-fonts-0.1.tar.bz2 -class tst_QScriptEngine : public QObject +class tst_QTextScriptEngine : public QObject { Q_OBJECT public: - tst_QScriptEngine(); - virtual ~tst_QScriptEngine(); + tst_QTextScriptEngine(); + virtual ~tst_QTextScriptEngine(); public slots: @@ -104,19 +104,19 @@ private slots: void linearB(); }; -tst_QScriptEngine::tst_QScriptEngine() +tst_QTextScriptEngine::tst_QTextScriptEngine() { } -tst_QScriptEngine::~tst_QScriptEngine() +tst_QTextScriptEngine::~tst_QTextScriptEngine() { } -void tst_QScriptEngine::init() +void tst_QTextScriptEngine::init() { } -void tst_QScriptEngine::cleanup() +void tst_QTextScriptEngine::cleanup() { } @@ -172,7 +172,7 @@ static bool shaping( const QFont &f, const ShapeTable *s) } #endif -void tst_QScriptEngine::devanagari() +void tst_QTextScriptEngine::devanagari() { #if defined(Q_WS_X11) { @@ -284,7 +284,7 @@ void tst_QScriptEngine::devanagari() #endif } -void tst_QScriptEngine::bengali() +void tst_QTextScriptEngine::bengali() { #if defined(Q_WS_X11) { @@ -531,7 +531,7 @@ void tst_QScriptEngine::bengali() #endif } -void tst_QScriptEngine::gurmukhi() +void tst_QTextScriptEngine::gurmukhi() { #if defined(Q_WS_X11) { @@ -556,7 +556,7 @@ void tst_QScriptEngine::gurmukhi() #endif } -void tst_QScriptEngine::oriya() +void tst_QTextScriptEngine::oriya() { #if defined(Q_WS_X11) { @@ -596,7 +596,7 @@ void tst_QScriptEngine::oriya() } -void tst_QScriptEngine::tamil() +void tst_QTextScriptEngine::tamil() { #if defined(Q_WS_X11) { @@ -667,7 +667,7 @@ void tst_QScriptEngine::tamil() } -void tst_QScriptEngine::telugu() +void tst_QTextScriptEngine::telugu() { #if defined(Q_WS_X11) { @@ -713,7 +713,7 @@ void tst_QScriptEngine::telugu() } -void tst_QScriptEngine::kannada() +void tst_QTextScriptEngine::kannada() { #if defined(Q_WS_X11) { @@ -783,7 +783,7 @@ void tst_QScriptEngine::kannada() -void tst_QScriptEngine::malayalam() +void tst_QTextScriptEngine::malayalam() { #if defined(Q_WS_X11) { @@ -838,7 +838,7 @@ void tst_QScriptEngine::malayalam() -void tst_QScriptEngine::khmer() +void tst_QTextScriptEngine::khmer() { #if defined(Q_WS_X11) { @@ -881,7 +881,7 @@ void tst_QScriptEngine::khmer() #endif } -void tst_QScriptEngine::linearB() +void tst_QTextScriptEngine::linearB() { #if defined(Q_WS_X11) { @@ -909,5 +909,5 @@ void tst_QScriptEngine::linearB() } -QTEST_MAIN(tst_QScriptEngine) +QTEST_MAIN(tst_QTextScriptEngine) #include "tst_qtextscriptengine.moc" -- cgit v0.12