#include <QtQml/qqmlcomponent.h>
#include <QtCore/qdebug.h>
#include <QtGui/qcolor.h>
+#include <QtCore/qnumeric.h>
#include <private/qv4compiler_p.h>
void mathMin();
void moduleApi();
+ void conversions_data();
+ void conversions();
+
+ void debuggingDumpInstructions(); // this test should be last.
+
private:
QQmlEngine engine;
};
QTest::newRow("unary minus") << "unaryMinus.qml";
QTest::newRow("null qobject") << "nullQObject.qml";
QTest::newRow("qobject -> bool") << "objectToBool.qml";
+ //QTest::newRow("conversion from bool") << "conversions.1.qml"; // QTBUG-24706
+ //QTest::newRow("conversion from int") << "conversions.2.qml"; // QTBUG-24706
+ QTest::newRow("conversion from float") << "conversions.3.qml";
+ //QTest::newRow("conversion from double") << "conversions.4.qml"; // QTBUG-24706
+ //QTest::newRow("conversion from real") << "conversions.5.qml"; // QTBUG-24706
+ //QTest::newRow("conversion from string") << "conversions.6.qml"; // QTBUG-24706
+ //QTest::newRow("conversion from url") << "conversions.7.qml"; // QTBUG-24706
+ QTest::newRow("conversion from vec3") << "conversions.8.qml";
}
void tst_v4::unnecessaryReeval()
delete o;
}
+void tst_v4::conversions_data()
+{
+ QTest::addColumn<QUrl>("file");
+ QTest::addColumn<QStringList>("warnings");
+ QTest::addColumn<bool>("boolProp");
+ QTest::addColumn<int>("intProp");
+ QTest::addColumn<float>("floatProp");
+ QTest::addColumn<double>("doubleProp");
+ QTest::addColumn<qreal>("qrealProp");
+ QTest::addColumn<QString>("qstringProp");
+ QTest::addColumn<QUrl>("qurlProp");
+ QTest::addColumn<QVector3D>("vec3Prop");
+
+ QTest::newRow("from bool") << testFileUrl("conversions.1.qml")
+ << (QStringList())
+ << true
+ << (int)true
+ << (float)1.0
+ << (double)1.0
+ << (qreal)1.0
+ << QString(QLatin1String("true"))
+ << QUrl(testFileUrl("").toString() + QString(QLatin1String("true")))
+ << QVector3D(1, 1, 1);
+
+ QTest::newRow("from integer") << testFileUrl("conversions.2.qml")
+ << (QStringList())
+ << (bool)4
+ << 4
+ << (float)4.0
+ << (double)4.0
+ << (qreal)4.0
+ << QString(QLatin1String("4"))
+ << QUrl(testFileUrl("").toString() + QString(QLatin1String("4")))
+ << QVector3D(4, 4, 4);
+
+ QTest::newRow("from float") << testFileUrl("conversions.3.qml")
+ << (QStringList() << (testFileUrl("conversions.3.qml").toString() + QLatin1String(":11: Unable to assign double to QUrl")))
+ << (bool)4.4
+ << (int)4.4
+ << (float)4.4
+ << (double)((float)4.4)
+ << (qreal)((float)4.4)
+ << QString::number((double)((float)4.4), 'g', 15)
+ << QUrl() // cannot assign double to url.
+ << QVector3D(4.4, 4.4, 4.4);
+
+ QTest::newRow("from double") << testFileUrl("conversions.4.qml")
+ << (QStringList())
+ << (bool)4.444444444
+ << (int)4.444444444
+ << (float)4.444444444
+ << (double)4.444444444
+ << (qreal)4.444444444
+ << QString::number((double)4.444444444)
+ << QUrl(testFileUrl("").toString() + QString::number((double)4.444444444))
+ << QVector3D(4.444444444, 4.444444444, 4.444444444);
+
+ QTest::newRow("from qreal") << testFileUrl("conversions.5.qml")
+ << (QStringList())
+ << (bool)4.44
+ << (int)4.44
+ << (float)4.44
+ << (double)4.44
+ << (qreal)4.44
+ << QString(QLatin1String("4.44"))
+ << QUrl(testFileUrl("").toString() + QString(QLatin1String("4.44")))
+ << QVector3D(4.44, 4.44, 4.44);
+
+ QTest::newRow("from string") << testFileUrl("conversions.6.qml")
+ << (QStringList())
+ << true
+ << 4
+ << (float)4.0
+ << (double)4.0
+ << (qreal)4.0
+ << QString(QLatin1String("4"))
+ << QUrl(testFileUrl("").toString() + QString(QLatin1String("4")))
+ << QVector3D(4, 4, 4);
+
+ /*
+ //XXX TODO: QTBUG-24706
+ QTest::newRow("from url") << testFileUrl("conversions.7.qml")
+ << (QStringList() << (testFileUrl("conversions.7.qml").toString() + QLatin1String(":7: Unable to assign QUrl to float")))
+ << true
+ << 0 // a url like "4" actually gets the value "file:///path/to/test/4"
+ << (float)0 // and the url.toString().toInt()/toDouble() of that is zero/qQNaN().
+ << (double)0
+ << (qreal)0
+ << QString(testFileUrl("").toString() + QString(QLatin1String("4")))
+ << QUrl(testFileUrl("").toString() + QString(QLatin1String("4")))
+ << QVector3D(0, 0, 0);
+ */
+
+ QTest::newRow("from vector") << testFileUrl("conversions.8.qml")
+ << (QStringList() << (testFileUrl("conversions.8.qml").toString() + QLatin1String(":11: Unable to assign QVector3D to QUrl"))
+ << (testFileUrl("conversions.8.qml").toString() + QLatin1String(":10: Unable to assign QVector3D to QString"))
+ << (testFileUrl("conversions.8.qml").toString() + QLatin1String(":9: Unable to assign QVector3D to double"))
+ << (testFileUrl("conversions.8.qml").toString() + QLatin1String(":8: Unable to assign QVector3D to double"))
+ << (testFileUrl("conversions.8.qml").toString() + QLatin1String(":7: Unable to assign QVector3D to float"))
+ << (testFileUrl("conversions.8.qml").toString() + QLatin1String(":6: Unable to assign QVector3D to int")))
+ << true // non-null therefore true
+ << (int)0 // the other values should be the default-ctor values.
+ << (float)0
+ << (double)0
+ << (qreal)0
+ << QString()
+ << QUrl()
+ << QVector3D(4, 4, 4); // except this one.
+}
+
+void tst_v4::conversions()
+{
+ QFETCH(QUrl, file);
+ QFETCH(QStringList, warnings);
+ QFETCH(bool, boolProp);
+ QFETCH(int, intProp);
+ QFETCH(float, floatProp);
+ QFETCH(double, doubleProp);
+ QFETCH(qreal, qrealProp);
+ QFETCH(QString, qstringProp);
+ QFETCH(QUrl, qurlProp);
+ QFETCH(QVector3D, vec3Prop);
+
+ foreach (const QString &w, warnings)
+ QTest::ignoreMessage(QtWarningMsg, qPrintable(w));
+
+ QQmlComponent component(&engine, file);
+ QObject *o = component.create();
+ QVERIFY(o != 0);
+ QCOMPARE(o->property("boolProp"), QVariant::fromValue<bool>(boolProp));
+ QCOMPARE(o->property("intProp"), QVariant::fromValue<int>(intProp));
+ QCOMPARE(o->property("floatProp"), QVariant::fromValue<float>(floatProp));
+ QCOMPARE(o->property("doubleProp"), QVariant::fromValue<double>(doubleProp));
+ QCOMPARE(o->property("qrealProp"), QVariant::fromValue<qreal>(qrealProp));
+ QCOMPARE(o->property("qstringProp"), QVariant::fromValue<QString>(qstringProp));
+ QCOMPARE(o->property("qurlProp"), QVariant::fromValue<QUrl>(qurlProp));
+ QCOMPARE(o->property("vec3Prop"), QVariant::fromValue<QVector3D>(vec3Prop));
+ delete o;
+}
+
+
+static QStringList messages;
+static void msgHandler(QtMsgType, const char *msg)
+{
+ messages << QLatin1String(msg);
+}
+
+static QByteArray getAddress(int address)
+{
+ return QByteArray::number(address);
+}
+
+static QByteArray getLeading(int address)
+{
+ QByteArray leading;
+ if (address != -1) {
+ leading = getAddress(address);
+ leading.prepend(QByteArray(8 - leading.count(), ' '));
+ }
+ return leading;
+}
+
+#include <private/qv4instruction_p.h>
+void tst_v4::debuggingDumpInstructions()
+{
+ QStringList expectedPreAddress;
+ expectedPreAddress << "\t\tNoop";
+ expectedPreAddress << "\t0:0:";
+ expectedPreAddress << "\t\tSubscribe\t\tObject_Reg(0) Notify_Signal(0) -> Subscribe_Slot(0)";
+ expectedPreAddress << "\t\tSubscribeId\t\tId_Offset(0) -> Subscribe_Slot(0)";
+ expectedPreAddress << "\t\tFetchAndSubscribe\tObject_Reg(0) Fast_Accessor(0x0) -> Output_Reg(0) Subscription_Slot(0)";
+ expectedPreAddress << "\t\tLoadId\t\t\tId_Offset(0) -> Output_Reg(0)";
+ expectedPreAddress << "\t\tLoadScope\t\t-> Output_Reg(0)";
+ expectedPreAddress << "\t\tLoadRoot\t\t-> Output_Reg(0)";
+ expectedPreAddress << "\t\tLoadModuleObject\t\t) -> Output_Reg(0)";
+ expectedPreAddress << "\t\tLoadAttached\t\tObject_Reg(0) Attached_Index(0) -> Output_Reg(0)";
+ expectedPreAddress << "\t\tUnaryNot\t\tInput_Reg(0) -> Output_Reg(0)";
+ expectedPreAddress << "\t\tUnaryMinusReal\t\tInput_Reg(0) -> Output_Reg(0)";
+ expectedPreAddress << "\t\tUnaryMinusInt\t\tInput_Reg(0) -> Output_Reg(0)";
+ expectedPreAddress << "\t\tUnaryPlusReal\t\tInput_Reg(0) -> Output_Reg(0)";
+ expectedPreAddress << "\t\tUnaryPlusInt\t\tInput_Reg(0) -> Output_Reg(0)";
+ expectedPreAddress << "\t\tConvertBoolToInt\tInput_Reg(0) -> Output_Reg(0)";
+ expectedPreAddress << "\t\tConvertBoolToReal\tInput_Reg(0) -> Output_Reg(0)";
+ expectedPreAddress << "\t\tConvertBoolToString\tInput_Reg(0) -> Output_Reg(0)";
+ expectedPreAddress << "\t\tConvertIntToBool\tInput_Reg(0) -> Output_Reg(0)";
+ expectedPreAddress << "\t\tConvertIntToReal\tInput_Reg(0) -> Output_Reg(0)";
+ expectedPreAddress << "\t\tConvertIntToString\tInput_Reg(0) -> Output_Reg(0)";
+ expectedPreAddress << "\t\tConvertRealToBool\tInput_Reg(0) -> Output_Reg(0)";
+ expectedPreAddress << "\t\tConvertRealToInt\tInput_Reg(0) -> Output_Reg(0)";
+ expectedPreAddress << "\t\tConvertRealToString\tInput_Reg(0) -> Output_Reg(0)";
+ expectedPreAddress << "\t\tConvertStringToBool\tInput_Reg(0) -> Output_Reg(0)";
+ expectedPreAddress << "\t\tConvertStringToInt\tInput_Reg(0) -> Output_Reg(0)";
+ expectedPreAddress << "\t\tConvertStringToReal\tInput_Reg(0) -> Output_Reg(0)";
+ expectedPreAddress << "\t\tConvertStringToUrl\tInput_Reg(0) -> Output_Reg(0)";
+ expectedPreAddress << "\t\tConvertStringToColor\tInput_Reg(0) -> Output_Reg(0)";
+ expectedPreAddress << "\t\tConvertUrlToBool\tInput_Reg(0) -> Output_Reg(0)";
+ expectedPreAddress << "\t\tConvertUrlToString\tInput_Reg(0) -> Output_Reg(0)";
+ expectedPreAddress << "\t\tConvertColorToBool\tInput_Reg(0) -> Output_Reg(0)";
+ expectedPreAddress << "\t\tConvertColorToString\tInput_Reg(0) -> Output_Reg(0)";
+ expectedPreAddress << "\t\tConvertObjectToBool\tInput_Reg(0) -> Output_Reg(0)";
+ expectedPreAddress << "\t\tConvertNullToObject\tInput_Reg(0) -> Output_Reg(0)";
+ expectedPreAddress << "\t\tResolveUrl\t\tInput_Reg(0) -> Output_Reg(0)";
+ expectedPreAddress << "\t\tMathSinReal\t\tInput_Reg(0) -> Output_Reg(0)";
+ expectedPreAddress << "\t\tMathCosReal\t\tInput_Reg(0) -> Output_Reg(0)";
+ expectedPreAddress << "\t\tMathAbsReal\t\tInput_Reg(0) -> Output_Reg(0)";
+ expectedPreAddress << "\t\tMathRoundReal\t\tInput_Reg(0) -> Output_Reg(0)";
+ expectedPreAddress << "\t\tMathFloorReal\t\tInput_Reg(0) -> Output_Reg(0)";
+ expectedPreAddress << "\t\tMathCeilReal\t\tInput_Reg(0) -> Output_Reg(0)";
+ expectedPreAddress << "\t\tMathPIReal\t\tInput_Reg(0) -> Output_Reg(0)";
+ expectedPreAddress << "\t\tLoadNull\t\tConstant(null) -> Output_Reg(0)";
+ expectedPreAddress << "\t\tLoadReal\t\tConstant(0) -> Output_Reg(0)";
+ expectedPreAddress << "\t\tLoadInt\t\t\tConstant(0) -> Output_Reg(0)";
+ expectedPreAddress << "\t\tLoadBool\t\tConstant(false) -> Output_Reg(0)";
+ expectedPreAddress << "\t\tLoadString\t\tString_DataIndex(0) String_Length(0) -> Output_Register(0)";
+ expectedPreAddress << "\t\tEnableV4Test\t\tString_DataIndex(0) String_Length(0)";
+ expectedPreAddress << "\t\tTestV4Store\t\tInput_Reg(0) Reg_Type(0)";
+ expectedPreAddress << "\t\tBitAndInt\t\tInput_Reg(0) Input_Reg(0) -> Output_Reg(0)";
+ expectedPreAddress << "\t\tBitOrInt\t\tInput_Reg(0) Input_Reg(0) -> Output_Reg(0)";
+ expectedPreAddress << "\t\tBitXorInt\t\tInput_Reg(0) Input_Reg(0) -> Output_Reg(0)";
+ expectedPreAddress << "\t\tAddReal\t\t\tInput_Reg(0) Input_Reg(0) -> Output_Reg(0)";
+ expectedPreAddress << "\t\tAddString\t\tInput_Reg(0) Input_Reg(0) -> Output_Reg(0)";
+ expectedPreAddress << "\t\tSubReal\t\t\tInput_Reg(0) Input_Reg(0) -> Output_Reg(0)";
+ expectedPreAddress << "\t\tMulReal\t\t\tInput_Reg(0) Input_Reg(0) -> Output_Reg(0)";
+ expectedPreAddress << "\t\tDivReal\t\t\tInput_Reg(0) Input_Reg(0) -> Output_Reg(0)";
+ expectedPreAddress << "\t\tModReal\t\t\tInput_Reg(0) Input_Reg(0) -> Output_Reg(0)";
+ expectedPreAddress << "\t\tLShiftInt\t\tInput_Reg(0) Input_Reg(0) -> Output_Reg(0)";
+ expectedPreAddress << "\t\tRShiftInt\t\tInput_Reg(0) Input_Reg(0) -> Output_Reg(0)";
+ expectedPreAddress << "\t\tURShiftInt\t\tInput_Reg(0) Input_Reg(0) -> Output_Reg(0)";
+ expectedPreAddress << "\t\tGtReal\t\t\tInput_Reg(0) Input_Reg(0) -> Output_Reg(0)";
+ expectedPreAddress << "\t\tLtReal\t\t\tInput_Reg(0) Input_Reg(0) -> Output_Reg(0)";
+ expectedPreAddress << "\t\tGeReal\t\t\tInput_Reg(0) Input_Reg(0) -> Output_Reg(0)";
+ expectedPreAddress << "\t\tLeReal\t\t\tInput_Reg(0) Input_Reg(0) -> Output_Reg(0)";
+ expectedPreAddress << "\t\tEqualReal\t\tInput_Reg(0) Input_Reg(0) -> Output_Reg(0)";
+ expectedPreAddress << "\t\tNotEqualReal\t\tInput_Reg(0) Input_Reg(0) -> Output_Reg(0)";
+ expectedPreAddress << "\t\tStrictEqualReal\t\tInput_Reg(0) Input_Reg(0) -> Output_Reg(0)";
+ expectedPreAddress << "\t\tStrictNotEqualReal\tInput_Reg(0) Input_Reg(0) -> Output_Reg(0)";
+ expectedPreAddress << "\t\tGtString\t\tInput_Reg(0) Input_Reg(0) -> Output_Reg(0)";
+ expectedPreAddress << "\t\tLtString\t\tInput_Reg(0) Input_Reg(0) -> Output_Reg(0)";
+ expectedPreAddress << "\t\tGeString\t\tInput_Reg(0) Input_Reg(0) -> Output_Reg(0)";
+ expectedPreAddress << "\t\tLeString\t\tInput_Reg(0) Input_Reg(0) -> Output_Reg(0)";
+ expectedPreAddress << "\t\tEqualString\t\tInput_Reg(0) Input_Reg(0) -> Output_Reg(0)";
+ expectedPreAddress << "\t\tNotEqualString\t\tInput_Reg(0) Input_Reg(0) -> Output_Reg(0)";
+ expectedPreAddress << "\t\tStrictEqualString\tInput_Reg(0) Input_Reg(0) -> Output_Reg(0)";
+ expectedPreAddress << "\t\tStrictNotEqualString\tInput_Reg(0) Input_Reg(0) -> Output_Reg(0)";
+ expectedPreAddress << "\t\tEqualObject\t\tInput_Reg(0) Input_Reg(0) -> Output_Reg(0)";
+ expectedPreAddress << "\t\tNotEqualObject\t\tInput_Reg(0) Input_Reg(0) -> Output_Reg(0)";
+ expectedPreAddress << "\t\tStrictEqualObject\tInput_Reg(0) Input_Reg(0) -> Output_Reg(0)";
+ expectedPreAddress << "\t\tStrictNotEqualObject\tInput_Reg(0) Input_Reg(0) -> Output_Reg(0)";
+ expectedPreAddress << "\t\tMathMaxReal\tInput_Reg(0) Input_Reg(0) -> Output_Reg(0)";
+ expectedPreAddress << "\t\tMathMinReal\tInput_Reg(0) Input_Reg(0) -> Output_Reg(0)";
+ expectedPreAddress << "\t\tNewString\t\tRegister(0)";
+ expectedPreAddress << "\t\tNewUrl\t\t\tRegister(0)";
+ expectedPreAddress << "\t\tCleanupRegister\t\tRegister(0)";
+ expectedPreAddress << "\t\tCopy\t\t\tInput_Reg(0) -> Output_Reg(0)";
+ expectedPreAddress << "\t\tFetch\t\t\tObject_Reg(0) Property_Index(0) -> Output_Reg(0)";
+ expectedPreAddress << "\t\tStore\t\t\tInput_Reg(0) -> Object_Reg(0) Property_Index(0)";
+ expectedPreAddress << "\t\tJump\t\t\tAddress(UNIT_TEST_JUMP_ADDRESS) [if false == Input_Reg(0)]"; //(address + size() + i->jump.count)
+ expectedPreAddress << "\t\tBranchTrue\t\tAddress(UNIT_TEST_BRANCH_ADDRESS) [if true == Input_Reg(0)]"; //(address + size() + i->branchop.offset)
+ expectedPreAddress << "\t\tBranchFalse\t\tAddress(UNIT_TEST_BRANCH_ADDRESS) [if false == Input_Reg(0)]"; //(address + size() + i->branchop.offset)
+ expectedPreAddress << "\t\tBranch\t\t\tAddress(UNIT_TEST_BRANCH_ADDRESS)"; //(address + size() + i->branchop.offset)
+ expectedPreAddress << "\t\tBlock\t\t\tMask(0)";
+ expectedPreAddress << "\t\tInitString\t\tString_DataIndex(0) -> String_Slot(0)";
+ QStringList expected;
+
+ messages = QStringList();
+ QtMsgHandler old = qInstallMsgHandler(msgHandler);
+
+ QQmlJS::Bytecode bc;
+#define DUMP_INSTR_IN_UNIT_TEST(I, FMT) { QQmlJS::V4InstrData<QQmlJS::V4Instr::I> i; memset(&i, 0, sizeof(i)); bc.append(i); }
+ FOR_EACH_V4_INSTR(DUMP_INSTR_IN_UNIT_TEST);
+#undef DUMP_INSTR_IN_UNIT_TEST // NOTE: we memset in order to ensure stable output.
+ const char *start = bc.constData();
+ const char *end = start + bc.size();
+ const char *codeAddr = start;
+ int whichExpected = 0;
+#define DUMP_INSTR_SIZE_IN_UNIT_TEST(I, FMT) { \
+ QString currExpected = expectedPreAddress.at(whichExpected++); \
+ currExpected.prepend(getLeading(codeAddr - start)); \
+ expected.append(currExpected); \
+ codeAddr += QQmlJS::V4Instr::size(static_cast<QQmlJS::V4Instr::Type>(QQmlJS::V4Instr::I)); \
+ }
+ FOR_EACH_V4_INSTR(DUMP_INSTR_SIZE_IN_UNIT_TEST);
+#undef DUMP_INSTR_SIZE_IN_UNIT_TEST // so that we generate the correct address for each instruction comparison
+ bc.dump(start, end);
+
+ // ensure that the output was expected.
+ qInstallMsgHandler(old);
+ QCOMPARE(messages.count(), expected.count());
+ for (int ii = 0; ii < messages.count(); ++ii) {
+ // Calculating the destination address of a null jump/branch instruction is tricky
+ // so instead we simply don't compare that part of those instructions.
+ QRegExp ignoreAddress("\\bAddress\\((\\w*)\\)");
+ ignoreAddress.setMinimal(true);
+ QString expectOut = expected.at(ii); expectOut.replace(ignoreAddress, "");
+ QString actualOut = messages.at(ii); actualOut.replace(ignoreAddress, "");
+ QCOMPARE(actualOut, expectOut);
+ }
+}
+
+
QTEST_MAIN(tst_v4)
#include "tst_v4.moc"