aboutsummaryrefslogtreecommitdiffstats
path: root/tests/auto/qml
diff options
context:
space:
mode:
Diffstat (limited to 'tests/auto/qml')
-rw-r--r--tests/auto/qml/debugger/qqmldebugjs/tst_qqmldebugjs.cpp36
-rw-r--r--tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp74
-rw-r--r--tests/auto/qml/debugger/shared/qqmlenginedebugclient.cpp6
-rw-r--r--tests/auto/qml/debugger/shared/qqmlenginedebugclient.h2
-rw-r--r--tests/auto/qml/qjsengine/idtranslatable-unicode.js5
-rw-r--r--tests/auto/qml/qjsengine/idtranslatable.js5
-rw-r--r--tests/auto/qml/qjsengine/qjsengine.pro1
-rw-r--r--tests/auto/qml/qjsengine/qjsengine.qrc8
-rw-r--r--tests/auto/qml/qjsengine/translatable-unicode.js9
-rw-r--r--tests/auto/qml/qjsengine/translatable.js12
-rw-r--r--tests/auto/qml/qjsengine/translatable2.js9
-rw-r--r--tests/auto/qml/qjsengine/translations/idtranslatable-unicode.qmbin0 -> 209 bytes
-rw-r--r--tests/auto/qml/qjsengine/translations/idtranslatable-unicode.ts26
-rw-r--r--tests/auto/qml/qjsengine/translations/idtranslatable_la.qmbin0 -> 342 bytes
-rw-r--r--tests/auto/qml/qjsengine/translations/idtranslatable_la.ts30
-rw-r--r--tests/auto/qml/qjsengine/translations/translatable-unicode.qmbin0 -> 322 bytes
-rw-r--r--tests/auto/qml/qjsengine/translations/translatable-unicode.ts37
-rw-r--r--tests/auto/qml/qjsengine/translations/translatable_la.qmbin0 -> 975 bytes
-rw-r--r--tests/auto/qml/qjsengine/translations/translatable_la.ts88
-rw-r--r--tests/auto/qml/qjsengine/tst_qjsengine.cpp486
-rw-r--r--tests/auto/qml/qqmlapplicationengine/tst_qqmlapplicationengine.cpp3
-rw-r--r--tests/auto/qml/qqmlchangeset/tst_qqmlchangeset.cpp36
-rw-r--r--tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp8
-rw-r--r--tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp2
-rw-r--r--tests/auto/qml/qqmlecmascript/data/assignSequenceTypes.1.qml2
-rw-r--r--tests/auto/qml/qqmlecmascript/data/assignSequenceTypes.3.qml2
-rw-r--r--tests/auto/qml/qqmlecmascript/data/assignSequenceTypes.4.qml2
-rw-r--r--tests/auto/qml/qqmlecmascript/data/assignSequenceTypes.6.qml2
-rw-r--r--tests/auto/qml/qqmlecmascript/data/extendedObjectPropertyLookup3.qml13
-rw-r--r--tests/auto/qml/qqmlecmascript/data/uncreatableExtendedObjectFailureCheck.qml8
-rw-r--r--tests/auto/qml/qqmlecmascript/testtypes.cpp41
-rw-r--r--tests/auto/qml/qqmlecmascript/testtypes.h2
-rw-r--r--tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp81
-rw-r--r--tests/auto/qml/qqmlengine/tst_qqmlengine.cpp2
-rw-r--r--tests/auto/qml/qqmllanguage/data/customExtendedParserProperties.qml12
-rw-r--r--tests/auto/qml/qqmllanguage/testtypes.cpp83
-rw-r--r--tests/auto/qml/qqmllanguage/testtypes.h39
-rw-r--r--tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp37
-rw-r--r--tests/auto/qml/qqmllistmodel/tst_qqmllistmodel.cpp4
-rw-r--r--tests/auto/qml/qqmlmoduleplugin/tst_qqmlmoduleplugin.cpp8
-rw-r--r--tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp1
-rw-r--r--tests/auto/qml/qqmlpropertymap/tst_qqmlpropertymap.cpp2
-rw-r--r--tests/auto/qml/qqmlxmlhttprequest/tst_qqmlxmlhttprequest.cpp83
-rw-r--r--tests/auto/qml/qv4debugger/tst_qv4debugger.cpp28
-rw-r--r--tests/auto/qml/v4misc/tst_v4misc.cpp2
45 files changed, 1151 insertions, 186 deletions
diff --git a/tests/auto/qml/debugger/qqmldebugjs/tst_qqmldebugjs.cpp b/tests/auto/qml/debugger/qqmldebugjs/tst_qqmldebugjs.cpp
index fef020704f..8763c4fa55 100644
--- a/tests/auto/qml/debugger/qqmldebugjs/tst_qqmldebugjs.cpp
+++ b/tests/auto/qml/debugger/qqmldebugjs/tst_qqmldebugjs.cpp
@@ -187,7 +187,7 @@ private slots:
void setBreakpointInScriptOnComment();
void setBreakpointInScriptOnEmptyLine();
void setBreakpointInScriptOnOptimizedBinding();
-// void setBreakpointInScriptWithCondition(); // Not supported yet.
+ void setBreakpointInScriptWithCondition();
void setBreakpointInScriptThatQuits();
//void setBreakpointInFunction(); //NOT SUPPORTED
// void setBreakpointOnEvent();
@@ -1082,13 +1082,8 @@ void tst_QQmlDebugJS::setBreakpointInScriptOnOptimizedBinding()
QCOMPARE(QFileInfo(body.value("script").toMap().value("name").toString()).fileName(), QLatin1String(BREAKPOINTRELOCATION_QMLFILE));
}
-#if 0
void tst_QQmlDebugJS::setBreakpointInScriptWithCondition()
{
- QFAIL("conditional breakpoints are not yet supported");
-
- //void setBreakpoint(QString type, QString target, int line = -1, int column = -1, bool enabled = false, QString condition = QString(), int ignoreCount = -1)
-
int out = 10;
int sourceLine = 50;
QVERIFY(init(CONDITION_QMLFILE));
@@ -1102,23 +1097,26 @@ void tst_QQmlDebugJS::setBreakpointInScriptWithCondition()
QString jsonString = client->response;
QVariantMap value = client->parser.call(QJSValueList() << QJSValue(jsonString)).toVariant().toMap();
- QVariantMap body = value.value("body").toMap();
-
- int frameIndex = body.value("index").toInt();
-
- //Verify the value of 'result'
- client->evaluate(QLatin1String("a"),frameIndex);
+ {
+ QVariantMap body = value.value("body").toMap();
+ int frameIndex = body.value("index").toInt();
- QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(result())));
+ //Verify the value of 'result'
+ client->evaluate(QLatin1String("a"),frameIndex);
+ QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(result())));
+ }
jsonString = client->response;
- value = client->parser.call(QJSValueList() << QJSValue(jsonString)).toVariant().toMap();
-
- body = value.value("body").toMap();
-
- QVERIFY(body.value("value").toInt() > out);
+ QJSValue val = client->parser.call(QJSValueList() << QJSValue(jsonString));
+ QVERIFY(val.isObject());
+ QJSValue body = val.property(QStringLiteral("body"));
+ QVERIFY(body.isObject());
+ val = body.property("value");
+ QVERIFY(val.isNumber());
+
+ const int a = val.toInt();
+ QVERIFY(a > out);
}
-#endif
void tst_QQmlDebugJS::setBreakpointInScriptThatQuits()
{
diff --git a/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp b/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp
index b544427c08..935b9d4120 100644
--- a/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp
+++ b/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp
@@ -61,6 +61,7 @@ struct QQmlProfilerData
int column; //used by RangeLocation
int framerate; //used by animation events
int animationcount; //used by animation events
+ qint64 amount; //used by heap events
QByteArray toByteArray() const;
};
@@ -79,6 +80,7 @@ public:
Complete, // end of transmission
PixmapCacheEvent,
SceneGraphFrame,
+ MemoryAllocation,
MaximumMessage
};
@@ -131,6 +133,12 @@ public:
MaximumSceneGraphFrameType
};
+ enum MemoryType {
+ HeapPage,
+ LargeItem,
+ SmallItem
+ };
+
QQmlProfilerClient(QQmlDebugConnection *connection)
: QQmlDebugClient(QLatin1String("CanvasFrameRate"), connection)
{
@@ -138,6 +146,7 @@ public:
QList<QQmlProfilerData> qmlMessages;
QList<QQmlProfilerData> javascriptMessages;
+ QList<QQmlProfilerData> jsHeapMessages;
QList<QQmlProfilerData> asynchronousMessages;
QList<QQmlProfilerData> pixmapMessages;
@@ -175,6 +184,7 @@ private:
void connect(bool block, const QString &testFile);
void checkTraceReceived();
+ void checkJsHeap();
private slots:
void cleanup();
@@ -303,6 +313,11 @@ void QQmlProfilerClient::messageReceived(const QByteArray &message)
}
break;
}
+ case QQmlProfilerClient::MemoryAllocation: {
+ stream >> data.detailType;
+ stream >> data.amount;
+ break;
+ }
default:
QString failMsg = QString("Unknown message type:") + data.messageType;
QFAIL(qPrintable(failMsg));
@@ -314,6 +329,8 @@ void QQmlProfilerClient::messageReceived(const QByteArray &message)
else if (data.messageType == QQmlProfilerClient::SceneGraphFrame ||
data.messageType == QQmlProfilerClient::Event)
asynchronousMessages.append(data);
+ else if (data.messageType == QQmlProfilerClient::MemoryAllocation)
+ jsHeapMessages.append(data);
else if (data.detailType == QQmlProfilerClient::Javascript)
javascriptMessages.append(data);
else
@@ -357,6 +374,48 @@ void tst_QQmlProfilerService::checkTraceReceived()
QCOMPARE(m_client->asynchronousMessages.last().detailType, (int)QQmlProfilerClient::EndTrace);
}
+void tst_QQmlProfilerService::checkJsHeap()
+{
+ QVERIFY2(m_client->jsHeapMessages.count() > 0, "no JavaScript heap messages received");
+
+ bool seen_alloc = false;
+ bool seen_small = false;
+ bool seen_large = false;
+ qint64 allocated = 0;
+ qint64 used = 0;
+ foreach (const QQmlProfilerData &message, m_client->jsHeapMessages) {
+ switch (message.detailType) {
+ case QQmlProfilerClient::HeapPage:
+ allocated += message.amount;
+ seen_alloc = true;
+ break;
+ case QQmlProfilerClient::SmallItem:
+ used += message.amount;
+ seen_small = true;
+ break;
+ case QQmlProfilerClient::LargeItem:
+ allocated += message.amount;
+ used += message.amount;
+ seen_large = true;
+ break;
+ }
+
+ QVERIFY2(used >= 0, QString::fromLatin1("Negative memory usage seen: %1")
+ .arg(used).toUtf8().constData());
+
+ QVERIFY2(allocated >= 0, QString::fromLatin1("Negative memory allocation seen: %1")
+ .arg(allocated).toUtf8().constData());
+
+ QVERIFY2(used <= allocated,
+ QString::fromLatin1("More memory usage than allocation seen: %1 > %2")
+ .arg(used).arg(allocated).toUtf8().constData());
+ }
+
+ QVERIFY2(seen_alloc, "No heap allocation seen");
+ QVERIFY2(seen_small, "No small item seen");
+ QVERIFY2(seen_large, "No large item seen");
+}
+
void tst_QQmlProfilerService::cleanup()
{
if (QTest::currentTestFailed()) {
@@ -388,6 +447,12 @@ void tst_QQmlProfilerService::cleanup()
<< data.line << data.column;
}
qDebug() << " ";
+ qDebug() << "Javascript Heap Messages:" << m_client->jsHeapMessages.count();
+ i = 0;
+ foreach (const QQmlProfilerData &data, m_client->jsHeapMessages) {
+ qDebug() << i++ << data.time << data.messageType << data.detailType;
+ }
+ qDebug() << " ";
qDebug() << "Process State:" << (m_process ? m_process->state() : QLatin1String("null"));
qDebug() << "Application Output:" << (m_process ? m_process->output() : QLatin1String("null"));
qDebug() << "Connection State:" << (m_connection ? m_connection->stateString() : QLatin1String("null"));
@@ -410,6 +475,7 @@ void tst_QQmlProfilerService::blockingConnectWithTraceEnabled()
m_client->setTraceState(true);
m_client->setTraceState(false);
checkTraceReceived();
+ checkJsHeap();
}
void tst_QQmlProfilerService::blockingConnectWithTraceDisabled()
@@ -422,6 +488,7 @@ void tst_QQmlProfilerService::blockingConnectWithTraceDisabled()
m_client->setTraceState(true);
m_client->setTraceState(false);
checkTraceReceived();
+ checkJsHeap();
}
void tst_QQmlProfilerService::nonBlockingConnect()
@@ -433,6 +500,7 @@ void tst_QQmlProfilerService::nonBlockingConnect()
m_client->setTraceState(true);
m_client->setTraceState(false);
checkTraceReceived();
+ checkJsHeap();
}
void tst_QQmlProfilerService::pixmapCacheData()
@@ -451,6 +519,7 @@ void tst_QQmlProfilerService::pixmapCacheData()
m_client->setTraceState(false);
checkTraceReceived();
+ checkJsHeap();
QVERIFY2(m_client->pixmapMessages.count() >= 4,
QString::number(m_client->pixmapMessages.count()).toUtf8().constData());
@@ -487,6 +556,7 @@ void tst_QQmlProfilerService::scenegraphData()
m_client->setTraceState(false);
checkTraceReceived();
+ checkJsHeap();
// check that at least one frame was rendered
// there should be a SGPolishAndSync + SGRendererFrame + SGRenderLoopFrame sequence
@@ -516,6 +586,7 @@ void tst_QQmlProfilerService::profileOnExit()
m_client->setTraceState(true);
checkTraceReceived();
+ checkJsHeap();
}
void tst_QQmlProfilerService::controlFromJS()
@@ -526,6 +597,7 @@ void tst_QQmlProfilerService::controlFromJS()
m_client->setTraceState(false);
checkTraceReceived();
+ checkJsHeap();
}
void tst_QQmlProfilerService::signalSourceLocation()
@@ -539,6 +611,7 @@ void tst_QQmlProfilerService::signalSourceLocation()
QVERIFY(QQmlDebugTest::waitForSignal(m_process, SIGNAL(readyReadStandardOutput())));
m_client->setTraceState(false);
checkTraceReceived();
+ checkJsHeap();
QVERIFY2(m_client->qmlMessages.count() >= 16,
QString::number(m_client->qmlMessages.count()).toUtf8().constData());
@@ -569,6 +642,7 @@ void tst_QQmlProfilerService::javascript()
QVERIFY(QQmlDebugTest::waitForSignal(m_process, SIGNAL(readyReadStandardOutput())));
m_client->setTraceState(false);
checkTraceReceived();
+ checkJsHeap();
QVERIFY2(m_client->javascriptMessages.count() >= 22,
QString::number(m_client->javascriptMessages.count()).toUtf8().constData());
diff --git a/tests/auto/qml/debugger/shared/qqmlenginedebugclient.cpp b/tests/auto/qml/debugger/shared/qqmlenginedebugclient.cpp
index 610d80d559..022ba8c440 100644
--- a/tests/auto/qml/debugger/shared/qqmlenginedebugclient.cpp
+++ b/tests/auto/qml/debugger/shared/qqmlenginedebugclient.cpp
@@ -84,7 +84,8 @@ QQmlEngineDebugClient::QQmlEngineDebugClient(
QQmlDebugConnection *connection)
: QQmlDebugClient(QLatin1String("QmlDebugger"), connection),
m_nextId(0),
- m_valid(false)
+ m_valid(false),
+ m_connection(connection)
{
}
@@ -467,6 +468,9 @@ void QQmlEngineDebugClient::messageReceived(const QByteArray &data)
{
m_valid = false;
QDataStream ds(data);
+ ds.setVersion(m_connection->dataStreamVersion());
+
+
int queryId;
QByteArray type;
ds >> type >> queryId;
diff --git a/tests/auto/qml/debugger/shared/qqmlenginedebugclient.h b/tests/auto/qml/debugger/shared/qqmlenginedebugclient.h
index 1d4b95a9e3..2712692389 100644
--- a/tests/auto/qml/debugger/shared/qqmlenginedebugclient.h
+++ b/tests/auto/qml/debugger/shared/qqmlenginedebugclient.h
@@ -242,6 +242,8 @@ private:
QmlDebugObjectReference m_object;
QList<QmlDebugObjectReference> m_objects;
QVariant m_exprResult;
+
+ QQmlDebugConnection *m_connection;
};
#endif // QQMLENGINEDEBUGCLIENT_H
diff --git a/tests/auto/qml/qjsengine/idtranslatable-unicode.js b/tests/auto/qml/qjsengine/idtranslatable-unicode.js
new file mode 100644
index 0000000000..e17d6172bc
--- /dev/null
+++ b/tests/auto/qml/qjsengine/idtranslatable-unicode.js
@@ -0,0 +1,5 @@
+qsTrId('\u01F8\u01D2\u0199\u01D0\u01E1');
+
+QT_TRID_NOOP("\u0191\u01CE\u0211\u0229\u019C\u018E\u019A\u01D0");
+
+qsTrId("\u0181\u01A1\u0213\u018F\u018C", 10);
diff --git a/tests/auto/qml/qjsengine/idtranslatable.js b/tests/auto/qml/qjsengine/idtranslatable.js
new file mode 100644
index 0000000000..554ca88d41
--- /dev/null
+++ b/tests/auto/qml/qjsengine/idtranslatable.js
@@ -0,0 +1,5 @@
+qsTrId("qtn_foo_bar");
+
+var more_greeting_strings = [ QT_TRID_NOOP("qtn_needle"), QT_TRID_NOOP("qtn_haystack") ];
+
+qsTrId("qtn_bar_baz", 10);
diff --git a/tests/auto/qml/qjsengine/qjsengine.pro b/tests/auto/qml/qjsengine/qjsengine.pro
index a62eb75c21..fc2452c2bc 100644
--- a/tests/auto/qml/qjsengine/qjsengine.pro
+++ b/tests/auto/qml/qjsengine/qjsengine.pro
@@ -4,6 +4,7 @@ TARGET = tst_qjsengine
QT += qml qml-private widgets testlib gui-private
macx:CONFIG -= app_bundle
SOURCES += tst_qjsengine.cpp
+RESOURCES += qjsengine.qrc
TESTDATA = script/*
DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0
diff --git a/tests/auto/qml/qjsengine/qjsengine.qrc b/tests/auto/qml/qjsengine/qjsengine.qrc
new file mode 100644
index 0000000000..d05d115966
--- /dev/null
+++ b/tests/auto/qml/qjsengine/qjsengine.qrc
@@ -0,0 +1,8 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource>
+ <file>translations/translatable_la.qm</file>
+ <file>translations/idtranslatable_la.qm</file>
+ <file>translations/translatable-unicode.qm</file>
+ <file>translations/idtranslatable-unicode.qm</file>
+</qresource>
+</RCC>
diff --git a/tests/auto/qml/qjsengine/translatable-unicode.js b/tests/auto/qml/qjsengine/translatable-unicode.js
new file mode 100644
index 0000000000..afe2aff21c
--- /dev/null
+++ b/tests/auto/qml/qjsengine/translatable-unicode.js
@@ -0,0 +1,9 @@
+qsTr("H\u2082O");
+qsTranslate("\u010C\u0101\u011F\u0115", "CO\u2082");
+
+var unicode_strings = [
+ QT_TR_NOOP("\u0391\u0392\u0393"),
+ QT_TRANSLATE_NOOP("\u010C\u0101\u011F\u0115", "\u0414\u0415\u0416")
+];
+
+qsTr("H\u2082O", "not the same H\u2082O");
diff --git a/tests/auto/qml/qjsengine/translatable.js b/tests/auto/qml/qjsengine/translatable.js
new file mode 100644
index 0000000000..5d6ad9b3b6
--- /dev/null
+++ b/tests/auto/qml/qjsengine/translatable.js
@@ -0,0 +1,12 @@
+qsTr("One");
+qsTranslate("FooContext", "Two");
+
+var greeting_strings = [
+ QT_TR_NOOP("Hello"),
+ QT_TRANSLATE_NOOP("FooContext", "Goodbye")
+];
+
+qsTr("One", "not the same one");
+
+qsTr("%n message(s) saved", "", 10);
+qsTranslate("FooContext", "%n fooish bar(s) found", "", 10);
diff --git a/tests/auto/qml/qjsengine/translatable2.js b/tests/auto/qml/qjsengine/translatable2.js
new file mode 100644
index 0000000000..eee66f17c1
--- /dev/null
+++ b/tests/auto/qml/qjsengine/translatable2.js
@@ -0,0 +1,9 @@
+qsTr("Three");
+qsTranslate("BarContext", "Four");
+
+var celebration_strings = [
+ QT_TR_NOOP("Happy birthday!"),
+ QT_TRANSLATE_NOOP("BarContext", "Congratulations!")
+];
+
+qsTr("Three", "not the same three");
diff --git a/tests/auto/qml/qjsengine/translations/idtranslatable-unicode.qm b/tests/auto/qml/qjsengine/translations/idtranslatable-unicode.qm
new file mode 100644
index 0000000000..8c5fb91b1d
--- /dev/null
+++ b/tests/auto/qml/qjsengine/translations/idtranslatable-unicode.qm
Binary files differ
diff --git a/tests/auto/qml/qjsengine/translations/idtranslatable-unicode.ts b/tests/auto/qml/qjsengine/translations/idtranslatable-unicode.ts
new file mode 100644
index 0000000000..74ebf43c47
--- /dev/null
+++ b/tests/auto/qml/qjsengine/translations/idtranslatable-unicode.ts
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.0" language="nb_NO">
+<defaultcodec>UTF-8</defaultcodec>
+<context>
+ <name></name>
+ <message id="Ǹǒƙǐǡ">
+ <location filename="idtranslatable-unicode.js" line="1"/>
+ <source></source>
+ <translation>Ƨưƈȼȝȿș</translation>
+ </message>
+ <message id="ƑǎȑȩƜƎƚǐ">
+ <location filename="idtranslatable-unicode.js" line="3"/>
+ <source></source>
+ <translation>Ǡȡȋȅȕ</translation>
+ </message>
+ <message id="ƁơȓƏƌ" numerus="yes">
+ <location filename="idtranslatable-unicode.js" line="5"/>
+ <source></source>
+ <translation>
+ <numerusform>Ƒưǹ</numerusform>
+ <numerusform>%n ƒơǒ(ș)</numerusform>
+ </translation>
+ </message>
+</context>
+</TS>
diff --git a/tests/auto/qml/qjsengine/translations/idtranslatable_la.qm b/tests/auto/qml/qjsengine/translations/idtranslatable_la.qm
new file mode 100644
index 0000000000..c8c0b72acb
--- /dev/null
+++ b/tests/auto/qml/qjsengine/translations/idtranslatable_la.qm
Binary files differ
diff --git a/tests/auto/qml/qjsengine/translations/idtranslatable_la.ts b/tests/auto/qml/qjsengine/translations/idtranslatable_la.ts
new file mode 100644
index 0000000000..b6d7053024
--- /dev/null
+++ b/tests/auto/qml/qjsengine/translations/idtranslatable_la.ts
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.0" language="nb_NO">
+<context>
+ <name></name>
+ <message id="qtn_foo_bar">
+ <location filename="idtranslatable.js" line="1"/>
+ <source></source>
+ <translation>First string</translation>
+ </message>
+ <message id="qtn_needle">
+ <location filename="idtranslatable.js" line="3"/>
+ <source></source>
+ <translation>Second string</translation>
+ </message>
+ <message id="qtn_haystack">
+ <location filename="idtranslatable.js" line="3"/>
+ <source></source>
+ <translation>Third string</translation>
+ </message>
+ <message id="qtn_bar_baz" numerus="yes">
+ <location filename="idtranslatable.js" line="5"/>
+ <source></source>
+ <translation>
+ <numerusform>Fourth string</numerusform>
+ <numerusform>%n fooish bar(s) found</numerusform>
+ </translation>
+ </message>
+</context>
+</TS>
diff --git a/tests/auto/qml/qjsengine/translations/translatable-unicode.qm b/tests/auto/qml/qjsengine/translations/translatable-unicode.qm
new file mode 100644
index 0000000000..aa75ce61df
--- /dev/null
+++ b/tests/auto/qml/qjsengine/translations/translatable-unicode.qm
Binary files differ
diff --git a/tests/auto/qml/qjsengine/translations/translatable-unicode.ts b/tests/auto/qml/qjsengine/translations/translatable-unicode.ts
new file mode 100644
index 0000000000..1b8b4d2309
--- /dev/null
+++ b/tests/auto/qml/qjsengine/translations/translatable-unicode.ts
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.0">
+<defaultcodec>UTF-8</defaultcodec>
+<context>
+ <name>translatable-unicode</name>
+ <message>
+ <location filename="translatable-unicode.js" line="1"/>
+ <source>H₂O</source>
+ <translation>ͻͼͽ</translation>
+ </message>
+ <message>
+ <location filename="translatable-unicode.js" line="5"/>
+ <source>ΑΒΓ</source>
+ <translation>ӜҴѼ</translation>
+ </message>
+ <message>
+ <location filename="translatable-unicode.js" line="9"/>
+ <source>H₂O</source>
+ <comment>not the same H₂O</comment>
+ <translation>ԶՊՒ</translation>
+ </message>
+</context>
+<context>
+ <name>Čāğĕ</name>
+ <message>
+ <location filename="translatable-unicode.js" line="2"/>
+ <source>CO₂</source>
+ <translation>בךע</translation>
+ </message>
+ <message>
+ <location filename="translatable-unicode.js" line="6"/>
+ <source>ДЕЖ</source>
+ <translation>خسس</translation>
+ </message>
+</context>
+</TS>
diff --git a/tests/auto/qml/qjsengine/translations/translatable_la.qm b/tests/auto/qml/qjsengine/translations/translatable_la.qm
new file mode 100644
index 0000000000..d76b1cad5f
--- /dev/null
+++ b/tests/auto/qml/qjsengine/translations/translatable_la.qm
Binary files differ
diff --git a/tests/auto/qml/qjsengine/translations/translatable_la.ts b/tests/auto/qml/qjsengine/translations/translatable_la.ts
new file mode 100644
index 0000000000..36271c9cbe
--- /dev/null
+++ b/tests/auto/qml/qjsengine/translations/translatable_la.ts
@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.0" language="nb_NO">
+<context>
+ <name>BarContext</name>
+ <message>
+ <location filename="translatable2.js" line="2"/>
+ <source>Four</source>
+ <translation>Fire</translation>
+ </message>
+ <message>
+ <location filename="translatable2.js" line="6"/>
+ <source>Congratulations!</source>
+ <translation>Gratulerer!</translation>
+ </message>
+</context>
+<context>
+ <name>FooContext</name>
+ <message>
+ <location filename="translatable.js" line="2"/>
+ <source>Two</source>
+ <translation>To</translation>
+ </message>
+ <message>
+ <location filename="translatable.js" line="6"/>
+ <source>Goodbye</source>
+ <translation>Farvel</translation>
+ </message>
+ <message numerus="yes">
+ <location filename="translatable.js" line="12"/>
+ <source>%n fooish bar(s) found</source>
+ <translation>
+ <numerusform>%n fooaktig bar funnet</numerusform>
+ <numerusform>%n fooaktige barer funnet</numerusform>
+ </translation>
+ </message>
+</context>
+<context>
+ <name>translatable</name>
+ <message>
+ <location filename="translatable.js" line="1"/>
+ <source>One</source>
+ <translation>En</translation>
+ </message>
+ <message>
+ <location filename="translatable.js" line="5"/>
+ <source>Hello</source>
+ <translation>Hallo</translation>
+ </message>
+ <message>
+ <location filename="translatable.js" line="9"/>
+ <source>One</source>
+ <comment>not the same one</comment>
+ <translation>Enda en</translation>
+ </message>
+ <message numerus="yes">
+ <location filename="translatable.js" line="11"/>
+ <source>%n message(s) saved</source>
+ <translation>
+ <numerusform>%n melding lagret</numerusform>
+ <numerusform>%n meldinger lagret</numerusform>
+ </translation>
+ </message>
+ <message>
+ <source>Goodbye</source>
+ <translation type="obsolete">Farvel</translation>
+ </message>
+</context>
+<context>
+ <name>translatable2</name>
+ <message>
+ <location filename="translatable2.js" line="1"/>
+ <source>Three</source>
+ <translation>Tre</translation>
+ </message>
+ <message>
+ <location filename="translatable2.js" line="5"/>
+ <source>Happy birthday!</source>
+ <translation>Gratulerer med dagen!</translation>
+ </message>
+ <message>
+ <location filename="translatable2.js" line="9"/>
+ <source>Three</source>
+ <comment>not the same three</comment>
+ <translation>Tre andre</translation>
+ </message>
+</context>
+</TS>
diff --git a/tests/auto/qml/qjsengine/tst_qjsengine.cpp b/tests/auto/qml/qjsengine/tst_qjsengine.cpp
index 51cd69998a..8a1bedb600 100644
--- a/tests/auto/qml/qjsengine/tst_qjsengine.cpp
+++ b/tests/auto/qml/qjsengine/tst_qjsengine.cpp
@@ -159,6 +159,27 @@ private slots:
void scopeOfEvaluate();
+ void callConstants();
+
+ void installTranslatorFunctions();
+ void translateScript_data();
+ void translateScript();
+ void translateScript_crossScript();
+ void translateScript_trNoOp();
+ void translateScript_callQsTrFromCpp();
+ void translateWithInvalidArgs_data();
+ void translateWithInvalidArgs();
+ void translationContext_data();
+ void translationContext();
+ void translateScriptIdBased();
+ void translateScriptUnicode_data();
+ void translateScriptUnicode();
+ void translateScriptUnicodeIdBased_data();
+ void translateScriptUnicodeIdBased();
+ void translateFromBuiltinCallback();
+
+ void privateMethods();
+
signals:
void testSignal();
};
@@ -3099,6 +3120,471 @@ void tst_QJSEngine::scopeOfEvaluate()
QCOMPARE(result.toInt(), 42);
}
+void tst_QJSEngine::callConstants()
+{
+ QJSEngine engine;
+ engine.evaluate("function f() {\n"
+ " var one; one();\n"
+ " var two = null; two();\n"
+ "}\n");
+}
+
+void tst_QJSEngine::installTranslatorFunctions()
+{
+ QJSEngine eng;
+ QJSValue global = eng.globalObject();
+ QVERIFY(global.property("qsTranslate").isUndefined());
+ QVERIFY(global.property("QT_TRANSLATE_NOOP").isUndefined());
+ QVERIFY(global.property("qsTr").isUndefined());
+ QVERIFY(global.property("QT_TR_NOOP").isUndefined());
+ QVERIFY(global.property("qsTrId").isUndefined());
+ QVERIFY(global.property("QT_TRID_NOOP").isUndefined());
+
+ eng.installTranslatorFunctions();
+ QVERIFY(global.property("qsTranslate").isCallable());
+ QVERIFY(global.property("QT_TRANSLATE_NOOP").isCallable());
+ QVERIFY(global.property("qsTr").isCallable());
+ QVERIFY(global.property("QT_TR_NOOP").isCallable());
+ QVERIFY(global.property("qsTrId").isCallable());
+ QVERIFY(global.property("QT_TRID_NOOP").isCallable());
+
+ {
+ QJSValue ret = eng.evaluate("qsTr('foo')");
+ QVERIFY(ret.isString());
+ QCOMPARE(ret.toString(), QString::fromLatin1("foo"));
+ }
+ {
+ QJSValue ret = eng.evaluate("qsTranslate('foo', 'bar')");
+ QVERIFY(ret.isString());
+ QCOMPARE(ret.toString(), QString::fromLatin1("bar"));
+ }
+ {
+ QJSValue ret = eng.evaluate("QT_TR_NOOP('foo')");
+ QVERIFY(ret.isString());
+ QCOMPARE(ret.toString(), QString::fromLatin1("foo"));
+ }
+ {
+ QJSValue ret = eng.evaluate("QT_TRANSLATE_NOOP('foo', 'bar')");
+ QVERIFY(ret.isString());
+ QCOMPARE(ret.toString(), QString::fromLatin1("bar"));
+ }
+
+ {
+ QJSValue ret = eng.evaluate("qsTrId('foo')");
+ QVERIFY(ret.isString());
+ QCOMPARE(ret.toString(), QString::fromLatin1("foo"));
+ }
+ {
+ QJSValue ret = eng.evaluate("QT_TRID_NOOP('foo')");
+ QVERIFY(ret.isString());
+ QCOMPARE(ret.toString(), QString::fromLatin1("foo"));
+ }
+ QVERIFY(eng.evaluate("QT_TRID_NOOP()").isUndefined());
+}
+
+class TranslationScope
+{
+public:
+ TranslationScope(const QString &fileName)
+ {
+ translator.load(fileName);
+ QCoreApplication::instance()->installTranslator(&translator);
+ }
+ ~TranslationScope()
+ {
+ QCoreApplication::instance()->removeTranslator(&translator);
+ }
+
+private:
+ QTranslator translator;
+};
+
+void tst_QJSEngine::translateScript_data()
+{
+ QTest::addColumn<QString>("expression");
+ QTest::addColumn<QString>("fileName");
+ QTest::addColumn<QString>("expectedTranslation");
+
+ QString fileName = QString::fromLatin1("translatable.js");
+ // Top-level
+ QTest::newRow("qsTr('One')@translatable.js")
+ << QString::fromLatin1("qsTr('One')") << fileName << QString::fromLatin1("En");
+ QTest::newRow("qsTr('Hello')@translatable.js")
+ << QString::fromLatin1("qsTr('Hello')") << fileName << QString::fromLatin1("Hallo");
+ // From function
+ QTest::newRow("(function() { return qsTr('One'); })()@translatable.js")
+ << QString::fromLatin1("(function() { return qsTr('One'); })()") << fileName << QString::fromLatin1("En");
+ QTest::newRow("(function() { return qsTr('Hello'); })()@translatable.js")
+ << QString::fromLatin1("(function() { return qsTr('Hello'); })()") << fileName << QString::fromLatin1("Hallo");
+ // Plural
+ QTest::newRow("qsTr('%n message(s) saved', '', 1)@translatable.js")
+ << QString::fromLatin1("qsTr('%n message(s) saved', '', 1)") << fileName << QString::fromLatin1("1 melding lagret");
+ QTest::newRow("qsTr('%n message(s) saved', '', 3).arg@translatable.js")
+ << QString::fromLatin1("qsTr('%n message(s) saved', '', 3)") << fileName << QString::fromLatin1("3 meldinger lagret");
+
+ // Top-level
+ QTest::newRow("qsTranslate('FooContext', 'Two')@translatable.js")
+ << QString::fromLatin1("qsTranslate('FooContext', 'Two')") << fileName << QString::fromLatin1("To");
+ QTest::newRow("qsTranslate('FooContext', 'Goodbye')@translatable.js")
+ << QString::fromLatin1("qsTranslate('FooContext', 'Goodbye')") << fileName << QString::fromLatin1("Farvel");
+ // From eval
+ QTest::newRow("eval('qsTranslate(\\'FooContext\\', \\'Two\\')')@translatable.js")
+ << QString::fromLatin1("eval('qsTranslate(\\'FooContext\\', \\'Two\\')')") << fileName << QString::fromLatin1("To");
+ QTest::newRow("eval('qsTranslate(\\'FooContext\\', \\'Goodbye\\')')@translatable.js")
+ << QString::fromLatin1("eval('qsTranslate(\\'FooContext\\', \\'Goodbye\\')')") << fileName << QString::fromLatin1("Farvel");
+
+ QTest::newRow("qsTranslate('FooContext', 'Goodbye', '')@translatable.js")
+ << QString::fromLatin1("qsTranslate('FooContext', 'Goodbye', '')") << fileName << QString::fromLatin1("Farvel");
+
+ QTest::newRow("qsTranslate('FooContext', 'Goodbye', '', 42)@translatable.js")
+ << QString::fromLatin1("qsTranslate('FooContext', 'Goodbye', '', 42)") << fileName << QString::fromLatin1("Goodbye");
+
+ QTest::newRow("qsTr('One', 'not the same one')@translatable.js")
+ << QString::fromLatin1("qsTr('One', 'not the same one')") << fileName << QString::fromLatin1("Enda en");
+
+ QTest::newRow("qsTr('One', 'not the same one', 42)@translatable.js")
+ << QString::fromLatin1("qsTr('One', 'not the same one', 42)") << fileName << QString::fromLatin1("One");
+
+ // Plural
+ QTest::newRow("qsTranslate('FooContext', '%n fooish bar(s) found', '', 1)@translatable.js")
+ << QString::fromLatin1("qsTranslate('FooContext', '%n fooish bar(s) found', '', 1)") << fileName << QString::fromLatin1("1 fooaktig bar funnet");
+ QTest::newRow("qsTranslate('FooContext', '%n fooish bar(s) found', '', 2)@translatable.js")
+ << QString::fromLatin1("qsTranslate('FooContext', '%n fooish bar(s) found', '', 2)") << fileName << QString::fromLatin1("2 fooaktige barer funnet");
+
+ // Don't exist in translation
+ QTest::newRow("qsTr('Three')@translatable.js")
+ << QString::fromLatin1("qsTr('Three')") << fileName << QString::fromLatin1("Three");
+ QTest::newRow("qsTranslate('FooContext', 'So long')@translatable.js")
+ << QString::fromLatin1("qsTranslate('FooContext', 'So long')") << fileName << QString::fromLatin1("So long");
+ QTest::newRow("qsTranslate('BarContext', 'Goodbye')@translatable.js")
+ << QString::fromLatin1("qsTranslate('BarContext', 'Goodbye')") << fileName << QString::fromLatin1("Goodbye");
+
+ // Translate strings from the second script (translatable2.js)
+
+ QString fileName2 = QString::fromLatin1("translatable2.js");
+ QTest::newRow("qsTr('Three')@translatable2.js")
+ << QString::fromLatin1("qsTr('Three')") << fileName2 << QString::fromLatin1("Tre");
+ QTest::newRow("qsTr('Happy birthday!')@translatable2.js")
+ << QString::fromLatin1("qsTr('Happy birthday!')") << fileName2 << QString::fromLatin1("Gratulerer med dagen!");
+
+ // Not translated because translation is only in translatable.js
+ QTest::newRow("qsTr('One')@translatable2.js")
+ << QString::fromLatin1("qsTr('One')") << fileName2 << QString::fromLatin1("One");
+ QTest::newRow("(function() { return qsTr('One'); })()@translatable2.js")
+ << QString::fromLatin1("(function() { return qsTr('One'); })()") << fileName2 << QString::fromLatin1("One");
+
+ // For qsTranslate() the filename shouldn't matter
+ QTest::newRow("qsTranslate('FooContext', 'Two')@translatable2.js")
+ << QString::fromLatin1("qsTranslate('FooContext', 'Two')") << fileName2 << QString::fromLatin1("To");
+ QTest::newRow("qsTranslate('BarContext', 'Congratulations!')@translatable.js")
+ << QString::fromLatin1("qsTranslate('BarContext', 'Congratulations!')") << fileName << QString::fromLatin1("Gratulerer!");
+}
+
+void tst_QJSEngine::translateScript()
+{
+ QFETCH(QString, expression);
+ QFETCH(QString, fileName);
+ QFETCH(QString, expectedTranslation);
+
+ QJSEngine engine;
+
+ TranslationScope tranScope(":/translations/translatable_la");
+ engine.installTranslatorFunctions();
+
+ QCOMPARE(engine.evaluate(expression, fileName).toString(), expectedTranslation);
+}
+
+void tst_QJSEngine::translateScript_crossScript()
+{
+ QJSEngine engine;
+ TranslationScope tranScope(":/translations/translatable_la");
+ engine.installTranslatorFunctions();
+
+ QString fileName = QString::fromLatin1("translatable.js");
+ QString fileName2 = QString::fromLatin1("translatable2.js");
+ // qsTr() should use the innermost filename as context
+ engine.evaluate("function foo(s) { return bar(s); }", fileName);
+ engine.evaluate("function bar(s) { return qsTr(s); }", fileName2);
+ QCOMPARE(engine.evaluate("bar('Three')", fileName2).toString(), QString::fromLatin1("Tre"));
+ QCOMPARE(engine.evaluate("bar('Three')", fileName).toString(), QString::fromLatin1("Tre"));
+ QCOMPARE(engine.evaluate("bar('One')", fileName2).toString(), QString::fromLatin1("One"));
+
+ engine.evaluate("function foo(s) { return bar(s); }", fileName2);
+ engine.evaluate("function bar(s) { return qsTr(s); }", fileName);
+ QCOMPARE(engine.evaluate("bar('Three')", fileName2).toString(), QString::fromLatin1("Three"));
+ QCOMPARE(engine.evaluate("bar('One')", fileName).toString(), QString::fromLatin1("En"));
+ QCOMPARE(engine.evaluate("bar('One')", fileName2).toString(), QString::fromLatin1("En"));
+}
+
+void tst_QJSEngine::translateScript_trNoOp()
+{
+ QJSEngine engine;
+ TranslationScope tranScope(":/translations/translatable_la");
+ engine.installTranslatorFunctions();
+
+ QVERIFY(engine.evaluate("QT_TR_NOOP()").isUndefined());
+ QCOMPARE(engine.evaluate("QT_TR_NOOP('One')").toString(), QString::fromLatin1("One"));
+
+ QVERIFY(engine.evaluate("QT_TRANSLATE_NOOP()").isUndefined());
+ QVERIFY(engine.evaluate("QT_TRANSLATE_NOOP('FooContext')").isUndefined());
+ QCOMPARE(engine.evaluate("QT_TRANSLATE_NOOP('FooContext', 'Two')").toString(), QString::fromLatin1("Two"));
+}
+
+void tst_QJSEngine::translateScript_callQsTrFromCpp()
+{
+ QJSEngine engine;
+ TranslationScope tranScope(":/translations/translatable_la");
+ engine.installTranslatorFunctions();
+
+ // There is no context, but it shouldn't crash
+ QCOMPARE(engine.globalObject().property("qsTr").call(QJSValueList() << "One").toString(), QString::fromLatin1("One"));
+}
+
+void tst_QJSEngine::translateWithInvalidArgs_data()
+{
+ QTest::addColumn<QString>("expression");
+ QTest::addColumn<QString>("expectedError");
+
+ QTest::newRow("qsTr()") << "qsTr()" << "Error: qsTr() requires at least one argument";
+ QTest::newRow("qsTr(123)") << "qsTr(123)" << "Error: qsTr(): first argument (sourceText) must be a string";
+ QTest::newRow("qsTr('foo', 123)") << "qsTr('foo', 123)" << "Error: qsTr(): second argument (disambiguation) must be a string";
+ QTest::newRow("qsTr('foo', 'bar', 'baz')") << "qsTr('foo', 'bar', 'baz')" << "Error: qsTr(): third argument (n) must be a number";
+ QTest::newRow("qsTr('foo', 'bar', true)") << "qsTr('foo', 'bar', true)" << "Error: qsTr(): third argument (n) must be a number";
+
+ QTest::newRow("qsTranslate()") << "qsTranslate()" << "Error: qsTranslate() requires at least two arguments";
+ QTest::newRow("qsTranslate('foo')") << "qsTranslate('foo')" << "Error: qsTranslate() requires at least two arguments";
+ QTest::newRow("qsTranslate(123, 'foo')") << "qsTranslate(123, 'foo')" << "Error: qsTranslate(): first argument (context) must be a string";
+ QTest::newRow("qsTranslate('foo', 123)") << "qsTranslate('foo', 123)" << "Error: qsTranslate(): second argument (sourceText) must be a string";
+ QTest::newRow("qsTranslate('foo', 'bar', 123)") << "qsTranslate('foo', 'bar', 123)" << "Error: qsTranslate(): third argument (disambiguation) must be a string";
+
+ QTest::newRow("qsTrId()") << "qsTrId()" << "Error: qsTrId() requires at least one argument";
+ QTest::newRow("qsTrId(123)") << "qsTrId(123)" << "TypeError: qsTrId(): first argument (id) must be a string";
+ QTest::newRow("qsTrId('foo', 'bar')") << "qsTrId('foo', 'bar')" << "TypeError: qsTrId(): second argument (n) must be a number";
+}
+
+void tst_QJSEngine::translateWithInvalidArgs()
+{
+ QFETCH(QString, expression);
+ QFETCH(QString, expectedError);
+ QJSEngine engine;
+ engine.installTranslatorFunctions();
+ QJSValue result = engine.evaluate(expression);
+ QVERIFY(result.isError());
+ QCOMPARE(result.toString(), expectedError);
+}
+
+void tst_QJSEngine::translationContext_data()
+{
+ QTest::addColumn<QString>("path");
+ QTest::addColumn<QString>("text");
+ QTest::addColumn<QString>("expectedTranslation");
+
+ QTest::newRow("translatable.js") << "translatable.js" << "One" << "En";
+ QTest::newRow("/translatable.js") << "/translatable.js" << "One" << "En";
+ QTest::newRow("/foo/translatable.js") << "/foo/translatable.js" << "One" << "En";
+ QTest::newRow("/foo/bar/translatable.js") << "/foo/bar/translatable.js" << "One" << "En";
+ QTest::newRow("./translatable.js") << "./translatable.js" << "One" << "En";
+ QTest::newRow("../translatable.js") << "../translatable.js" << "One" << "En";
+ QTest::newRow("foo/translatable.js") << "foo/translatable.js" << "One" << "En";
+ QTest::newRow("file:///home/qt/translatable.js") << "file:///home/qt/translatable.js" << "One" << "En";
+ QTest::newRow(":/resources/translatable.js") << ":/resources/translatable.js" << "One" << "En";
+ QTest::newRow("/translatable.js.foo") << "/translatable.js.foo" << "One" << "En";
+ QTest::newRow("/translatable.txt") << "/translatable.txt" << "One" << "En";
+ QTest::newRow("translatable") << "translatable" << "One" << "En";
+ QTest::newRow("foo/translatable") << "foo/translatable" << "One" << "En";
+
+ QTest::newRow("translatable.js/") << "translatable.js/" << "One" << "One";
+ QTest::newRow("nosuchscript.js") << "" << "One" << "One";
+ QTest::newRow("(empty)") << "" << "One" << "One";
+}
+
+void tst_QJSEngine::translationContext()
+{
+ TranslationScope tranScope(":/translations/translatable_la");
+
+ QJSEngine engine;
+ engine.installTranslatorFunctions();
+
+ QFETCH(QString, path);
+ QFETCH(QString, text);
+ QFETCH(QString, expectedTranslation);
+ QJSValue ret = engine.evaluate(QString::fromLatin1("qsTr('%0')").arg(text), path);
+ QVERIFY(ret.isString());
+ QCOMPARE(ret.toString(), expectedTranslation);
+}
+
+void tst_QJSEngine::translateScriptIdBased()
+{
+ QJSEngine engine;
+
+ TranslationScope tranScope(":/translations/idtranslatable_la");
+ engine.installTranslatorFunctions();
+
+ QString fileName = QString::fromLatin1("idtranslatable.js");
+
+ QHash<QString, QString> expectedTranslations;
+ expectedTranslations["qtn_foo_bar"] = "First string";
+ expectedTranslations["qtn_needle"] = "Second string";
+ expectedTranslations["qtn_haystack"] = "Third string";
+ expectedTranslations["qtn_bar_baz"] = "Fourth string";
+
+ QHash<QString, QString>::const_iterator it;
+ for (it = expectedTranslations.constBegin(); it != expectedTranslations.constEnd(); ++it) {
+ for (int x = 0; x < 2; ++x) {
+ QString fn;
+ if (x)
+ fn = fileName;
+ // Top-level
+ QCOMPARE(engine.evaluate(QString::fromLatin1("qsTrId('%0')")
+ .arg(it.key()), fn).toString(),
+ it.value());
+ QCOMPARE(engine.evaluate(QString::fromLatin1("QT_TRID_NOOP('%0')")
+ .arg(it.key()), fn).toString(),
+ it.key());
+ // From function
+ QCOMPARE(engine.evaluate(QString::fromLatin1("(function() { return qsTrId('%0'); })()")
+ .arg(it.key()), fn).toString(),
+ it.value());
+ QCOMPARE(engine.evaluate(QString::fromLatin1("(function() { return QT_TRID_NOOP('%0'); })()")
+ .arg(it.key()), fn).toString(),
+ it.key());
+ }
+ }
+
+ // Plural form
+ QCOMPARE(engine.evaluate("qsTrId('qtn_bar_baz', 10)").toString(),
+ QString::fromLatin1("10 fooish bar(s) found"));
+ QCOMPARE(engine.evaluate("qsTrId('qtn_foo_bar', 10)").toString(),
+ QString::fromLatin1("qtn_foo_bar")); // Doesn't have plural
+}
+
+// How to add a new test row:
+// - Find a nice list of Unicode characters to choose from
+// - Write source string/context/comment in .js using Unicode escape sequences (\uABCD)
+// - Update corresponding .ts file (e.g. lupdate foo.js -ts foo.ts -codecfortr UTF-8)
+// - Enter translation in Linguist
+// - Update corresponding .qm file (e.g. lrelease foo.ts)
+// - Evaluate script that performs translation; make sure the correct result is returned
+// (e.g. by setting the resulting string as the text of a QLabel and visually verifying
+// that it looks the same as what you entered in Linguist :-) )
+// - Generate the expectedTranslation column data using toUtf8().toHex()
+void tst_QJSEngine::translateScriptUnicode_data()
+{
+ QTest::addColumn<QString>("expression");
+ QTest::addColumn<QString>("fileName");
+ QTest::addColumn<QString>("expectedTranslation");
+
+ QString fileName = QString::fromLatin1("translatable-unicode.js");
+ QTest::newRow("qsTr('H\\u2082O')@translatable-unicode.js")
+ << QString::fromLatin1("qsTr('H\\u2082O')") << fileName << QString::fromUtf8("\xcd\xbb\xcd\xbc\xcd\xbd");
+ QTest::newRow("qsTranslate('\\u010C\\u0101\\u011F\\u0115', 'CO\\u2082')@translatable-unicode.js")
+ << QString::fromLatin1("qsTranslate('\\u010C\\u0101\\u011F\\u0115', 'CO\\u2082')") << fileName << QString::fromUtf8("\xd7\x91\xd7\x9a\xd7\xa2");
+ QTest::newRow("qsTr('\\u0391\\u0392\\u0393')@translatable-unicode.js")
+ << QString::fromLatin1("qsTr('\\u0391\\u0392\\u0393')") << fileName << QString::fromUtf8("\xd3\x9c\xd2\xb4\xd1\xbc");
+ QTest::newRow("qsTranslate('\\u010C\\u0101\\u011F\\u0115', '\\u0414\\u0415\\u0416')@translatable-unicode.js")
+ << QString::fromLatin1("qsTranslate('\\u010C\\u0101\\u011F\\u0115', '\\u0414\\u0415\\u0416')") << fileName << QString::fromUtf8("\xd8\xae\xd8\xb3\xd8\xb3");
+ QTest::newRow("qsTr('H\\u2082O', 'not the same H\\u2082O')@translatable-unicode.js")
+ << QString::fromLatin1("qsTr('H\\u2082O', 'not the same H\\u2082O')") << fileName << QString::fromUtf8("\xd4\xb6\xd5\x8a\xd5\x92");
+ QTest::newRow("qsTr('H\\u2082O')")
+ << QString::fromLatin1("qsTr('H\\u2082O')") << QString() << QString::fromUtf8("\x48\xe2\x82\x82\x4f");
+ QTest::newRow("qsTranslate('\\u010C\\u0101\\u011F\\u0115', 'CO\\u2082')")
+ << QString::fromLatin1("qsTranslate('\\u010C\\u0101\\u011F\\u0115', 'CO\\u2082')") << QString() << QString::fromUtf8("\xd7\x91\xd7\x9a\xd7\xa2");
+}
+
+void tst_QJSEngine::translateScriptUnicode()
+{
+ QFETCH(QString, expression);
+ QFETCH(QString, fileName);
+ QFETCH(QString, expectedTranslation);
+
+ QJSEngine engine;
+
+ TranslationScope tranScope(":/translations/translatable-unicode");
+ engine.installTranslatorFunctions();
+
+ QCOMPARE(engine.evaluate(expression, fileName).toString(), expectedTranslation);
+}
+
+void tst_QJSEngine::translateScriptUnicodeIdBased_data()
+{
+ QTest::addColumn<QString>("expression");
+ QTest::addColumn<QString>("expectedTranslation");
+
+ QTest::newRow("qsTrId('\\u01F8\\u01D2\\u0199\\u01D0\\u01E1'')")
+ << QString::fromLatin1("qsTrId('\\u01F8\\u01D2\\u0199\\u01D0\\u01E1')") << QString::fromUtf8("\xc6\xa7\xc6\xb0\xc6\x88\xc8\xbc\xc8\x9d\xc8\xbf\xc8\x99");
+ QTest::newRow("qsTrId('\\u0191\\u01CE\\u0211\\u0229\\u019C\\u018E\\u019A\\u01D0')")
+ << QString::fromLatin1("qsTrId('\\u0191\\u01CE\\u0211\\u0229\\u019C\\u018E\\u019A\\u01D0')") << QString::fromUtf8("\xc7\xa0\xc8\xa1\xc8\x8b\xc8\x85\xc8\x95");
+ QTest::newRow("qsTrId('\\u0181\\u01A1\\u0213\\u018F\\u018C', 10)")
+ << QString::fromLatin1("qsTrId('\\u0181\\u01A1\\u0213\\u018F\\u018C', 10)") << QString::fromUtf8("\x31\x30\x20\xc6\x92\xc6\xa1\xc7\x92\x28\xc8\x99\x29");
+ QTest::newRow("qsTrId('\\u0181\\u01A1\\u0213\\u018F\\u018C')")
+ << QString::fromLatin1("qsTrId('\\u0181\\u01A1\\u0213\\u018F\\u018C')") << QString::fromUtf8("\xc6\x91\xc6\xb0\xc7\xb9");
+ QTest::newRow("qsTrId('\\u01CD\\u0180\\u01A8\\u0190\\u019E\\u01AB')")
+ << QString::fromLatin1("qsTrId('\\u01CD\\u0180\\u01A8\\u0190\\u019E\\u01AB')") << QString::fromUtf8("\xc7\x8d\xc6\x80\xc6\xa8\xc6\x90\xc6\x9e\xc6\xab");
+}
+
+void tst_QJSEngine::translateScriptUnicodeIdBased()
+{
+ QFETCH(QString, expression);
+ QFETCH(QString, expectedTranslation);
+
+ QJSEngine engine;
+
+ TranslationScope tranScope(":/translations/idtranslatable-unicode");
+ engine.installTranslatorFunctions();
+
+ QCOMPARE(engine.evaluate(expression).toString(), expectedTranslation);
+}
+
+void tst_QJSEngine::translateFromBuiltinCallback()
+{
+ QJSEngine eng;
+ eng.installTranslatorFunctions();
+
+ // Callback has no translation context.
+ eng.evaluate("function foo() { qsTr('foo'); }");
+
+ // Stack at translation time will be:
+ // qsTr, foo, forEach, global
+ // qsTr() needs to walk to the outer-most (global) frame before it finds
+ // a translation context, and this should not crash.
+ eng.evaluate("[10,20].forEach(foo)", "script.js");
+}
+
+class ObjectWithPrivateMethods : public QObject
+{
+ Q_OBJECT
+private slots:
+ void myPrivateMethod() {}
+};
+
+void tst_QJSEngine::privateMethods()
+{
+ ObjectWithPrivateMethods object;
+ QJSEngine engine;
+ QJSValue jsWrapper = engine.newQObject(&object);
+ QQmlEngine::setObjectOwnership(&object, QQmlEngine::CppOwnership);
+
+ QSet<QString> privateMethods;
+ {
+ const QMetaObject *mo = object.metaObject();
+ for (int i = 0; i < mo->methodCount(); ++i) {
+ const QMetaMethod method = mo->method(i);
+ if (method.access() == QMetaMethod::Private)
+ privateMethods << QString::fromUtf8(method.name());
+ }
+ }
+
+ QVERIFY(privateMethods.contains("myPrivateMethod"));
+ QVERIFY(privateMethods.contains("_q_reregisterTimers"));
+ privateMethods << QStringLiteral("deleteLater") << QStringLiteral("destroyed");
+
+ QJSValueIterator it(jsWrapper);
+ while (it.hasNext()) {
+ it.next();
+ QVERIFY(!privateMethods.contains(it.name()));
+ }
+}
+
QTEST_MAIN(tst_QJSEngine)
#include "tst_qjsengine.moc"
diff --git a/tests/auto/qml/qqmlapplicationengine/tst_qqmlapplicationengine.cpp b/tests/auto/qml/qqmlapplicationengine/tst_qqmlapplicationengine.cpp
index b261bb5191..9dcf68f50c 100644
--- a/tests/auto/qml/qqmlapplicationengine/tst_qqmlapplicationengine.cpp
+++ b/tests/auto/qml/qqmlapplicationengine/tst_qqmlapplicationengine.cpp
@@ -64,6 +64,7 @@ private:
void tst_qqmlapplicationengine::initTestCase()
{
+ qputenv("QT_MESSAGE_PATTERN", ""); // don't let it modify the debug output from testapp
buildDir = QDir::currentPath();
QQmlDataTest::initTestCase(); //Changes current path to src dir
srcDir = QDir::currentPath();
@@ -123,7 +124,7 @@ void tst_qqmlapplicationengine::application()
test_stderr_target.replace('\n', QByteArray("\r\n"));
#endif
QCOMPARE(test_stdout, QByteArray(""));
- QCOMPARE(test_stderr, test_stderr_target);
+ QCOMPARE(QString(test_stderr), QString(test_stderr_target));
delete testProcess;
QDir::setCurrent(srcDir);
#else // !QT_NO_PROCESS
diff --git a/tests/auto/qml/qqmlchangeset/tst_qqmlchangeset.cpp b/tests/auto/qml/qqmlchangeset/tst_qqmlchangeset.cpp
index 0f09de26d3..cfc850a9c6 100644
--- a/tests/auto/qml/qqmlchangeset/tst_qqmlchangeset.cpp
+++ b/tests/auto/qml/qqmlchangeset/tst_qqmlchangeset.cpp
@@ -148,7 +148,7 @@ public:
return false;
}
if (signal.moveId != -1) {
- QQmlChangeSet::Insert insert(signal.index, signal.count, signal.moveId, signal.offset);
+ QQmlChangeSet::Change insert(signal.index, signal.count, signal.moveId, signal.offset);
for (int i = insert.start(); i < insert.end(); ++i)
list.insert(i, removedValues.take(insert.moveKey(i)));
} else {
@@ -160,7 +160,7 @@ public:
return false;
}
if (signal.moveId != -1) {
- QQmlChangeSet::Remove remove(signal.index, signal.count, signal.moveId, signal.offset);
+ QQmlChangeSet::Change remove(signal.index, signal.count, signal.moveId, signal.offset);
for (int i = remove.start(); i < remove.end(); ++i)
removedValues.insert(remove.moveKey(i), list.at(i));
}
@@ -1182,9 +1182,9 @@ void tst_qqmlchangeset::sequence()
}
SignalList changes;
- foreach (const QQmlChangeSet::Remove &remove, set.removes())
+ foreach (const QQmlChangeSet::Change &remove, set.removes())
changes << Remove(remove.index, remove.count, remove.moveId, remove.offset);
- foreach (const QQmlChangeSet::Insert &insert, set.inserts())
+ foreach (const QQmlChangeSet::Change &insert, set.inserts())
changes << Insert(insert.index, insert.count, insert.moveId, insert.offset);
foreach (const QQmlChangeSet::Change &change, set.changes())
changes << Change(change.index, change.count);
@@ -1322,15 +1322,15 @@ void tst_qqmlchangeset::apply()
}
SignalList changes;
- foreach (const QQmlChangeSet::Remove &remove, set.removes())
+ foreach (const QQmlChangeSet::Change &remove, set.removes())
changes << Remove(remove.index, remove.count, remove.moveId, remove.offset);
- foreach (const QQmlChangeSet::Insert &insert, set.inserts())
+ foreach (const QQmlChangeSet::Change &insert, set.inserts())
changes << Insert(insert.index, insert.count, insert.moveId, insert.offset);
SignalList linearChanges;
- foreach (const QQmlChangeSet::Remove &remove, linearSet.removes())
+ foreach (const QQmlChangeSet::Change &remove, linearSet.removes())
linearChanges << Remove(remove.index, remove.count, remove.moveId, remove.offset);
- foreach (const QQmlChangeSet::Insert &insert, linearSet.inserts())
+ foreach (const QQmlChangeSet::Change &insert, linearSet.inserts())
linearChanges << Insert(insert.index, insert.count, insert.moveId, insert.offset);
// The output in the failing tests isn't incorrect, merely sub-optimal.
@@ -1364,17 +1364,17 @@ void tst_qqmlchangeset::removeConsecutive()
QFETCH(SignalList, input);
QFETCH(SignalList, output);
- QVector<QQmlChangeSet::Remove> removes;
+ QVector<QQmlChangeSet::Change> removes;
foreach (const Signal &signal, input) {
QVERIFY(signal.isRemove());
- removes.append(QQmlChangeSet::Remove(signal.index, signal.count, signal.moveId, signal.offset));
+ removes.append(QQmlChangeSet::Change(signal.index, signal.count, signal.moveId, signal.offset));
}
QQmlChangeSet set;
set.remove(removes);
SignalList changes;
- foreach (const QQmlChangeSet::Remove &remove, set.removes())
+ foreach (const QQmlChangeSet::Change &remove, set.removes())
changes << Remove(remove.index, remove.count, remove.moveId, remove.offset);
QVERIFY(set.inserts().isEmpty());
QVERIFY(set.changes().isEmpty());
@@ -1404,17 +1404,17 @@ void tst_qqmlchangeset::insertConsecutive()
QFETCH(SignalList, input);
QFETCH(SignalList, output);
- QVector<QQmlChangeSet::Insert> inserts;
+ QVector<QQmlChangeSet::Change> inserts;
foreach (const Signal &signal, input) {
QVERIFY(signal.isInsert());
- inserts.append(QQmlChangeSet::Insert(signal.index, signal.count, signal.moveId, signal.offset));
+ inserts.append(QQmlChangeSet::Change(signal.index, signal.count, signal.moveId, signal.offset));
}
QQmlChangeSet set;
set.insert(inserts);
SignalList changes;
- foreach (const QQmlChangeSet::Insert &insert, set.inserts())
+ foreach (const QQmlChangeSet::Change &insert, set.inserts())
changes << Insert(insert.index, insert.count, insert.moveId, insert.offset);
QVERIFY(set.removes().isEmpty());
QVERIFY(set.changes().isEmpty());
@@ -1462,12 +1462,12 @@ void tst_qqmlchangeset::debug()
changeSet.insert(15, 2);
changeSet.change(24, 8);
- QTest::ignoreMessage(QtDebugMsg, "QQmlChangeSet(Remove(0,12) Remove(5,4) Insert(3,9) Insert(15,2) Change(24,8) )");
+ QTest::ignoreMessage(QtDebugMsg, "QQmlChangeSet(Change(0,12) Change(5,4) Change(3,9) Change(15,2) Change(24,8) )");
qDebug() << changeSet;
changeSet.clear();
- QTest::ignoreMessage(QtDebugMsg, "QQmlChangeSet(Remove(12,4,0,0) Insert(5,4,0,0) )");
+ QTest::ignoreMessage(QtDebugMsg, "QQmlChangeSet(Change(12,4) Change(5,4) )");
changeSet.move(12, 5, 4, 0);
qDebug() << changeSet;
@@ -1537,9 +1537,9 @@ void tst_qqmlchangeset::random()
}
SignalList output;
- foreach (const QQmlChangeSet::Remove &remove, accumulatedSet.removes())
+ foreach (const QQmlChangeSet::Change &remove, accumulatedSet.removes())
output << Remove(remove.index, remove.count, remove.moveId, remove.offset);
- foreach (const QQmlChangeSet::Insert &insert, accumulatedSet.inserts())
+ foreach (const QQmlChangeSet::Change &insert, accumulatedSet.inserts())
output << Insert(insert.index, insert.count, insert.moveId, insert.offset);
QVector<int> inputList;
diff --git a/tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp b/tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp
index dbf28a5471..d5a5f10634 100644
--- a/tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp
+++ b/tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp
@@ -267,8 +267,8 @@ void tst_qqmlcomponent::qmlCreateParentReference()
void tst_qqmlcomponent::async()
{
- TestHTTPServer server(SERVER_PORT);
- QVERIFY(server.isValid());
+ TestHTTPServer server;
+ QVERIFY2(server.listen(SERVER_PORT), qPrintable(server.errorString()));
server.serveDirectory(dataDirectory());
QQmlComponent component(&engine);
@@ -287,8 +287,8 @@ void tst_qqmlcomponent::async()
void tst_qqmlcomponent::asyncHierarchy()
{
- TestHTTPServer server(SERVER_PORT);
- QVERIFY(server.isValid());
+ TestHTTPServer server;
+ QVERIFY2(server.listen(SERVER_PORT), qPrintable(server.errorString()));
server.serveDirectory(dataDirectory());
// ensure that the item hierarchy is compiled correctly.
diff --git a/tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp b/tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp
index 553663ac22..147887109f 100644
--- a/tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp
+++ b/tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp
@@ -348,7 +348,7 @@ void tst_qqmlcontext::setContextProperty()
QQmlContext ctxt(engine.rootContext());
ctxt.setContextProperty("ctxtProp", QVariant());
- QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: TypeError: Cannot read property 'a' of undefined");
+ QTest::ignoreMessage(QtWarningMsg, "<Unknown File>:1: TypeError: Cannot read property 'a' of undefined");
QObject *obj = component.create(&ctxt);
QVariant v = obj->property("obj");
diff --git a/tests/auto/qml/qqmlecmascript/data/assignSequenceTypes.1.qml b/tests/auto/qml/qqmlecmascript/data/assignSequenceTypes.1.qml
index be283fdda1..027fdbdfcb 100644
--- a/tests/auto/qml/qqmlecmascript/data/assignSequenceTypes.1.qml
+++ b/tests/auto/qml/qqmlecmascript/data/assignSequenceTypes.1.qml
@@ -3,7 +3,7 @@ import Qt.test 1.0
MySequenceConversionObject {
intListProperty: [1, 2]
- qrealListProperty: [1.1, 2.2]
+ qrealListProperty: [1.1, 2.2, 3]
boolListProperty: [false, true]
urlListProperty: [ "http://www.example1.com", "http://www.example2.com" ]
stringListProperty: [ "one", "two" ]
diff --git a/tests/auto/qml/qqmlecmascript/data/assignSequenceTypes.3.qml b/tests/auto/qml/qqmlecmascript/data/assignSequenceTypes.3.qml
index ad8a92e317..e486feb96c 100644
--- a/tests/auto/qml/qqmlecmascript/data/assignSequenceTypes.3.qml
+++ b/tests/auto/qml/qqmlecmascript/data/assignSequenceTypes.3.qml
@@ -3,7 +3,7 @@ import Qt.test 1.0
MySequenceConversionObject {
intListProperty: 1
- qrealListProperty: 1.1
+ qrealListProperty: 1
boolListProperty: false
urlListProperty: Qt.resolvedUrl("example.html")
}
diff --git a/tests/auto/qml/qqmlecmascript/data/assignSequenceTypes.4.qml b/tests/auto/qml/qqmlecmascript/data/assignSequenceTypes.4.qml
index a9f2e642d1..10e49af8e0 100644
--- a/tests/auto/qml/qqmlecmascript/data/assignSequenceTypes.4.qml
+++ b/tests/auto/qml/qqmlecmascript/data/assignSequenceTypes.4.qml
@@ -4,7 +4,7 @@ import Qt.test 1.0
MySequenceConversionObject {
Component.onCompleted: {
intListProperty = [1, 2]
- qrealListProperty = [1.1, 2.2]
+ qrealListProperty = [1.1, 2.2, 3]
boolListProperty = [false, true]
urlListProperty = [ "http://www.example1.com", "http://www.example2.com" ]
stringListProperty = [ "one", "two" ]
diff --git a/tests/auto/qml/qqmlecmascript/data/assignSequenceTypes.6.qml b/tests/auto/qml/qqmlecmascript/data/assignSequenceTypes.6.qml
index 7a794eb694..bc72b78af7 100644
--- a/tests/auto/qml/qqmlecmascript/data/assignSequenceTypes.6.qml
+++ b/tests/auto/qml/qqmlecmascript/data/assignSequenceTypes.6.qml
@@ -4,7 +4,7 @@ import Qt.test 1.0
MySequenceConversionObject {
Component.onCompleted: {
intListProperty = 1;
- qrealListProperty = 1.1;
+ qrealListProperty = 1;
boolListProperty = false;
urlListProperty = Qt.resolvedUrl("example.html");
}
diff --git a/tests/auto/qml/qqmlecmascript/data/extendedObjectPropertyLookup3.qml b/tests/auto/qml/qqmlecmascript/data/extendedObjectPropertyLookup3.qml
new file mode 100644
index 0000000000..ef574f9361
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/extendedObjectPropertyLookup3.qml
@@ -0,0 +1,13 @@
+import Qt.test 1.0
+import QtQuick 2.0
+
+QtObject {
+ property ImplementedExtensionObject a : ImplementedExtensionObject { id: root; extendedProperty : 42 }
+ property int b: root.abstractProperty
+ property int c: root.implementedProperty
+ property int d: root.extendedProperty
+
+ function getAbstractProperty() { return b; }
+ function getImplementedProperty() { return c; }
+ function getExtendedProperty() { return d; }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/uncreatableExtendedObjectFailureCheck.qml b/tests/auto/qml/qqmlecmascript/data/uncreatableExtendedObjectFailureCheck.qml
new file mode 100644
index 0000000000..3619d8588c
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/uncreatableExtendedObjectFailureCheck.qml
@@ -0,0 +1,8 @@
+import Qt.test 1.0
+import QtQuick 2.0
+
+QtObject {
+ property AbstractExtensionObject a;
+ a: AbstractExtensionObject { id: root }
+ property int b: Math.max(root.abstractProperty, 0)
+}
diff --git a/tests/auto/qml/qqmlecmascript/testtypes.cpp b/tests/auto/qml/qqmlecmascript/testtypes.cpp
index 560d86005c..c4e6709958 100644
--- a/tests/auto/qml/qqmlecmascript/testtypes.cpp
+++ b/tests/auto/qml/qqmlecmascript/testtypes.cpp
@@ -63,6 +63,44 @@ private:
int m_value;
};
+class AbstractExtensionObject : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(int abstractProperty READ abstractProperty WRITE setAbstractProperty NOTIFY abstractPropertyChanged)
+public:
+
+ AbstractExtensionObject(QObject *parent = 0) : QObject(parent), m_abstractProperty(-1) {}
+
+ void setAbstractProperty(int abstractProperty) { m_abstractProperty = abstractProperty; emit abstractPropertyChanged(); }
+ int abstractProperty() const { return m_abstractProperty; }
+
+ virtual void shouldBeImplemented() = 0;
+
+signals:
+ void abstractPropertyChanged();
+
+private:
+ int m_abstractProperty;
+};
+
+class ImplementedExtensionObject : public AbstractExtensionObject
+{
+ Q_OBJECT
+ Q_PROPERTY(int implementedProperty READ implementedProperty WRITE setImplementedProperty NOTIFY implementedPropertyChanged)
+public:
+ ImplementedExtensionObject(QObject *parent = 0) : AbstractExtensionObject(parent), m_implementedProperty(883) {}
+ void shouldBeImplemented() {}
+
+ void setImplementedProperty(int implementedProperty) { m_implementedProperty = implementedProperty; emit implementedPropertyChanged(); }
+ int implementedProperty() const { return m_implementedProperty; }
+
+signals:
+ void implementedPropertyChanged();
+
+private:
+ int m_implementedProperty;
+};
+
class ExtensionObject : public QObject
{
Q_OBJECT
@@ -376,6 +414,9 @@ void registerTypes()
qmlRegisterType<MyRevisionedClass,1>("Qt.test",1,1,"MyRevisionedClass");
qmlRegisterType<MyWorkerObject>("Qt.test", 1,0, "MyWorkerObject");
+ qmlRegisterExtendedUncreatableType<AbstractExtensionObject, ExtensionObject>("Qt.test", 1,0, "AbstractExtensionObject", QStringLiteral("Abstracts are uncreatable"));
+ qmlRegisterType<ImplementedExtensionObject>("Qt.test", 1,0, "ImplementedExtensionObject");
+
// test scarce resource property binding post-evaluation optimization
// and for testing memory usage in property var circular reference test
qmlRegisterType<ScarceResourceObject>("Qt.test", 1,0, "MyScarceResourceObject");
diff --git a/tests/auto/qml/qqmlecmascript/testtypes.h b/tests/auto/qml/qqmlecmascript/testtypes.h
index d5a1220f23..8f9dae4d17 100644
--- a/tests/auto/qml/qqmlecmascript/testtypes.h
+++ b/tests/auto/qml/qqmlecmascript/testtypes.h
@@ -1135,7 +1135,7 @@ class testQObjectApi : public QObject
{
Q_OBJECT
Q_ENUMS(MyEnum)
- Q_PROPERTY (int qobjectTestProperty READ qobjectTestProperty NOTIFY qobjectTestPropertyChanged)
+ Q_PROPERTY (int qobjectTestProperty READ qobjectTestProperty NOTIFY qobjectTestPropertyChanged FINAL)
Q_PROPERTY (int qobjectTestWritableProperty READ qobjectTestWritableProperty WRITE setQObjectTestWritableProperty NOTIFY qobjectTestWritablePropertyChanged)
Q_PROPERTY (int qobjectTestWritableFinalProperty READ qobjectTestWritableFinalProperty WRITE setQObjectTestWritableFinalProperty NOTIFY qobjectTestWritableFinalPropertyChanged FINAL)
diff --git a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
index 34413b23de..2550dd5473 100644
--- a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
+++ b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
@@ -122,6 +122,8 @@ private slots:
void selfDeletingBinding();
void extendedObjectPropertyLookup();
void extendedObjectPropertyLookup2();
+ void uncreatableExtendedObjectFailureCheck();
+ void extendedObjectPropertyLookup3();
void scriptErrors();
void functionErrors();
void propertyAssignmentErrors();
@@ -323,6 +325,7 @@ private slots:
void importedScriptsAccessOnObjectWithInvalidContext();
void contextObjectOnLazyBindings();
void garbageCollectionDuringCreation();
+ void qtbug_39520();
private:
// static void propertyVarWeakRefCallback(v8::Persistent<v8::Value> object, void* parameter);
@@ -1834,6 +1837,38 @@ void tst_qqmlecmascript::extendedObjectPropertyLookup2()
delete object;
}
+
+/*
+Test failure when trying to create and uncreatable extended type object.
+ */
+void tst_qqmlecmascript::uncreatableExtendedObjectFailureCheck()
+{
+ QQmlComponent component(&engine, testFileUrl("uncreatableExtendedObjectFailureCheck.qml"));
+
+ QObject *object = component.create();
+ QVERIFY(object == 0);
+}
+
+/*
+Test that an subclass of an uncreatable extended object contains all the required properties.
+ */
+void tst_qqmlecmascript::extendedObjectPropertyLookup3()
+{
+ QQmlComponent component(&engine, testFileUrl("extendedObjectPropertyLookup3.qml"));
+
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+
+ QVariant returnValue;
+ QVERIFY(QMetaObject::invokeMethod(object, "getAbstractProperty", Q_RETURN_ARG(QVariant, returnValue)));
+ QCOMPARE(returnValue.toInt(), -1);
+ QVERIFY(QMetaObject::invokeMethod(object, "getImplementedProperty", Q_RETURN_ARG(QVariant, returnValue)));
+ QCOMPARE(returnValue.toInt(), 883);
+ QVERIFY(QMetaObject::invokeMethod(object, "getExtendedProperty", Q_RETURN_ARG(QVariant, returnValue)));
+ QCOMPARE(returnValue.toInt(), 42);
+
+ delete object;
+}
/*
Test file/lineNumbers for binding/Script errors.
*/
@@ -3925,7 +3960,7 @@ void tst_qqmlecmascript::verifyContextLifetime(QQmlContextData *ctxt) {
Q_UNUSED(temporaryScope)
}
- engine->gc();
+ ctxt->engine->collectGarbage();
qml = scripts->getIndexed(i);
newContext = QV4::QmlContextWrapper::getContext(qml);
QVERIFY(scriptContext == newContext);
@@ -4172,8 +4207,8 @@ void tst_qqmlecmascript::importScripts()
QFETCH(QStringList, propertyNames);
QFETCH(QVariantList, propertyValues);
- TestHTTPServer server(8111);
- QVERIFY(server.isValid());
+ TestHTTPServer server;
+ QVERIFY2(server.listen(8111), qPrintable(server.errorString()));
server.serveDirectory(dataDirectory() + "/remote");
QStringList importPathList = engine.importPathList();
@@ -5549,7 +5584,7 @@ void tst_qqmlecmascript::assignSequenceTypes()
MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
QVERIFY(object != 0);
QCOMPARE(object->intListProperty(), (QList<int>() << 1 << 2));
- QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1 << 2.2));
+ QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1 << 2.2 << 3));
QCOMPARE(object->boolListProperty(), (QList<bool>() << false << true));
QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl("http://www.example1.com") << QUrl("http://www.example2.com")));
QCOMPARE(object->stringListProperty(), (QList<QString>() << QLatin1String("one") << QLatin1String("two")));
@@ -5577,7 +5612,7 @@ void tst_qqmlecmascript::assignSequenceTypes()
MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
QVERIFY(object != 0);
QCOMPARE(object->intListProperty(), (QList<int>() << 1));
- QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1));
+ QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1));
QCOMPARE(object->boolListProperty(), (QList<bool>() << false));
QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl(testFileUrl("example.html"))));
delete object;
@@ -5589,7 +5624,7 @@ void tst_qqmlecmascript::assignSequenceTypes()
MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
QVERIFY(object != 0);
QCOMPARE(object->intListProperty(), (QList<int>() << 1 << 2));
- QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1 << 2.2));
+ QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1 << 2.2 << 3));
QCOMPARE(object->boolListProperty(), (QList<bool>() << false << true));
QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl("http://www.example1.com") << QUrl("http://www.example2.com")));
QCOMPARE(object->stringListProperty(), (QList<QString>() << QLatin1String("one") << QLatin1String("two")));
@@ -5617,7 +5652,7 @@ void tst_qqmlecmascript::assignSequenceTypes()
MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
QVERIFY(object != 0);
QCOMPARE(object->intListProperty(), (QList<int>() << 1));
- QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1));
+ QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1));
QCOMPARE(object->boolListProperty(), (QList<bool>() << false));
QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl(testFileUrl("example.html"))));
delete object;
@@ -6000,8 +6035,8 @@ void tst_qqmlecmascript::include()
// Remote - error
{
- TestHTTPServer server(8111);
- QVERIFY(server.isValid());
+ TestHTTPServer server;
+ QVERIFY2(server.listen(8111), qPrintable(server.errorString()));
server.serveDirectory(dataDirectory());
QQmlComponent component(&engine, testFileUrl("include_remote_missing.qml"));
@@ -6042,8 +6077,8 @@ void tst_qqmlecmascript::includeRemoteSuccess()
#endif
// Remote - success
- TestHTTPServer server(8111);
- QVERIFY(server.isValid());
+ TestHTTPServer server;
+ QVERIFY2(server.listen(8111), qPrintable(server.errorString()));
server.serveDirectory(dataDirectory());
QQmlComponent component(&engine, testFileUrl("include_remote.qml"));
@@ -7648,6 +7683,30 @@ void tst_qqmlecmascript::garbageCollectionDuringCreation()
QCOMPARE(container->dataChildren.count(), 0);
}
+void tst_qqmlecmascript::qtbug_39520()
+{
+ QQmlComponent component(&engine);
+ component.setData("import QtQuick 2.0\n"
+ "Item {\n"
+ " property string s\n"
+ " Component.onCompleted: test()\n"
+ " function test() {\n"
+ " var count = 1 * 1000 * 1000\n"
+ " var t = ''\n"
+ " for (var i = 0; i < count; ++i)\n"
+ " t += 'testtest ' + i + '\n'\n"
+ " s = t\n"
+ " }\n"
+ "}\n",
+ QUrl());
+
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
+
+ QString s = object->property("s").toString();
+ QCOMPARE(s.count('\n'), 1 * 1000 * 1000);
+}
+
QTEST_MAIN(tst_qqmlecmascript)
#include "tst_qqmlecmascript.moc"
diff --git a/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp b/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp
index 004514d39c..23c50f940b 100644
--- a/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp
+++ b/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp
@@ -488,7 +488,7 @@ void tst_qqmlengine::outputWarningsToStandardError()
delete o;
QCOMPARE(messageHandler.messages().count(), 1);
- QCOMPARE(messageHandler.messages().at(0), QLatin1String("<Unknown File>: Unable to assign [undefined] to int"));
+ QCOMPARE(messageHandler.messages().at(0), QLatin1String("<Unknown File>:1:48: Unable to assign [undefined] to int"));
messageHandler.clear();
engine.setOutputWarningsToStandardError(false);
diff --git a/tests/auto/qml/qqmllanguage/data/customExtendedParserProperties.qml b/tests/auto/qml/qqmllanguage/data/customExtendedParserProperties.qml
new file mode 100644
index 0000000000..e53a7c6bd5
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/customExtendedParserProperties.qml
@@ -0,0 +1,12 @@
+import Test 1.0
+import QtQml 2.0
+SimpleExtendedObjectWithCustomParser {
+ id : obj
+ intProperty: 42
+ property string qmlString: "Hello"
+ property var someObject: QtObject {}
+
+ property int c : obj.extendedProperty
+
+ function getExtendedProperty() { return c; }
+}
diff --git a/tests/auto/qml/qqmllanguage/testtypes.cpp b/tests/auto/qml/qqmllanguage/testtypes.cpp
index 8ffa327cf2..b37c6836eb 100644
--- a/tests/auto/qml/qqmllanguage/testtypes.cpp
+++ b/tests/auto/qml/qqmllanguage/testtypes.cpp
@@ -40,6 +40,8 @@
****************************************************************************/
#include "testtypes.h"
+#include <private/qqmlcompiler_p.h>
+
void registerTypes()
{
qmlRegisterInterface<MyInterface>("MyInterface");
@@ -94,6 +96,8 @@ void registerTypes()
qmlRegisterCustomType<CustomBinding>("Test", 1, 0, "CustomBinding", new CustomBindingParser);
qmlRegisterCustomType<SimpleObjectWithCustomParser>("Test", 1, 0, "SimpleObjectWithCustomParser", new SimpleObjectCustomParser);
+ qmlRegisterCustomExtendedType<SimpleObjectWithCustomParser, SimpleObjectExtension>("Test", 1, 0, "SimpleExtendedObjectWithCustomParser", new SimpleObjectCustomParser);
+
qmlRegisterType<RootObjectInCreationTester>("Test", 1, 0, "RootObjectInCreationTester");
}
@@ -105,105 +109,70 @@ QVariant myCustomVariantTypeConverter(const QString &data)
}
-QByteArray CustomBindingParser::compile(const QV4::CompiledData::QmlUnit *qmlUnit, const QList<const QV4::CompiledData::Binding *> &bindings)
-{
- QByteArray result;
- QDataStream ds(&result, QIODevice::WriteOnly);
-
- ds << bindings.count();
- for (int i = 0; i < bindings.count(); ++i) {
- const QV4::CompiledData::Binding *binding = bindings.at(i);
- ds << qmlUnit->header.stringAt(binding->propertyNameIndex);
-
- Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Script);
- int bindingId = bindingIdentifier(binding);
- ds << bindingId;
-
- ds << binding->location.line;
- }
-
- return result;
-}
-
-void CustomBindingParser::setCustomData(QObject *object, const QByteArray &data, QQmlCompiledData*)
+void CustomBindingParser::applyBindings(QObject *object, QQmlCompiledData *cdata, const QList<const QV4::CompiledData::Binding *> &bindings)
{
CustomBinding *customBinding = qobject_cast<CustomBinding*>(object);
Q_ASSERT(customBinding);
- customBinding->m_bindingData = data;
+ customBinding->cdata = cdata;
+ customBinding->bindings = bindings;
}
void CustomBinding::componentComplete()
{
Q_ASSERT(m_target);
- QDataStream ds(m_bindingData);
- int count;
- ds >> count;
- for (int i = 0; i < count; ++i) {
- QString name;
- ds >> name;
+ foreach (const QV4::CompiledData::Binding *binding, bindings) {
+ QString name = cdata->compilationUnit->data->stringAt(binding->propertyNameIndex);
- int bindingId;
- ds >> bindingId;
+ int bindingId = binding->value.compiledScriptIndex;
- int line;
- ds >> line;
+ QQmlContextData *context = QQmlContextData::get(qmlContext(this));
- QQmlBinding *binding = QQmlBinding::createBinding(QQmlBinding::Identifier(bindingId), m_target, qmlContext(this));
+ QV4::Scope scope(QQmlEnginePrivate::getV4Engine(qmlEngine(this)));
+ QV4::ScopedValue function(scope, QV4::QmlBindingWrapper::createQmlCallableForFunction(context, m_target, cdata->compilationUnit->runtimeFunctions[bindingId]));
+ QQmlBinding *qmlBinding = new QQmlBinding(function, m_target, context);
QQmlProperty property(m_target, name, qmlContext(this));
- binding->setTarget(property);
- QQmlPropertyPrivate::setBinding(property, binding);
+ qmlBinding->setTarget(property);
+ QQmlPropertyPrivate::setBinding(property, qmlBinding);
}
}
-QByteArray EnumSupportingCustomParser::compile(const QV4::CompiledData::QmlUnit *qmlUnit, const QList<const QV4::CompiledData::Binding *> &bindings)
+void EnumSupportingCustomParser::verifyBindings(const QV4::CompiledData::QmlUnit *qmlUnit, const QList<const QV4::CompiledData::Binding *> &bindings)
{
- Q_UNUSED(qmlUnit)
-
if (bindings.count() != 1) {
error(bindings.first(), QStringLiteral("Custom parser invoked incorrectly for unit test"));
- return QByteArray();
+ return;
}
const QV4::CompiledData::Binding *binding = bindings.first();
if (qmlUnit->header.stringAt(binding->propertyNameIndex) != QStringLiteral("foo")) {
error(binding, QStringLiteral("Custom parser invoked with the wrong property name"));
- return QByteArray();
+ return;
}
if (binding->type != QV4::CompiledData::Binding::Type_Script) {
error(binding, QStringLiteral("Custom parser invoked with the wrong property value. Expected script that evaluates to enum"));
- return QByteArray();
+ return;
}
QByteArray script = qmlUnit->header.stringAt(binding->stringIndex).toUtf8();
bool ok;
int v = evaluateEnum(script, &ok);
if (!ok) {
error(binding, QStringLiteral("Custom parser invoked with the wrong property value. Script did not evaluate to enum"));
- return QByteArray();
+ return;
}
if (v != MyEnum1Class::A_13) {
error(binding, QStringLiteral("Custom parser invoked with the wrong property value. Enum value is not the expected value."));
- return QByteArray();
+ return;
}
-
- return QByteArray();
-}
-
-
-QByteArray SimpleObjectCustomParser::compile(const QV4::CompiledData::QmlUnit *, const QList<const QV4::CompiledData::Binding *> &bindings)
-{
- return QByteArray::number(bindings.count());
}
-void SimpleObjectCustomParser::setCustomData(QObject *object, const QByteArray &data, QQmlCompiledData*)
+void SimpleObjectCustomParser::applyBindings(QObject *object, QQmlCompiledData *, const QList<const QV4::CompiledData::Binding *> &bindings)
{
- SimpleObjectWithCustomParser *o = qobject_cast<SimpleObjectWithCustomParser*>(object);
- Q_ASSERT(o);
- bool ok = false;
- o->setCustomBindingsCount(data.toInt(&ok));
- Q_ASSERT(ok);
+ SimpleObjectWithCustomParser *o = qobject_cast<SimpleObjectWithCustomParser*>(object);
+ Q_ASSERT(o);
+ o->setCustomBindingsCount(bindings.count());
}
diff --git a/tests/auto/qml/qqmllanguage/testtypes.h b/tests/auto/qml/qqmllanguage/testtypes.h
index 1c13a2e21c..bb1e9c158d 100644
--- a/tests/auto/qml/qqmllanguage/testtypes.h
+++ b/tests/auto/qml/qqmllanguage/testtypes.h
@@ -54,7 +54,7 @@
#include <QtQml/qqmlpropertyvaluesource.h>
#include <QtQml/qqmlscriptstring.h>
#include <QtQml/qqmlproperty.h>
-
+#include <private/qqmlcompiler_p.h>
#include <private/qqmlcustomparser_p.h>
QVariant myCustomVariantTypeConverter(const QString &data);
@@ -739,15 +739,15 @@ class MyCustomParserType : public QObject
class MyCustomParserTypeParser : public QQmlCustomParser
{
public:
- QByteArray compile(const QV4::CompiledData::QmlUnit *, const QList<const QV4::CompiledData::Binding *> &) { return QByteArray(); }
- void setCustomData(QObject *, const QByteArray &, QQmlCompiledData*) {}
+ virtual void verifyBindings(const QV4::CompiledData::QmlUnit *, const QList<const QV4::CompiledData::Binding *> &) {}
+ virtual void applyBindings(QObject *, QQmlCompiledData *, const QList<const QV4::CompiledData::Binding *> &) {}
};
class EnumSupportingCustomParser : public QQmlCustomParser
{
public:
- QByteArray compile(const QV4::CompiledData::QmlUnit *qmlUnit, const QList<const QV4::CompiledData::Binding *> &bindings);
- void setCustomData(QObject *, const QByteArray &, QQmlCompiledData*) {}
+ virtual void verifyBindings(const QV4::CompiledData::QmlUnit *, const QList<const QV4::CompiledData::Binding *> &);
+ virtual void applyBindings(QObject *, QQmlCompiledData *, const QList<const QV4::CompiledData::Binding *> &) {}
};
class MyParserStatus : public QObject, public QQmlParserStatus
@@ -1112,13 +1112,15 @@ public:
void setTarget(QObject *newTarget) { m_target = newTarget; }
QPointer<QObject> m_target;
+ QQmlRefPointer<QQmlCompiledData> cdata;
+ QList<const QV4::CompiledData::Binding*> bindings;
QByteArray m_bindingData;
};
class CustomBindingParser : public QQmlCustomParser
{
- virtual QByteArray compile(const QV4::CompiledData::QmlUnit *qmlUnit, const QList<const QV4::CompiledData::Binding *> &bindings);
- virtual void setCustomData(QObject *object, const QByteArray &data, QQmlCompiledData *);
+ virtual void verifyBindings(const QV4::CompiledData::QmlUnit *, const QList<const QV4::CompiledData::Binding *> &) {}
+ virtual void applyBindings(QObject *, QQmlCompiledData *, const QList<const QV4::CompiledData::Binding *> &);
};
class SimpleObjectWithCustomParser : public QObject
@@ -1142,10 +1144,29 @@ private:
int m_customBindingsCount;
};
+class SimpleObjectExtension : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(int extendedProperty READ extendedProperty WRITE setExtendedProperty NOTIFY extendedPropertyChanged)
+public:
+ SimpleObjectExtension(QObject *parent = 0)
+ : QObject(parent)
+ , m_extendedProperty(1584)
+ {}
+
+ void setExtendedProperty(int extendedProperty) { m_extendedProperty = extendedProperty; emit extendedPropertyChanged(); }
+ int extendedProperty() const { return m_extendedProperty; }
+
+signals:
+ void extendedPropertyChanged();
+private:
+ int m_extendedProperty;
+};
+
class SimpleObjectCustomParser : public QQmlCustomParser
{
- virtual QByteArray compile(const QV4::CompiledData::QmlUnit *, const QList<const QV4::CompiledData::Binding *> &bindings);
- virtual void setCustomData(QObject *object, const QByteArray &data, QQmlCompiledData *);
+ virtual void verifyBindings(const QV4::CompiledData::QmlUnit *, const QList<const QV4::CompiledData::Binding *> &) {}
+ virtual void applyBindings(QObject *, QQmlCompiledData *, const QList<const QV4::CompiledData::Binding *> &);
};
class RootObjectInCreationTester : public QObject
diff --git a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
index 7976987b58..8bc937d2bc 100644
--- a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
+++ b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
@@ -232,6 +232,7 @@ private slots:
void customParserBindingScopes();
void customParserEvaluateEnum();
void customParserProperties();
+ void customParserWithExtendedObject();
void preservePropertyCacheOnGroupObjects();
void propertyCacheInSync();
@@ -2359,7 +2360,8 @@ void tst_qqmllanguage::basicRemote()
QFETCH(QString, type);
QFETCH(QString, error);
- TestHTTPServer server(14447);
+ TestHTTPServer server;
+ QVERIFY2(server.listen(14447), qPrintable(server.errorString()));
server.serveDirectory(dataDirectory());
QQmlComponent component(&engine, url);
@@ -2403,7 +2405,8 @@ void tst_qqmllanguage::importsRemote()
QFETCH(QString, type);
QFETCH(QString, error);
- TestHTTPServer server(14447);
+ TestHTTPServer server;
+ QVERIFY2(server.listen(14447), qPrintable(server.errorString()));
server.serveDirectory(dataDirectory());
testType(qml,type,error);
@@ -2495,7 +2498,8 @@ void tst_qqmllanguage::importsInstalledRemote()
QFETCH(QString, type);
QFETCH(QString, error);
- TestHTTPServer server(14447);
+ TestHTTPServer server;
+ QVERIFY2(server.listen(14447), qPrintable(server.errorString()));
server.serveDirectory(dataDirectory());
QString serverdir = "http://127.0.0.1:14447/lib/";
@@ -2561,7 +2565,8 @@ void tst_qqmllanguage::importsPath()
QFETCH(QString, qml);
QFETCH(QString, value);
- TestHTTPServer server(14447);
+ TestHTTPServer server;
+ QVERIFY2(server.listen(14447), qPrintable(server.errorString()));
server.serveDirectory(dataDirectory());
engine.setImportPathList(QStringList(defaultImportPathList) << importPath);
@@ -3137,7 +3142,8 @@ void tst_qqmllanguage::registeredCompositeType()
// QTBUG-18268
void tst_qqmllanguage::remoteLoadCrash()
{
- TestHTTPServer server(14448);
+ TestHTTPServer server;
+ QVERIFY2(server.listen(14448), qPrintable(server.errorString()));
server.serveDirectory(dataDirectory());
QQmlComponent component(&engine);
@@ -3627,7 +3633,8 @@ void tst_qqmllanguage::compositeSingletonQmlDirError()
// Load a remote composite singleton type via qmldir that defines the type as a singleton
void tst_qqmllanguage::compositeSingletonRemote()
{
- TestHTTPServer server(14447);
+ TestHTTPServer server;
+ QVERIFY2(server.listen(14447), qPrintable(server.errorString()));
server.serveDirectory(dataDirectory());
QQmlComponent component(&engine, testFile("singletonTest15.qml"));
@@ -3718,6 +3725,24 @@ void tst_qqmllanguage::customParserProperties()
QVERIFY(!testObject->property("someObject").isNull());
}
+void tst_qqmllanguage::customParserWithExtendedObject()
+{
+ QQmlComponent component(&engine, testFile("customExtendedParserProperties.qml"));
+ VERIFY_ERRORS(0);
+ QScopedPointer<QObject> o(component.create());
+ QVERIFY(!o.isNull());
+ SimpleObjectWithCustomParser *testObject = qobject_cast<SimpleObjectWithCustomParser*>(o.data());
+ QVERIFY(testObject);
+ QCOMPARE(testObject->customBindingsCount(), 0);
+ QCOMPARE(testObject->intProperty(), 42);
+ QCOMPARE(testObject->property("qmlString").toString(), QStringLiteral("Hello"));
+ QVERIFY(!testObject->property("someObject").isNull());
+
+ QVariant returnValue;
+ QVERIFY(QMetaObject::invokeMethod(o.data(), "getExtendedProperty", Q_RETURN_ARG(QVariant, returnValue)));
+ QCOMPARE(returnValue.toInt(), 1584);
+}
+
void tst_qqmllanguage::preservePropertyCacheOnGroupObjects()
{
QQmlComponent component(&engine, testFile("preservePropertyCacheOnGroupObjects.qml"));
diff --git a/tests/auto/qml/qqmllistmodel/tst_qqmllistmodel.cpp b/tests/auto/qml/qqmllistmodel/tst_qqmllistmodel.cpp
index b37f0e3d26..ede80b355a 100644
--- a/tests/auto/qml/qqmllistmodel/tst_qqmllistmodel.cpp
+++ b/tests/auto/qml/qqmllistmodel/tst_qqmllistmodel.cpp
@@ -353,12 +353,12 @@ void tst_qqmllistmodel::dynamic_i18n_data()
QTest::newRow("qsTr")
<< QString::fromUtf8("ListElement { foo: qsTr(\"test\") }")
<< QVariant(QString::fromUtf8("test"))
- << QString("ListElement: cannot use script for property value");
+ << QString();
QTest::newRow("qsTrId")
<< "ListElement { foo: qsTrId(\"qtn_test\") }"
<< QVariant(QString("qtn_test"))
- << QString("ListElement: cannot use script for property value");
+ << QString();
}
void tst_qqmllistmodel::dynamic_i18n()
diff --git a/tests/auto/qml/qqmlmoduleplugin/tst_qqmlmoduleplugin.cpp b/tests/auto/qml/qqmlmoduleplugin/tst_qqmlmoduleplugin.cpp
index 15be1fdbc0..1861b37bea 100644
--- a/tests/auto/qml/qqmlmoduleplugin/tst_qqmlmoduleplugin.cpp
+++ b/tests/auto/qml/qqmlmoduleplugin/tst_qqmlmoduleplugin.cpp
@@ -247,8 +247,8 @@ void tst_qqmlmoduleplugin::importPluginWithQmlFile()
void tst_qqmlmoduleplugin::remoteImportWithQuotedUrl()
{
- TestHTTPServer server(SERVER_PORT);
- QVERIFY(server.isValid());
+ TestHTTPServer server;
+ QVERIFY2(server.listen(SERVER_PORT), qPrintable(server.errorString()));
server.serveDirectory(m_dataImportsDirectory);
QQmlEngine engine;
@@ -268,8 +268,8 @@ void tst_qqmlmoduleplugin::remoteImportWithQuotedUrl()
void tst_qqmlmoduleplugin::remoteImportWithUnquotedUri()
{
- TestHTTPServer server(SERVER_PORT);
- QVERIFY(server.isValid());
+ TestHTTPServer server;
+ QVERIFY2(server.listen(SERVER_PORT), qPrintable(server.errorString()));
server.serveDirectory(m_dataImportsDirectory);
QQmlEngine engine;
diff --git a/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp b/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp
index 27c3fd985e..fc4f7edcb8 100644
--- a/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp
+++ b/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp
@@ -46,7 +46,6 @@
#include <QtQml/private/qqmlproperty_p.h>
#include <private/qqmlbinding_p.h>
#include <private/qqmlboundsignal_p.h>
-#include <QtWidgets/QLineEdit>
#include <QtCore/qfileinfo.h>
#include <QtCore/qdir.h>
#include <QtCore/private/qobject_p.h>
diff --git a/tests/auto/qml/qqmlpropertymap/tst_qqmlpropertymap.cpp b/tests/auto/qml/qqmlpropertymap/tst_qqmlpropertymap.cpp
index b8c2ce4460..c0d66785bb 100644
--- a/tests/auto/qml/qqmlpropertymap/tst_qqmlpropertymap.cpp
+++ b/tests/auto/qml/qqmlpropertymap/tst_qqmlpropertymap.cpp
@@ -451,7 +451,7 @@ void tst_QQmlPropertyMap::disallowExtending()
obj.reset(component.create());
QVERIFY(obj.isNull());
QCOMPARE(component.errors().count(), 1);
- QCOMPARE(component.errors().at(0).toString(), QStringLiteral("<Unknown File>: Fully dynamic types cannot declare new properties."));
+ QCOMPARE(component.errors().at(0).toString(), QStringLiteral("<Unknown File>:3:1: Fully dynamic types cannot declare new properties."));
}
void tst_QQmlPropertyMap::QTBUG_35906()
diff --git a/tests/auto/qml/qqmlxmlhttprequest/tst_qqmlxmlhttprequest.cpp b/tests/auto/qml/qqmlxmlhttprequest/tst_qqmlxmlhttprequest.cpp
index 17becb3714..e1ccde2c42 100644
--- a/tests/auto/qml/qqmlxmlhttprequest/tst_qqmlxmlhttprequest.cpp
+++ b/tests/auto/qml/qqmlxmlhttprequest/tst_qqmlxmlhttprequest.cpp
@@ -240,13 +240,12 @@ void tst_qqmlxmlhttprequest::open()
QFETCH(QString, url);
QFETCH(bool, remote);
- QScopedPointer<TestHTTPServer> server; // ensure deletion in case test fails
+ TestHTTPServer server;
if (remote) {
- server.reset(new TestHTTPServer(SERVER_PORT));
- QVERIFY(server->isValid());
- QVERIFY(server->wait(testFileUrl("open_network.expect"),
- testFileUrl("open_network.reply"),
- testFileUrl("testdocument.html")));
+ QVERIFY2(server.listen(SERVER_PORT), qPrintable(server.errorString()));
+ QVERIFY(server.wait(testFileUrl("open_network.expect"),
+ testFileUrl("open_network.reply"),
+ testFileUrl("testdocument.html")));
}
QQmlComponent component(&engine, qmlFile);
@@ -322,8 +321,8 @@ void tst_qqmlxmlhttprequest::open_arg_count()
// Test valid setRequestHeader() calls
void tst_qqmlxmlhttprequest::setRequestHeader()
{
- TestHTTPServer server(SERVER_PORT);
- QVERIFY(server.isValid());
+ TestHTTPServer server;
+ QVERIFY2(server.listen(SERVER_PORT), qPrintable(server.errorString()));
QVERIFY(server.wait(testFileUrl("setRequestHeader.expect"),
testFileUrl("setRequestHeader.reply"),
testFileUrl("testdocument.html")));
@@ -340,8 +339,8 @@ void tst_qqmlxmlhttprequest::setRequestHeader()
// Test valid setRequestHeader() calls with different header cases
void tst_qqmlxmlhttprequest::setRequestHeader_caseInsensitive()
{
- TestHTTPServer server(SERVER_PORT);
- QVERIFY(server.isValid());
+ TestHTTPServer server;
+ QVERIFY2(server.listen(SERVER_PORT), qPrintable(server.errorString()));
QVERIFY(server.wait(testFileUrl("setRequestHeader.expect"),
testFileUrl("setRequestHeader.reply"),
testFileUrl("testdocument.html")));
@@ -397,8 +396,8 @@ void tst_qqmlxmlhttprequest::setRequestHeader_illegalName()
{
QFETCH(QString, name);
- TestHTTPServer server(SERVER_PORT);
- QVERIFY(server.isValid());
+ TestHTTPServer server;
+ QVERIFY2(server.listen(SERVER_PORT), qPrintable(server.errorString()));
QVERIFY(server.wait(testFileUrl("open_network.expect"),
testFileUrl("open_network.reply"),
testFileUrl("testdocument.html")));
@@ -423,8 +422,8 @@ void tst_qqmlxmlhttprequest::setRequestHeader_illegalName()
// Test that attempting to set a header after a request is sent throws an exception
void tst_qqmlxmlhttprequest::setRequestHeader_sent()
{
- TestHTTPServer server(SERVER_PORT);
- QVERIFY(server.isValid());
+ TestHTTPServer server;
+ QVERIFY2(server.listen(SERVER_PORT), qPrintable(server.errorString()));
QVERIFY(server.wait(testFileUrl("open_network.expect"),
testFileUrl("open_network.reply"),
testFileUrl("testdocument.html")));
@@ -475,8 +474,8 @@ void tst_qqmlxmlhttprequest::send_alreadySent()
void tst_qqmlxmlhttprequest::send_ignoreData()
{
{
- TestHTTPServer server(SERVER_PORT);
- QVERIFY(server.isValid());
+ TestHTTPServer server;
+ QVERIFY2(server.listen(SERVER_PORT), qPrintable(server.errorString()));
QVERIFY(server.wait(testFileUrl("send_ignoreData_GET.expect"),
testFileUrl("send_ignoreData.reply"),
testFileUrl("testdocument.html")));
@@ -492,8 +491,8 @@ void tst_qqmlxmlhttprequest::send_ignoreData()
}
{
- TestHTTPServer server(SERVER_PORT);
- QVERIFY(server.isValid());
+ TestHTTPServer server;
+ QVERIFY2(server.listen(SERVER_PORT), qPrintable(server.errorString()));
QVERIFY(server.wait(testFileUrl("send_ignoreData_HEAD.expect"),
testFileUrl("send_ignoreData.reply"),
QUrl()));
@@ -509,8 +508,8 @@ void tst_qqmlxmlhttprequest::send_ignoreData()
}
{
- TestHTTPServer server(SERVER_PORT);
- QVERIFY(server.isValid());
+ TestHTTPServer server;
+ QVERIFY2(server.listen(SERVER_PORT), qPrintable(server.errorString()));
QVERIFY(server.wait(testFileUrl("send_ignoreData_DELETE.expect"),
testFileUrl("send_ignoreData.reply"),
QUrl()));
@@ -532,8 +531,8 @@ void tst_qqmlxmlhttprequest::send_withdata()
QFETCH(QString, file_expected);
QFETCH(QString, file_qml);
- TestHTTPServer server(SERVER_PORT);
- QVERIFY(server.isValid());
+ TestHTTPServer server;
+ QVERIFY2(server.listen(SERVER_PORT), qPrintable(server.errorString()));
QVERIFY(server.wait(testFileUrl(file_expected),
testFileUrl("send_data.reply"),
testFileUrl("testdocument.html")));
@@ -602,8 +601,8 @@ void tst_qqmlxmlhttprequest::abort_opened()
// Test abort() aborts in progress send
void tst_qqmlxmlhttprequest::abort()
{
- TestHTTPServer server(SERVER_PORT);
- QVERIFY(server.isValid());
+ TestHTTPServer server;
+ QVERIFY2(server.listen(SERVER_PORT), qPrintable(server.errorString()));
QVERIFY(server.wait(testFileUrl("abort.expect"),
testFileUrl("abort.reply"),
testFileUrl("testdocument.html")));
@@ -626,8 +625,8 @@ void tst_qqmlxmlhttprequest::getResponseHeader()
{
QQmlEngine engine; // Avoid cookie contamination
- TestHTTPServer server(SERVER_PORT);
- QVERIFY(server.isValid());
+ TestHTTPServer server;
+ QVERIFY2(server.listen(SERVER_PORT), qPrintable(server.errorString()));
QVERIFY(server.wait(testFileUrl("getResponseHeader.expect"),
testFileUrl("getResponseHeader.reply"),
testFileUrl("testdocument.html")));
@@ -693,8 +692,8 @@ void tst_qqmlxmlhttprequest::getAllResponseHeaders()
{
QQmlEngine engine; // Avoid cookie contamination
- TestHTTPServer server(SERVER_PORT);
- QVERIFY(server.isValid());
+ TestHTTPServer server;
+ QVERIFY2(server.listen(SERVER_PORT), qPrintable(server.errorString()));
QVERIFY(server.wait(testFileUrl("getResponseHeader.expect"),
testFileUrl("getResponseHeader.reply"),
testFileUrl("testdocument.html")));
@@ -754,8 +753,8 @@ void tst_qqmlxmlhttprequest::status()
QFETCH(QUrl, replyUrl);
QFETCH(int, status);
- TestHTTPServer server(SERVER_PORT);
- QVERIFY(server.isValid());
+ TestHTTPServer server;
+ QVERIFY2(server.listen(SERVER_PORT), qPrintable(server.errorString()));
QVERIFY(server.wait(testFileUrl("status.expect"),
replyUrl,
testFileUrl("testdocument.html")));
@@ -793,8 +792,8 @@ void tst_qqmlxmlhttprequest::statusText()
QFETCH(QUrl, replyUrl);
QFETCH(QString, statusText);
- TestHTTPServer server(SERVER_PORT);
- QVERIFY(server.isValid());
+ TestHTTPServer server;
+ QVERIFY2(server.listen(SERVER_PORT), qPrintable(server.errorString()));
QVERIFY(server.wait(testFileUrl("status.expect"),
replyUrl,
testFileUrl("testdocument.html")));
@@ -833,8 +832,8 @@ void tst_qqmlxmlhttprequest::responseText()
QFETCH(QUrl, bodyUrl);
QFETCH(QString, responseText);
- TestHTTPServer server(SERVER_PORT);
- QVERIFY(server.isValid());
+ TestHTTPServer server;
+ QVERIFY2(server.listen(SERVER_PORT), qPrintable(server.errorString()));
QVERIFY(server.wait(testFileUrl("status.expect"),
replyUrl,
bodyUrl));
@@ -934,8 +933,8 @@ void tst_qqmlxmlhttprequest::invalidMethodUsage()
void tst_qqmlxmlhttprequest::redirects()
{
{
- TestHTTPServer server(SERVER_PORT);
- QVERIFY(server.isValid());
+ TestHTTPServer server;
+ QVERIFY2(server.listen(SERVER_PORT), qPrintable(server.errorString()));
server.addRedirect("redirect.html", "http://127.0.0.1:14445/redirecttarget.html");
server.serveDirectory(dataDirectory());
@@ -951,8 +950,8 @@ void tst_qqmlxmlhttprequest::redirects()
}
{
- TestHTTPServer server(SERVER_PORT);
- QVERIFY(server.isValid());
+ TestHTTPServer server;
+ QVERIFY2(server.listen(SERVER_PORT), qPrintable(server.errorString()));
server.addRedirect("redirect.html", "http://127.0.0.1:14445/redirectmissing.html");
server.serveDirectory(dataDirectory());
@@ -968,8 +967,8 @@ void tst_qqmlxmlhttprequest::redirects()
}
{
- TestHTTPServer server(SERVER_PORT);
- QVERIFY(server.isValid());
+ TestHTTPServer server;
+ QVERIFY2(server.listen(SERVER_PORT), qPrintable(server.errorString()));
server.addRedirect("redirect.html", "http://127.0.0.1:14445/redirect.html");
server.serveDirectory(dataDirectory());
@@ -1070,8 +1069,8 @@ void tst_qqmlxmlhttprequest::stateChangeCallingContext()
// ensure that we don't crash by attempting to evaluate
// without a valid calling context.
- TestHTTPServer server(SERVER_PORT);
- QVERIFY(server.isValid());
+ TestHTTPServer server;
+ QVERIFY2(server.listen(SERVER_PORT), qPrintable(server.errorString()));
server.serveDirectory(dataDirectory(), TestHTTPServer::Delay);
QQmlComponent component(&engine, testFileUrl("stateChangeCallingContext.qml"));
diff --git a/tests/auto/qml/qv4debugger/tst_qv4debugger.cpp b/tests/auto/qml/qv4debugger/tst_qv4debugger.cpp
index b7e5cf48e0..45652d7191 100644
--- a/tests/auto/qml/qv4debugger/tst_qv4debugger.cpp
+++ b/tests/auto/qml/qv4debugger/tst_qv4debugger.cpp
@@ -89,7 +89,7 @@ public:
QV4::Scope scope(v4);
QV4::Scoped<QV4::String> name(scope, v4->newString(functionName));
- QV4::ScopedValue function(scope, v4->newBuiltinFunction(v4->rootContext, name, injectedFunction));
+ QV4::ScopedValue function(scope, BuiltinFunction::create(v4->rootContext, name, injectedFunction));
v4->globalObject->put(name, function);
}
@@ -266,6 +266,7 @@ private slots:
void removePendingBreakPoint();
void addBreakPointWhilePaused();
void removeBreakPointForNextInstruction();
+ void conditionalBreakPoint();
// context access:
void readArguments();
@@ -393,7 +394,7 @@ void tst_qv4debugger::addBreakPointWhilePaused()
static QV4::ReturnedValue someCall(QV4::CallContext *ctx)
{
- ctx->engine->debugger->removeBreakPoint("removeBreakPointForNextInstruction", 2);
+ ctx->d()->engine->debugger->removeBreakPoint("removeBreakPointForNextInstruction", 2);
return QV4::Encode::undefined();
}
@@ -412,6 +413,29 @@ void tst_qv4debugger::removeBreakPointForNextInstruction()
QVERIFY(!m_debuggerAgent->m_wasPaused);
}
+void tst_qv4debugger::conditionalBreakPoint()
+{
+ m_debuggerAgent->m_captureContextInfo = true;
+ QString script =
+ "function test() {\n"
+ " for (var i = 0; i < 15; ++i) {\n"
+ " var x = i;\n"
+ " }\n"
+ "}\n"
+ "test()\n";
+
+ m_debuggerAgent->addBreakPoint("conditionalBreakPoint", 3, /*enabled*/true, QStringLiteral("i > 10"));
+ evaluateJavaScript(script, "conditionalBreakPoint");
+ QVERIFY(m_debuggerAgent->m_wasPaused);
+ QCOMPARE(m_debuggerAgent->m_statesWhenPaused.count(), 4);
+ QV4::Debugging::Debugger::ExecutionState state = m_debuggerAgent->m_statesWhenPaused.first();
+ QCOMPARE(state.fileName, QString("conditionalBreakPoint"));
+ QCOMPARE(state.lineNumber, 3);
+ QCOMPARE(m_debuggerAgent->m_capturedLocals[0].size(), 2);
+ QVERIFY(m_debuggerAgent->m_capturedLocals[0].contains(QStringLiteral("i")));
+ QCOMPARE(m_debuggerAgent->m_capturedLocals[0]["i"].toInt(), 11);
+}
+
void tst_qv4debugger::readArguments()
{
m_debuggerAgent->m_captureContextInfo = true;
diff --git a/tests/auto/qml/v4misc/tst_v4misc.cpp b/tests/auto/qml/v4misc/tst_v4misc.cpp
index 79ccdc9a4b..17f2fed3f9 100644
--- a/tests/auto/qml/v4misc/tst_v4misc.cpp
+++ b/tests/auto/qml/v4misc/tst_v4misc.cpp
@@ -139,7 +139,7 @@ void tst_v4misc::rangeSplitting_3()
interval.validate();
QCOMPARE(interval.end(), 71);
- LifeTimeInterval newInterval = interval.split(64, LifeTimeInterval::Invalid);
+ LifeTimeInterval newInterval = interval.split(64, LifeTimeInterval::InvalidPosition);
interval.validate();
newInterval.validate();
QVERIFY(!newInterval.isValid());