summaryrefslogtreecommitdiffstats
path: root/tests/auto
diff options
context:
space:
mode:
authorGabriel de Dietrich <gabriel.dietrich-de@nokia.com>2011-02-08 10:57:34 (GMT)
committerGabriel de Dietrich <gabriel.dietrich-de@nokia.com>2011-02-08 10:57:34 (GMT)
commiteb7958c65b09569c2531d2c443a6d0fe0b507d97 (patch)
tree91544e4a4cf5c65b3acec7c219ebe63176a14994 /tests/auto
parentef998bca70a799806c5754edfa49ea625881bc3e (diff)
parent44298c848ac254fe1942eb32eed7651dec5bf0e3 (diff)
downloadQt-eb7958c65b09569c2531d2c443a6d0fe0b507d97.zip
Qt-eb7958c65b09569c2531d2c443a6d0fe0b507d97.tar.gz
Qt-eb7958c65b09569c2531d2c443a6d0fe0b507d97.tar.bz2
Merge branch 'master-upstream'
Diffstat (limited to 'tests/auto')
-rw-r--r--tests/auto/declarative/qdeclarativeborderimage/data/colors-round-remote.sci7
-rw-r--r--tests/auto/declarative/qdeclarativeborderimage/tst_qdeclarativeborderimage.cpp1
-rw-r--r--tests/auto/declarative/qdeclarativelistview/tst_qdeclarativelistview.cpp13
-rw-r--r--tests/auto/declarative/qdeclarativeloader/tst_qdeclarativeloader.cpp94
-rw-r--r--tests/auto/declarative/qdeclarativetextedit/tst_qdeclarativetextedit.cpp12
-rw-r--r--tests/auto/linguist/lupdate/testdata/good/parseqml/main.qml3
-rw-r--r--tests/auto/linguist/lupdate/testdata/good/parseqml/project.ts.result5
-rw-r--r--tests/auto/qcolor/tst_qcolor.cpp10
-rw-r--r--tests/auto/qcoreapplication/tst_qcoreapplication.cpp45
-rw-r--r--tests/auto/qeventloop/tst_qeventloop.cpp41
-rw-r--r--tests/auto/qfontdatabase/tst_qfontdatabase.cpp4
-rw-r--r--tests/auto/qglthreads/tst_qglthreads.cpp2
-rw-r--r--tests/auto/qgraphicsgridlayout/tst_qgraphicsgridlayout.cpp158
-rw-r--r--tests/auto/qgraphicslinearlayout/tst_qgraphicslinearlayout.cpp26
-rw-r--r--tests/auto/qgraphicsview/tst_qgraphicsview.cpp8
-rw-r--r--tests/auto/qhttp/tst_qhttp.cpp4
-rw-r--r--tests/auto/qlayout/qlayout.pro6
-rw-r--r--tests/auto/qlayout/tst_qlayout.cpp3
-rw-r--r--tests/auto/qmake/testcompiler.cpp23
-rw-r--r--tests/auto/qmutex/tst_qmutex.cpp38
-rw-r--r--tests/auto/qnetworkreply/tst_qnetworkreply.cpp30
-rw-r--r--tests/auto/qpainterpath/tst_qpainterpath.cpp51
-rw-r--r--tests/auto/qscriptclass/tst_qscriptclass.cpp599
-rw-r--r--tests/auto/qscriptcontext/tst_qscriptcontext.cpp330
-rw-r--r--tests/auto/qscriptcontextinfo/tst_qscriptcontextinfo.cpp8
-rw-r--r--tests/auto/qscriptengine/tst_qscriptengine.cpp864
-rw-r--r--tests/auto/qscriptextqobject/tst_qscriptextqobject.cpp46
-rw-r--r--tests/auto/qstatemachine/tst_qstatemachine.cpp68
-rw-r--r--tests/auto/qstring/tst_qstring.cpp4
-rw-r--r--tests/auto/qtextcursor/tst_qtextcursor.cpp28
-rw-r--r--tests/auto/qtipc/qsharedmemory/tst_qsharedmemory.cpp5
-rw-r--r--tests/auto/qwidget/tst_qwidget.cpp95
-rw-r--r--tests/auto/qwidget/tst_qwidget_mac_helpers.h13
-rw-r--r--tests/auto/qwidget/tst_qwidget_mac_helpers.mm44
34 files changed, 1852 insertions, 836 deletions
diff --git a/tests/auto/declarative/qdeclarativeborderimage/data/colors-round-remote.sci b/tests/auto/declarative/qdeclarativeborderimage/data/colors-round-remote.sci
new file mode 100644
index 0000000..c673bed
--- /dev/null
+++ b/tests/auto/declarative/qdeclarativeborderimage/data/colors-round-remote.sci
@@ -0,0 +1,7 @@
+border.left:10
+border.top:20
+border.right:30
+border.bottom:40
+horizontalTileRule:Round
+verticalTileRule:Repeat
+source:http://127.0.0.1:14446/colors.png
diff --git a/tests/auto/declarative/qdeclarativeborderimage/tst_qdeclarativeborderimage.cpp b/tests/auto/declarative/qdeclarativeborderimage/tst_qdeclarativeborderimage.cpp
index e6543e6..bc2f170 100644
--- a/tests/auto/declarative/qdeclarativeborderimage/tst_qdeclarativeborderimage.cpp
+++ b/tests/auto/declarative/qdeclarativeborderimage/tst_qdeclarativeborderimage.cpp
@@ -294,6 +294,7 @@ void tst_qdeclarativeborderimage::sciSource_data()
QTest::newRow("local") << QUrl::fromLocalFile(SRCDIR "/data/colors-round.sci").toString() << true;
QTest::newRow("local not found") << QUrl::fromLocalFile(SRCDIR "/data/no-such-file.sci").toString() << false;
QTest::newRow("remote") << SERVER_ADDR "/colors-round.sci" << true;
+ QTest::newRow("remote image") << SERVER_ADDR "/colors-round-remote.sci" << true;
QTest::newRow("remote not found") << SERVER_ADDR "/no-such-file.sci" << false;
}
diff --git a/tests/auto/declarative/qdeclarativelistview/tst_qdeclarativelistview.cpp b/tests/auto/declarative/qdeclarativelistview/tst_qdeclarativelistview.cpp
index b343010..9b6f04c 100644
--- a/tests/auto/declarative/qdeclarativelistview/tst_qdeclarativelistview.cpp
+++ b/tests/auto/declarative/qdeclarativelistview/tst_qdeclarativelistview.cpp
@@ -1329,6 +1329,19 @@ void tst_QDeclarativeListView::positionViewAtIndex()
QTRY_COMPARE(item->y(), i*20.);
}
+ // Position at End using last index
+ listview->positionViewAtIndex(model.count()-1, QDeclarativeListView::End);
+ QTRY_COMPARE(listview->contentY(), 480.);
+
+ // Confirm items positioned correctly
+ itemCount = findItems<QDeclarativeItem>(contentItem, "wrapper").count();
+ for (int i = 24; i < model.count(); ++i) {
+ QDeclarativeItem *item = findItem<QDeclarativeItem>(contentItem, "wrapper", i);
+ if (!item) qWarning() << "Item" << i << "not found";
+ QTRY_VERIFY(item);
+ QTRY_COMPARE(item->y(), i*20.);
+ }
+
// Position at End
listview->positionViewAtIndex(20, QDeclarativeListView::End);
QTRY_COMPARE(listview->contentY(), 100.);
diff --git a/tests/auto/declarative/qdeclarativeloader/tst_qdeclarativeloader.cpp b/tests/auto/declarative/qdeclarativeloader/tst_qdeclarativeloader.cpp
index 358822e..bfa81ed 100644
--- a/tests/auto/declarative/qdeclarativeloader/tst_qdeclarativeloader.cpp
+++ b/tests/auto/declarative/qdeclarativeloader/tst_qdeclarativeloader.cpp
@@ -69,8 +69,9 @@ public:
tst_QDeclarativeLoader();
private slots:
- void sourceOrComponent();
- void sourceOrComponent_data();
+ void url();
+ void invalidUrl();
+ void component();
void clear();
void urlToComponent();
void componentToUrl();
@@ -99,71 +100,56 @@ tst_QDeclarativeLoader::tst_QDeclarativeLoader()
{
}
-void tst_QDeclarativeLoader::sourceOrComponent()
+void tst_QDeclarativeLoader::url()
{
- QFETCH(QString, sourceDefinition);
- QFETCH(QUrl, sourceUrl);
- QFETCH(QString, errorString);
-
- bool error = !errorString.isEmpty();
- if (error)
- QTest::ignoreMessage(QtWarningMsg, errorString.toUtf8().constData());
-
QDeclarativeComponent component(&engine);
- component.setData(QByteArray(
- "import QtQuick 1.0\n"
- "Loader {\n"
- " property int onItemChangedCount: 0\n"
- " property int onSourceChangedCount: 0\n"
- " property int onStatusChangedCount: 0\n"
- " property int onProgressChangedCount: 0\n"
- " property int onLoadedCount: 0\n")
- + sourceDefinition.toUtf8()
- + QByteArray(
- " onItemChanged: onItemChangedCount += 1\n"
- " onSourceChanged: onSourceChangedCount += 1\n"
- " onStatusChanged: onStatusChangedCount += 1\n"
- " onProgressChanged: onProgressChangedCount += 1\n"
- " onLoaded: onLoadedCount += 1\n"
- "}")
- , TEST_FILE(""));
-
+ component.setData(QByteArray("import QtQuick 1.0\nLoader { property int did_load: 0; onLoaded: did_load=123; source: \"Rect120x60.qml\" }"), TEST_FILE(""));
QDeclarativeLoader *loader = qobject_cast<QDeclarativeLoader*>(component.create());
QVERIFY(loader != 0);
- QCOMPARE(loader->item() == 0, error);
- QCOMPARE(loader->source(), sourceUrl);
+ QVERIFY(loader->item());
+ QVERIFY(loader->source() == QUrl::fromLocalFile(SRCDIR "/data/Rect120x60.qml"));
QCOMPARE(loader->progress(), 1.0);
+ QCOMPARE(loader->status(), QDeclarativeLoader::Ready);
+ QCOMPARE(loader->property("did_load").toInt(), 123);
+ QCOMPARE(static_cast<QGraphicsItem*>(loader)->children().count(), 1);
- QCOMPARE(loader->status(), error ? QDeclarativeLoader::Error : QDeclarativeLoader::Ready);
- QCOMPARE(static_cast<QGraphicsItem*>(loader)->children().count(), error ? 0: 1);
+ delete loader;
+}
- if (!error) {
- QDeclarativeComponent *c = qobject_cast<QDeclarativeComponent*>(loader->QGraphicsObject::children().at(0));
- QVERIFY(c);
- QCOMPARE(loader->sourceComponent(), c);
- }
+void tst_QDeclarativeLoader::component()
+{
+ QDeclarativeComponent component(&engine, TEST_FILE("/SetSourceComponent.qml"));
+ QDeclarativeItem *item = qobject_cast<QDeclarativeItem*>(component.create());
+ QVERIFY(item);
- QCOMPARE(loader->property("onSourceChangedCount").toInt(), 1);
- QCOMPARE(loader->property("onStatusChangedCount").toInt(), 1);
- QCOMPARE(loader->property("onProgressChangedCount").toInt(), 1);
+ QDeclarativeLoader *loader = qobject_cast<QDeclarativeLoader*>(item->QGraphicsObject::children().at(1));
+ QVERIFY(loader);
+ QVERIFY(loader->item());
+ QCOMPARE(loader->progress(), 1.0);
+ QCOMPARE(loader->status(), QDeclarativeLoader::Ready);
+ QCOMPARE(static_cast<QGraphicsItem*>(loader)->children().count(), 1);
- QCOMPARE(loader->property("onItemChangedCount").toInt(), error ? 0 : 1);
- QCOMPARE(loader->property("onLoadedCount").toInt(), error ? 0 : 1);
+ QDeclarativeComponent *c = qobject_cast<QDeclarativeComponent*>(item->QGraphicsObject::children().at(0));
+ QVERIFY(c);
+ QCOMPARE(loader->sourceComponent(), c);
- delete loader;
+ delete item;
}
-void tst_QDeclarativeLoader::sourceOrComponent_data()
+void tst_QDeclarativeLoader::invalidUrl()
{
- QTest::addColumn<QString>("sourceDefinition");
- QTest::addColumn<QUrl>("sourceUrl");
- QTest::addColumn<QString>("errorString");
+ QTest::ignoreMessage(QtWarningMsg, QString(QUrl::fromLocalFile(SRCDIR "/data/IDontExist.qml").toString() + ": File not found").toUtf8().constData());
- QTest::newRow("source") << "source: 'Rect120x60.qml'\n" << QUrl::fromLocalFile(SRCDIR "/data/Rect120x60.qml") << "";
- QTest::newRow("sourceComponent") << "Component { id: comp; Rectangle { width: 100; height: 50 } }\n sourceComponent: comp\n" << QUrl() << "";
+ QDeclarativeComponent component(&engine);
+ component.setData(QByteArray("import QtQuick 1.0\nLoader { source: \"IDontExist.qml\" }"), TEST_FILE(""));
+ QDeclarativeLoader *loader = qobject_cast<QDeclarativeLoader*>(component.create());
+ QVERIFY(loader != 0);
+ QVERIFY(loader->item() == 0);
+ QCOMPARE(loader->progress(), 1.0);
+ QCOMPARE(loader->status(), QDeclarativeLoader::Error);
+ QCOMPARE(static_cast<QGraphicsItem*>(loader)->children().count(), 0);
- QTest::newRow("invalid source") << "source: 'IDontExist.qml'\n" << QUrl::fromLocalFile(SRCDIR "/data/IDontExist.qml")
- << QString(QUrl::fromLocalFile(SRCDIR "/data/IDontExist.qml").toString() + ": File not found");
+ delete loader;
}
void tst_QDeclarativeLoader::clear()
@@ -460,7 +446,7 @@ void tst_QDeclarativeLoader::networkRequestUrl()
server.serveDirectory(SRCDIR "/data");
QDeclarativeComponent component(&engine);
- component.setData(QByteArray("import QtQuick 1.0\nLoader { property int signalCount : 0; source: \"http://127.0.0.1:14450/Rect120x60.qml\"; onLoaded: signalCount += 1 }"), QUrl::fromLocalFile(SRCDIR "/dummy.qml"));
+ component.setData(QByteArray("import QtQuick 1.0\nLoader { property int did_load : 0; source: \"http://127.0.0.1:14450/Rect120x60.qml\"; onLoaded: did_load=123 }"), QUrl::fromLocalFile(SRCDIR "/dummy.qml"));
if (component.isError())
qDebug() << component.errors();
QDeclarativeLoader *loader = qobject_cast<QDeclarativeLoader*>(component.create());
@@ -470,7 +456,7 @@ void tst_QDeclarativeLoader::networkRequestUrl()
QVERIFY(loader->item());
QCOMPARE(loader->progress(), 1.0);
- QCOMPARE(loader->property("signalCount").toInt(), 1);
+ QCOMPARE(loader->property("did_load").toInt(), 123);
QCOMPARE(static_cast<QGraphicsItem*>(loader)->children().count(), 1);
delete loader;
diff --git a/tests/auto/declarative/qdeclarativetextedit/tst_qdeclarativetextedit.cpp b/tests/auto/declarative/qdeclarativetextedit/tst_qdeclarativetextedit.cpp
index 615b919..ba1a95f 100644
--- a/tests/auto/declarative/qdeclarativetextedit/tst_qdeclarativetextedit.cpp
+++ b/tests/auto/declarative/qdeclarativetextedit/tst_qdeclarativetextedit.cpp
@@ -373,6 +373,8 @@ void tst_qdeclarativetextedit::alignments()
QImage expect(expectfile);
QCOMPARE(actual,expect);
+
+ delete canvas;
}
@@ -745,6 +747,8 @@ void tst_qdeclarativetextedit::mouseSelection()
QVERIFY(str.length() > 3); // don't reallly care *what* was selected (and it's too sensitive to platform)
else
QVERIFY(str.isEmpty());
+
+ delete canvas;
}
void tst_qdeclarativetextedit::inputMethodHints()
@@ -759,6 +763,8 @@ void tst_qdeclarativetextedit::inputMethodHints()
QVERIFY(textEditObject->inputMethodHints() & Qt::ImhNoPredictiveText);
textEditObject->setInputMethodHints(Qt::ImhUppercaseOnly);
QVERIFY(textEditObject->inputMethodHints() & Qt::ImhUppercaseOnly);
+
+ delete canvas;
}
void tst_qdeclarativetextedit::cursorDelegate()
@@ -785,6 +791,8 @@ void tst_qdeclarativetextedit::cursorDelegate()
//Test Delegate gets deleted
textEditObject->setCursorDelegate(0);
QVERIFY(!textEditObject->findChild<QDeclarativeItem*>("cursorInstance"));
+
+ delete view;
}
void tst_qdeclarativetextedit::delegateLoading_data()
@@ -867,6 +875,8 @@ void tst_qdeclarativetextedit::navigation()
QVERIFY(input->hasActiveFocus() == false);
simulateKey(canvas, Qt::Key_Left);
QVERIFY(input->hasActiveFocus() == true);
+
+ delete canvas;
}
void tst_qdeclarativetextedit::copyAndPaste() {
@@ -941,6 +951,8 @@ void tst_qdeclarativetextedit::readOnly()
simulateKey(canvas, Qt::Key_Space);
simulateKey(canvas, Qt::Key_Escape);
QCOMPARE(edit->text(), initial);
+
+ delete canvas;
}
void tst_qdeclarativetextedit::simulateKey(QDeclarativeView *view, int key)
diff --git a/tests/auto/linguist/lupdate/testdata/good/parseqml/main.qml b/tests/auto/linguist/lupdate/testdata/good/parseqml/main.qml
index 768a4e2..c966fa1 100644
--- a/tests/auto/linguist/lupdate/testdata/good/parseqml/main.qml
+++ b/tests/auto/linguist/lupdate/testdata/good/parseqml/main.qml
@@ -93,5 +93,8 @@ QtObject {
//: qsTrId() with comment, meta-data and plurals.
//~ well-tested True
qsTrId("qtn_bar_baz", 10);
+
+ //% "Source text"
+ qsTrId("qtn_baz_biz");
}
}
diff --git a/tests/auto/linguist/lupdate/testdata/good/parseqml/project.ts.result b/tests/auto/linguist/lupdate/testdata/good/parseqml/project.ts.result
index 7dac8cb..4843902 100644
--- a/tests/auto/linguist/lupdate/testdata/good/parseqml/project.ts.result
+++ b/tests/auto/linguist/lupdate/testdata/good/parseqml/project.ts.result
@@ -27,6 +27,11 @@
</translation>
<extra-well-tested>True</extra-well-tested>
</message>
+ <message id="qtn_baz_biz">
+ <location filename="main.qml" line="98"/>
+ <source>Source text</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>BarContext</name>
diff --git a/tests/auto/qcolor/tst_qcolor.cpp b/tests/auto/qcolor/tst_qcolor.cpp
index fcd608b..d42c26c 100644
--- a/tests/auto/qcolor/tst_qcolor.cpp
+++ b/tests/auto/qcolor/tst_qcolor.cpp
@@ -148,6 +148,8 @@ private slots:
void specConstructor_data();
void specConstructor();
+ void achromaticHslHue();
+
#ifdef Q_WS_X11
void allowX11ColorNames();
void setallowX11ColorNames();
@@ -1459,6 +1461,14 @@ void tst_QColor::specConstructor()
QCOMPARE(color.spec(), spec);
}
+void tst_QColor::achromaticHslHue()
+{
+ QColor color = Qt::black;
+
+ QColor hsl = color.toHsl();
+ QCOMPARE(hsl.hslHue(), -1);
+}
+
#ifdef Q_WS_X11
void tst_QColor::allowX11ColorNames()
{
diff --git a/tests/auto/qcoreapplication/tst_qcoreapplication.cpp b/tests/auto/qcoreapplication/tst_qcoreapplication.cpp
index 95055d1..bc69461 100644
--- a/tests/auto/qcoreapplication/tst_qcoreapplication.cpp
+++ b/tests/auto/qcoreapplication/tst_qcoreapplication.cpp
@@ -59,6 +59,9 @@ private slots:
void applicationPid();
void globalPostedEventsCount();
void processEventsAlwaysSendsPostedEvents();
+ void reexec();
+ void execAfterExit();
+ void eventLoopExecAfterExit();
};
class EventSpy : public QObject
@@ -524,5 +527,47 @@ void tst_QCoreApplication::processEventsAlwaysSendsPostedEvents()
} while (t.elapsed() < 3000);
}
+void tst_QCoreApplication::reexec()
+{
+ int argc = 1;
+ char *argv[] = { "tst_qcoreapplication" };
+ QCoreApplication app(argc, argv);
+
+ // exec once
+ QMetaObject::invokeMethod(&app, "quit", Qt::QueuedConnection);
+ QCOMPARE(app.exec(), 0);
+
+ // and again
+ QMetaObject::invokeMethod(&app, "quit", Qt::QueuedConnection);
+ QCOMPARE(app.exec(), 0);
+}
+
+void tst_QCoreApplication::execAfterExit()
+{
+ int argc = 1;
+ char *argv[] = { "tst_qcoreapplication" };
+ QCoreApplication app(argc, argv);
+
+ app.exit(1);
+ QMetaObject::invokeMethod(&app, "quit", Qt::QueuedConnection);
+ QCOMPARE(app.exec(), 0);
+}
+
+void tst_QCoreApplication::eventLoopExecAfterExit()
+{
+ int argc = 1;
+ char *argv[] = { "tst_qcoreapplication" };
+ QCoreApplication app(argc, argv);
+
+ // exec once and exit
+ QMetaObject::invokeMethod(&app, "quit", Qt::QueuedConnection);
+ QCOMPARE(app.exec(), 0);
+
+ // and again, but this time using a QEventLoop
+ QEventLoop loop;
+ QMetaObject::invokeMethod(&loop, "quit", Qt::QueuedConnection);
+ QCOMPARE(loop.exec(), 0);
+}
+
QTEST_APPLESS_MAIN(tst_QCoreApplication)
#include "tst_qcoreapplication.moc"
diff --git a/tests/auto/qeventloop/tst_qeventloop.cpp b/tests/auto/qeventloop/tst_qeventloop.cpp
index 7af722f..6860f19 100644
--- a/tests/auto/qeventloop/tst_qeventloop.cpp
+++ b/tests/auto/qeventloop/tst_qeventloop.cpp
@@ -112,6 +112,10 @@ signals:
public:
QMutex mutex;
QWaitCondition cond;
+ volatile int result1;
+ volatile int result2;
+ MultipleExecThread() : result1(0xdead), result2(0xbeef) {}
+
void run()
{
QMutexLocker locker(&mutex);
@@ -124,13 +128,13 @@ public:
connect(&timer, SIGNAL(timeout()), SLOT(quit()), Qt::DirectConnection);
timer.setInterval(1000);
timer.start();
- (void) exec();
+ result1 = exec();
// this should return immediately, since exit() has been called
cond.wakeOne();
cond.wait(&mutex);
QEventLoop eventLoop;
- (void) eventLoop.exec();
+ result2 = eventLoop.exec();
}
};
@@ -197,7 +201,9 @@ private slots:
void symbianNestedActiveSchedulerLoop();
void processEvents();
void exec();
+ void reexec();
void exit();
+ void execAfterExit();
void wakeUp();
void quit();
void processEventsExcludeSocket();
@@ -398,7 +404,9 @@ void tst_QEventLoop::exec()
}
{
- // calling exec() after exit()/quit() should return immediately
+ // calling QEventLoop::exec() after a thread loop has exit()ed should return immediately
+ // Note: this behaviour differs from QCoreApplication and QEventLoop
+ // see tst_QCoreApplication::eventLoopExecAfterExit, tst_QEventLoop::reexec
MultipleExecThread thread;
// start thread and wait for checkpoint
@@ -411,6 +419,8 @@ void tst_QEventLoop::exec()
thread.cond.wakeOne();
thread.cond.wait(&thread.mutex);
QVERIFY(spy.count() > 0);
+ int v = thread.result1;
+ QCOMPARE(v, 0);
// exec should return immediately
spy.clear();
@@ -418,6 +428,8 @@ void tst_QEventLoop::exec()
thread.mutex.unlock();
thread.wait();
QCOMPARE(spy.count(), 0);
+ v = thread.result2;
+ QCOMPARE(v, -1);
}
{
@@ -462,9 +474,32 @@ void tst_QEventLoop::exec()
#endif
}
+void tst_QEventLoop::reexec()
+{
+ QEventLoop loop;
+
+ // exec once
+ QMetaObject::invokeMethod(&loop, "quit", Qt::QueuedConnection);
+ QCOMPARE(loop.exec(), 0);
+
+ // and again
+ QMetaObject::invokeMethod(&loop, "quit", Qt::QueuedConnection);
+ QCOMPARE(loop.exec(), 0);
+}
+
void tst_QEventLoop::exit()
{ DEPENDS_ON(exec()); }
+void tst_QEventLoop::execAfterExit()
+{
+ QEventLoop loop;
+ EventLoopExiter obj(&loop);
+
+ QMetaObject::invokeMethod(&obj, "exit", Qt::QueuedConnection);
+ loop.exit(1);
+ QCOMPARE(loop.exec(), 0);
+}
+
void tst_QEventLoop::wakeUp()
{
EventLoopThread thread;
diff --git a/tests/auto/qfontdatabase/tst_qfontdatabase.cpp b/tests/auto/qfontdatabase/tst_qfontdatabase.cpp
index fe216e7..b1876b0 100644
--- a/tests/auto/qfontdatabase/tst_qfontdatabase.cpp
+++ b/tests/auto/qfontdatabase/tst_qfontdatabase.cpp
@@ -224,9 +224,6 @@ void tst_QFontDatabase::addAppFont_data()
void tst_QFontDatabase::addAppFont()
{
-#ifdef Q_OS_SYMBIAN
- QSKIP( "Symbian: Application fonts are not yet supported", SkipAll );
-#else
QFETCH(bool, useMemoryFont);
QSignalSpy fontDbChangedSpy(QApplication::instance(), SIGNAL(fontDatabaseChanged()));
@@ -276,7 +273,6 @@ void tst_QFontDatabase::addAppFont()
QCOMPARE(fontDbChangedSpy.count(), 2);
QVERIFY(db.families() == oldFamilies);
-#endif
}
QTEST_MAIN(tst_QFontDatabase)
diff --git a/tests/auto/qglthreads/tst_qglthreads.cpp b/tests/auto/qglthreads/tst_qglthreads.cpp
index 434fd9d..45c8cbc 100644
--- a/tests/auto/qglthreads/tst_qglthreads.cpp
+++ b/tests/auto/qglthreads/tst_qglthreads.cpp
@@ -210,7 +210,7 @@ public:
// That's why we create only small textures.
width = 50;
height = 20;
-#else
+#endif
QImage image(width, height, QImage::Format_RGB32);
QPainter p(&image);
p.fillRect(image.rect(), QColor(rand() % 256, rand() % 256, rand() % 256));
diff --git a/tests/auto/qgraphicsgridlayout/tst_qgraphicsgridlayout.cpp b/tests/auto/qgraphicsgridlayout/tst_qgraphicsgridlayout.cpp
index 51f9f3b..837df78 100644
--- a/tests/auto/qgraphicsgridlayout/tst_qgraphicsgridlayout.cpp
+++ b/tests/auto/qgraphicsgridlayout/tst_qgraphicsgridlayout.cpp
@@ -121,6 +121,11 @@ private slots:
void avoidRecursionInInsertItem();
void styleInfoLeak();
void task236367_maxSizeHint();
+ void spanningItem2x2_data();
+ void spanningItem2x2();
+ void spanningItem2x3_data();
+ void spanningItem2x3();
+ void spanningItem();
void heightForWidth();
void widthForHeight();
void heightForWidthWithSpanning();
@@ -3230,6 +3235,159 @@ void tst_QGraphicsGridLayout::heightForWidthWithSpanning()
QCOMPARE(layout->effectiveSizeHint(Qt::MaximumSize, QSizeF(200, -1)), QSizeF(200, 10000));
}
+Q_DECLARE_METATYPE(QSizePolicy::Policy)
+void tst_QGraphicsGridLayout::spanningItem2x2_data()
+{
+ QTest::addColumn<QSizePolicy::Policy>("sizePolicy");
+ QTest::addColumn<int>("itemHeight");
+ QTest::addColumn<int>("expectedHeight");
+
+ QTest::newRow("A larger spanning item with 2 widgets with fixed policy") << QSizePolicy::Fixed << 39 << 80;
+ QTest::newRow("A larger spanning item with 2 widgets with preferred policy") << QSizePolicy::Preferred << 39 << 80;
+ QTest::newRow("An equally-sized spanning item with 2 widgets with fixed policy") << QSizePolicy::Fixed << 40 << 80;
+ QTest::newRow("An equally-sized spanning item with 2 widgets with preferred policy") << QSizePolicy::Preferred << 40 << 80;
+ QTest::newRow("A smaller spanning item with 2 widgets with fixed policy") << QSizePolicy::Fixed << 41 << 82;
+ QTest::newRow("A smaller spanning item with 2 widgets with preferred policy") << QSizePolicy::Preferred << 41 << 82;
+}
+
+void tst_QGraphicsGridLayout::spanningItem2x2()
+{
+ QFETCH(QSizePolicy::Policy, sizePolicy);
+ QFETCH(int, itemHeight);
+ QFETCH(int, expectedHeight);
+ QGraphicsWidget *form = new QGraphicsWidget(0, Qt::Window);
+ QGraphicsGridLayout *layout = new QGraphicsGridLayout(form);
+ layout->setContentsMargins(0, 0, 0, 0);
+ layout->setSpacing(0);
+
+ QGraphicsWidget *w1 = new QGraphicsWidget;
+ w1->setMinimumSize(80,80);
+ w1->setMaximumSize(80,80);
+
+ QGraphicsWidget *w2 = new QGraphicsWidget;
+ w2->setMinimumSize(80,itemHeight);
+ w2->setPreferredSize(80,itemHeight);
+ w2->setSizePolicy(QSizePolicy::Fixed, sizePolicy);
+
+ QGraphicsWidget *w3 = new QGraphicsWidget;
+ w3->setMinimumSize(80,itemHeight);
+ w3->setPreferredSize(80,itemHeight);
+ w3->setSizePolicy(QSizePolicy::Fixed, sizePolicy);
+
+ layout->addItem(w1, 0, 0, 2, 1);
+ layout->addItem(w2, 0, 1);
+ layout->addItem(w3, 1, 1);
+
+ QCOMPARE(layout->minimumSize(), QSizeF(160,expectedHeight));
+ if(sizePolicy == QSizePolicy::Fixed)
+ QCOMPARE(layout->maximumSize(), QSizeF(160,expectedHeight));
+ else
+ QCOMPARE(layout->maximumSize(), QSizeF(160,QWIDGETSIZE_MAX));
+}
+
+void tst_QGraphicsGridLayout::spanningItem2x3_data()
+{
+ QTest::addColumn<bool>("w1_fixed");
+ QTest::addColumn<bool>("w2_fixed");
+ QTest::addColumn<bool>("w3_fixed");
+ QTest::addColumn<bool>("w4_fixed");
+ QTest::addColumn<bool>("w5_fixed");
+
+ for(int w1 = 0; w1 < 2; w1++)
+ for(int w2 = 0; w2 < 2; w2++)
+ for(int w3 = 0; w3 < 2; w3++)
+ for(int w4 = 0; w4 < 2; w4++)
+ for(int w5 = 0; w5 < 2; w5++) {
+ QString description = QString("Fixed sizes:") + (w1?" w1":"") + (w2?" w2":"") + (w3?" w3":"") + (w4?" w4":"") + (w5?" w5":"");
+ QTest::newRow(description.toLatin1()) << (bool)w1 << (bool)w2 << (bool)w3 << (bool)w4 << (bool)w5;
+ }
+}
+
+void tst_QGraphicsGridLayout::spanningItem2x3()
+{
+ QFETCH(bool, w1_fixed);
+ QFETCH(bool, w2_fixed);
+ QFETCH(bool, w3_fixed);
+ QFETCH(bool, w4_fixed);
+ QFETCH(bool, w5_fixed);
+ QGraphicsGridLayout *layout = new QGraphicsGridLayout;
+ layout->setContentsMargins(0, 0, 0, 0);
+ layout->setSpacing(0);
+
+ QGraphicsWidget *w1 = new QGraphicsWidget;
+ w1->setMinimumSize(80,80);
+ w1->setMaximumSize(80,80);
+ if (w1_fixed)
+ w1->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
+
+ QGraphicsWidget *w2 = new QGraphicsWidget;
+ w2->setMinimumSize(80,48);
+ w2->setPreferredSize(80,48);
+ if (w2_fixed)
+ w2->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
+
+ QGraphicsWidget *w3 = new QGraphicsWidget;
+ w3->setMinimumSize(80,30);
+ w3->setPreferredSize(80,30);
+ if (w3_fixed)
+ w3->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
+
+ QGraphicsWidget *w4 = new QGraphicsWidget;
+ w4->setMinimumSize(80,30);
+ w4->setMaximumSize(80,30);
+ if (w4_fixed)
+ w4->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
+
+ QGraphicsWidget *w5 = new QGraphicsWidget;
+ w5->setMinimumSize(40,24);
+ w5->setMaximumSize(40,24);
+ if (w5_fixed)
+ w5->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
+
+ layout->addItem(w1, 0, 0, 2, 1);
+ layout->addItem(w2, 0, 1);
+ layout->addItem(w3, 1, 1);
+ layout->addItem(w4, 0, 2);
+ layout->addItem(w5, 1, 2);
+
+ QCOMPARE(layout->minimumSize(), QSizeF(240,80));
+ // Only w2 and w3 grow vertically, so when they have a fixed vertical size policy,
+ // the whole layout cannot grow vertically.
+ if (w2_fixed && w3_fixed)
+ QCOMPARE(layout->maximumSize(), QSizeF(QWIDGETSIZE_MAX,80));
+ else
+ QCOMPARE(layout->maximumSize(), QSizeF(QWIDGETSIZE_MAX,QWIDGETSIZE_MAX));
+}
+
+void tst_QGraphicsGridLayout::spanningItem()
+{
+ QGraphicsWidget *form = new QGraphicsWidget(0, Qt::Window);
+ QGraphicsGridLayout *layout = new QGraphicsGridLayout(form);
+ layout->setContentsMargins(0, 0, 0, 0);
+ layout->setSpacing(0);
+
+ QGraphicsWidget *w1 = new QGraphicsWidget;
+ w1->setMinimumSize(80,80);
+ w1->setMaximumSize(80,80);
+
+ QGraphicsWidget *w2 = new QGraphicsWidget;
+ w2->setMinimumSize(80,38);
+ w2->setPreferredSize(80,38);
+ w2->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
+
+ QGraphicsWidget *w3 = new QGraphicsWidget;
+ w3->setMinimumSize(80,38);
+ w3->setPreferredSize(80,38);
+ w3->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
+
+ layout->addItem(w1, 0, 0, 2, 1);
+ layout->addItem(w2, 0, 1);
+ layout->addItem(w3, 1, 1);
+
+ QCOMPARE(layout->minimumSize(), QSizeF(160,80));
+ QCOMPARE(layout->maximumSize(), QSizeF(160,80));
+}
+
void tst_QGraphicsGridLayout::stretchAndHeightForWidth()
{
QGraphicsWidget *widget = new QGraphicsWidget(0, Qt::Window);
diff --git a/tests/auto/qgraphicslinearlayout/tst_qgraphicslinearlayout.cpp b/tests/auto/qgraphicslinearlayout/tst_qgraphicslinearlayout.cpp
index a024f65..62ba1b4 100644
--- a/tests/auto/qgraphicslinearlayout/tst_qgraphicslinearlayout.cpp
+++ b/tests/auto/qgraphicslinearlayout/tst_qgraphicslinearlayout.cpp
@@ -106,6 +106,7 @@ private slots:
void testAlignmentInLargerLayout();
void testOffByOneInLargerLayout();
void testDefaultAlignment();
+ void combineSizePolicies();
// Task specific tests
void task218400_insertStretchCrash();
@@ -1583,6 +1584,31 @@ void tst_QGraphicsLinearLayout::testDefaultAlignment()
QCOMPARE(w2->geometry(), QRectF(0,50,100,100));
}
+void tst_QGraphicsLinearLayout::combineSizePolicies()
+{
+ QGraphicsWidget *widget = new QGraphicsWidget;
+ QGraphicsLinearLayout *layout = new QGraphicsLinearLayout(Qt::Horizontal, widget);
+ layout->setContentsMargins(0, 0, 0, 0);
+ layout->setSpacing(0);
+
+ QGraphicsWidget *w1 = new QGraphicsWidget;
+ w1->setMaximumSize(200,200);
+ w1->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
+ layout->addItem(w1);
+
+ QGraphicsWidget *w2 = new QGraphicsWidget;
+ w2->setPreferredSize(50,50);
+ w2->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
+ layout->addItem(w2);
+ QCOMPARE(layout->maximumHeight(), qreal(200));
+
+ // now remove the fixed vertical size policy, and set instead the maximum height to 50
+ // this should in effect give the same maximumHeight
+ w2->setMaximumHeight(50);
+ w2->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);
+ QCOMPARE(layout->maximumHeight(), qreal(200));
+}
+
QTEST_MAIN(tst_QGraphicsLinearLayout)
#include "tst_qgraphicslinearlayout.moc"
diff --git a/tests/auto/qgraphicsview/tst_qgraphicsview.cpp b/tests/auto/qgraphicsview/tst_qgraphicsview.cpp
index cf697bb..f8fc5d0 100644
--- a/tests/auto/qgraphicsview/tst_qgraphicsview.cpp
+++ b/tests/auto/qgraphicsview/tst_qgraphicsview.cpp
@@ -2967,7 +2967,7 @@ protected:
void tst_QGraphicsView::task186827_deleteReplayedItem()
{
// make sure the mouse is not over the window, causing spontaneous mouse moves
- QCursor::setPos(0, 0);
+ QCursor::setPos(1, 1);
QGraphicsScene scene;
scene.addRect(0, 0, 50, 50);
@@ -3357,6 +3357,10 @@ void tst_QGraphicsView::moveItemWhileScrolling()
int a = adjustForAntialiasing ? 2 : 1;
expectedRegion += QRect(40, 50, 10, 10).adjusted(-a, -a, a, a);
expectedRegion += QRect(40, 60, 10, 10).adjusted(-a, -a, a, a);
+#ifdef QT_MAC_USE_COCOA
+ if (QApplicationPrivate::graphicsSystem() == 0)
+ QEXPECT_FAIL("", "This will fail with Cocoa because paint events are not send in the order expected by graphicsview", Continue);
+#endif
COMPARE_REGIONS(view.lastPaintedRegion, expectedRegion);
}
@@ -4500,7 +4504,7 @@ void tst_QGraphicsView::hoverLeave()
QVERIFY(item->receivedEnterEvent);
QCOMPARE(item->enterWidget, view.viewport());
- QCursor::setPos(0,0);
+ QCursor::setPos(1,1);
QTest::qWait(200);
QVERIFY(item->receivedLeaveEvent);
QCOMPARE(item->leaveWidget, view.viewport());
diff --git a/tests/auto/qhttp/tst_qhttp.cpp b/tests/auto/qhttp/tst_qhttp.cpp
index f706228..61123c2 100644
--- a/tests/auto/qhttp/tst_qhttp.cpp
+++ b/tests/auto/qhttp/tst_qhttp.cpp
@@ -856,7 +856,7 @@ void tst_QHttp::proxy2()
QTestEventLoop::instance().enterLoop(30);
QVERIFY(!QTestEventLoop::instance().timeout());
- QCOMPARE(readyRead_ba.count("Welcome to fluke.troll.no"), 2);
+ QCOMPARE(readyRead_ba.count("Welcome to qt-test-server"), 2);
readyRead_ba.clear();
}
@@ -891,7 +891,7 @@ void tst_QHttp::proxy3()
QTestEventLoop::instance().enterLoop(30);
QVERIFY(!QTestEventLoop::instance().timeout());
- QCOMPARE(readyRead_ba.count("Welcome to fluke.troll.no"), 2);
+ QCOMPARE(readyRead_ba.count("Welcome to qt-test-server"), 2);
readyRead_ba.clear();
}
diff --git a/tests/auto/qlayout/qlayout.pro b/tests/auto/qlayout/qlayout.pro
index dfa8584..bb1ae4a 100644
--- a/tests/auto/qlayout/qlayout.pro
+++ b/tests/auto/qlayout/qlayout.pro
@@ -10,5 +10,11 @@ wince*|symbian: {
addFiles.files = baseline
addFiles.path = .
DEPLOYMENT += addFiles
+} else {
+ DEFINES += SRCDIR=\\\"$$PWD\\\"
+
+ test_data.files = baseline/*
+ test_data.path = $${target.path}/baseline
+ INSTALLS += test_data
}
diff --git a/tests/auto/qlayout/tst_qlayout.cpp b/tests/auto/qlayout/tst_qlayout.cpp
index 65eae55..3090ebb 100644
--- a/tests/auto/qlayout/tst_qlayout.cpp
+++ b/tests/auto/qlayout/tst_qlayout.cpp
@@ -156,7 +156,8 @@ void tst_QLayout::smartMaxSize()
{
QVector<int> expectedWidths;
- QFile f(QLatin1String("baseline/smartmaxsize"));
+ QFile f(QLatin1String(SRCDIR "/baseline/smartmaxsize"));
+
QCOMPARE(f.open(QIODevice::ReadOnly | QIODevice::Text), true);
QTextStream stream(&f);
diff --git a/tests/auto/qmake/testcompiler.cpp b/tests/auto/qmake/testcompiler.cpp
index 021fe9b..dbdeee8 100644
--- a/tests/auto/qmake/testcompiler.cpp
+++ b/tests/auto/qmake/testcompiler.cpp
@@ -142,23 +142,16 @@ bool TestCompiler::runCommand( QString cmdline )
bool failed = false;
child.setReadChannel(QProcess::StandardError);
- while (QProcess::Running == child.state()) {
- if (child.waitForReadyRead(1000)) {
- QString output = child.readAllStandardError();
- testOutput_.append(output);
-
- output.prepend('\n');
- if (output.contains("\nProject MESSAGE: FAILED"))
- failed = true;
- }
- }
-
child.waitForFinished(-1);
- return failed
- ? false
- : (child.exitStatus() == QProcess::NormalExit)
- && (child.exitCode() == 0);
+ foreach (const QByteArray &output, child.readAllStandardError().split('\n')) {
+ testOutput_.append(QString::fromLocal8Bit(output));
+
+ if (output.startsWith("Project MESSAGE: FAILED"))
+ failed = true;
+ }
+
+ return !failed && child.exitStatus() == QProcess::NormalExit && child.exitCode() == 0;
}
void TestCompiler::setBaseCommands( QString makeCmd, QString qmakeCmd )
diff --git a/tests/auto/qmutex/tst_qmutex.cpp b/tests/auto/qmutex/tst_qmutex.cpp
index 3c4c767..ea983cb 100644
--- a/tests/auto/qmutex/tst_qmutex.cpp
+++ b/tests/auto/qmutex/tst_qmutex.cpp
@@ -67,6 +67,7 @@ private slots:
void lock_unlock_locked_tryLock();
void stressTest();
void tryLockRace();
+ void qtbug16115_trylock();
};
static const int iterations = 100;
@@ -464,5 +465,42 @@ void tst_QMutex::tryLockRace()
TryLockRaceThread::mutex.unlock();
}
+static volatile int qtbug16115_trylock_counter;
+
+void tst_QMutex::qtbug16115_trylock()
+{
+ //Used to deadlock on unix
+ struct TrylockThread : QThread {
+ TrylockThread(QMutex &mut) : mut(mut) {}
+ QMutex &mut;
+ void run() {
+ for (int i = 0; i < 1000000; ++i) {
+ if (mut.tryLock(0)) {
+ Q_ASSERT((++qtbug16115_trylock_counter) == 1);
+ Q_ASSERT((--qtbug16115_trylock_counter) == 0);
+ mut.unlock();
+ }
+ }
+ }
+ };
+ QMutex mut;
+ TrylockThread t1(mut);
+ TrylockThread t2(mut);
+ TrylockThread t3(mut);
+ t1.start();
+ t2.start();
+ t3.start();
+
+ for (int i = 0; i < 1000000; ++i) {
+ mut.lock();
+ Q_ASSERT((++qtbug16115_trylock_counter) == 1);
+ Q_ASSERT((--qtbug16115_trylock_counter) == 0);
+ mut.unlock();
+ }
+ t1.wait();
+ t2.wait();
+ t3.wait();
+}
+
QTEST_MAIN(tst_QMutex)
#include "tst_qmutex.moc"
diff --git a/tests/auto/qnetworkreply/tst_qnetworkreply.cpp b/tests/auto/qnetworkreply/tst_qnetworkreply.cpp
index 91eff6f..1d2a69f 100644
--- a/tests/auto/qnetworkreply/tst_qnetworkreply.cpp
+++ b/tests/auto/qnetworkreply/tst_qnetworkreply.cpp
@@ -213,6 +213,7 @@ private Q_SLOTS:
void ioGetFromBuiltinHttp();
void ioGetFromHttpWithReuseParallel();
void ioGetFromHttpWithReuseSequential();
+ void ioGetFromHttpWithAuth_data();
void ioGetFromHttpWithAuth();
void ioGetFromHttpWithAuthSynchronous();
void ioGetFromHttpWithProxyAuth();
@@ -2178,15 +2179,27 @@ void tst_QNetworkReply::ioGetFromHttpWithReuseSequential()
}
}
+void tst_QNetworkReply::ioGetFromHttpWithAuth_data()
+{
+ QTest::addColumn<QUrl>("url");
+ QTest::addColumn<QByteArray>("expectedData");
+
+ QFile reference(SRCDIR "/rfc3252.txt");
+ reference.open(QIODevice::ReadOnly);
+ QByteArray referenceData = reference.readAll();
+ QTest::newRow("basic") << QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/rfcs-auth/rfc3252.txt") << referenceData;
+ QTest::newRow("digest") << QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/auth-digest/") << QByteArray("digest authentication successful\n");
+}
+
void tst_QNetworkReply::ioGetFromHttpWithAuth()
{
// This test sends three requests
// The first two in parallel
// The third after the first two finished
- QFile reference(SRCDIR "/rfc3252.txt");
- QVERIFY(reference.open(QIODevice::ReadOnly));
- QNetworkRequest request(QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/rfcs-auth/rfc3252.txt"));
+ QFETCH(QUrl, url);
+ QFETCH(QByteArray, expectedData);
+ QNetworkRequest request(url);
{
QNetworkReplyPtr reply1 = manager.get(request);
QNetworkReplyPtr reply2 = manager.get(request);
@@ -2211,14 +2224,12 @@ void tst_QNetworkReply::ioGetFromHttpWithAuth()
QCOMPARE(reply1->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
QCOMPARE(reply2->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
- QByteArray referenceData = reference.readAll();
- QCOMPARE(reader1.data, referenceData);
- QCOMPARE(reader2.data, referenceData);
+ QCOMPARE(reader1.data, expectedData);
+ QCOMPARE(reader2.data, expectedData);
QCOMPARE(authspy.count(), 1);
}
- reference.seek(0);
// rinse and repeat:
{
QNetworkReplyPtr reply = manager.get(request);
@@ -2234,13 +2245,12 @@ void tst_QNetworkReply::ioGetFromHttpWithAuth()
this, SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*)));
QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
- QCOMPARE(reader.data, reference.readAll());
+ QCOMPARE(reader.data, expectedData);
QCOMPARE(authspy.count(), 0);
}
// now check with synchronous calls:
- reference.seek(0);
{
request.setAttribute(
static_cast<QNetworkRequest::Attribute>(SynchronousRequestAttribute),
@@ -2256,7 +2266,7 @@ void tst_QNetworkReply::ioGetFromHttpWithAuth()
// the only thing we check here is that the auth cache was used when using synchronous requests
QCOMPARE(replySync->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
- QCOMPARE(replySync->readAll(), reference.readAll());
+ QCOMPARE(replySync->readAll(), expectedData);
}
}
diff --git a/tests/auto/qpainterpath/tst_qpainterpath.cpp b/tests/auto/qpainterpath/tst_qpainterpath.cpp
index f60e782..8382edc 100644
--- a/tests/auto/qpainterpath/tst_qpainterpath.cpp
+++ b/tests/auto/qpainterpath/tst_qpainterpath.cpp
@@ -103,6 +103,8 @@ private slots:
void testToFillPolygons();
+ void testNaNandInfinites();
+
void closing();
void operators_data();
@@ -1042,6 +1044,11 @@ void tst_QPainterPath::pointAtPercent_data()
QRectF rect(241, 273, 185, 228);
path.addEllipse(rect);
QTest::newRow("Case 17") << path << qreal(1.0) << QPointF(rect.right(), qreal(0.5) * (rect.top() + rect.bottom()));
+
+ path = QPainterPath();
+ path.moveTo(100, 100);
+ QTest::newRow("Case 18") << path << qreal(0.0) << QPointF(100, 100);
+ QTest::newRow("Case 19") << path << qreal(1.0) << QPointF(100, 100);
}
void tst_QPainterPath::pointAtPercent()
@@ -1163,6 +1170,50 @@ void tst_QPainterPath::testToFillPolygons()
QCOMPARE(polygons.first().count(QPointF(70, 50)), 0);
}
+void tst_QPainterPath::testNaNandInfinites()
+{
+ QPainterPath path1;
+ QPainterPath path2 = path1;
+
+ QPointF p1 = QPointF(qSNaN(), 1);
+ QPointF p2 = QPointF(qQNaN(), 1);
+ QPointF p3 = QPointF(qQNaN(), 1);
+ QPointF pInf = QPointF(qInf(), 1);
+
+ // all these operations with NaN/Inf should be ignored
+ // can't test operator>> reliably, as we can't create a path with NaN to << later
+
+ path1.moveTo(p1);
+ path1.moveTo(qSNaN(), qQNaN());
+ path1.moveTo(pInf);
+
+ path1.lineTo(p1);
+ path1.lineTo(qSNaN(), qQNaN());
+ path1.lineTo(pInf);
+
+ path1.cubicTo(p1, p2, p3);
+ path1.cubicTo(p1, QPointF(1, 1), QPointF(2, 2));
+ path1.cubicTo(pInf, QPointF(10, 10), QPointF(5, 1));
+
+ path1.quadTo(p1, p2);
+ path1.quadTo(QPointF(1, 1), p3);
+ path1.quadTo(QPointF(1, 1), pInf);
+
+ path1.arcTo(QRectF(p1, p2), 5, 5);
+ path1.arcTo(QRectF(pInf, QPointF(1, 1)), 5, 5);
+
+ path1.addRect(QRectF(p1, p2));
+ path1.addRect(QRectF(pInf, QPointF(1, 1)));
+
+ path1.addEllipse(QRectF(p1, p2));
+ path1.addEllipse(QRectF(pInf, QPointF(1, 1)));
+
+ QCOMPARE(path1, path2);
+
+ path1.lineTo(QPointF(1, 1));
+ QVERIFY(path1 != path2);
+}
+
void tst_QPainterPath::connectPathDuplicatePoint()
{
QPainterPath a;
diff --git a/tests/auto/qscriptclass/tst_qscriptclass.cpp b/tests/auto/qscriptclass/tst_qscriptclass.cpp
index 16f09b6..5286a5a 100644
--- a/tests/auto/qscriptclass/tst_qscriptclass.cpp
+++ b/tests/auto/qscriptclass/tst_qscriptclass.cpp
@@ -65,15 +65,27 @@ public:
private slots:
void newInstance();
- void getAndSetProperty();
+ void setScriptClassOfExistingObject();
+ void setScriptClassOfNonQtScriptObject();
+ void getAndSetPropertyFromCpp();
+ void getAndSetPropertyFromJS();
+ void deleteUndeletableProperty();
+ void writeReadOnlyProperty();
+ void writePropertyWithoutWriteAccess();
void getProperty_invalidValue();
void enumerate();
- void extension();
+ void extension_None();
+ void extension_Callable();
+ void extension_Callable_construct();
+ void extension_HasInstance();
void originalProperties1();
void originalProperties2();
void originalProperties3();
void originalProperties4();
void defaultImplementations();
+ void scriptClassObjectInPrototype();
+ void scriptClassWithNullEngine();
+ void scriptClassInOtherEngine();
};
tst_QScriptClass::tst_QScriptClass()
@@ -306,7 +318,12 @@ void TestClass::setProperty(QScriptValue &object, const QScriptString &name,
CustomProperty *prop = findCustomProperty(name);
if (!prop)
return;
- prop->value = value;
+ if (prop->pflags & QScriptValue::ReadOnly)
+ return;
+ if (!value.isValid()) // deleteProperty() requested
+ removeCustomProperty(name);
+ else
+ prop->value = value;
}
QScriptValue::PropertyFlags TestClass::propertyFlags(
@@ -611,7 +628,12 @@ void tst_QScriptClass::newInstance()
QCOMPARE(obj2.scriptClass(), (QScriptClass*)&cls);
QVERIFY(!obj2.equals(obj1));
QVERIFY(!obj2.strictlyEquals(obj1));
+}
+void tst_QScriptClass::setScriptClassOfExistingObject()
+{
+ QScriptEngine eng;
+ TestClass cls(&eng);
QScriptValue obj3 = eng.newObject();
QCOMPARE(obj3.scriptClass(), (QScriptClass*)0);
obj3.setScriptClass(&cls);
@@ -625,7 +647,12 @@ void tst_QScriptClass::newInstance()
TestClass cls2(&eng);
obj3.setScriptClass(&cls2);
QCOMPARE(obj3.scriptClass(), (QScriptClass*)&cls2);
+}
+void tst_QScriptClass::setScriptClassOfNonQtScriptObject()
+{
+ QScriptEngine eng;
+ TestClass cls(&eng);
// undefined behavior really, but shouldn't crash
QScriptValue arr = eng.newArray();
QVERIFY(arr.isArray());
@@ -639,7 +666,7 @@ void tst_QScriptClass::newInstance()
QVERIFY(arr.isObject());
}
-void tst_QScriptClass::getAndSetProperty()
+void tst_QScriptClass::getAndSetPropertyFromCpp()
{
QScriptEngine eng;
@@ -651,7 +678,9 @@ void tst_QScriptClass::getAndSetProperty()
QScriptString bar = eng.toStringHandle("bar");
QScriptValue num(&eng, 123);
- // should behave just like normal
+ // Initially our TestClass instances have no custom properties,
+ // and queryProperty() will always return false.
+ // Hence, the properties will be created as normal JS properties.
for (int x = 0; x < 2; ++x) {
QScriptValue &o = (x == 0) ? obj1 : obj2;
for (int y = 0; y < 2; ++y) {
@@ -757,6 +786,80 @@ void tst_QScriptClass::getAndSetProperty()
QVERIFY(!obj1.property(bar).isValid());
}
+void tst_QScriptClass::getAndSetPropertyFromJS()
+{
+ QScriptEngine eng;
+ TestClass cls(&eng);
+ cls.addCustomProperty(eng.toStringHandle("x"),
+ QScriptClass::HandlesReadAccess
+ | QScriptClass::HandlesWriteAccess,
+ /*id=*/1, /*flags=*/0, /*value=*/123);
+ eng.globalObject().setProperty("o", eng.newObject(&cls));
+
+ // Accessing a custom property
+ QCOMPARE(eng.evaluate("o.x").toInt32(), 123);
+ QCOMPARE(eng.evaluate("o.x = 456; o.x").toInt32(), 456);
+
+ // Accessing a new JS property
+ QVERIFY(eng.evaluate("o.y").isUndefined());
+ QCOMPARE(eng.evaluate("o.y = 789; o.y").toInt32(), 789);
+
+ // Deleting custom property
+ QVERIFY(eng.evaluate("delete o.x").toBool());
+ QVERIFY(eng.evaluate("o.x").isUndefined());
+
+ // Deleting JS property
+ QVERIFY(eng.evaluate("delete o.y").toBool());
+ QVERIFY(eng.evaluate("o.y").isUndefined());
+}
+
+void tst_QScriptClass::deleteUndeletableProperty()
+{
+ QScriptEngine eng;
+ TestClass cls(&eng);
+ cls.addCustomProperty(eng.toStringHandle("x"), QScriptClass::HandlesWriteAccess,
+ /*id=*/0, QScriptValue::Undeletable, QScriptValue());
+ eng.globalObject().setProperty("o", eng.newObject(&cls));
+ QVERIFY(!eng.evaluate("delete o.x").toBool());
+}
+
+void tst_QScriptClass::writeReadOnlyProperty()
+{
+ QScriptEngine eng;
+ TestClass cls(&eng);
+ cls.addCustomProperty(eng.toStringHandle("x"),
+ QScriptClass::HandlesReadAccess
+ | QScriptClass::HandlesWriteAccess,
+ /*id=*/0, QScriptValue::ReadOnly, 123);
+ eng.globalObject().setProperty("o", eng.newObject(&cls));
+ // Note that if a property is read-only, the setProperty()
+ // reimplementation will still get called; it's up to that
+ // function to respect the ReadOnly flag.
+ QCOMPARE(eng.evaluate("o.x = 456; o.x").toInt32(), 123);
+}
+
+void tst_QScriptClass::writePropertyWithoutWriteAccess()
+{
+ QScriptEngine eng;
+ TestClass cls(&eng);
+ cls.addCustomProperty(eng.toStringHandle("x"),
+ QScriptClass::HandlesReadAccess,
+ /*id=*/0, /*flags=*/0, 123);
+ eng.globalObject().setProperty("o", eng.newObject(&cls));
+ QCOMPARE(eng.evaluate("o.x").toInt32(), 123);
+
+ // This will create a JS property on the instance that
+ // shadows the custom property.
+ // This behavior is not documented. It might be more
+ // intuitive to treat a property that only handles read
+ // access as a read-only, non-shadowable property.
+ QCOMPARE(eng.evaluate("o.x = 456; o.x").toInt32(), 456);
+
+ QVERIFY(eng.evaluate("delete o.x").toBool());
+ // Now the custom property is seen again.
+ QCOMPARE(eng.evaluate("o.x").toInt32(), 123);
+}
+
void tst_QScriptClass::getProperty_invalidValue()
{
QScriptEngine eng;
@@ -806,10 +909,12 @@ void tst_QScriptClass::enumerate()
cls.setIterationEnabled(true);
QScriptValueIterator it(obj);
+ // This test relies on the order in which properties are enumerated,
+ // which we don't guarantee. However, for compatibility's sake we prefer
+ // that normal JS properties come before QScriptClass properties.
for (int x = 0; x < 2; ++x) {
QVERIFY(it.hasNext());
it.next();
- QEXPECT_FAIL("", "", Abort);
QVERIFY(it.scriptName() == foo);
QVERIFY(it.hasNext());
it.next();
@@ -828,229 +933,238 @@ void tst_QScriptClass::enumerate()
}
}
-void tst_QScriptClass::extension()
+void tst_QScriptClass::extension_None()
+{
+ QScriptEngine eng;
+ TestClass cls(&eng);
+ cls.setCallableMode(TestClass::NotCallable);
+ QVERIFY(!cls.supportsExtension(QScriptClass::Callable));
+ QVERIFY(!cls.supportsExtension(QScriptClass::HasInstance));
+ QScriptValue obj = eng.newObject(&cls);
+ QVERIFY(!obj.call().isValid());
+ QCOMPARE((int)cls.lastExtensionType(), -1);
+ QVERIFY(!obj.instanceOf(obj));
+ QCOMPARE((int)cls.lastExtensionType(), -1);
+ QVERIFY(!obj.construct().isValid());
+}
+
+void tst_QScriptClass::extension_Callable()
{
QScriptEngine eng;
+ TestClass cls(&eng);
+ cls.setCallableMode(TestClass::CallableReturnsSum);
+ QVERIFY(cls.supportsExtension(QScriptClass::Callable));
+
+ QScriptValue obj = eng.newObject(&cls);
+ eng.globalObject().setProperty("obj", obj);
+ obj.setProperty("one", QScriptValue(&eng, 1));
+ obj.setProperty("two", QScriptValue(&eng, 2));
+ obj.setProperty("three", QScriptValue(&eng, 3));
+ // From C++
+ cls.clearReceivedArgs();
{
- TestClass cls(&eng);
- cls.setCallableMode(TestClass::NotCallable);
- QVERIFY(!cls.supportsExtension(QScriptClass::Callable));
- QVERIFY(!cls.supportsExtension(QScriptClass::HasInstance));
- QScriptValue obj = eng.newObject(&cls);
- QVERIFY(!obj.call().isValid());
- QCOMPARE((int)cls.lastExtensionType(), -1);
- QVERIFY(!obj.instanceOf(obj));
- QCOMPARE((int)cls.lastExtensionType(), -1);
- QVERIFY(!obj.construct().isValid());
+ QScriptValueList args;
+ args << QScriptValue(&eng, 4) << QScriptValue(&eng, 5);
+ QScriptValue ret = obj.call(obj, args);
+ QCOMPARE(cls.lastExtensionType(), QScriptClass::Callable);
+ QCOMPARE(cls.lastExtensionArgument().userType(), qMetaTypeId<QScriptContext*>());
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toNumber(), qsreal(1+2+3+4+5));
}
- // Callable
+ // From JS
+ cls.clearReceivedArgs();
{
- TestClass cls(&eng);
- cls.setCallableMode(TestClass::CallableReturnsSum);
- QVERIFY(cls.supportsExtension(QScriptClass::Callable));
-
- QScriptValue obj = eng.newObject(&cls);
- eng.globalObject().setProperty("obj", obj);
- obj.setProperty("one", QScriptValue(&eng, 1));
- obj.setProperty("two", QScriptValue(&eng, 2));
- obj.setProperty("three", QScriptValue(&eng, 3));
- // From C++
- cls.clearReceivedArgs();
- {
- QScriptValueList args;
- args << QScriptValue(&eng, 4) << QScriptValue(&eng, 5);
- QScriptValue ret = obj.call(obj, args);
- QCOMPARE(cls.lastExtensionType(), QScriptClass::Callable);
- QCOMPARE(cls.lastExtensionArgument().userType(), qMetaTypeId<QScriptContext*>());
- QVERIFY(ret.isNumber());
- QCOMPARE(ret.toNumber(), qsreal(15));
- }
- // From JS
- cls.clearReceivedArgs();
- {
- QScriptValue ret = eng.evaluate("obj(4, 5)");
- QCOMPARE(cls.lastExtensionType(), QScriptClass::Callable);
- QCOMPARE(cls.lastExtensionArgument().userType(), qMetaTypeId<QScriptContext*>());
- QVERIFY(ret.isNumber());
- QCOMPARE(ret.toNumber(), qsreal(15));
- }
+ QScriptValue ret = eng.evaluate("obj(4, 5)");
+ QCOMPARE(cls.lastExtensionType(), QScriptClass::Callable);
+ QCOMPARE(cls.lastExtensionArgument().userType(), qMetaTypeId<QScriptContext*>());
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toNumber(), qsreal(1+2+3+4+5));
+ }
- cls.setCallableMode(TestClass::CallableReturnsArgument);
- // From C++
- cls.clearReceivedArgs();
- {
- QScriptValue ret = obj.call(obj, QScriptValueList() << 123);
- QCOMPARE(cls.lastExtensionType(), QScriptClass::Callable);
- QCOMPARE(cls.lastExtensionArgument().userType(), qMetaTypeId<QScriptContext*>());
- QVERIFY(ret.isNumber());
- QCOMPARE(ret.toInt32(), 123);
- }
- cls.clearReceivedArgs();
- {
- QScriptValue ret = obj.call(obj, QScriptValueList() << true);
- QCOMPARE(cls.lastExtensionType(), QScriptClass::Callable);
- QCOMPARE(cls.lastExtensionArgument().userType(), qMetaTypeId<QScriptContext*>());
- QVERIFY(ret.isBoolean());
- QCOMPARE(ret.toBoolean(), true);
- }
- {
- QScriptValue ret = obj.call(obj, QScriptValueList() << QString::fromLatin1("ciao"));
- QVERIFY(ret.isString());
- QCOMPARE(ret.toString(), QString::fromLatin1("ciao"));
- }
- {
- QScriptValue objobj = eng.newObject();
- QScriptValue ret = obj.call(obj, QScriptValueList() << objobj);
- QVERIFY(ret.isObject());
- QVERIFY(ret.strictlyEquals(objobj));
- }
- {
- QScriptValue ret = obj.call(obj, QScriptValueList() << QScriptValue());
- QVERIFY(ret.isUndefined());
- }
- // From JS
- cls.clearReceivedArgs();
- {
- QScriptValue ret = eng.evaluate("obj(123)");
- QVERIFY(ret.isNumber());
- QCOMPARE(ret.toInt32(), 123);
- }
+ cls.setCallableMode(TestClass::CallableReturnsArgument);
+ // From C++
+ cls.clearReceivedArgs();
+ {
+ QScriptValue ret = obj.call(obj, QScriptValueList() << 123);
+ QCOMPARE(cls.lastExtensionType(), QScriptClass::Callable);
+ QCOMPARE(cls.lastExtensionArgument().userType(), qMetaTypeId<QScriptContext*>());
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toInt32(), 123);
+ }
+ cls.clearReceivedArgs();
+ {
+ QScriptValue ret = obj.call(obj, QScriptValueList() << true);
+ QCOMPARE(cls.lastExtensionType(), QScriptClass::Callable);
+ QCOMPARE(cls.lastExtensionArgument().userType(), qMetaTypeId<QScriptContext*>());
+ QVERIFY(ret.isBoolean());
+ QCOMPARE(ret.toBoolean(), true);
+ }
+ {
+ QScriptValue ret = obj.call(obj, QScriptValueList() << QString::fromLatin1("ciao"));
+ QVERIFY(ret.isString());
+ QCOMPARE(ret.toString(), QString::fromLatin1("ciao"));
+ }
+ {
+ QScriptValue objobj = eng.newObject();
+ QScriptValue ret = obj.call(obj, QScriptValueList() << objobj);
+ QVERIFY(ret.isObject());
+ QVERIFY(ret.strictlyEquals(objobj));
+ }
+ {
+ QScriptValue ret = obj.call(obj, QScriptValueList() << QScriptValue());
+ QVERIFY(ret.isUndefined());
+ }
+ // From JS
+ cls.clearReceivedArgs();
+ {
+ QScriptValue ret = eng.evaluate("obj(123)");
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toInt32(), 123);
+ }
- cls.setCallableMode(TestClass::CallableReturnsInvalidVariant);
- {
- QScriptValue ret = obj.call(obj);
- QVERIFY(ret.isUndefined());
- }
+ cls.setCallableMode(TestClass::CallableReturnsInvalidVariant);
+ {
+ QScriptValue ret = obj.call(obj);
+ QVERIFY(ret.isUndefined());
+ }
- cls.setCallableMode(TestClass::CallableReturnsThisObject);
- // From C++
- {
- QScriptValue ret = obj.call(obj);
- QVERIFY(ret.isObject());
- QVERIFY(ret.strictlyEquals(obj));
- }
- // From JS
- {
- QScriptValue ret = eng.evaluate("obj()");
- QVERIFY(ret.isObject());
- QVERIFY(ret.strictlyEquals(eng.globalObject()));
- }
+ cls.setCallableMode(TestClass::CallableReturnsThisObject);
+ // From C++
+ {
+ QScriptValue ret = obj.call(obj);
+ QVERIFY(ret.isObject());
+ QVERIFY(ret.strictlyEquals(obj));
+ }
+ // From JS
+ {
+ QScriptValue ret = eng.evaluate("obj()");
+ QVERIFY(ret.isObject());
+ QVERIFY(ret.strictlyEquals(eng.globalObject()));
+ }
- cls.setCallableMode(TestClass::CallableReturnsCallee);
- // From C++
- {
- QScriptValue ret = obj.call();
- QVERIFY(ret.isObject());
- QVERIFY(ret.strictlyEquals(obj));
- }
- // From JS
- {
- QScriptValue ret = eng.evaluate("obj()");
- QVERIFY(ret.isObject());
- QVERIFY(ret.strictlyEquals(obj));
- }
+ cls.setCallableMode(TestClass::CallableReturnsCallee);
+ // From C++
+ {
+ QScriptValue ret = obj.call();
+ QVERIFY(ret.isObject());
+ QVERIFY(ret.strictlyEquals(obj));
+ }
+ // From JS
+ {
+ QScriptValue ret = eng.evaluate("obj()");
+ QVERIFY(ret.isObject());
+ QVERIFY(ret.strictlyEquals(obj));
+ }
- cls.setCallableMode(TestClass::CallableReturnsArgumentsObject);
- // From C++
- {
- QScriptValue ret = obj.call(obj, QScriptValueList() << 123);
- QVERIFY(ret.isObject());
- QVERIFY(ret.property("length").isNumber());
- QCOMPARE(ret.property("length").toInt32(), 1);
- QVERIFY(ret.property(0).isNumber());
- QCOMPARE(ret.property(0).toInt32(), 123);
- }
- // From JS
- {
- QScriptValue ret = eng.evaluate("obj(123)");
- QVERIFY(ret.isObject());
- QVERIFY(ret.property("length").isNumber());
- QCOMPARE(ret.property("length").toInt32(), 1);
- QVERIFY(ret.property(0).isNumber());
- QCOMPARE(ret.property(0).toInt32(), 123);
- }
+ cls.setCallableMode(TestClass::CallableReturnsArgumentsObject);
+ // From C++
+ {
+ QScriptValue ret = obj.call(obj, QScriptValueList() << 123);
+ QVERIFY(ret.isObject());
+ QVERIFY(ret.property("length").isNumber());
+ QCOMPARE(ret.property("length").toInt32(), 1);
+ QVERIFY(ret.property(0).isNumber());
+ QCOMPARE(ret.property(0).toInt32(), 123);
+ }
+ // From JS
+ {
+ QScriptValue ret = eng.evaluate("obj(123)");
+ QVERIFY(ret.isObject());
+ QVERIFY(ret.property("length").isNumber());
+ QCOMPARE(ret.property("length").toInt32(), 1);
+ QVERIFY(ret.property(0).isNumber());
+ QCOMPARE(ret.property(0).toInt32(), 123);
+ }
+}
- // construct()
- // From C++
- cls.clearReceivedArgs();
- cls.setCallableMode(TestClass::CallableReturnsGlobalObject);
- {
- QScriptValue ret = obj.construct();
- QCOMPARE(cls.lastExtensionType(), QScriptClass::Callable);
- QCOMPARE(cls.lastExtensionArgument().userType(), qMetaTypeId<QScriptContext*>());
- QVERIFY(ret.isObject());
- QVERIFY(ret.strictlyEquals(eng.globalObject()));
- }
- // From JS
- cls.clearReceivedArgs();
- {
- QScriptValue ret = eng.evaluate("new obj()");
- QCOMPARE(cls.lastExtensionType(), QScriptClass::Callable);
- QCOMPARE(cls.lastExtensionArgument().userType(), qMetaTypeId<QScriptContext*>());
- QVERIFY(ret.isObject());
- QVERIFY(ret.strictlyEquals(eng.globalObject()));
- }
- // From C++
- cls.clearReceivedArgs();
- cls.setCallableMode(TestClass::CallableInitializesThisObject);
- {
- QScriptValue ret = obj.construct();
- QCOMPARE(cls.lastExtensionType(), QScriptClass::Callable);
- QCOMPARE(cls.lastExtensionArgument().userType(), qMetaTypeId<QScriptContext*>());
- QVERIFY(ret.isQObject());
- QCOMPARE(ret.toQObject(), (QObject*)&eng);
- }
- // From JS
- cls.clearReceivedArgs();
- {
- QScriptValue ret = eng.evaluate("new obj()");
- QCOMPARE(cls.lastExtensionType(), QScriptClass::Callable);
- QCOMPARE(cls.lastExtensionArgument().userType(), qMetaTypeId<QScriptContext*>());
- QVERIFY(ret.isQObject());
- QCOMPARE(ret.toQObject(), (QObject*)&eng);
- }
+void tst_QScriptClass::extension_Callable_construct()
+{
+ QScriptEngine eng;
+ TestClass cls(&eng);
+ QScriptValue obj = eng.newObject(&cls);
+ eng.globalObject().setProperty("obj", obj);
+
+ // From C++
+ cls.clearReceivedArgs();
+ cls.setCallableMode(TestClass::CallableReturnsGlobalObject);
+ {
+ QScriptValue ret = obj.construct();
+ QCOMPARE(cls.lastExtensionType(), QScriptClass::Callable);
+ QCOMPARE(cls.lastExtensionArgument().userType(), qMetaTypeId<QScriptContext*>());
+ QVERIFY(ret.isObject());
+ QVERIFY(ret.strictlyEquals(eng.globalObject()));
+ }
+ // From JS
+ cls.clearReceivedArgs();
+ {
+ QScriptValue ret = eng.evaluate("new obj()");
+ QCOMPARE(cls.lastExtensionType(), QScriptClass::Callable);
+ QCOMPARE(cls.lastExtensionArgument().userType(), qMetaTypeId<QScriptContext*>());
+ QVERIFY(ret.isObject());
+ QVERIFY(ret.strictlyEquals(eng.globalObject()));
+ }
+ // From C++
+ cls.clearReceivedArgs();
+ cls.setCallableMode(TestClass::CallableInitializesThisObject);
+ {
+ QScriptValue ret = obj.construct();
+ QCOMPARE(cls.lastExtensionType(), QScriptClass::Callable);
+ QCOMPARE(cls.lastExtensionArgument().userType(), qMetaTypeId<QScriptContext*>());
+ QVERIFY(ret.isQObject());
+ QCOMPARE(ret.toQObject(), (QObject*)&eng);
}
- // HasInstance
+ // From JS
+ cls.clearReceivedArgs();
{
- TestClass cls(&eng);
- cls.setHasInstance(true);
- QVERIFY(cls.supportsExtension(QScriptClass::HasInstance));
+ QScriptValue ret = eng.evaluate("new obj()");
+ QCOMPARE(cls.lastExtensionType(), QScriptClass::Callable);
+ QCOMPARE(cls.lastExtensionArgument().userType(), qMetaTypeId<QScriptContext*>());
+ QVERIFY(ret.isQObject());
+ QCOMPARE(ret.toQObject(), (QObject*)&eng);
+ }
+}
- QScriptValue obj = eng.newObject(&cls);
- obj.setProperty("foo", QScriptValue(&eng, 123));
- QScriptValue plain = eng.newObject();
- QVERIFY(!plain.instanceOf(obj));
+void tst_QScriptClass::extension_HasInstance()
+{
+ QScriptEngine eng;
+ TestClass cls(&eng);
+ cls.setHasInstance(true);
+ QVERIFY(cls.supportsExtension(QScriptClass::HasInstance));
- eng.globalObject().setProperty("HasInstanceTester", obj);
- eng.globalObject().setProperty("hasInstanceValue", plain);
- cls.clearReceivedArgs();
- {
- QScriptValue ret = eng.evaluate("hasInstanceValue instanceof HasInstanceTester");
- QCOMPARE(cls.lastExtensionType(), QScriptClass::HasInstance);
- QCOMPARE(cls.lastExtensionArgument().userType(), qMetaTypeId<QScriptValueList>());
- QScriptValueList lst = qvariant_cast<QScriptValueList>(cls.lastExtensionArgument());
- QCOMPARE(lst.size(), 2);
- QVERIFY(lst.at(0).strictlyEquals(obj));
- QVERIFY(lst.at(1).strictlyEquals(plain));
- QVERIFY(ret.isBoolean());
- QVERIFY(!ret.toBoolean());
- }
+ QScriptValue obj = eng.newObject(&cls);
+ obj.setProperty("foo", QScriptValue(&eng, 123));
+ QScriptValue plain = eng.newObject();
+ QVERIFY(!plain.instanceOf(obj));
- plain.setProperty("foo", QScriptValue(&eng, 456));
- QVERIFY(!plain.instanceOf(obj));
- {
- QScriptValue ret = eng.evaluate("hasInstanceValue instanceof HasInstanceTester");
- QVERIFY(ret.isBoolean());
- QVERIFY(!ret.toBoolean());
- }
+ eng.globalObject().setProperty("HasInstanceTester", obj);
+ eng.globalObject().setProperty("hasInstanceValue", plain);
+ cls.clearReceivedArgs();
+ {
+ QScriptValue ret = eng.evaluate("hasInstanceValue instanceof HasInstanceTester");
+ QCOMPARE(cls.lastExtensionType(), QScriptClass::HasInstance);
+ QCOMPARE(cls.lastExtensionArgument().userType(), qMetaTypeId<QScriptValueList>());
+ QScriptValueList lst = qvariant_cast<QScriptValueList>(cls.lastExtensionArgument());
+ QCOMPARE(lst.size(), 2);
+ QVERIFY(lst.at(0).strictlyEquals(obj));
+ QVERIFY(lst.at(1).strictlyEquals(plain));
+ QVERIFY(ret.isBoolean());
+ QVERIFY(!ret.toBoolean());
+ }
- plain.setProperty("foo", obj.property("foo"));
- QVERIFY(plain.instanceOf(obj));
- {
- QScriptValue ret = eng.evaluate("hasInstanceValue instanceof HasInstanceTester");
- QVERIFY(ret.isBoolean());
- QVERIFY(ret.toBoolean());
- }
+ plain.setProperty("foo", QScriptValue(&eng, 456));
+ QVERIFY(!plain.instanceOf(obj));
+ {
+ QScriptValue ret = eng.evaluate("hasInstanceValue instanceof HasInstanceTester");
+ QVERIFY(ret.isBoolean());
+ QVERIFY(!ret.toBoolean());
+ }
+
+ plain.setProperty("foo", obj.property("foo"));
+ QVERIFY(plain.instanceOf(obj));
+ {
+ QScriptValue ret = eng.evaluate("hasInstanceValue instanceof HasInstanceTester");
+ QVERIFY(ret.isBoolean());
+ QVERIFY(ret.toBoolean());
}
}
@@ -1324,5 +1438,66 @@ void tst_QScriptClass::defaultImplementations()
QVERIFY(!defaultClass.extension(QScriptClass::HasInstance).isValid());
}
+void tst_QScriptClass::scriptClassObjectInPrototype()
+{
+ QScriptEngine eng;
+ TestClass cls(&eng);
+ QScriptValue plainObject = eng.newObject();
+ QScriptValue classObject = eng.newObject(&cls);
+ plainObject.setPrototype(classObject);
+ QVERIFY(plainObject.prototype().equals(classObject));
+ eng.globalObject().setProperty("plainObject", plainObject);
+ eng.globalObject().setProperty("classObject", classObject);
+
+ QScriptString name = eng.toStringHandle("x");
+ cls.addCustomProperty(name, QScriptClass::HandlesReadAccess, /*id=*/1, /*flags=*/0, /*value=*/123);
+ QVERIFY(plainObject.property(name).equals(classObject.property(name)));
+ QVERIFY(eng.evaluate("plainObject.x == classObject.x").toBool());
+
+ // Add a property that shadows the one in the script class.
+ plainObject.setProperty(name, 456);
+ QVERIFY(!plainObject.property(name).equals(classObject.property(name)));
+ QVERIFY(eng.evaluate("plainObject.x != classObject.x").toBool());
+
+ QVERIFY(eng.evaluate("delete plainObject.x").toBool());
+ QVERIFY(eng.evaluate("plainObject.x == classObject.x").toBool());
+}
+
+void tst_QScriptClass::scriptClassWithNullEngine()
+{
+ QScriptClass cls(0);
+ QCOMPARE(cls.engine(), (QScriptEngine*)0);
+ QScriptEngine eng;
+ QScriptValue obj = eng.newObject(&cls);
+ QVERIFY(obj.isObject());
+ QCOMPARE(obj.scriptClass(), &cls);
+ // The class could have been "bound" to the engine at this point,
+ // but it's currently not.
+ // This behavior is not documented and is subject to change.
+ QCOMPARE(cls.engine(), (QScriptEngine*)0);
+ // The engine pointer stored in the QScriptClass is not actually used
+ // during property access, so this still works.
+ obj.setProperty("x", 123);
+ QVERIFY(obj.property("x").isNumber());
+}
+
+void tst_QScriptClass::scriptClassInOtherEngine()
+{
+ QScriptEngine eng;
+ TestClass cls(&eng);
+ QScriptEngine eng2;
+ // We don't check that the class is associated with another engine, so
+ // we only get a warning when trying to set the prototype of the new
+ // instance.
+ // This behavior is not documented and is subject to change.
+ QTest::ignoreMessage(QtWarningMsg, "QScriptValue::setPrototype() failed: cannot set a prototype created in a different engine");
+ QScriptValue obj = eng2.newObject(&cls);
+ QVERIFY(obj.isObject());
+ QCOMPARE(obj.scriptClass(), &cls);
+
+ obj.setProperty("x", 123);
+ QVERIFY(obj.property("x").isNumber());
+}
+
QTEST_MAIN(tst_QScriptClass)
#include "tst_qscriptclass.moc"
diff --git a/tests/auto/qscriptcontext/tst_qscriptcontext.cpp b/tests/auto/qscriptcontext/tst_qscriptcontext.cpp
index cb6311e..eee67df 100644
--- a/tests/auto/qscriptcontext/tst_qscriptcontext.cpp
+++ b/tests/auto/qscriptcontext/tst_qscriptcontext.cpp
@@ -66,7 +66,9 @@ public:
private slots:
void callee();
+ void callee_implicitCall();
void arguments();
+ void argumentsInJS();
void thisObject();
void returnValue();
void throwError_data();
@@ -77,16 +79,24 @@ private slots:
void throwValue();
void evaluateInFunction();
void pushAndPopContext();
+ void pushAndPopContext_variablesInActivation();
+ void pushAndPopContext_setThisObject();
+ void pushAndPopContext_throwException();
void lineNumber();
void backtrace_data();
void backtrace();
- void scopeChain();
- void pushAndPopScope();
- void getSetActivationObject();
+ void scopeChain_globalContext();
+ void scopeChain_closure();
+ void scopeChain_withStatement();
+ void pushAndPopScope_globalContext();
+ void pushAndPopScope_globalContext2();
+ void getSetActivationObject_globalContext();
void getSetActivationObject_customContext();
void inheritActivationAndThisObject();
void toString();
- void calledAsConstructor();
+ void calledAsConstructor_fromCpp();
+ void calledAsConstructor_fromJS();
+ void calledAsConstructor_parentContext();
void argumentsObjectInNative();
void jsActivationObject();
void qobjectAsActivationObject();
@@ -121,33 +131,33 @@ void tst_QScriptContext::callee()
{
QScriptEngine eng;
- {
- QScriptValue fun = eng.newFunction(get_callee);
- fun.setProperty("foo", QScriptValue(&eng, "bar"));
- eng.globalObject().setProperty("get_callee", fun);
+ QScriptValue fun = eng.newFunction(get_callee);
+ fun.setProperty("foo", QScriptValue(&eng, "bar"));
+ eng.globalObject().setProperty("get_callee", fun);
- QScriptValue result = eng.evaluate("get_callee()");
- QCOMPARE(result.isFunction(), true);
- QCOMPARE(result.property("foo").toString(), QString("bar"));
- }
+ QScriptValue result = eng.evaluate("get_callee()");
+ QCOMPARE(result.isFunction(), true);
+ QCOMPARE(result.property("foo").toString(), QString("bar"));
+}
+void tst_QScriptContext::callee_implicitCall()
+{
+ QScriptEngine eng;
// callee when toPrimitive() is called internally
- {
- QScriptValue fun = eng.newFunction(store_callee_and_return_primitive);
- QScriptValue obj = eng.newObject();
- obj.setProperty("toString", fun);
- QVERIFY(!obj.property("callee").isValid());
- (void)obj.toString();
- QVERIFY(obj.property("callee").isFunction());
- QVERIFY(obj.property("callee").strictlyEquals(fun));
-
- obj.setProperty("callee", QScriptValue());
- QVERIFY(!obj.property("callee").isValid());
- obj.setProperty("valueOf", fun);
- (void)obj.toNumber();
- QVERIFY(obj.property("callee").isFunction());
- QVERIFY(obj.property("callee").strictlyEquals(fun));
- }
+ QScriptValue fun = eng.newFunction(store_callee_and_return_primitive);
+ QScriptValue obj = eng.newObject();
+ obj.setProperty("toString", fun);
+ QVERIFY(!obj.property("callee").isValid());
+ (void)obj.toString();
+ QVERIFY(obj.property("callee").isFunction());
+ QVERIFY(obj.property("callee").strictlyEquals(fun));
+
+ obj.setProperty("callee", QScriptValue());
+ QVERIFY(!obj.property("callee").isValid());
+ obj.setProperty("valueOf", fun);
+ (void)obj.toNumber();
+ QVERIFY(obj.property("callee").isFunction());
+ QVERIFY(obj.property("callee").strictlyEquals(fun));
}
static QScriptValue get_arguments(QScriptContext *ctx, QScriptEngine *eng)
@@ -167,6 +177,8 @@ void tst_QScriptContext::arguments()
{
QScriptEngine eng;
+ // See section 10.6 ("Arguments Object") of ECMA-262.
+
{
QScriptValue args = eng.currentContext()->argumentsObject();
QVERIFY(args.isObject());
@@ -178,6 +190,8 @@ void tst_QScriptContext::arguments()
}
for (int x = 0; x < 2; ++x) {
+ // The expected arguments array should be the same regardless of
+ // whether get_arguments() is called as a constructor.
QString prefix;
if (x == 0)
prefix = "";
@@ -224,11 +238,15 @@ void tst_QScriptContext::arguments()
QCOMPARE(result.propertyFlags("length"), QScriptValue::SkipInEnumeration);
QCOMPARE(result.property("callee").strictlyEquals(fun), true);
QCOMPARE(result.propertyFlags("callee"), QScriptValue::SkipInEnumeration);
+
+ // callee and length properties should be writable.
QScriptValue replacedCallee(&eng, 123);
result.setProperty("callee", replacedCallee);
QVERIFY(result.property("callee").equals(replacedCallee));
QScriptValue replacedLength(&eng, 456);
result.setProperty("length", replacedLength);
+
+ // callee and length properties should be deletable.
QVERIFY(result.property("length").equals(replacedLength));
result.setProperty("callee", QScriptValue());
QVERIFY(!result.property("callee").isValid());
@@ -262,28 +280,31 @@ void tst_QScriptContext::arguments()
QCOMPARE(result.property("2").toBoolean(), true);
QCOMPARE(result.property("3").isUndefined(), true);
}
+ }
+}
- // arguments object returned from script
- {
- QScriptValue result = eng.evaluate("(function() { return arguments; })(123)");
- QCOMPARE(result.isArray(), false);
- QVERIFY(result.isObject());
- QCOMPARE(result.property("length").toUInt32(), quint32(1));
- QCOMPARE(result.property("0").isNumber(), true);
- QCOMPARE(result.property("0").toNumber(), 123.0);
- }
+void tst_QScriptContext::argumentsInJS()
+{
+ QScriptEngine eng;
+ {
+ QScriptValue result = eng.evaluate("(function() { return arguments; })(123)");
+ QCOMPARE(result.isArray(), false);
+ QVERIFY(result.isObject());
+ QCOMPARE(result.property("length").toUInt32(), quint32(1));
+ QCOMPARE(result.property("0").isNumber(), true);
+ QCOMPARE(result.property("0").toNumber(), 123.0);
+ }
- {
- QScriptValue result = eng.evaluate("(function() { return arguments; })('ciao', null, true, undefined)");
- QCOMPARE(result.isArray(), false);
- QCOMPARE(result.property("length").toUInt32(), quint32(4));
- QCOMPARE(result.property("0").isString(), true);
- QCOMPARE(result.property("0").toString(), QString("ciao"));
- QCOMPARE(result.property("1").isNull(), true);
- QCOMPARE(result.property("2").isBoolean(), true);
- QCOMPARE(result.property("2").toBoolean(), true);
- QCOMPARE(result.property("3").isUndefined(), true);
- }
+ {
+ QScriptValue result = eng.evaluate("(function() { return arguments; })('ciao', null, true, undefined)");
+ QCOMPARE(result.isArray(), false);
+ QCOMPARE(result.property("length").toUInt32(), quint32(4));
+ QCOMPARE(result.property("0").isString(), true);
+ QCOMPARE(result.property("0").toString(), QString("ciao"));
+ QCOMPARE(result.property("1").isNull(), true);
+ QCOMPARE(result.property("2").isBoolean(), true);
+ QCOMPARE(result.property("2").toBoolean(), true);
+ QCOMPARE(result.property("3").isUndefined(), true);
}
}
@@ -517,58 +538,65 @@ void tst_QScriptContext::pushAndPopContext()
QTest::ignoreMessage(QtWarningMsg, "QScriptEngine::popContext() doesn't match with pushContext()");
eng.popContext();
QCOMPARE(eng.currentContext(), topLevel);
+}
- {
- QScriptContext *ctx3 = eng.pushContext();
- ctx3->activationObject().setProperty("foo", QScriptValue(&eng, 123));
- QVERIFY(eng.evaluate("foo").strictlyEquals(QScriptValue(&eng, 123)));
- QCOMPARE(ctx3->activationObject().propertyFlags("foo"), QScriptValue::PropertyFlags(0));
-
- ctx3->activationObject().setProperty(4, 456);
- QVERIFY(ctx3->activationObject().property(4, QScriptValue::ResolveLocal).equals(456));
-
- eng.evaluate("var bar = 'ciao'");
- QVERIFY(ctx3->activationObject().property("bar", QScriptValue::ResolveLocal).strictlyEquals(QScriptValue(&eng, "ciao")));
-
- ctx3->activationObject().setProperty("baz", 789, QScriptValue::ReadOnly);
- QVERIFY(eng.evaluate("baz").equals(789));
- QCOMPARE(ctx3->activationObject().propertyFlags("baz"), QScriptValue::ReadOnly);
-
- QSet<QString> activationPropertyNames;
- QScriptValueIterator it(ctx3->activationObject());
- while (it.hasNext()) {
- it.next();
- activationPropertyNames.insert(it.name());
- }
- QCOMPARE(activationPropertyNames.size(), 4);
- QVERIFY(activationPropertyNames.contains("foo"));
- QVERIFY(activationPropertyNames.contains("4"));
- QVERIFY(activationPropertyNames.contains("bar"));
- QVERIFY(activationPropertyNames.contains("baz"));
-
- eng.popContext();
+void tst_QScriptContext::pushAndPopContext_variablesInActivation()
+{
+ QScriptEngine eng;
+ QScriptContext *ctx = eng.pushContext();
+ ctx->activationObject().setProperty("foo", QScriptValue(&eng, 123));
+ // evaluate() should use the current context.
+ QVERIFY(eng.evaluate("foo").strictlyEquals(QScriptValue(&eng, 123)));
+ QCOMPARE(ctx->activationObject().propertyFlags("foo"), QScriptValue::PropertyFlags(0));
+
+ ctx->activationObject().setProperty(4, 456);
+ QVERIFY(ctx->activationObject().property(4, QScriptValue::ResolveLocal).equals(456));
+
+ // New JS variables should become properties of the current context's activation.
+ eng.evaluate("var bar = 'ciao'");
+ QVERIFY(ctx->activationObject().property("bar", QScriptValue::ResolveLocal).strictlyEquals(QScriptValue(&eng, "ciao")));
+
+ ctx->activationObject().setProperty("baz", 789, QScriptValue::ReadOnly);
+ QVERIFY(eng.evaluate("baz").equals(789));
+ QCOMPARE(ctx->activationObject().propertyFlags("baz"), QScriptValue::ReadOnly);
+
+ QSet<QString> activationPropertyNames;
+ QScriptValueIterator it(ctx->activationObject());
+ while (it.hasNext()) {
+ it.next();
+ activationPropertyNames.insert(it.name());
}
+ QCOMPARE(activationPropertyNames.size(), 4);
+ QVERIFY(activationPropertyNames.contains("foo"));
+ QVERIFY(activationPropertyNames.contains("4"));
+ QVERIFY(activationPropertyNames.contains("bar"));
+ QVERIFY(activationPropertyNames.contains("baz"));
- {
- QScriptContext *ctx4 = eng.pushContext();
- QScriptValue obj = eng.newObject();
- obj.setProperty("prop", QScriptValue(&eng, 456));
- ctx4->setThisObject(obj);
- QScriptValue ret = eng.evaluate("var tmp = this.prop; tmp + 1");
- QCOMPARE(eng.currentContext(), ctx4);
- QVERIFY(ret.strictlyEquals(QScriptValue(&eng, 457)));
- eng.popContext();
- }
+ eng.popContext();
+}
- // throwing an exception
- {
- QScriptContext *ctx5 = eng.pushContext();
- QScriptValue ret = eng.evaluate("throw new Error('oops')");
- QVERIFY(ret.isError());
- QVERIFY(eng.hasUncaughtException());
- QCOMPARE(eng.currentContext(), ctx5);
- eng.popContext();
- }
+void tst_QScriptContext::pushAndPopContext_setThisObject()
+{
+ QScriptEngine eng;
+ QScriptContext *ctx = eng.pushContext();
+ QScriptValue obj = eng.newObject();
+ obj.setProperty("prop", QScriptValue(&eng, 456));
+ ctx->setThisObject(obj);
+ QScriptValue ret = eng.evaluate("var tmp = this.prop; tmp + 1");
+ QCOMPARE(eng.currentContext(), ctx);
+ QVERIFY(ret.strictlyEquals(QScriptValue(&eng, 457)));
+ eng.popContext();
+}
+
+void tst_QScriptContext::pushAndPopContext_throwException()
+{
+ QScriptEngine eng;
+ QScriptContext *ctx = eng.pushContext();
+ QScriptValue ret = eng.evaluate("throw new Error('oops')");
+ QVERIFY(ret.isError());
+ QVERIFY(eng.hasUncaughtException());
+ QCOMPARE(eng.currentContext(), ctx);
+ eng.popContext();
}
void tst_QScriptContext::popNativeContextScope()
@@ -596,7 +624,7 @@ void tst_QScriptContext::popNativeContextScope()
QVERIFY(ctx->activationObject().strictlyEquals(customScope));
QCOMPARE(ctx->scopeChain().size(), 2);
QVERIFY(ctx->scopeChain().at(0).strictlyEquals(customScope));
- QEXPECT_FAIL("", "QTBUG-11012", Continue);
+ QEXPECT_FAIL("", "QTBUG-11012: Global object is replaced in scope chain", Continue);
QVERIFY(ctx->scopeChain().at(1).strictlyEquals(eng.globalObject()));
QVERIFY(!eng.evaluate("baz = 456; var foo = 789; function barbar() {}").isError());
@@ -918,7 +946,7 @@ static QScriptValue getScopeChain(QScriptContext *ctx, QScriptEngine *eng)
return qScriptValueFromValue(eng, ctx->parentContext()->scopeChain());
}
-void tst_QScriptContext::scopeChain()
+void tst_QScriptContext::scopeChain_globalContext()
{
QScriptEngine eng;
{
@@ -932,19 +960,35 @@ void tst_QScriptContext::scopeChain()
QCOMPARE(ret.size(), 1);
QVERIFY(ret.at(0).strictlyEquals(eng.globalObject()));
}
- {
- eng.evaluate("function foo() { function bar() { return getScopeChain(); } return bar() }");
- QScriptValueList ret = qscriptvalue_cast<QScriptValueList>(eng.evaluate("foo()"));
- QEXPECT_FAIL("", "Number of items in returned scope chain is incorrect", Abort);
- QCOMPARE(ret.size(), 3);
- QVERIFY(ret.at(2).strictlyEquals(eng.globalObject()));
- QCOMPARE(ret.at(1).toString(), QString::fromLatin1("activation"));
- QVERIFY(ret.at(1).property("arguments").isObject());
- QCOMPARE(ret.at(0).toString(), QString::fromLatin1("activation"));
- QVERIFY(ret.at(0).property("arguments").isObject());
- }
+}
+
+void tst_QScriptContext::scopeChain_closure()
+{
+ QScriptEngine eng;
+ eng.globalObject().setProperty("getScopeChain", eng.newFunction(getScopeChain));
+
+ eng.evaluate("function foo() { function bar() { return getScopeChain(); } return bar() }");
+ QScriptValueList ret = qscriptvalue_cast<QScriptValueList>(eng.evaluate("foo()"));
+ // JSC will not create an activation for bar() unless we insert a call
+ // to eval() in the function body; JSC has no way of knowing that the
+ // native function will be asking for the activation, and we don't want
+ // to needlessly create it.
+ QEXPECT_FAIL("", "QTBUG-10313: JSC optimizes away the activation object", Abort);
+ QCOMPARE(ret.size(), 3);
+ QVERIFY(ret.at(2).strictlyEquals(eng.globalObject()));
+ QCOMPARE(ret.at(1).toString(), QString::fromLatin1("activation"));
+ QVERIFY(ret.at(1).property("arguments").isObject());
+ QCOMPARE(ret.at(0).toString(), QString::fromLatin1("activation"));
+ QVERIFY(ret.at(0).property("arguments").isObject());
+}
+
+void tst_QScriptContext::scopeChain_withStatement()
+{
+ QScriptEngine eng;
+ eng.globalObject().setProperty("getScopeChain", eng.newFunction(getScopeChain));
{
QScriptValueList ret = qscriptvalue_cast<QScriptValueList>(eng.evaluate("o = { x: 123 }; with(o) getScopeChain();"));
+ QEXPECT_FAIL("", "QTBUG-17131: with-scope isn't reflected by QScriptContext", Abort);
QCOMPARE(ret.size(), 2);
QVERIFY(ret.at(1).strictlyEquals(eng.globalObject()));
QVERIFY(ret.at(0).isObject());
@@ -962,7 +1006,7 @@ void tst_QScriptContext::scopeChain()
}
}
-void tst_QScriptContext::pushAndPopScope()
+void tst_QScriptContext::pushAndPopScope_globalContext()
{
QScriptEngine eng;
QScriptContext *ctx = eng.currentContext();
@@ -1019,14 +1063,19 @@ void tst_QScriptContext::pushAndPopScope()
ctx->pushScope(QScriptValue());
QCOMPARE(ctx->scopeChain().size(), 1);
+}
+void tst_QScriptContext::pushAndPopScope_globalContext2()
+{
+ QScriptEngine eng;
+ QScriptContext *ctx = eng.currentContext();
QVERIFY(ctx->popScope().strictlyEquals(eng.globalObject()));
QVERIFY(ctx->scopeChain().isEmpty());
// Used to work with old back-end, doesn't with new one because JSC requires that the last object in
// a scope chain is the Global Object.
QTest::ignoreMessage(QtWarningMsg, "QScriptContext::pushScope() failed: initial object in scope chain has to be the Global Object");
- ctx->pushScope(obj);
+ ctx->pushScope(eng.newObject());
QCOMPARE(ctx->scopeChain().size(), 0);
QScriptEngine eng2;
@@ -1043,7 +1092,7 @@ static QScriptValue get_activationObject(QScriptContext *ctx, QScriptEngine *)
return ctx->activationObject();
}
-void tst_QScriptContext::getSetActivationObject()
+void tst_QScriptContext::getSetActivationObject_globalContext()
{
QScriptEngine eng;
QScriptContext *ctx = eng.currentContext();
@@ -1076,7 +1125,7 @@ void tst_QScriptContext::getSetActivationObject()
QScriptValue ret = eng.evaluate("get_activationObject(1, 2, 3)");
QVERIFY(ret.isObject());
QScriptValue arguments = ret.property("arguments");
- QEXPECT_FAIL("", "Getting arguments property of activation object doesn't work", Abort);
+ QEXPECT_FAIL("", "QTBUG-17136: arguments property of activation object is missing", Abort);
QVERIFY(arguments.isObject());
QCOMPARE(arguments.property("length").toInt32(), 3);
QCOMPARE(arguments.property("0").toInt32(), 1);
@@ -1099,6 +1148,8 @@ void tst_QScriptContext::getSetActivationObject_customContext()
QCOMPARE(act.property("foo").toInt32(), 123);
}
+// Helper function that's intended to have the same behavior
+// as the built-in eval() function.
static QScriptValue myEval(QScriptContext *ctx, QScriptEngine *eng)
{
QString code = ctx->argument(0).toString();
@@ -1127,13 +1178,14 @@ void tst_QScriptContext::inheritActivationAndThisObject()
QCOMPARE(ret.toInt32(), 123);
}
- // QT-2219
{
eng.globalObject().setProperty("a", 123);
QScriptValue ret = eng.evaluate("(function() { myEval('var a = 456'); return a; })()");
QVERIFY(ret.isNumber());
QCOMPARE(ret.toInt32(), 456);
- QEXPECT_FAIL("", "QT-2219: Wrong activation object is returned from native function's parent context", Continue);
+ // Since JSC doesn't create an activation object for the anonymous function call,
+ // myEval() will use the global object as the activation, which is wrong.
+ QEXPECT_FAIL("", "QTBUG-10313: Wrong activation object is returned from native function's parent context", Continue);
QVERIFY(eng.globalObject().property("a").strictlyEquals(123));
}
}
@@ -1172,11 +1224,11 @@ static QScriptValue storeCalledAsConstructorV3(QScriptContext *ctx, QScriptEngin
return eng->undefinedValue();
}
-void tst_QScriptContext::calledAsConstructor()
+void tst_QScriptContext::calledAsConstructor_fromCpp()
{
QScriptEngine eng;
- QScriptValue fun1 = eng.newFunction(storeCalledAsConstructor);
{
+ QScriptValue fun1 = eng.newFunction(storeCalledAsConstructor);
fun1.call();
QVERIFY(!fun1.property("calledAsConstructor").toBool());
fun1.construct();
@@ -1189,25 +1241,31 @@ void tst_QScriptContext::calledAsConstructor()
fun.construct();
QVERIFY(fun.property("calledAsConstructor").toBool());
}
- {
- eng.globalObject().setProperty("fun1", fun1);
- eng.evaluate("fun1();");
- QVERIFY(!fun1.property("calledAsConstructor").toBool());
- eng.evaluate("new fun1();");
- QVERIFY(fun1.property("calledAsConstructor").toBool());
- }
- {
- QScriptValue fun3 = eng.newFunction(storeCalledAsConstructorV3);
- eng.globalObject().setProperty("fun3", fun3);
- eng.evaluate("function test() { fun3() }");
- eng.evaluate("test();");
- QVERIFY(!fun3.property("calledAsConstructor").toBool());
- eng.evaluate("new test();");
- if (qt_script_isJITEnabled())
- QEXPECT_FAIL("", "QTBUG-6132: calledAsConstructor is not correctly set for JS functions when JIT is enabled", Continue);
- QVERIFY(fun3.property("calledAsConstructor").toBool());
- }
+}
+
+void tst_QScriptContext::calledAsConstructor_fromJS()
+{
+ QScriptEngine eng;
+ QScriptValue fun1 = eng.newFunction(storeCalledAsConstructor);
+ eng.globalObject().setProperty("fun1", fun1);
+ eng.evaluate("fun1();");
+ QVERIFY(!fun1.property("calledAsConstructor").toBool());
+ eng.evaluate("new fun1();");
+ QVERIFY(fun1.property("calledAsConstructor").toBool());
+}
+void tst_QScriptContext::calledAsConstructor_parentContext()
+{
+ QScriptEngine eng;
+ QScriptValue fun3 = eng.newFunction(storeCalledAsConstructorV3);
+ eng.globalObject().setProperty("fun3", fun3);
+ eng.evaluate("function test() { fun3() }");
+ eng.evaluate("test();");
+ QVERIFY(!fun3.property("calledAsConstructor").toBool());
+ eng.evaluate("new test();");
+ if (qt_script_isJITEnabled())
+ QEXPECT_FAIL("", "QTBUG-6132: calledAsConstructor is not correctly set for JS functions when JIT is enabled", Continue);
+ QVERIFY(fun3.property("calledAsConstructor").toBool());
}
static QScriptValue argumentsObjectInNative_test1(QScriptContext *ctx, QScriptEngine *eng)
@@ -1269,7 +1327,7 @@ void tst_QScriptContext::jsActivationObject()
QScriptValue result1 = eng.evaluate("f2('hello', 'useless', 'world')");
QScriptValue result2 = eng.evaluate("f3()");
QVERIFY(result1.isObject());
- QEXPECT_FAIL("", "JSC optimize away the activation object", Abort);
+ QEXPECT_FAIL("", "QTBUG-10313: JSC optimizes away the activation object", Abort);
QCOMPARE(result1.property("v1").toInt32() , 42);
QCOMPARE(result1.property("arguments").property(1).toString() , QString::fromLatin1("useless"));
QVERIFY(result2.isObject());
diff --git a/tests/auto/qscriptcontextinfo/tst_qscriptcontextinfo.cpp b/tests/auto/qscriptcontextinfo/tst_qscriptcontextinfo.cpp
index aba16b2..89c5330 100644
--- a/tests/auto/qscriptcontextinfo/tst_qscriptcontextinfo.cpp
+++ b/tests/auto/qscriptcontextinfo/tst_qscriptcontextinfo.cpp
@@ -93,6 +93,7 @@ private slots:
void qtPropertyFunction();
void nullContext();
void streaming();
+ void comparison_null();
void assignmentAndComparison();
};
@@ -366,6 +367,13 @@ void tst_QScriptContextInfo::streaming()
}
}
+void tst_QScriptContextInfo::comparison_null()
+{
+ QScriptContextInfo info1, info2, info3(0);
+ QCOMPARE(info1, info2);
+ QCOMPARE(info1, info3);
+}
+
void tst_QScriptContextInfo::assignmentAndComparison()
{
QScriptEngine eng;
diff --git a/tests/auto/qscriptengine/tst_qscriptengine.cpp b/tests/auto/qscriptengine/tst_qscriptengine.cpp
index c4c53e9..2f7e0b5 100644
--- a/tests/auto/qscriptengine/tst_qscriptengine.cpp
+++ b/tests/auto/qscriptengine/tst_qscriptengine.cpp
@@ -93,7 +93,8 @@ private slots:
void constructWithParent();
void currentContext();
void pushPopContext();
- void getSetDefaultPrototype();
+ void getSetDefaultPrototype_int();
+ void getSetDefaultPrototype_customType();
void newFunction();
void newFunctionWithArg();
void newFunctionWithProto();
@@ -109,7 +110,9 @@ private slots:
void newVariant_promoteNonObject();
void newVariant_promoteNonQScriptObject();
void newRegExp();
+ void jsRegExp();
void newDate();
+ void jsParseDate();
void newQObject();
void newQObject_ownership();
void newQObject_promoteObject();
@@ -121,6 +124,7 @@ private slots:
void newActivationObject();
void getSetGlobalObject();
void globalObjectProperties();
+ void globalObjectProperties_enumerate();
void createGlobalObjectProperty();
void globalObjectGetterSetterProperty();
void customGlobalObjectWithPrototype();
@@ -136,7 +140,14 @@ private slots:
void nestedEvaluate();
void uncaughtException();
void errorMessage_QT679();
- void valueConversion();
+ void valueConversion_basic();
+ void valueConversion_customType();
+ void valueConversion_sequence();
+ void valueConversion_QVariant();
+ void valueConversion_hooliganTask248802();
+ void valueConversion_basic2();
+ void valueConversion_dateTime();
+ void valueConversion_regExp();
void qScriptValueFromValue_noEngine();
void importExtension();
void infiniteRecursion();
@@ -152,32 +163,51 @@ private slots:
void numberParsing_data();
void numberParsing();
void automaticSemicolonInsertion();
+ void abortEvaluation_notEvaluating();
void abortEvaluation();
+ void abortEvaluation_tryCatch();
+ void abortEvaluation_fromNative();
void abortEvaluation_QTBUG9433();
- void isEvaluating();
+ void isEvaluating_notEvaluating();
+ void isEvaluating_fromNative();
+ void isEvaluating_fromEvent();
void printFunctionWithCustomHandler();
void printThrowsException();
void errorConstructors();
- void argumentsProperty();
- void numberClass();
- void forInStatement();
- void functionExpression();
+ void argumentsProperty_globalContext();
+ void argumentsProperty_JS();
+ void argumentsProperty_evaluateInNativeFunction();
+ void jsNumberClass();
+ void jsForInStatement_simple();
+ void jsForInStatement_prototypeProperties();
+ void jsForInStatement_mutateWhileIterating();
+ void jsForInStatement_arrays();
+ void jsForInStatement_nullAndUndefined();
+ void jsFunctionDeclarationAsStatement();
void stringObjects();
+ void jsStringPrototypeReplaceBugs();
void getterSetterThisObject_global();
void getterSetterThisObject_plain();
void getterSetterThisObject_prototypeChain();
void getterSetterThisObject_activation();
- void continueInSwitch();
- void readOnlyPrototypeProperty();
+ void jsContinueInSwitch();
+ void jsShadowReadOnlyPrototypeProperty();
void toObject();
- void reservedWords_data();
- void reservedWords();
- void futureReservedWords_data();
- void futureReservedWords();
- void throwInsideWithStatement();
- void getSetAgent();
- void reentrancy();
- void incDecNonObjectProperty();
+ void jsReservedWords_data();
+ void jsReservedWords();
+ void jsFutureReservedWords_data();
+ void jsFutureReservedWords();
+ void jsThrowInsideWithStatement();
+ void getSetAgent_ownership();
+ void getSetAgent_deleteAgent();
+ void getSetAgent_differentEngine();
+ void reentrancy_stringHandles();
+ void reentrancy_processEventsInterval();
+ void reentrancy_typeConversion();
+ void reentrancy_globalObjectProperties();
+ void reentrancy_Array();
+ void reentrancy_objectCreation();
+ void jsIncDecNonObjectProperty();
void installTranslatorFunctions_data();
void installTranslatorFunctions();
void translateScript_data();
@@ -609,54 +639,65 @@ void tst_QScriptEngine::newRegExp()
QCOMPARE(rexp.toRegExp().pattern(), QRegExp("foo").pattern());
}
- {
- QScriptValue r = eng.evaluate("/foo/gim");
- QVERIFY(r.isRegExp());
- QCOMPARE(r.toString(), QString::fromLatin1("/foo/gim"));
+}
+
+void tst_QScriptEngine::jsRegExp()
+{
+ // See ECMA-262 Section 15.10, "RegExp Objects".
+ // These should really be JS-only tests, as they test the implementation's
+ // ECMA-compliance, not the C++ API. Compliance should already be covered
+ // by the Mozilla tests (qscriptjstestsuite).
+ // We can consider updating the expected results of this test if the
+ // RegExp implementation changes.
- QScriptValue rxCtor = eng.globalObject().property("RegExp");
- QScriptValue r2 = rxCtor.call(QScriptValue(), QScriptValueList() << r);
- QVERIFY(r2.isRegExp());
- QVERIFY(r2.strictlyEquals(r));
+ QScriptEngine eng;
+ QScriptValue r = eng.evaluate("/foo/gim");
+ QVERIFY(r.isRegExp());
+ QCOMPARE(r.toString(), QString::fromLatin1("/foo/gim"));
- QScriptValue r3 = rxCtor.call(QScriptValue(), QScriptValueList() << r << "gim");
- QVERIFY(r3.isError());
- QCOMPARE(r3.toString(), QString::fromLatin1("TypeError: Cannot supply flags when constructing one RegExp from another."));
+ QScriptValue rxCtor = eng.globalObject().property("RegExp");
+ QScriptValue r2 = rxCtor.call(QScriptValue(), QScriptValueList() << r);
+ QVERIFY(r2.isRegExp());
+ QVERIFY(r2.strictlyEquals(r));
- QScriptValue r4 = rxCtor.call(QScriptValue(), QScriptValueList() << "foo" << "gim");
- QVERIFY(r4.isRegExp());
+ QScriptValue r3 = rxCtor.call(QScriptValue(), QScriptValueList() << r << "gim");
+ QVERIFY(r3.isError());
+ QVERIFY(r3.toString().contains(QString::fromLatin1("TypeError"))); // Cannot supply flags when constructing one RegExp from another
- QScriptValue r5 = rxCtor.construct(QScriptValueList() << r);
- QVERIFY(r5.isRegExp());
- QCOMPARE(r5.toString(), QString::fromLatin1("/foo/gim"));
- // In JSC, constructing a RegExp from another produces the same identical object.
- // This is different from SpiderMonkey and old back-end.
- QVERIFY(r5.strictlyEquals(r));
+ QScriptValue r4 = rxCtor.call(QScriptValue(), QScriptValueList() << "foo" << "gim");
+ QVERIFY(r4.isRegExp());
- QScriptValue r6 = rxCtor.construct(QScriptValueList() << "foo" << "bar");
- QVERIFY(r6.isError());
- QCOMPARE(r6.toString(), QString::fromLatin1("SyntaxError: Invalid regular expression: invalid regular expression flag"));
+ QScriptValue r5 = rxCtor.construct(QScriptValueList() << r);
+ QVERIFY(r5.isRegExp());
+ QCOMPARE(r5.toString(), QString::fromLatin1("/foo/gim"));
+ // In JSC, constructing a RegExp from another produces the same identical object.
+ // This is different from SpiderMonkey and old back-end.
+ QVERIFY(r5.strictlyEquals(r));
- QScriptValue r7 = eng.evaluate("/foo/gimp");
- QVERIFY(r7.isError());
- QCOMPARE(r7.toString(), QString::fromLatin1("SyntaxError: Invalid regular expression: invalid regular expression flag"));
+ QScriptValue r6 = rxCtor.construct(QScriptValueList() << "foo" << "bar");
+ QVERIFY(r6.isError());
+ QVERIFY(r6.toString().contains(QString::fromLatin1("SyntaxError"))); // Invalid regular expression flag
- QScriptValue r8 = eng.evaluate("/foo/migmigmig");
- QVERIFY(r8.isRegExp());
- QCOMPARE(r8.toString(), QString::fromLatin1("/foo/gim"));
+ QScriptValue r7 = eng.evaluate("/foo/gimp");
+ QVERIFY(r7.isError());
+ QVERIFY(r7.toString().contains(QString::fromLatin1("SyntaxError"))); // Invalid regular expression flag
- QScriptValue r9 = rxCtor.construct();
- QVERIFY(r9.isRegExp());
- QCOMPARE(r9.toString(), QString::fromLatin1("/(?:)/"));
+ // JSC doesn't complain about duplicate flags.
+ QScriptValue r8 = eng.evaluate("/foo/migmigmig");
+ QVERIFY(r8.isRegExp());
+ QCOMPARE(r8.toString(), QString::fromLatin1("/foo/gim"));
- QScriptValue r10 = rxCtor.construct(QScriptValueList() << "" << "gim");
- QVERIFY(r10.isRegExp());
- QCOMPARE(r10.toString(), QString::fromLatin1("/(?:)/gim"));
+ QScriptValue r9 = rxCtor.construct();
+ QVERIFY(r9.isRegExp());
+ QCOMPARE(r9.toString(), QString::fromLatin1("/(?:)/"));
- QScriptValue r11 = rxCtor.construct(QScriptValueList() << "{1.*}" << "g");
- QVERIFY(r11.isRegExp());
- QCOMPARE(r11.toString(), QString::fromLatin1("/{1.*}/g"));
- }
+ QScriptValue r10 = rxCtor.construct(QScriptValueList() << "" << "gim");
+ QVERIFY(r10.isRegExp());
+ QCOMPARE(r10.toString(), QString::fromLatin1("/(?:)/gim"));
+
+ QScriptValue r11 = rxCtor.construct(QScriptValueList() << "{1.*}" << "g");
+ QVERIFY(r11.isRegExp());
+ QCOMPARE(r11.toString(), QString::fromLatin1("/{1.*}/g"));
}
void tst_QScriptEngine::newDate()
@@ -695,7 +736,11 @@ void tst_QScriptEngine::newDate()
// toDateTime() result should be in local time
QCOMPARE(date.toDateTime(), dt.toLocalTime());
}
+}
+void tst_QScriptEngine::jsParseDate()
+{
+ QScriptEngine eng;
// Date.parse() should return NaN when it fails
{
QScriptValue ret = eng.evaluate("Date.parse()");
@@ -1196,6 +1241,8 @@ static QScriptValue getSetFoo(QScriptContext *ctx, QScriptEngine *)
void tst_QScriptEngine::globalObjectProperties()
{
+ // See ECMA-262 Section 15.1, "The Global Object".
+
QScriptEngine eng;
QScriptValue global = eng.globalObject();
@@ -1271,8 +1318,13 @@ void tst_QScriptEngine::globalObjectProperties()
QVERIFY(!global.property("Math").isFunction());
QEXPECT_FAIL("", "[ECMA compliance] JSC sets DontDelete flag for Math object", Continue);
QCOMPARE(global.propertyFlags("Math"), QScriptValue::SkipInEnumeration);
+}
+
+void tst_QScriptEngine::globalObjectProperties_enumerate()
+{
+ QScriptEngine eng;
+ QScriptValue global = eng.globalObject();
- // enumeration
QSet<QString> expectedNames;
expectedNames
<< "isNaN"
@@ -1500,7 +1552,7 @@ void tst_QScriptEngine::globalObjectWithCustomPrototype()
{
QScriptValue ret = engine.evaluate("this.__proto__ = { 'a': 123 }; a");
QVERIFY(ret.isNumber());
- QEXPECT_FAIL("", "QTBUG-9737", Continue);
+ QEXPECT_FAIL("", "QTBUG-9737: Prototype change in JS not reflected on C++ side", Continue);
QVERIFY(ret.strictlyEquals(global.property("a")));
}
}
@@ -1510,7 +1562,9 @@ void tst_QScriptEngine::builtinFunctionNames_data()
QTest::addColumn<QString>("expression");
QTest::addColumn<QString>("expectedName");
- QTest::newRow("print") << QString("print") << QString("print");
+ // See ECMA-262 Chapter 15, "Standard Built-in ECMAScript Objects".
+
+ QTest::newRow("print") << QString("print") << QString("print"); // QtScript extension.
QTest::newRow("parseInt") << QString("parseInt") << QString("parseInt");
QTest::newRow("parseFloat") << QString("parseFloat") << QString("parseFloat");
QTest::newRow("isNaN") << QString("isNaN") << QString("isNaN");
@@ -1521,8 +1575,8 @@ void tst_QScriptEngine::builtinFunctionNames_data()
QTest::newRow("encodeURIComponent") << QString("encodeURIComponent") << QString("encodeURIComponent");
QTest::newRow("escape") << QString("escape") << QString("escape");
QTest::newRow("unescape") << QString("unescape") << QString("unescape");
- QTest::newRow("version") << QString("version") << QString("version");
- QTest::newRow("gc") << QString("gc") << QString("gc");
+ QTest::newRow("version") << QString("version") << QString("version"); // QtScript extension.
+ QTest::newRow("gc") << QString("gc") << QString("gc"); // QtScript extension.
QTest::newRow("Array") << QString("Array") << QString("Array");
QTest::newRow("Array.prototype.toString") << QString("Array.prototype.toString") << QString("toString");
@@ -1673,6 +1727,7 @@ void tst_QScriptEngine::builtinFunctionNames()
QFETCH(QString, expression);
QFETCH(QString, expectedName);
QScriptEngine eng;
+ // The "name" property is actually non-standard, but JSC supports it.
QScriptValue ret = eng.evaluate(QString::fromLatin1("%0.name").arg(expression));
QVERIFY(ret.isString());
QCOMPARE(ret.toString(), expectedName);
@@ -1894,22 +1949,24 @@ static QScriptValue eval_nested(QScriptContext *ctx, QScriptEngine *eng)
return result;
}
+// Tests that nested evaluate uses the "this" that was passed.
void tst_QScriptEngine::nestedEvaluate()
{
QScriptEngine eng;
QScriptValue fun = eng.newFunction(eval_nested);
eng.globalObject().setProperty("fun", fun);
+ // From JS function call
{
QScriptValue result = eng.evaluate("o = { id:'foo'}; o.fun = fun; o.fun()");
QCOMPARE(result.property("local_bar").toString(), QString("local"));
QCOMPARE(result.property("thisObjectIdBefore").toString(), QString("foo"));
QCOMPARE(result.property("thisObjectIdAfter").toString(), QString("foo"));
QCOMPARE(result.property("evaluatedThisObjectId").toString(), QString("foo"));
- QScriptValue bar = eng.evaluate("bar");
+ QScriptValue bar = eng.evaluate("bar"); // Was introduced in local scope.
QVERIFY(bar.isError());
- QCOMPARE(bar.toString(), QString::fromLatin1("ReferenceError: Can't find variable: bar"));
+ QVERIFY(bar.toString().contains(QString::fromLatin1("ReferenceError")));
}
-
+ // From QScriptValue::call()
{
QScriptValue result = fun.call(eng.evaluate("p = { id:'foo' }") , QScriptValueList() );
QCOMPARE(result.property("local_bar").toString(), QString("local"));
@@ -1918,7 +1975,7 @@ void tst_QScriptEngine::nestedEvaluate()
QCOMPARE(result.property("evaluatedThisObjectId").toString(), QString("foo"));
QScriptValue bar = eng.evaluate("bar");
QVERIFY(bar.isError());
- QCOMPARE(bar.toString(), QString::fromLatin1("ReferenceError: Can't find variable: bar"));
+ QVERIFY(bar.toString().contains(QString::fromLatin1("ReferenceError")));
}
}
@@ -1985,6 +2042,7 @@ void tst_QScriptEngine::errorMessage_QT679()
engine.globalObject().setProperty("foo", 15);
QScriptValue error = engine.evaluate("'hello world';\nfoo.bar.blah");
QVERIFY(error.isError());
+ // The exact message is back-end specific and subject to change.
QCOMPARE(error.toString(), QString::fromLatin1("TypeError: Result of expression 'foo.bar' [undefined] is not an object."));
}
@@ -1997,37 +2055,40 @@ public:
Q_DECLARE_METATYPE(Foo)
Q_DECLARE_METATYPE(Foo*)
-void tst_QScriptEngine::getSetDefaultPrototype()
+void tst_QScriptEngine::getSetDefaultPrototype_int()
{
QScriptEngine eng;
- {
- QScriptValue object = eng.newObject();
- QCOMPARE(eng.defaultPrototype(qMetaTypeId<int>()).isValid(), false);
- eng.setDefaultPrototype(qMetaTypeId<int>(), object);
- QCOMPARE(eng.defaultPrototype(qMetaTypeId<int>()).strictlyEquals(object), true);
- QScriptValue value = eng.newVariant(int(123));
- QCOMPARE(value.prototype().isObject(), true);
- QCOMPARE(value.prototype().strictlyEquals(object), true);
- eng.setDefaultPrototype(qMetaTypeId<int>(), QScriptValue());
- QCOMPARE(eng.defaultPrototype(qMetaTypeId<int>()).isValid(), false);
- QScriptValue value2 = eng.newVariant(int(123));
- QCOMPARE(value2.prototype().strictlyEquals(object), false);
- }
- {
- QScriptValue object = eng.newObject();
- QCOMPARE(eng.defaultPrototype(qMetaTypeId<Foo>()).isValid(), false);
- eng.setDefaultPrototype(qMetaTypeId<Foo>(), object);
- QCOMPARE(eng.defaultPrototype(qMetaTypeId<Foo>()).strictlyEquals(object), true);
- QScriptValue value = eng.newVariant(qVariantFromValue(Foo()));
- QCOMPARE(value.prototype().isObject(), true);
- QCOMPARE(value.prototype().strictlyEquals(object), true);
+ QScriptValue object = eng.newObject();
+ QCOMPARE(eng.defaultPrototype(qMetaTypeId<int>()).isValid(), false);
+ eng.setDefaultPrototype(qMetaTypeId<int>(), object);
+ QCOMPARE(eng.defaultPrototype(qMetaTypeId<int>()).strictlyEquals(object), true);
+ QScriptValue value = eng.newVariant(int(123));
+ QCOMPARE(value.prototype().isObject(), true);
+ QCOMPARE(value.prototype().strictlyEquals(object), true);
- eng.setDefaultPrototype(qMetaTypeId<Foo>(), QScriptValue());
- QCOMPARE(eng.defaultPrototype(qMetaTypeId<Foo>()).isValid(), false);
- QScriptValue value2 = eng.newVariant(qVariantFromValue(Foo()));
- QCOMPARE(value2.prototype().strictlyEquals(object), false);
- }
+ eng.setDefaultPrototype(qMetaTypeId<int>(), QScriptValue());
+ QCOMPARE(eng.defaultPrototype(qMetaTypeId<int>()).isValid(), false);
+ QScriptValue value2 = eng.newVariant(int(123));
+ QCOMPARE(value2.prototype().strictlyEquals(object), false);
+}
+
+void tst_QScriptEngine::getSetDefaultPrototype_customType()
+{
+ QScriptEngine eng;
+
+ QScriptValue object = eng.newObject();
+ QCOMPARE(eng.defaultPrototype(qMetaTypeId<Foo>()).isValid(), false);
+ eng.setDefaultPrototype(qMetaTypeId<Foo>(), object);
+ QCOMPARE(eng.defaultPrototype(qMetaTypeId<Foo>()).strictlyEquals(object), true);
+ QScriptValue value = eng.newVariant(qVariantFromValue(Foo()));
+ QCOMPARE(value.prototype().isObject(), true);
+ QCOMPARE(value.prototype().strictlyEquals(object), true);
+
+ eng.setDefaultPrototype(qMetaTypeId<Foo>(), QScriptValue());
+ QCOMPARE(eng.defaultPrototype(qMetaTypeId<Foo>()).isValid(), false);
+ QScriptValue value2 = eng.newVariant(qVariantFromValue(Foo()));
+ QCOMPARE(value2.prototype().strictlyEquals(object), false);
}
static QScriptValue fooToScriptValue(QScriptEngine *eng, const Foo &foo)
@@ -2061,7 +2122,7 @@ Q_DECLARE_METATYPE(QStack<int>)
Q_DECLARE_METATYPE(QQueue<char>)
Q_DECLARE_METATYPE(QLinkedList<QStack<int> >)
-void tst_QScriptEngine::valueConversion()
+void tst_QScriptEngine::valueConversion_basic()
{
QScriptEngine eng;
{
@@ -2123,7 +2184,11 @@ void tst_QScriptEngine::valueConversion()
QCOMPARE(qScriptValueToValue<QChar>(code), c);
QCOMPARE(qScriptValueToValue<QChar>(qScriptValueFromValue(&eng, c)), c);
}
+}
+void tst_QScriptEngine::valueConversion_customType()
+{
+ QScriptEngine eng;
{
// a type that we don't have built-in conversion of
// (it's stored as a variant)
@@ -2169,7 +2234,11 @@ void tst_QScriptEngine::valueConversion()
QVERIFY(fooVal2.property("x").strictlyEquals(QScriptValue(&eng, 56)));
QVERIFY(fooVal2.property("y").strictlyEquals(QScriptValue(&eng, 78)));
}
+}
+void tst_QScriptEngine::valueConversion_sequence()
+{
+ QScriptEngine eng;
qScriptRegisterSequenceMetaType<QLinkedList<QString> >(&eng);
{
@@ -2248,7 +2317,11 @@ void tst_QScriptEngine::valueConversion()
QCOMPARE(qscriptvalue_cast<QObjectList>(val), lst);
}
+}
+void tst_QScriptEngine::valueConversion_QVariant()
+{
+ QScriptEngine eng;
// qScriptValueFromValue() should be "smart" when the argument is a QVariant
{
QScriptValue val = qScriptValueFromValue(&eng, QVariant());
@@ -2325,7 +2398,12 @@ void tst_QScriptEngine::valueConversion()
QCOMPARE(val.toVariant(), var);
}
- // task 248802
+ QCOMPARE(qscriptvalue_cast<QVariant>(QScriptValue(123)), QVariant(123));
+}
+
+void tst_QScriptEngine::valueConversion_hooliganTask248802()
+{
+ QScriptEngine eng;
qScriptRegisterMetaType<Foo>(&eng, fooToScriptValueV2, fooFromScriptValueV2);
{
QScriptValue num(&eng, 123);
@@ -2343,6 +2421,11 @@ void tst_QScriptEngine::valueConversion()
QCOMPARE(foo.x, 123);
}
+}
+
+void tst_QScriptEngine::valueConversion_basic2()
+{
+ QScriptEngine eng;
// more built-in types
{
QScriptValue val = qScriptValueFromValue(&eng, uint(123));
@@ -2379,6 +2462,11 @@ void tst_QScriptEngine::valueConversion()
QVERIFY(val.isNumber());
QCOMPARE(val.toInt32(), 123);
}
+}
+
+void tst_QScriptEngine::valueConversion_dateTime()
+{
+ QScriptEngine eng;
{
QDateTime in = QDateTime::currentDateTime();
QScriptValue val = qScriptValueFromValue(&eng, in);
@@ -2391,6 +2479,11 @@ void tst_QScriptEngine::valueConversion()
QVERIFY(val.isDate());
QCOMPARE(val.toDateTime().date(), in);
}
+}
+
+void tst_QScriptEngine::valueConversion_regExp()
+{
+ QScriptEngine eng;
{
QRegExp in = QRegExp("foo");
QScriptValue val = qScriptValueFromValue(&eng, in);
@@ -2416,8 +2509,6 @@ void tst_QScriptEngine::valueConversion()
QEXPECT_FAIL("", "QTBUG-6136: JSC-based back-end doesn't preserve QRegExp::minimal (always false)", Continue);
QCOMPARE(val.toRegExp().isMinimal(), in.isMinimal());
}
-
- QCOMPARE(qscriptvalue_cast<QVariant>(QScriptValue(123)), QVariant(123));
}
void tst_QScriptEngine::qScriptValueFromValue_noEngine()
@@ -2522,7 +2613,7 @@ void tst_QScriptEngine::importExtension()
QEXPECT_FAIL("", "JSC throws syntax error eagerly", Continue);
QCOMPARE(eng.uncaughtExceptionLineNumber(), 4);
QVERIFY(ret.isError());
- QCOMPARE(ret.property("message").toString(), QLatin1String("Parse error"));
+ QVERIFY(ret.toString().contains(QLatin1String("SyntaxError")));
}
QStringList imp = eng.importedExtensions();
QCOMPARE(imp.size(), 2);
@@ -2548,6 +2639,9 @@ static QScriptValue recurse2(QScriptContext *ctx, QScriptEngine *eng)
void tst_QScriptEngine::infiniteRecursion()
{
+ // Infinite recursion in JS should cause the VM to throw an error
+ // when the JS stack is exhausted.
+ // The exact error is back-end specific and subject to change.
const QString stackOverflowError = QString::fromLatin1("RangeError: Maximum call stack size exceeded.");
QScriptEngine eng;
{
@@ -2610,6 +2704,8 @@ void tst_QScriptEngine::castWithPrototypeChain()
baz2.b = 456;
QScriptValue baz2Value = qScriptValueFromValue(&eng, &baz2);
{
+ // qscriptvalue_cast() does magic; if the QScriptValue contains
+ // t of type T, and the target type is T*, &t is returned.
Baz *pbaz = qscriptvalue_cast<Baz*>(baz2Value);
QVERIFY(pbaz != 0);
QCOMPARE(pbaz->b, baz2.b);
@@ -2632,6 +2728,13 @@ void tst_QScriptEngine::castWithPrototypeChain()
}
// establish chain -- now casting should work
+ // Why? because qscriptvalue_cast() does magic again.
+ // It the instance itself is not of type T, qscriptvalue_cast()
+ // searches the prototype chain for T, and if it finds one, it infers
+ // that the instance can also be casted to that type. This cast is
+ // _not_ safe and thus relies on the developer doing the right thing.
+ // This is an undocumented feature to enable qscriptvalue_cast() to
+ // be used by prototype functions to cast the JS this-object to C++.
bazProto.setPrototype(barProto);
{
@@ -2740,6 +2843,9 @@ void tst_QScriptEngine::collectGarbage()
void tst_QScriptEngine::reportAdditionalMemoryCost()
{
QScriptEngine eng;
+ // There isn't any reliable way to test whether calling
+ // this function affects garbage collection responsiveness;
+ // the best we can do is call it with a few different values.
for (int x = 0; x < 1000; ++x) {
eng.reportAdditionalMemoryCost(0);
eng.reportAdditionalMemoryCost(10);
@@ -2757,6 +2863,8 @@ void tst_QScriptEngine::reportAdditionalMemoryCost()
void tst_QScriptEngine::gcWithNestedDataStructure()
{
+ // The GC must be able to traverse deeply nested objects, otherwise this
+ // test would crash.
QScriptEngine eng;
eng.evaluate(
"function makeList(size)"
@@ -2778,6 +2886,7 @@ void tst_QScriptEngine::gcWithNestedDataStructure()
if (x == 1)
eng.evaluate("gc()");
QScriptValue l = head;
+ // Make sure all the nodes are still alive.
for (int i = 0; i < 200; ++i) {
QCOMPARE(l.property("data").toString(), QString::number(i));
l = l.property("next");
@@ -2807,6 +2916,8 @@ void tst_QScriptEngine::processEventsWhileRunning()
if (x == 0)
eng.pushContext();
+ // This is running for a silly amount of time just to make sure
+ // the script doesn't finish before event processing is triggered.
QString script = QString::fromLatin1(
"var end = Number(new Date()) + 2000;"
"var x = 0;"
@@ -3012,13 +3123,15 @@ void tst_QScriptEngine::numberParsing()
}
// see ECMA-262, section 7.9
+// This is testing ECMA compliance, not our C++ API, but it's important that
+// the back-end is conformant in this regard.
void tst_QScriptEngine::automaticSemicolonInsertion()
{
QScriptEngine eng;
{
QScriptValue ret = eng.evaluate("{ 1 2 } 3");
QVERIFY(ret.isError());
- QCOMPARE(ret.toString(), QString::fromLatin1("SyntaxError: Parse error"));
+ QVERIFY(ret.toString().contains("SyntaxError"));
}
{
QScriptValue ret = eng.evaluate("{ 1\n2 } 3");
@@ -3028,7 +3141,7 @@ void tst_QScriptEngine::automaticSemicolonInsertion()
{
QScriptValue ret = eng.evaluate("for (a; b\n)");
QVERIFY(ret.isError());
- QCOMPARE(ret.toString(), QString::fromLatin1("SyntaxError: Parse error"));
+ QVERIFY(ret.toString().contains("SyntaxError"));
}
{
QScriptValue ret = eng.evaluate("(function() { return\n1 + 2 })()");
@@ -3043,7 +3156,7 @@ void tst_QScriptEngine::automaticSemicolonInsertion()
{
QScriptValue ret = eng.evaluate("if (a > b)\nelse c = d");
QVERIFY(ret.isError());
- QCOMPARE(ret.toString(), QString::fromLatin1("SyntaxError: Parse error"));
+ QVERIFY(ret.toString().contains("SyntaxError"));
}
{
eng.evaluate("function c() { return { foo: function() { return 5; } } }");
@@ -3055,7 +3168,7 @@ void tst_QScriptEngine::automaticSemicolonInsertion()
{
QScriptValue ret = eng.evaluate("throw\n1");
QVERIFY(ret.isError());
- QCOMPARE(ret.toString(), QString::fromLatin1("SyntaxError: Parse error"));
+ QVERIFY(ret.toString().contains("SyntaxError"));
}
{
QScriptValue ret = eng.evaluate("a = Number(1)\n++a");
@@ -3257,7 +3370,7 @@ static QScriptValue myFunctionAbortingEvaluation(QScriptContext *, QScriptEngine
return eng->nullValue(); // should be ignored
}
-void tst_QScriptEngine::abortEvaluation()
+void tst_QScriptEngine::abortEvaluation_notEvaluating()
{
QScriptEngine eng;
@@ -3270,7 +3383,11 @@ void tst_QScriptEngine::abortEvaluation()
QVERIFY(ret.isString());
QCOMPARE(ret.toString(), QString::fromLatin1("ciao"));
}
+}
+void tst_QScriptEngine::abortEvaluation()
+{
+ QScriptEngine eng;
EventReceiver3 receiver(&eng);
eng.setProcessEventsInterval(100);
@@ -3301,6 +3418,13 @@ void tst_QScriptEngine::abortEvaluation()
}
}
+}
+
+void tst_QScriptEngine::abortEvaluation_tryCatch()
+{
+ QScriptEngine eng;
+ EventReceiver3 receiver(&eng);
+ eng.setProcessEventsInterval(100);
// scripts cannot intercept the abortion with try/catch
for (int y = 0; y < 4; ++y) {
QCoreApplication::postEvent(&receiver, new QEvent(QEvent::Type(QEvent::User+1)));
@@ -3334,13 +3458,15 @@ void tst_QScriptEngine::abortEvaluation()
break;
}
}
+}
- {
- QScriptValue fun = eng.newFunction(myFunctionAbortingEvaluation);
- eng.globalObject().setProperty("myFunctionAbortingEvaluation", fun);
- QScriptValue ret = eng.evaluate("myFunctionAbortingEvaluation()");
- QVERIFY(!ret.isValid());
- }
+void tst_QScriptEngine::abortEvaluation_fromNative()
+{
+ QScriptEngine eng;
+ QScriptValue fun = eng.newFunction(myFunctionAbortingEvaluation);
+ eng.globalObject().setProperty("myFunctionAbortingEvaluation", fun);
+ QScriptValue ret = eng.evaluate("myFunctionAbortingEvaluation()");
+ QVERIFY(!ret.isValid());
}
class ThreadedEngine : public QThread {
@@ -3407,7 +3533,7 @@ public:
bool wasEvaluating;
};
-void tst_QScriptEngine::isEvaluating()
+void tst_QScriptEngine::isEvaluating_notEvaluating()
{
QScriptEngine eng;
@@ -3419,30 +3545,34 @@ void tst_QScriptEngine::isEvaluating()
QVERIFY(!eng.isEvaluating());
eng.evaluate("0 = 0");
QVERIFY(!eng.isEvaluating());
+}
- {
- QScriptValue fun = eng.newFunction(myFunctionReturningIsEvaluating);
- eng.globalObject().setProperty("myFunctionReturningIsEvaluating", fun);
- QScriptValue ret = eng.evaluate("myFunctionReturningIsEvaluating()");
- QVERIFY(ret.isBoolean());
- QVERIFY(ret.toBoolean());
- }
+void tst_QScriptEngine::isEvaluating_fromNative()
+{
+ QScriptEngine eng;
+ QScriptValue fun = eng.newFunction(myFunctionReturningIsEvaluating);
+ eng.globalObject().setProperty("myFunctionReturningIsEvaluating", fun);
+ QScriptValue ret = eng.evaluate("myFunctionReturningIsEvaluating()");
+ QVERIFY(ret.isBoolean());
+ QVERIFY(ret.toBoolean());
+}
- {
- EventReceiver4 receiver(&eng);
- QCoreApplication::postEvent(&receiver, new QEvent(QEvent::Type(QEvent::User+1)));
+void tst_QScriptEngine::isEvaluating_fromEvent()
+{
+ QScriptEngine eng;
+ EventReceiver4 receiver(&eng);
+ QCoreApplication::postEvent(&receiver, new QEvent(QEvent::Type(QEvent::User+1)));
- QString script = QString::fromLatin1(
- "var end = Number(new Date()) + 1000;"
- "var x = 0;"
- "while (Number(new Date()) < end) {"
- " ++x;"
- "}");
+ QString script = QString::fromLatin1(
+ "var end = Number(new Date()) + 1000;"
+ "var x = 0;"
+ "while (Number(new Date()) < end) {"
+ " ++x;"
+ "}");
- eng.setProcessEventsInterval(100);
- eng.evaluate(script);
- QVERIFY(receiver.wasEvaluating);
- }
+ eng.setProcessEventsInterval(100);
+ eng.evaluate(script);
+ QVERIFY(receiver.wasEvaluating);
}
static QtMsgType theMessageType;
@@ -3456,24 +3586,33 @@ static void myMsgHandler(QtMsgType type, const char *msg)
void tst_QScriptEngine::printFunctionWithCustomHandler()
{
+ // The built-in print() function passes the output to Qt's message
+ // handler. By installing a custom message handler, the output can be
+ // redirected without changing the print() function itself.
+ // This behavior is not documented.
QScriptEngine eng;
QtMsgHandler oldHandler = qInstallMsgHandler(myMsgHandler);
QVERIFY(eng.globalObject().property("print").isFunction());
+
theMessageType = QtSystemMsg;
QVERIFY(theMessage.isEmpty());
QVERIFY(eng.evaluate("print('test')").isUndefined());
QCOMPARE(theMessageType, QtDebugMsg);
QCOMPARE(theMessage, QString::fromLatin1("test"));
+
theMessageType = QtSystemMsg;
theMessage.clear();
QVERIFY(eng.evaluate("print(3, true, 'little pigs')").isUndefined());
QCOMPARE(theMessageType, QtDebugMsg);
QCOMPARE(theMessage, QString::fromLatin1("3 true little pigs"));
+
qInstallMsgHandler(oldHandler);
}
void tst_QScriptEngine::printThrowsException()
{
+ // If an argument to print() causes an exception to be thrown when
+ // it's converted to a string, print() should propagate the exception.
QScriptEngine eng;
QScriptValue ret = eng.evaluate("print({ toString: function() { throw 'foo'; } });");
QVERIFY(eng.hasUncaughtException());
@@ -3506,34 +3645,30 @@ void tst_QScriptEngine::errorConstructors()
}
}
-static QScriptValue argumentsProperty_fun(QScriptContext *, QScriptEngine *eng)
+void tst_QScriptEngine::argumentsProperty_globalContext()
{
- eng->evaluate("var a = arguments[0];");
- eng->evaluate("arguments[0] = 200;");
- return eng->evaluate("a + arguments[0]");
+ QScriptEngine eng;
+ {
+ // Unlike function calls, the global context doesn't have an
+ // arguments property.
+ QScriptValue ret = eng.evaluate("arguments");
+ QVERIFY(ret.isError());
+ QVERIFY(ret.toString().contains(QString::fromLatin1("ReferenceError")));
+ }
+ eng.evaluate("arguments = 10");
+ {
+ QScriptValue ret = eng.evaluate("arguments");
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toInt32(), 10);
+ }
+ QVERIFY(eng.evaluate("delete arguments").toBoolean());
+ QVERIFY(!eng.globalObject().property("arguments").isValid());
}
-
-void tst_QScriptEngine::argumentsProperty()
+void tst_QScriptEngine::argumentsProperty_JS()
{
{
QScriptEngine eng;
- {
- QScriptValue ret = eng.evaluate("arguments");
- QVERIFY(ret.isError());
- QCOMPARE(ret.toString(), QString::fromLatin1("ReferenceError: Can't find variable: arguments"));
- }
- eng.evaluate("arguments = 10");
- {
- QScriptValue ret = eng.evaluate("arguments");
- QVERIFY(ret.isNumber());
- QCOMPARE(ret.toInt32(), 10);
- }
- QVERIFY(eng.evaluate("delete arguments").toBoolean());
- QVERIFY(!eng.globalObject().property("arguments").isValid());
- }
- {
- QScriptEngine eng;
eng.evaluate("o = { arguments: 123 }");
QScriptValue ret = eng.evaluate("with (o) { arguments; }");
QVERIFY(ret.isNumber());
@@ -3542,25 +3677,40 @@ void tst_QScriptEngine::argumentsProperty()
{
QScriptEngine eng;
QVERIFY(!eng.globalObject().property("arguments").isValid());
+ // This is testing ECMA-262 compliance. In function calls, "arguments"
+ // appears like a local variable, and it can be replaced.
QScriptValue ret = eng.evaluate("(function() { arguments = 456; return arguments; })()");
QVERIFY(ret.isNumber());
QCOMPARE(ret.toInt32(), 456);
QVERIFY(!eng.globalObject().property("arguments").isValid());
}
+}
- {
- QScriptEngine eng;
- QScriptValue fun = eng.newFunction(argumentsProperty_fun);
- eng.globalObject().setProperty("fun", eng.newFunction(argumentsProperty_fun));
- QScriptValue result = eng.evaluate("fun(18)");
- QVERIFY(result.isNumber());
- QCOMPARE(result.toInt32(), 218);
- }
+static QScriptValue argumentsProperty_fun(QScriptContext *, QScriptEngine *eng)
+{
+ // Since evaluate() is done in the current context, "arguments" should
+ // refer to currentContext()->argumentsObject().
+ // This is for consistency with the built-in JS eval() function.
+ eng->evaluate("var a = arguments[0];");
+ eng->evaluate("arguments[0] = 200;");
+ return eng->evaluate("a + arguments[0]");
}
-void tst_QScriptEngine::numberClass()
+void tst_QScriptEngine::argumentsProperty_evaluateInNativeFunction()
{
QScriptEngine eng;
+ QScriptValue fun = eng.newFunction(argumentsProperty_fun);
+ eng.globalObject().setProperty("fun", eng.newFunction(argumentsProperty_fun));
+ QScriptValue result = eng.evaluate("fun(18)");
+ QVERIFY(result.isNumber());
+ QCOMPARE(result.toInt32(), 200+18);
+}
+
+void tst_QScriptEngine::jsNumberClass()
+{
+ // See ECMA-262 Section 15.7, "Number Objects".
+
+ QScriptEngine eng;
QScriptValue ctor = eng.globalObject().property("Number");
QVERIFY(ctor.property("length").isNumber());
@@ -3669,7 +3819,7 @@ void tst_QScriptEngine::numberClass()
}
}
-void tst_QScriptEngine::forInStatement()
+void tst_QScriptEngine::jsForInStatement_simple()
{
QScriptEngine eng;
{
@@ -3692,8 +3842,11 @@ void tst_QScriptEngine::forInStatement()
QCOMPARE(lst.at(0), QString::fromLatin1("p"));
QCOMPARE(lst.at(1), QString::fromLatin1("q"));
}
+}
- // properties in prototype
+void tst_QScriptEngine::jsForInStatement_prototypeProperties()
+{
+ QScriptEngine eng;
{
QScriptValue ret = eng.evaluate("o = { }; o.__proto__ = { p: 123 }; r = [];"
"for (var p in o) r[r.length] = p; r");
@@ -3718,6 +3871,11 @@ void tst_QScriptEngine::forInStatement()
QCOMPARE(lst.at(0), QString::fromLatin1("p"));
}
+}
+
+void tst_QScriptEngine::jsForInStatement_mutateWhileIterating()
+{
+ QScriptEngine eng;
// deleting property during enumeration
{
QScriptValue ret = eng.evaluate("o = { p: 123 }; r = [];"
@@ -3743,7 +3901,11 @@ void tst_QScriptEngine::forInStatement()
QCOMPARE(lst.at(0), QString::fromLatin1("p"));
}
- // arrays
+}
+
+void tst_QScriptEngine::jsForInStatement_arrays()
+{
+ QScriptEngine eng;
{
QScriptValue ret = eng.evaluate("a = [123, 456]; r = [];"
"for (var p in a) r[r.length] = p; r");
@@ -3774,10 +3936,11 @@ void tst_QScriptEngine::forInStatement()
QCOMPARE(lst.at(3), QString::fromLatin1("2"));
QCOMPARE(lst.at(4), QString::fromLatin1("bar"));
}
+}
- // null and undefined
- // according to the spec, we should throw an exception; however, for
- // compability with the real world, we don't
+void tst_QScriptEngine::jsForInStatement_nullAndUndefined()
+{
+ QScriptEngine eng;
{
QScriptValue ret = eng.evaluate("r = true; for (var p in undefined) r = false; r");
QVERIFY(ret.isBool());
@@ -3790,9 +3953,17 @@ void tst_QScriptEngine::forInStatement()
}
}
-void tst_QScriptEngine::functionExpression()
+void tst_QScriptEngine::jsFunctionDeclarationAsStatement()
{
- // task 175679
+ // ECMA-262 does not allow function declarations to be used as statements,
+ // but several popular implementations (including JSC) do. See the NOTE
+ // at the beginning of chapter 12 in ECMA-262 5th edition, where it's
+ // recommended that implementations either disallow this usage or issue
+ // a warning.
+ // Since we had a bug report long ago about QtScript not supporting this
+ // "feature" (and thus deviating from other implementations), we still
+ // check this behavior.
+
QScriptEngine eng;
QVERIFY(!eng.globalObject().property("bar").isValid());
eng.evaluate("function foo(arg) {\n"
@@ -3825,6 +3996,8 @@ void tst_QScriptEngine::functionExpression()
void tst_QScriptEngine::stringObjects()
{
+ // See ECMA-262 Section 15.5, "String Objects".
+
QScriptEngine eng;
QString str("ciao");
// in C++
@@ -3886,7 +4059,11 @@ void tst_QScriptEngine::stringObjects()
QVERIFY(ret7.isBoolean());
QVERIFY(ret7.toBoolean());
}
+}
+void tst_QScriptEngine::jsStringPrototypeReplaceBugs()
+{
+ QScriptEngine eng;
// task 212440
{
QScriptValue ret = eng.evaluate("replace_args = []; \"a a a\".replace(/(a)/g, function() { replace_args.push(arguments); }); replace_args");
@@ -4038,8 +4215,10 @@ void tst_QScriptEngine::getterSetterThisObject_activation()
}
}
-void tst_QScriptEngine::continueInSwitch()
+void tst_QScriptEngine::jsContinueInSwitch()
{
+ // This is testing ECMA-262 compliance, not C++ API.
+
QScriptEngine eng;
// switch - continue
{
@@ -4116,35 +4295,17 @@ void tst_QScriptEngine::continueInSwitch()
}
}
-void tst_QScriptEngine::readOnlyPrototypeProperty()
+void tst_QScriptEngine::jsShadowReadOnlyPrototypeProperty()
{
- QSKIP("JSC semantics differ from old back-end and SpiderMonkey", SkipAll);
+ // SpiderMonkey has different behavior than JSC and V8; it disallows
+ // creating a property on the instance if there's a property with the
+ // same name in the prototype, and that property is read-only. We
+ // adopted that behavior in the old (4.5) QtScript back-end, but it
+ // just seems weird -- and non-compliant. Adopt the JSC behavior instead.
QScriptEngine eng;
- QCOMPARE(eng.evaluate("o = {}; o.__proto__ = parseInt; o.length").toInt32(), 2);
- QCOMPARE(eng.evaluate("o.length = 4; o.length").toInt32(), 2);
- QVERIFY(!eng.evaluate("o.hasOwnProperty('length')").toBoolean());
- QCOMPARE(eng.evaluate("o.length *= 2; o.length").toInt32(), 2);
- QCOMPARE(eng.evaluate("o.length /= 2; o.length").toInt32(), 2);
- QCOMPARE(eng.evaluate("o.length %= 2; o.length").toInt32(), 2);
- QCOMPARE(eng.evaluate("o.length += 2; o.length").toInt32(), 2);
- QCOMPARE(eng.evaluate("o.length -= 2; o.length").toInt32(), 2);
- QCOMPARE(eng.evaluate("o.length <<= 2; o.length").toInt32(), 2);
- QCOMPARE(eng.evaluate("o.length >>= 2; o.length").toInt32(), 2);
- QCOMPARE(eng.evaluate("o.length >>>= 2; o.length").toInt32(), 2);
- QCOMPARE(eng.evaluate("o.length &= 0; o.length").toInt32(), 2);
- QCOMPARE(eng.evaluate("o.length ^= 255; o.length").toInt32(), 2);
- QCOMPARE(eng.evaluate("o.length |= 255; o.length").toInt32(), 2);
-
- {
- QScriptValue ret = eng.evaluate("o.__defineGetter__('length', function() {})");
- QVERIFY(ret.isError());
- QCOMPARE(ret.toString(), QString::fromLatin1("Error: cannot redefine read-only property"));
- }
- {
- QScriptValue ret = eng.evaluate("o.__defineSetter__('length', function() {})");
- QVERIFY(ret.isError());
- QCOMPARE(ret.toString(), QString::fromLatin1("Error: cannot redefine read-only property"));
- }
+ QVERIFY(eng.evaluate("o = {}; o.__proto__ = parseInt; o.length").isNumber());
+ QCOMPARE(eng.evaluate("o.length = 123; o.length").toInt32(), 123);
+ QVERIFY(eng.evaluate("o.hasOwnProperty('length')").toBoolean());
}
void tst_QScriptEngine::toObject()
@@ -4226,7 +4387,7 @@ void tst_QScriptEngine::toObject()
QVERIFY(stringValue.isString());
}
-void tst_QScriptEngine::reservedWords_data()
+void tst_QScriptEngine::jsReservedWords_data()
{
QTest::addColumn<QString>("word");
QTest::newRow("break") << QString("break");
@@ -4259,8 +4420,13 @@ void tst_QScriptEngine::reservedWords_data()
QTest::newRow("with") << QString("with");
}
-void tst_QScriptEngine::reservedWords()
+void tst_QScriptEngine::jsReservedWords()
{
+ // See ECMA-262 Section 7.6.1, "Reserved Words".
+ // We prefer that the implementation is less strict than the spec; e.g.
+ // it's good to allow reserved words as identifiers in object literals,
+ // and when accessing properties using dot notation.
+
QFETCH(QString, word);
{
QScriptEngine eng;
@@ -4298,7 +4464,7 @@ void tst_QScriptEngine::reservedWords()
}
}
-void tst_QScriptEngine::futureReservedWords_data()
+void tst_QScriptEngine::jsFutureReservedWords_data()
{
QTest::addColumn<QString>("word");
QTest::addColumn<bool>("allowed");
@@ -4335,8 +4501,12 @@ void tst_QScriptEngine::futureReservedWords_data()
QTest::newRow("volatile") << QString("volatile") << true;
}
-void tst_QScriptEngine::futureReservedWords()
+void tst_QScriptEngine::jsFutureReservedWords()
{
+ // See ECMA-262 Section 7.6.1.2, "Future Reserved Words".
+ // In real-world implementations, most of these words are
+ // actually allowed as normal identifiers.
+
QFETCH(QString, word);
QFETCH(bool, allowed);
{
@@ -4364,8 +4534,10 @@ void tst_QScriptEngine::futureReservedWords()
}
}
-void tst_QScriptEngine::throwInsideWithStatement()
+void tst_QScriptEngine::jsThrowInsideWithStatement()
{
+ // This is testing ECMA-262 compliance, not C++ API.
+
// task 209988
QScriptEngine eng;
{
@@ -4379,7 +4551,7 @@ void tst_QScriptEngine::throwInsideWithStatement()
" bad;"
"}");
QVERIFY(ret.isError());
- QCOMPARE(ret.toString(), QString::fromLatin1("ReferenceError: Can't find variable: bad"));
+ QVERIFY(ret.toString().contains(QString::fromLatin1("ReferenceError")));
}
{
QScriptValue ret = eng.evaluate(
@@ -4392,7 +4564,7 @@ void tst_QScriptEngine::throwInsideWithStatement()
" bad;"
"}");
QVERIFY(ret.isError());
- QCOMPARE(ret.toString(), QString::fromLatin1("ReferenceError: Can't find variable: bad"));
+ QVERIFY(ret.toString().contains(QString::fromLatin1("ReferenceError")));
}
{
eng.clearExceptions();
@@ -4419,7 +4591,7 @@ void tst_QScriptEngine::throwInsideWithStatement()
QVERIFY(ret.isNumber());
QScriptValue ret2 = eng.evaluate("bug");
QVERIFY(ret2.isError());
- QCOMPARE(ret2.toString(), QString::fromLatin1("ReferenceError: Can't find variable: bug"));
+ QVERIFY(ret2.toString().contains(QString::fromLatin1("ReferenceError")));
}
}
@@ -4429,106 +4601,116 @@ public:
TestAgent(QScriptEngine *engine) : QScriptEngineAgent(engine) {}
};
-void tst_QScriptEngine::getSetAgent()
+void tst_QScriptEngine::getSetAgent_ownership()
{
- // case 1: engine deleted before agent --> agent deleted too
- {
- QScriptEngine *eng = new QScriptEngine;
- QCOMPARE(eng->agent(), (QScriptEngineAgent*)0);
- TestAgent *agent = new TestAgent(eng);
- eng->setAgent(agent);
- QCOMPARE(eng->agent(), (QScriptEngineAgent*)agent);
- eng->setAgent(0); // the engine maintains ownership of the old agent
- QCOMPARE(eng->agent(), (QScriptEngineAgent*)0);
- delete eng;
- }
- // case 2: agent deleted before engine --> engine's agent should become 0
- {
- QScriptEngine *eng = new QScriptEngine;
- TestAgent *agent = new TestAgent(eng);
- eng->setAgent(agent);
- QCOMPARE(eng->agent(), (QScriptEngineAgent*)agent);
- delete agent;
- QCOMPARE(eng->agent(), (QScriptEngineAgent*)0);
- eng->evaluate("(function(){ return 123; })()");
- delete eng;
- }
- {
- QScriptEngine eng;
- QScriptEngine eng2;
- TestAgent *agent = new TestAgent(&eng);
- QTest::ignoreMessage(QtWarningMsg, "QScriptEngine::setAgent(): cannot set agent belonging to different engine");
- eng2.setAgent(agent);
- QCOMPARE(eng2.agent(), (QScriptEngineAgent*)0);
- }
+ // engine deleted before agent --> agent deleted too
+ QScriptEngine *eng = new QScriptEngine;
+ QCOMPARE(eng->agent(), (QScriptEngineAgent*)0);
+ TestAgent *agent = new TestAgent(eng);
+ eng->setAgent(agent);
+ QCOMPARE(eng->agent(), (QScriptEngineAgent*)agent);
+ eng->setAgent(0); // the engine maintains ownership of the old agent
+ QCOMPARE(eng->agent(), (QScriptEngineAgent*)0);
+ delete eng;
}
-void tst_QScriptEngine::reentrancy()
+void tst_QScriptEngine::getSetAgent_deleteAgent()
{
+ // agent deleted before engine --> engine's agent should become 0
+ QScriptEngine *eng = new QScriptEngine;
+ TestAgent *agent = new TestAgent(eng);
+ eng->setAgent(agent);
+ QCOMPARE(eng->agent(), (QScriptEngineAgent*)agent);
+ delete agent;
+ QCOMPARE(eng->agent(), (QScriptEngineAgent*)0);
+ eng->evaluate("(function(){ return 123; })()");
+ delete eng;
+}
+
+void tst_QScriptEngine::getSetAgent_differentEngine()
+{
+ QScriptEngine eng;
+ QScriptEngine eng2;
+ TestAgent *agent = new TestAgent(&eng);
+ QTest::ignoreMessage(QtWarningMsg, "QScriptEngine::setAgent(): cannot set agent belonging to different engine");
+ eng2.setAgent(agent);
+ QCOMPARE(eng2.agent(), (QScriptEngineAgent*)0);
+}
+
+void tst_QScriptEngine::reentrancy_stringHandles()
+{
+ QScriptEngine eng1;
+ QScriptEngine eng2;
+ QScriptString s1 = eng1.toStringHandle("foo");
+ QScriptString s2 = eng2.toStringHandle("foo");
+ QVERIFY(s1 != s2);
+}
+
+void tst_QScriptEngine::reentrancy_processEventsInterval()
+{
+ QScriptEngine eng1;
+ QScriptEngine eng2;
+ eng1.setProcessEventsInterval(123);
+ QCOMPARE(eng2.processEventsInterval(), -1);
+ eng2.setProcessEventsInterval(456);
+ QCOMPARE(eng1.processEventsInterval(), 123);
+}
+
+void tst_QScriptEngine::reentrancy_typeConversion()
+{
+ QScriptEngine eng1;
+ QScriptEngine eng2;
+ qScriptRegisterMetaType<Foo>(&eng1, fooToScriptValue, fooFromScriptValue);
+ Foo foo;
+ foo.x = 12;
+ foo.y = 34;
{
- QScriptEngine eng1;
- QScriptEngine eng2;
- QScriptString s1 = eng1.toStringHandle("foo");
- QScriptString s2 = eng2.toStringHandle("foo");
- QVERIFY(s1 != s2);
- }
- {
- QScriptEngine eng1;
- QScriptEngine eng2;
- eng1.setProcessEventsInterval(123);
- QCOMPARE(eng2.processEventsInterval(), -1);
- eng2.setProcessEventsInterval(456);
- QCOMPARE(eng1.processEventsInterval(), 123);
+ QScriptValue fooVal = qScriptValueFromValue(&eng1, foo);
+ QVERIFY(fooVal.isObject());
+ QVERIFY(!fooVal.isVariant());
+ QCOMPARE(fooVal.property("x").toInt32(), 12);
+ QCOMPARE(fooVal.property("y").toInt32(), 34);
+ fooVal.setProperty("x", 56);
+ fooVal.setProperty("y", 78);
+
+ Foo foo2 = qScriptValueToValue<Foo>(fooVal);
+ QCOMPARE(foo2.x, 56);
+ QCOMPARE(foo2.y, 78);
}
{
- QScriptEngine eng1;
- QScriptEngine eng2;
- qScriptRegisterMetaType<Foo>(&eng1, fooToScriptValue, fooFromScriptValue);
- Foo foo;
- foo.x = 12;
- foo.y = 34;
- {
- QScriptValue fooVal = qScriptValueFromValue(&eng1, foo);
- QVERIFY(fooVal.isObject());
- QVERIFY(!fooVal.isVariant());
- QCOMPARE(fooVal.property("x").toInt32(), 12);
- QCOMPARE(fooVal.property("y").toInt32(), 34);
- fooVal.setProperty("x", 56);
- fooVal.setProperty("y", 78);
-
- Foo foo2 = qScriptValueToValue<Foo>(fooVal);
- QCOMPARE(foo2.x, 56);
- QCOMPARE(foo2.y, 78);
- }
- {
- QScriptValue fooVal = qScriptValueFromValue(&eng2, foo);
- QVERIFY(fooVal.isVariant());
+ QScriptValue fooVal = qScriptValueFromValue(&eng2, foo);
+ QVERIFY(fooVal.isVariant());
- Foo foo2 = qScriptValueToValue<Foo>(fooVal);
- QCOMPARE(foo2.x, 12);
- QCOMPARE(foo2.y, 34);
- }
- QVERIFY(!eng1.defaultPrototype(qMetaTypeId<Foo>()).isValid());
- QVERIFY(!eng2.defaultPrototype(qMetaTypeId<Foo>()).isValid());
- QScriptValue proto1 = eng1.newObject();
- eng1.setDefaultPrototype(qMetaTypeId<Foo>(), proto1);
- QVERIFY(!eng2.defaultPrototype(qMetaTypeId<Foo>()).isValid());
- QScriptValue proto2 = eng2.newObject();
- eng2.setDefaultPrototype(qMetaTypeId<Foo>(), proto2);
- QVERIFY(eng2.defaultPrototype(qMetaTypeId<Foo>()).isValid());
- QVERIFY(eng1.defaultPrototype(qMetaTypeId<Foo>()).strictlyEquals(proto1));
- }
- {
- QScriptEngine eng1;
- QScriptEngine eng2;
- QVERIFY(!eng2.globalObject().property("a").isValid());
- eng1.evaluate("a = 10");
- QVERIFY(eng1.globalObject().property("a").isNumber());
- QVERIFY(!eng2.globalObject().property("a").isValid());
- eng2.evaluate("a = 20");
- QVERIFY(eng2.globalObject().property("a").isNumber());
- QCOMPARE(eng1.globalObject().property("a").toInt32(), 10);
+ Foo foo2 = qScriptValueToValue<Foo>(fooVal);
+ QCOMPARE(foo2.x, 12);
+ QCOMPARE(foo2.y, 34);
}
+ QVERIFY(!eng1.defaultPrototype(qMetaTypeId<Foo>()).isValid());
+ QVERIFY(!eng2.defaultPrototype(qMetaTypeId<Foo>()).isValid());
+ QScriptValue proto1 = eng1.newObject();
+ eng1.setDefaultPrototype(qMetaTypeId<Foo>(), proto1);
+ QVERIFY(!eng2.defaultPrototype(qMetaTypeId<Foo>()).isValid());
+ QScriptValue proto2 = eng2.newObject();
+ eng2.setDefaultPrototype(qMetaTypeId<Foo>(), proto2);
+ QVERIFY(eng2.defaultPrototype(qMetaTypeId<Foo>()).isValid());
+ QVERIFY(eng1.defaultPrototype(qMetaTypeId<Foo>()).strictlyEquals(proto1));
+}
+
+void tst_QScriptEngine::reentrancy_globalObjectProperties()
+{
+ QScriptEngine eng1;
+ QScriptEngine eng2;
+ QVERIFY(!eng2.globalObject().property("a").isValid());
+ eng1.evaluate("a = 10");
+ QVERIFY(eng1.globalObject().property("a").isNumber());
+ QVERIFY(!eng2.globalObject().property("a").isValid());
+ eng2.evaluate("a = 20");
+ QVERIFY(eng2.globalObject().property("a").isNumber());
+ QCOMPARE(eng1.globalObject().property("a").toInt32(), 10);
+}
+
+void tst_QScriptEngine::reentrancy_Array()
+{
// weird bug with JSC backend
{
QScriptEngine eng;
@@ -4540,79 +4722,82 @@ void tst_QScriptEngine::reentrancy()
QScriptEngine eng;
QCOMPARE(eng.evaluate("Array()").toString(), QString());
}
+}
+void tst_QScriptEngine::reentrancy_objectCreation()
+{
+ QScriptEngine eng1;
+ QScriptEngine eng2;
{
- QScriptEngine eng1;
- QScriptEngine eng2;
- {
- QScriptValue d1 = eng1.newDate(0);
- QScriptValue d2 = eng2.newDate(0);
- QCOMPARE(d1.toDateTime(), d2.toDateTime());
- QCOMPARE(d2.toDateTime(), d1.toDateTime());
- }
- {
- QScriptValue r1 = eng1.newRegExp("foo", "gim");
- QScriptValue r2 = eng2.newRegExp("foo", "gim");
- QCOMPARE(r1.toRegExp(), r2.toRegExp());
- QCOMPARE(r2.toRegExp(), r1.toRegExp());
- }
- {
- QScriptValue o1 = eng1.newQObject(this);
- QScriptValue o2 = eng2.newQObject(this);
- QCOMPARE(o1.toQObject(), o2.toQObject());
- QCOMPARE(o2.toQObject(), o1.toQObject());
- }
- {
- QScriptValue mo1 = eng1.newQMetaObject(&staticMetaObject);
- QScriptValue mo2 = eng2.newQMetaObject(&staticMetaObject);
- QCOMPARE(mo1.toQMetaObject(), mo2.toQMetaObject());
- QCOMPARE(mo2.toQMetaObject(), mo1.toQMetaObject());
- }
+ QScriptValue d1 = eng1.newDate(0);
+ QScriptValue d2 = eng2.newDate(0);
+ QCOMPARE(d1.toDateTime(), d2.toDateTime());
+ QCOMPARE(d2.toDateTime(), d1.toDateTime());
+ }
+ {
+ QScriptValue r1 = eng1.newRegExp("foo", "gim");
+ QScriptValue r2 = eng2.newRegExp("foo", "gim");
+ QCOMPARE(r1.toRegExp(), r2.toRegExp());
+ QCOMPARE(r2.toRegExp(), r1.toRegExp());
+ }
+ {
+ QScriptValue o1 = eng1.newQObject(this);
+ QScriptValue o2 = eng2.newQObject(this);
+ QCOMPARE(o1.toQObject(), o2.toQObject());
+ QCOMPARE(o2.toQObject(), o1.toQObject());
+ }
+ {
+ QScriptValue mo1 = eng1.newQMetaObject(&staticMetaObject);
+ QScriptValue mo2 = eng2.newQMetaObject(&staticMetaObject);
+ QCOMPARE(mo1.toQMetaObject(), mo2.toQMetaObject());
+ QCOMPARE(mo2.toQMetaObject(), mo1.toQMetaObject());
}
}
-void tst_QScriptEngine:: incDecNonObjectProperty()
+void tst_QScriptEngine::jsIncDecNonObjectProperty()
{
+ // This is testing ECMA-262 compliance, not C++ API.
+
QScriptEngine eng;
{
QScriptValue ret = eng.evaluate("var a; a.n++");
QVERIFY(ret.isError());
- QCOMPARE(ret.toString(), QString::fromLatin1("TypeError: Result of expression 'a' [undefined] is not an object."));
+ QVERIFY(ret.toString().contains(QString::fromLatin1("TypeError")));
}
{
QScriptValue ret = eng.evaluate("var a; a.n--");
QVERIFY(ret.isError());
- QCOMPARE(ret.toString(), QString::fromLatin1("TypeError: Result of expression 'a' [undefined] is not an object."));
+ QVERIFY(ret.toString().contains(QString::fromLatin1("TypeError")));
}
{
QScriptValue ret = eng.evaluate("var a = null; a.n++");
QVERIFY(ret.isError());
- QCOMPARE(ret.toString(), QString::fromLatin1("TypeError: Result of expression 'a' [null] is not an object."));
+ QVERIFY(ret.toString().contains(QString::fromLatin1("TypeError")));
}
{
QScriptValue ret = eng.evaluate("var a = null; a.n--");
QVERIFY(ret.isError());
- QCOMPARE(ret.toString(), QString::fromLatin1("TypeError: Result of expression 'a' [null] is not an object."));
+ QVERIFY(ret.toString().contains(QString::fromLatin1("TypeError")));
}
{
QScriptValue ret = eng.evaluate("var a; ++a.n");
QVERIFY(ret.isError());
- QCOMPARE(ret.toString(), QString::fromLatin1("TypeError: Result of expression 'a' [null] is not an object."));
+ QVERIFY(ret.toString().contains(QString::fromLatin1("TypeError")));
}
{
QScriptValue ret = eng.evaluate("var a; --a.n");
QVERIFY(ret.isError());
- QCOMPARE(ret.toString(), QString::fromLatin1("TypeError: Result of expression 'a' [null] is not an object."));
+ QVERIFY(ret.toString().contains(QString::fromLatin1("TypeError")));
}
{
QScriptValue ret = eng.evaluate("var a; a.n += 1");
QVERIFY(ret.isError());
- QCOMPARE(ret.toString(), QString::fromLatin1("TypeError: Result of expression 'a' [null] is not an object."));
+ QVERIFY(ret.toString().contains(QString::fromLatin1("TypeError")));
}
{
QScriptValue ret = eng.evaluate("var a; a.n -= 1");
QVERIFY(ret.isError());
- QCOMPARE(ret.toString(), QString::fromLatin1("TypeError: Result of expression 'a' [null] is not an object."));
+ QVERIFY(ret.toString().contains(QString::fromLatin1("TypeError")));
}
{
QScriptValue ret = eng.evaluate("var a = 'ciao'; a.length++");
@@ -5436,6 +5621,7 @@ void tst_QScriptEngine::collectGarbageAfterConnect()
.isUndefined());
QVERIFY(widget != 0);
engine.evaluate("widget = null;");
+ // The connection should not keep the widget alive.
collectGarbage_helper(engine);
QVERIFY(widget == 0);
}
@@ -5599,6 +5785,17 @@ void tst_QScriptEngine::reentrency()
void tst_QScriptEngine::newFixedStaticScopeObject()
{
+ // "Static scope objects" is an optimization we do for QML.
+ // It enables the creation of JS objects that can guarantee to the
+ // compiler that no properties will be added or removed. This enables
+ // the compiler to generate a very simple (fast) property access, as
+ // opposed to a full virtual lookup. Due to the inherent use of scope
+ // chains in QML, this can make a huge difference (10x improvement for
+ // benchmark in QTBUG-8576).
+ // Ideally we would not need a special object type for this, and the
+ // VM would dynamically optimize it to be fast...
+ // See also QScriptEngine benchmark.
+
QScriptEngine eng;
static const int propertyCount = 4;
QString names[] = { "foo", "bar", "baz", "Math" };
@@ -5739,6 +5936,11 @@ void tst_QScriptEngine::newFixedStaticScopeObject()
void tst_QScriptEngine::newGrowingStaticScopeObject()
{
+ // The main use case for a growing static scope object is to set it as
+ // the activation object of a QScriptContext, so that all JS variable
+ // declarations end up in that object. It needs to be "growable" since
+ // we don't know in advance how many variables a script will declare.
+
QScriptEngine eng;
QScriptValue scope = QScriptDeclarativeClass::newStaticScopeObject(&eng);
@@ -5826,10 +6028,10 @@ void tst_QScriptEngine::newGrowingStaticScopeObject()
{
QScriptValue fun = eng.evaluate("(function() { return futureProperty; })");
QVERIFY(fun.isFunction());
- QCOMPARE(fun.call().toString(), QString::fromLatin1("ReferenceError: Can't find variable: futureProperty"));
+ QVERIFY(fun.call().toString().contains(QString::fromLatin1("ReferenceError")));
scope.setProperty("futureProperty", "added after the function was compiled");
// If scope were dynamic, this would return the new property.
- QCOMPARE(fun.call().toString(), QString::fromLatin1("ReferenceError: Can't find variable: futureProperty"));
+ QVERIFY(fun.call().toString().contains(QString::fromLatin1("ReferenceError")));
}
eng.popContext();
diff --git a/tests/auto/qscriptextqobject/tst_qscriptextqobject.cpp b/tests/auto/qscriptextqobject/tst_qscriptextqobject.cpp
index cb29586..1607bed 100644
--- a/tests/auto/qscriptextqobject/tst_qscriptextqobject.cpp
+++ b/tests/auto/qscriptextqobject/tst_qscriptextqobject.cpp
@@ -549,10 +549,19 @@ private slots:
void getSetDynamicProperty_doNotHideJSProperty();
void getSetChildren();
void callQtInvokable();
+ void callQtInvokable2();
+ void callQtInvokable3();
+ void callQtInvokable4();
+ void callQtInvokable5();
+ void callQtInvokable6();
+ void callQtInvokable7();
void connectAndDisconnect();
+ void connectAndDisconnect_emitFromJS();
+ void connectAndDisconnect_senderWrapperCollected();
void connectAndDisconnectWithBadArgs();
void connectAndDisconnect_senderDeleted();
void cppConnectAndDisconnect();
+ void cppConnectAndDisconnect2();
void classEnums();
void classConstructor();
void overrideInvokable();
@@ -1270,7 +1279,10 @@ void tst_QScriptExtQObject::callQtInvokable()
QCOMPARE(m_myObject->qtFunctionActuals().size(), 2);
QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 123);
QCOMPARE(m_myObject->qtFunctionActuals().at(1).toInt(), 456);
+}
+void tst_QScriptExtQObject::callQtInvokable2()
+{
m_myObject->resetQtFunctionInvoked();
QVERIFY(m_engine->evaluate("myObject.myInvokableWithVoidStarArg(null)").isUndefined());
QCOMPARE(m_myObject->qtFunctionInvoked(), 44);
@@ -1359,7 +1371,10 @@ void tst_QScriptExtQObject::callQtInvokable()
QCOMPARE(ret.isArray(), true);
QCOMPARE(m_myObject->qtFunctionInvoked(), 11);
}
+}
+void tst_QScriptExtQObject::callQtInvokable3()
+{
{
QScriptValue ret = m_engine->evaluate("myObject.myInvokableWithVectorOfIntArg(myObject.myInvokableReturningVectorOfInt())");
QCOMPARE(ret.isUndefined(), true);
@@ -1485,7 +1500,10 @@ void tst_QScriptExtQObject::callQtInvokable()
QCOMPARE(ret.property("0").strictlyEquals(QScriptValue(m_engine, 1)), true);
QCOMPARE(ret.property("1").strictlyEquals(QScriptValue(m_engine, 5)), true);
}
+}
+void tst_QScriptExtQObject::callQtInvokable4()
+{
m_myObject->resetQtFunctionInvoked();
{
QScriptValue ret = m_engine->evaluate("myObject.myInvokableWithQObjectStarArg(myObject)");
@@ -1571,7 +1589,10 @@ void tst_QScriptExtQObject::callQtInvokable()
QCOMPARE(v.userType(), int(QMetaType::ULongLong));
QCOMPARE(qvariant_cast<qulonglong>(v), qulonglong(123));
}
+}
+void tst_QScriptExtQObject::callQtInvokable5()
+{
m_myObject->resetQtFunctionInvoked();
{
QScriptValue fun = m_engine->evaluate("myObject.myInvokableWithQBrushArg");
@@ -1659,7 +1680,10 @@ void tst_QScriptExtQObject::callQtInvokable()
QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
QCOMPARE(qvariant_cast<QObject*>(m_myObject->qtFunctionActuals().at(0)), (QObject*)m_myObject);
}
+}
+void tst_QScriptExtQObject::callQtInvokable6()
+{
// QScriptValue arguments should be passed on without conversion
m_myObject->resetQtFunctionInvoked();
{
@@ -1723,18 +1747,21 @@ void tst_QScriptExtQObject::callQtInvokable()
QCOMPARE(m_myObject->qtFunctionInvoked(), 55);
}
}
+}
+void tst_QScriptExtQObject::callQtInvokable7()
+{
// qscript_call()
{
m_myObject->resetQtFunctionInvoked();
QScriptValue ret = m_engine->evaluate("new myObject(123)");
QVERIFY(ret.isError());
- QCOMPARE(ret.toString(), QString::fromLatin1("TypeError: Result of expression 'myObject' [MyQObject(name = \"\")] is not a constructor."));
+ QVERIFY(ret.toString().contains(QString::fromLatin1("TypeError")));
}
{
m_myObject->resetQtFunctionInvoked();
QScriptValue ret = m_engine->evaluate("myObject(123)");
- QCOMPARE(ret.toString(), QString::fromLatin1("TypeError: Result of expression 'myObject' [MyQObject(name = \"\")] is not a function."));
+ QVERIFY(ret.toString().contains(QString::fromLatin1("TypeError")));
}
// task 233624
@@ -1971,9 +1998,10 @@ void tst_QScriptExtQObject::connectAndDisconnect()
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
-
+void tst_QScriptExtQObject::connectAndDisconnect_emitFromJS()
+{
// no arguments
QVERIFY(m_engine->evaluate("myObject.mySignal.connect(myObject.mySlot)").isUndefined());
m_myObject->resetQtFunctionInvoked();
@@ -2022,7 +2050,10 @@ void tst_QScriptExtQObject::connectAndDisconnect()
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());
+}
+void tst_QScriptExtQObject::connectAndDisconnect_senderWrapperCollected()
+{
// when the wrapper dies, the connection stays alive
QVERIFY(m_engine->evaluate("myObject.mySignal.connect(myObject.mySlot)").isUndefined());
m_myObject->resetQtFunctionInvoked();
@@ -2210,7 +2241,14 @@ void tst_QScriptExtQObject::cppConnectAndDisconnect()
QVERIFY(!qScriptDisconnect(&edit2, SIGNAL(textChanged(const QString &)), receiver, fun));
}
}
+}
+void tst_QScriptExtQObject::cppConnectAndDisconnect2()
+{
+ QScriptEngine eng;
+ QLineEdit edit;
+ QLineEdit edit2;
+ QScriptValue fun = eng.evaluate("function fun(text) { signalObject = this; signalArg = text; }; fun");
// make sure we don't crash when engine is deleted
{
QScriptEngine *eng2 = new QScriptEngine;
diff --git a/tests/auto/qstatemachine/tst_qstatemachine.cpp b/tests/auto/qstatemachine/tst_qstatemachine.cpp
index a03657f..231cab0 100644
--- a/tests/auto/qstatemachine/tst_qstatemachine.cpp
+++ b/tests/auto/qstatemachine/tst_qstatemachine.cpp
@@ -211,6 +211,9 @@ private slots:
void postEventFromOtherThread();
void eventFilterForApplication();
void eventClassesExported();
+ void stopInTransitionToFinalState();
+ void stopInEventTest_data();
+ void stopInEventTest();
};
tst_QStateMachine::tst_QStateMachine()
@@ -4374,5 +4377,70 @@ void tst_QStateMachine::eventClassesExported()
QStateMachine::SignalEvent *signalEvent = new QStateMachine::SignalEvent(0, 0, QList<QVariant>());
}
+void tst_QStateMachine::stopInTransitionToFinalState()
+{
+ QStateMachine machine;
+ QState *s1 = new QState(&machine);
+ QFinalState *s2 = new QFinalState(&machine);
+ QAbstractTransition *t1 = s1->addTransition(s2);
+ machine.setInitialState(s1);
+
+ QObject::connect(t1, SIGNAL(triggered()), &machine, SLOT(stop()));
+ QSignalSpy stoppedSpy(&machine, SIGNAL(stopped()));
+ QSignalSpy finishedSpy(&machine, SIGNAL(finished()));
+ QSignalSpy s2EnteredSpy(s2, SIGNAL(entered()));
+ machine.start();
+
+ // Stopping should take precedence over finished.
+ QTRY_COMPARE(stoppedSpy.count(), 1);
+ QCOMPARE(finishedSpy.count(), 0);
+ QCOMPARE(s2EnteredSpy.count(), 1);
+ QCOMPARE(machine.configuration().size(), 1);
+ QVERIFY(machine.configuration().contains(s2));
+}
+
+class StopInEventTestTransition : public QAbstractTransition
+{
+public:
+ bool eventTest(QEvent *e)
+ {
+ if (e->type() == QEvent::User)
+ machine()->stop();
+ return false;
+ }
+ void onTransition(QEvent *)
+ { }
+};
+
+void tst_QStateMachine::stopInEventTest_data()
+{
+ QTest::addColumn<int>("eventPriority");
+ QTest::newRow("NormalPriority") << int(QStateMachine::NormalPriority);
+ QTest::newRow("HighPriority") << int(QStateMachine::HighPriority);
+}
+
+void tst_QStateMachine::stopInEventTest()
+{
+ QFETCH(int, eventPriority);
+
+ QStateMachine machine;
+ QState *s1 = new QState(&machine);
+ s1->addTransition(new StopInEventTestTransition());
+ machine.setInitialState(s1);
+
+ QSignalSpy startedSpy(&machine, SIGNAL(started()));
+ machine.start();
+ QTRY_COMPARE(startedSpy.count(), 1);
+
+ QSignalSpy stoppedSpy(&machine, SIGNAL(stopped()));
+ QSignalSpy finishedSpy(&machine, SIGNAL(finished()));
+ machine.postEvent(new QEvent(QEvent::User), QStateMachine::EventPriority(eventPriority));
+
+ QTRY_COMPARE(stoppedSpy.count(), 1);
+ QCOMPARE(finishedSpy.count(), 0);
+ QCOMPARE(machine.configuration().size(), 1);
+ QVERIFY(machine.configuration().contains(s1));
+}
+
QTEST_MAIN(tst_QStateMachine)
#include "tst_qstatemachine.moc"
diff --git a/tests/auto/qstring/tst_qstring.cpp b/tests/auto/qstring/tst_qstring.cpp
index 969521f..abc8d9a 100644
--- a/tests/auto/qstring/tst_qstring.cpp
+++ b/tests/auto/qstring/tst_qstring.cpp
@@ -4319,6 +4319,9 @@ void tst_QString::localeAwareCompare_data()
void tst_QString::localeAwareCompare()
{
+#ifdef Q_OS_SYMBIAN
+ QSKIP("QTBUG-16921: There is no way to set up the system locale, so this test is not reliable in Symbian.");
+#else
#ifdef Q_OS_WIN
# ifndef Q_OS_WINCE
QSKIP("On others than Win CE, we cannot set the system or user locale.", SkipAll);
@@ -4416,6 +4419,7 @@ void tst_QString::localeAwareCompare()
if (!locale.isEmpty())
setlocale(LC_ALL, "");
#endif
+#endif // Q_OS_SYMBIAN
}
void tst_QString::split_data()
diff --git a/tests/auto/qtextcursor/tst_qtextcursor.cpp b/tests/auto/qtextcursor/tst_qtextcursor.cpp
index ee2baef..4d52dd7 100644
--- a/tests/auto/qtextcursor/tst_qtextcursor.cpp
+++ b/tests/auto/qtextcursor/tst_qtextcursor.cpp
@@ -134,6 +134,7 @@ private slots:
void endOfLine();
void editBlocksDuringRemove();
+ void selectAllDuringRemove();
void update_data();
void update();
@@ -1388,6 +1389,17 @@ public slots:
++recordingCount;
}
+ void selectAllContents()
+ {
+ // Only test the first time
+ if (!recordingCount) {
+ recordingCount++;
+ cursor->select(QTextCursor::Document);
+ lastRecordedPosition = cursor->position();
+ lastRecordedAnchor = cursor->anchor();
+ }
+ }
+
private:
QTextCursor *cursor;
};
@@ -1411,6 +1423,22 @@ void tst_QTextCursor::editBlocksDuringRemove()
QVERIFY(doc->toPlainText().isEmpty());
}
+void tst_QTextCursor::selectAllDuringRemove()
+{
+ CursorListener listener(&cursor);
+
+ cursor.insertText("Hello World");
+ cursor.movePosition(QTextCursor::End);
+
+ connect(doc, SIGNAL(contentsChanged()), &listener, SLOT(selectAllContents()));
+ listener.recordingCount = 0;
+ QTextCursor localCursor = cursor;
+ localCursor.deletePreviousChar();
+
+ QCOMPARE(listener.lastRecordedPosition, 10);
+ QCOMPARE(listener.lastRecordedAnchor, 0);
+}
+
void tst_QTextCursor::update_data()
{
QTest::addColumn<QString>("text");
diff --git a/tests/auto/qtipc/qsharedmemory/tst_qsharedmemory.cpp b/tests/auto/qtipc/qsharedmemory/tst_qsharedmemory.cpp
index be6049b..6aa0995 100644
--- a/tests/auto/qtipc/qsharedmemory/tst_qsharedmemory.cpp
+++ b/tests/auto/qtipc/qsharedmemory/tst_qsharedmemory.cpp
@@ -348,6 +348,8 @@ void tst_QSharedMemory::attach()
QVERIFY(sm.detach());
// Make sure detach doesn't screw up something and we can't re-attach.
QVERIFY(sm.attach());
+ QVERIFY(sm.data() != 0);
+ QVERIFY(sm.size() != 0);
QVERIFY(sm.detach());
QCOMPARE(sm.size(), 0);
QVERIFY(sm.data() == 0);
@@ -374,7 +376,8 @@ void tst_QSharedMemory::lock()
QVERIFY(shm.lock());
QTest::ignoreMessage(QtWarningMsg, "QSharedMemory::lock: already locked");
QVERIFY(shm.lock());
- // don't lock forever
+ // we didn't unlock(), so ignore the warning from auto-detach in destructor
+ QTest::ignoreMessage(QtWarningMsg, "QSharedMemory::lock: already locked");
}
/*!
diff --git a/tests/auto/qwidget/tst_qwidget.cpp b/tests/auto/qwidget/tst_qwidget.cpp
index 95c4ea6..35014c9 100644
--- a/tests/auto/qwidget/tst_qwidget.cpp
+++ b/tests/auto/qwidget/tst_qwidget.cpp
@@ -2745,9 +2745,6 @@ void tst_QWidget::lostUpdatesOnHide()
void tst_QWidget::raise()
{
-#ifdef QT_MAC_USE_COCOA
- QSKIP("Cocoa has no Z-Order for views, we hack it, but it results in paint events.", SkipAll);
-#endif
QTest::qWait(10);
QWidget *parent = new QWidget(0);
QList<UpdateWidget *> allChildren;
@@ -2772,6 +2769,12 @@ void tst_QWidget::raise()
QTest::qWaitForWindowShown(parent);
QTest::qWait(10);
+#ifdef QT_MAC_USE_COCOA
+ if (child1->internalWinId()) {
+ QSKIP("Cocoa has no Z-Order for views, we hack it, but it results in paint events.", SkipAll);
+ }
+#endif
+
QList<QObject *> list1;
list1 << child1 << child2 << child3 << child4;
QVERIFY(parent->children() == list1);
@@ -2796,6 +2799,9 @@ void tst_QWidget::raise()
foreach (UpdateWidget *child, allChildren) {
int expectedPaintEvents = child == child2 ? 1 : 0;
int expectedZOrderChangeEvents = child == child2 ? 1 : 0;
+#ifdef QT_MAC_USE_COCOA
+ QSKIP("Not yet sure why this fails.", SkipSingle);
+#endif
QTRY_COMPARE(child->numPaintEvents, expectedPaintEvents);
QCOMPARE(child->numZOrderChangeEvents, expectedZOrderChangeEvents);
child->reset();
@@ -3046,9 +3052,6 @@ protected:
void tst_QWidget::testContentsPropagation()
{
-#ifdef Q_WS_MAC
- QSKIP("Pixmap is not antialiased whereas widget is.", SkipAll);
-#endif
ContentsPropagationWidget widget;
#ifdef Q_WS_QWS
widget.resize(500,500);
@@ -3852,29 +3855,6 @@ void tst_QWidget::testDeletionInEventHandlers()
#ifdef Q_WS_MAC
-bool testAndRelease(const HIViewRef view)
-{
-// qDebug() << CFGetRetainCount(view);
- if (CFGetRetainCount(view) != 2)
- return false;
- CFRelease(view);
- CFRelease(view);
- return true;
-}
-
-typedef QPair<QWidget *, HIViewRef> WidgetViewPair;
-
-WidgetViewPair createAndRetain(QWidget * const parent = 0)
-{
- QWidget * const widget = new QWidget(parent);
- const HIViewRef view = (HIViewRef)widget->winId();
- // Retain twice so we can safely call CFGetRetaintCount even if the retain count
- // is off by one because of a double release.
- CFRetain(view);
- CFRetain(view);
- return qMakePair(widget, view);
-}
-
/*
Test that retaining and releasing the HIView returned by QWidget::winId()
works even if the widget itself is deleted.
@@ -4756,9 +4736,6 @@ void tst_QWidget::update()
QRegion expectedVisible = QRegion(w.rect())
- child.visibleRegion().translated(childOffset);
QCOMPARE(w.visibleRegion(), expectedVisible);
-#ifdef QT_MAC_USE_COCOA
- QEXPECT_FAIL(0, "Cocoa compositor paints the content view", Continue);
-#endif
QCOMPARE(w.paintedRegion, expectedVisible);
#ifdef QT_MAC_USE_COCOA
QEXPECT_FAIL(0, "Cocoa compositor says to paint this.", Continue);
@@ -4808,14 +4785,8 @@ void tst_QWidget::update()
& sibling.visibleRegion().translated(siblingOffset));
QCOMPARE(w.numPaintEvents, 1);
-#ifdef QT_MAC_USE_COCOA
- QEXPECT_FAIL(0, "Cocoa compositor paints the content view", Continue);
-#endif
QCOMPARE(w.paintedRegion,
w.visibleRegion() & sibling.visibleRegion().translated(siblingOffset));
-#ifdef QT_MAC_USE_COCOA
- QEXPECT_FAIL(0, "Cocoa compositor paints the content view", Continue);
-#endif
QCOMPARE(w.paintedRegion,
(w.visibleRegion() - child.visibleRegion().translated(childOffset))
& sibling.visibleRegion().translated(siblingOffset));
@@ -4838,7 +4809,8 @@ void tst_QWidget::update()
QCOMPARE(sibling.paintedRegion, sibling.visibleRegion());
#ifdef QT_MAC_USE_COCOA
- QEXPECT_FAIL(0, "Cocoa compositor paints child and sibling", Continue);
+ if (child.internalWinId()) // child is native
+ QEXPECT_FAIL(0, "Cocoa compositor paints child and sibling", Continue);
#endif
QCOMPARE(child.numPaintEvents, 0);
QCOMPARE(child.visibleRegion(),
@@ -5469,6 +5441,7 @@ public:
rect.width(), rect.height()); \
QCOMPARE(pixmap.size(), rect.size()); \
QPixmap expectedPixmap(pixmap); /* ensure equal formats */ \
+ expectedPixmap.detach(); \
expectedPixmap.fill(color); \
QImage image = pixmap.toImage(); \
uint alphaCorrection = image.format() == QImage::Format_RGB32 ? 0xff000000 : 0; \
@@ -5515,9 +5488,6 @@ void tst_QWidget::moveChild()
QTest::qWait(30);
const QPoint tlwOffset = parent.geometry().topLeft();
-#ifdef QT_MAC_USE_COCOA
- QEXPECT_FAIL(0, "Cocoa compositor paints the entire content view, even when opaque", Continue);
-#endif
QTRY_COMPARE(parent.r, QRegion(parent.rect()) - child.geometry());
QTRY_COMPARE(child.r, QRegion(child.rect()));
VERIFY_COLOR(child.geometry().translated(tlwOffset),
@@ -8916,6 +8886,7 @@ void tst_QWidget::setClearAndResizeMask()
UpdateWidget child(&topLevel);
child.setAutoFillBackground(true); // NB! Opaque child.
+ child.setPalette(Qt::red);
child.resize(100, 100);
child.show();
QTest::qWait(10);
@@ -8931,10 +8902,11 @@ void tst_QWidget::setClearAndResizeMask()
// and ensure that the child widget doesn't get any update.
#ifdef Q_WS_MAC
// Mac always issues a full update when calling setMask, and we cannot force it to not do so.
- QCOMPARE(child.numPaintEvents, 1);
-#else
- QCOMPARE(child.numPaintEvents, 0);
+ if (child.internalWinId())
+ QCOMPARE(child.numPaintEvents, 1);
+ else
#endif
+ QCOMPARE(child.numPaintEvents, 0);
// and the parent widget gets an update for the newly exposed area.
QTRY_COMPARE(topLevel.numPaintEvents, 1);
QRegion expectedParentExpose(child.rect());
@@ -8951,10 +8923,11 @@ void tst_QWidget::setClearAndResizeMask()
// and ensure that that the child widget gets an update for the area outside the old mask.
QTRY_COMPARE(child.numPaintEvents, 1);
outsideOldMask = child.rect();
-#ifndef Q_WS_MAC
+#ifdef Q_WS_MAC
// Mac always issues a full update when calling setMask, and we cannot force it to not do so.
- outsideOldMask -= childMask;
+ if (!child.internalWinId())
#endif
+ outsideOldMask -= childMask;
QCOMPARE(child.paintedRegion, outsideOldMask);
// and the parent widget doesn't get any update.
QCOMPARE(topLevel.numPaintEvents, 0);
@@ -8967,11 +8940,12 @@ void tst_QWidget::setClearAndResizeMask()
QTest::qWait(100);
#ifdef Q_WS_MAC
// Mac always issues a full update when calling setMask, and we cannot force it to not do so.
- QTRY_COMPARE(child.numPaintEvents, 1);
-#else
+ if (child.internalWinId())
+ QTRY_COMPARE(child.numPaintEvents, 1);
+ else
+#endif
// and ensure that we don't get any updates at all.
QTRY_COMPARE(child.numPaintEvents, 0);
-#endif
QCOMPARE(topLevel.numPaintEvents, 0);
// ...and the same applies when clearing the mask.
@@ -8979,10 +8953,11 @@ void tst_QWidget::setClearAndResizeMask()
QTest::qWait(100);
#ifdef Q_WS_MAC
// Mac always issues a full update when calling setMask, and we cannot force it to not do so.
- QTRY_VERIFY(child.numPaintEvents > 0);
-#else
- QCOMPARE(child.numPaintEvents, 0);
+ if (child.internalWinId())
+ QTRY_VERIFY(child.numPaintEvents > 0);
+ else
#endif
+ QCOMPARE(child.numPaintEvents, 0);
QCOMPARE(topLevel.numPaintEvents, 0);
QWidget resizeParent;
@@ -9008,10 +8983,11 @@ void tst_QWidget::setClearAndResizeMask()
QTest::qWait(200);
#ifdef Q_WS_MAC
// Mac always issues a full update when calling setMask, and we cannot force it to not do so.
- QTRY_COMPARE(resizeChild.paintedRegion, resizeChild.mask());
-#else
- QTRY_COMPARE(resizeChild.paintedRegion, QRegion());
+ if (child.internalWinId())
+ QTRY_COMPARE(resizeChild.paintedRegion, resizeChild.mask());
+ else
#endif
+ QTRY_COMPARE(resizeChild.paintedRegion, QRegion());
resizeChild.paintedRegion = QRegion();
const QRegion oldMask = resizeChild.mask();
@@ -9019,10 +8995,11 @@ void tst_QWidget::setClearAndResizeMask()
QTest::qWait(100);
#ifdef Q_WS_MAC
// Mac always issues a full update when calling setMask, and we cannot force it to not do so.
- QTRY_COMPARE(resizeChild.paintedRegion, resizeChild.mask());
-#else
- QTRY_COMPARE(resizeChild.paintedRegion, resizeChild.mask() - oldMask);
+ if (child.internalWinId())
+ QTRY_COMPARE(resizeChild.paintedRegion, resizeChild.mask());
+ else
#endif
+ QTRY_COMPARE(resizeChild.paintedRegion, resizeChild.mask() - oldMask);
}
void tst_QWidget::maskedUpdate()
diff --git a/tests/auto/qwidget/tst_qwidget_mac_helpers.h b/tests/auto/qwidget/tst_qwidget_mac_helpers.h
index 029d8cd..d4f16b9 100644
--- a/tests/auto/qwidget/tst_qwidget_mac_helpers.h
+++ b/tests/auto/qwidget/tst_qwidget_mac_helpers.h
@@ -39,9 +39,20 @@
**
****************************************************************************/
#include <QtCore/QString>
-class QWidget;
+#include <QtCore/QPair>
+#include <QtGui/QWidget>
#pragma once // Yeah, it's deprecated in general, but it's standard practive for Mac OS X.
QString nativeWindowTitle(QWidget *widget, Qt::WindowState state);
bool nativeWindowModified(QWidget *widget);
+
+#ifndef QT_MAC_USE_COCOA
+typedef QPair<QWidget *, HIViewRef> WidgetViewPair;
+bool testAndRelease(const HIViewRef view);
+WidgetViewPair createAndRetain(QWidget * const parent = 0);
+#else
+typedef QPair<QWidget *, WId> WidgetViewPair;
+bool testAndRelease(const WId);
+WidgetViewPair createAndRetain(QWidget * const parent = 0);
+#endif
diff --git a/tests/auto/qwidget/tst_qwidget_mac_helpers.mm b/tests/auto/qwidget/tst_qwidget_mac_helpers.mm
index ca34b17..fce0b46 100644
--- a/tests/auto/qwidget/tst_qwidget_mac_helpers.mm
+++ b/tests/auto/qwidget/tst_qwidget_mac_helpers.mm
@@ -72,3 +72,47 @@ bool nativeWindowModified(QWidget *widget)
return [qt_mac_window_for(widget) isDocumentEdited];
#endif
}
+
+#ifndef QT_MAC_USE_COCOA
+bool testAndRelease(const HIViewRef view)
+{
+// qDebug() << CFGetRetainCount(view);
+ if (CFGetRetainCount(view) != 2)
+ return false;
+ CFRelease(view);
+ CFRelease(view);
+ return true;
+}
+
+WidgetViewPair createAndRetain(QWidget * const parent)
+{
+ QWidget * const widget = new QWidget(parent);
+ const HIViewRef view = (HIViewRef)widget->winId();
+ // Retain twice so we can safely call CFGetRetaintCount even if the retain count
+ // is off by one because of a double release.
+ CFRetain(view);
+ CFRetain(view);
+ return qMakePair(widget, view);
+}
+#else
+bool testAndRelease(const WId view)
+{
+ if ([id(view) retainCount] != 2)
+ return false;
+ [id(view) release];
+ [id(view) release];
+ return true;
+}
+
+WidgetViewPair createAndRetain(QWidget * const parent)
+{
+ QWidget * const widget = new QWidget(parent);
+ const WId view = widget->winId();
+ // Retain twice so we can safely call retainCount even if the retain count
+ // is off by one because of a double release.
+ [id(view) retain];
+ [id(view) retain];
+ return qMakePair(widget, view);
+}
+#endif
+