aboutsummaryrefslogtreecommitdiffstats
path: root/tests/auto/qml/qmlcppcodegen
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@qt.io>2022-07-29 16:27:57 +0200
committerUlf Hermann <ulf.hermann@qt.io>2022-08-29 13:21:06 +0200
commitf4577447a1430180c41555979a606026786c3f04 (patch)
tree7b9cee2595fd273e5f5eecf4d5be5893474d945e /tests/auto/qml/qmlcppcodegen
parentcad5c89a0f0ebb24f17171fdbab8355832f0f415 (diff)
QmlCompiler: Implement remaining operators
Some of the math operators were still missing. Add them and test them all. Since the "runInterpreted()" test function takes too long now, split the qmlcppcodegen test in two: One that runs in compiled mode and one that runs in interpreted mode. Fixes: QTBUG-105188 Change-Id: I4b641d5e51b5a7e2a9254be40f257d7b249deb13 Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Diffstat (limited to 'tests/auto/qml/qmlcppcodegen')
-rw-r--r--tests/auto/qml/qmlcppcodegen/CMakeLists.txt12
-rw-r--r--tests/auto/qml/qmlcppcodegen/data/CMakeLists.txt1
-rw-r--r--tests/auto/qml/qmlcppcodegen/data/mathOperations.qml235
-rw-r--r--tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp257
4 files changed, 469 insertions, 36 deletions
diff --git a/tests/auto/qml/qmlcppcodegen/CMakeLists.txt b/tests/auto/qml/qmlcppcodegen/CMakeLists.txt
index 3486597f55..cf9095f956 100644
--- a/tests/auto/qml/qmlcppcodegen/CMakeLists.txt
+++ b/tests/auto/qml/qmlcppcodegen/CMakeLists.txt
@@ -12,3 +12,15 @@ qt_internal_add_test(tst_qmlcppcodegen
codegen_test_module
codegen_test_moduleplugin
)
+
+qt_internal_add_test(tst_qmlcppcodegen_interpreted
+ SOURCES
+ tst_qmlcppcodegen.cpp
+ LIBRARIES
+ Qt::QmlPrivate
+ Qt::Gui
+ codegen_test_module
+ codegen_test_moduleplugin
+ DEFINES
+ QT_TEST_FORCE_INTERPRETER
+)
diff --git a/tests/auto/qml/qmlcppcodegen/data/CMakeLists.txt b/tests/auto/qml/qmlcppcodegen/data/CMakeLists.txt
index 2fd929349e..e7774cb112 100644
--- a/tests/auto/qml/qmlcppcodegen/data/CMakeLists.txt
+++ b/tests/auto/qml/qmlcppcodegen/data/CMakeLists.txt
@@ -109,6 +109,7 @@ set(qml_files
listPropertyAsModel.qml
listlength.qml
math.qml
+ mathOperations.qml
methods.qml
modulePrefix.qml
moveRegVoid.qml
diff --git a/tests/auto/qml/qmlcppcodegen/data/mathOperations.qml b/tests/auto/qml/qmlcppcodegen/data/mathOperations.qml
new file mode 100644
index 0000000000..554fc71c13
--- /dev/null
+++ b/tests/auto/qml/qmlcppcodegen/data/mathOperations.qml
@@ -0,0 +1,235 @@
+pragma Strict
+import QtQml
+
+QtObject {
+ property double a
+ property double b
+
+ property int ia: a
+ property int ib: b
+
+ property bool ba: a
+ property bool bb: b
+
+ // unary double
+
+ property double d_unot: !a
+ property double d_uplus: +a
+ property double d_uminus: -a
+ property double d_ucompl: ~a
+ property double d_increment: {
+ var x = a;
+ return ++x;
+ }
+ property double d_decrement: {
+ var x = a;
+ return --x;
+ }
+
+ property double d_bitAndConst: a & 9
+ property double d_bitOrConst: a | 9
+ property double d_bitXorConst: a ^ 9
+
+ property double d_ushrConst: a >>> 9
+ property double d_shrConst: a >> 9
+ property double d_shlConst: a << 9
+
+ // unary bool
+
+ property double b_unot: !ba
+ property double b_uplus: +ba
+ property double b_uminus: -ba
+ property double b_ucompl: ~ba
+ property double b_increment: {
+ var x = ba;
+ return ++x;
+ }
+ property double b_decrement: {
+ var x = ba;
+ return --x;
+ }
+
+ property double b_bitAndConst: ba & 9
+ property double b_bitOrConst: ba | 9
+ property double b_bitXorConst: ba ^ 9
+
+ property double b_ushrConst: ba >>> 9
+ property double b_shrConst: ba >> 9
+ property double b_shlConst: ba << 9
+
+ // unary int
+
+ property double i_unot: !ia
+ property double i_uplus: +ia
+ property double i_uminus: -ia
+ property double i_ucompl: ~ia
+ property double i_increment: {
+ var x = ia;
+ return ++x;
+ }
+ property double i_decrement: {
+ var x = ia;
+ return --x;
+ }
+
+ property double i_bitAndConst: ia & 9
+ property double i_bitOrConst: ia | 9
+ property double i_bitXorConst: ia ^ 9
+
+ property double i_ushrConst: ia >>> 9
+ property double i_shrConst: ia >> 9
+ property double i_shlConst: ia << 9
+
+ // double/double
+
+ property double ddadd: a + b
+ property double ddsub: a - b
+ property double ddmul: a * b
+ property double dddiv: a / b
+ property double ddexp: a ** b
+ property double ddmod: a % b
+
+ property double ddbitAnd: a & b
+ property double ddbitOr: a | b
+ property double ddbitXor: a ^ b
+
+ property double ddushr: a >>> b
+ property double ddshr: a >> b
+ property double ddshl: a << b
+
+ // int/int
+
+ property double iiadd: ia + ib
+ property double iisub: ia - ib
+ property double iimul: ia * ib
+ property double iidiv: ia / ib
+ property double iiexp: ia ** ib
+ property double iimod: ia % ib
+
+ property double iibitAnd: ia & ib
+ property double iibitOr: ia | ib
+ property double iibitXor: ia ^ ib
+
+ property double iiushr: ia >>> ib
+ property double iishr: ia >> ib
+ property double iishl: ia << ib
+
+ // bool/bool
+
+ property double bbadd: ba + bb
+ property double bbsub: ba - bb
+ property double bbmul: ba * bb
+ property double bbdiv: ba / bb
+ property double bbexp: ba ** bb
+ property double bbmod: ba % bb
+
+ property double bbbitAnd: ba & bb
+ property double bbbitOr: ba | bb
+ property double bbbitXor: ba ^ bb
+
+ property double bbushr: ba >>> bb
+ property double bbshr: ba >> bb
+ property double bbshl: ba << bb
+
+ // int/double
+
+ property double idadd: ia + b
+ property double idsub: ia - b
+ property double idmul: ia * b
+ property double iddiv: ia / b
+ property double idexp: ia ** b
+ property double idmod: ia % b
+
+ property double idbitAnd: ia & b
+ property double idbitOr: ia | b
+ property double idbitXor: ia ^ b
+
+ property double idushr: ia >>> b
+ property double idshr: ia >> b
+ property double idshl: ia << b
+
+ // double/int
+
+ property double diadd: a + ib
+ property double disub: a - ib
+ property double dimul: a * ib
+ property double didiv: a / ib
+ property double diexp: a ** ib
+ property double dimod: a % ib
+
+ property double dibitAnd: a & ib
+ property double dibitOr: a | ib
+ property double dibitXor: a ^ ib
+
+ property double diushr: a >>> ib
+ property double dishr: a >> ib
+ property double dishl: a << ib
+
+ // bool/double
+
+ property double bdadd: ba + b
+ property double bdsub: ba - b
+ property double bdmul: ba * b
+ property double bddiv: ba / b
+ property double bdexp: ba ** b
+ property double bdmod: ba % b
+
+ property double bdbitAnd: ba & b
+ property double bdbitOr: ba | b
+ property double bdbitXor: ba ^ b
+
+ property double bdushr: ba >>> b
+ property double bdshr: ba >> b
+ property double bdshl: ba << b
+
+ // double/bool
+
+ property double dbadd: a + bb
+ property double dbsub: a - bb
+ property double dbmul: a * bb
+ property double dbdiv: a / bb
+ property double dbexp: a ** bb
+ property double dbmod: a % bb
+
+ property double dbbitAnd: a & bb
+ property double dbbitOr: a | bb
+ property double dbbitXor: a ^ bb
+
+ property double dbushr: a >>> bb
+ property double dbshr: a >> bb
+ property double dbshl: a << bb
+
+ // bool/int
+
+ property double biadd: ba + ib
+ property double bisub: ba - ib
+ property double bimul: ba * ib
+ property double bidiv: ba / ib
+ property double biexp: ba ** ib
+ property double bimod: ba % ib
+
+ property double bibitAnd: ba & ib
+ property double bibitOr: ba | ib
+ property double bibitXor: ba ^ ib
+
+ property double biushr: ba >>> ib
+ property double bishr: ba >> ib
+ property double bishl: ba << ib
+
+ // int/bool
+
+ property double ibadd: ia + bb
+ property double ibsub: ia - bb
+ property double ibmul: ia * bb
+ property double ibdiv: ia / bb
+ property double ibexp: ia ** bb
+ property double ibmod: ia % bb
+
+ property double ibbitAnd: ia & bb
+ property double ibbitOr: ia | bb
+ property double ibbitXor: ia ^ bb
+
+ property double ibushr: ia >>> bb
+ property double ibshr: ia >> bb
+ property double ibshl: ia << bb
+}
diff --git a/tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp b/tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp
index 746e373062..899cee2f80 100644
--- a/tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp
+++ b/tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp
@@ -23,6 +23,8 @@ class tst_QmlCppCodegen : public QObject
{
Q_OBJECT
private slots:
+ void initTestCase();
+
void simpleBinding();
void cppValueTypeList();
void anchorsFill();
@@ -39,7 +41,6 @@ private slots:
void excessiveParameters();
void jsImport();
void jsmoduleImport();
- void runInterpreted();
void methods();
void math();
void unknownParameter();
@@ -136,8 +137,16 @@ private slots:
void stringToByteArray();
void listPropertyAsModel();
void notNotString();
+ void mathOperations();
};
+void tst_QmlCppCodegen::initTestCase()
+{
+#ifdef QT_TEST_FORCE_INTERPRETER
+ qputenv("QV4_FORCE_INTERPRETER", "1");
+#endif
+}
+
void tst_QmlCppCodegen::simpleBinding()
{
QQmlEngine engine;
@@ -1595,6 +1604,25 @@ void tst_QmlCppCodegen::listIndices()
QCOMPARE(qvariant_cast<QObject *>(o->property("nan")), nullptr);
}
+static const double numbers[] = {
+ qQNaN(), -qInf(),
+ std::numeric_limits<double>::min(),
+ std::numeric_limits<float>::min(),
+ std::numeric_limits<qint32>::min(),
+ -1000.2, -100, -2, -1.333, -1, -0.84, -0.5,
+
+ // -0 and 0 are not different on the QML side. Therefore, don't keep them adjacent.
+ // Otherwise the bindings won't get re-evaluated.
+ std::copysign(0.0, -1), 1, 0.0,
+
+ 0.5, 0.77, 1.4545, 2, 199, 2002.13,
+ std::numeric_limits<qint32>::max(),
+ std::numeric_limits<quint32>::max(),
+ std::numeric_limits<float>::max(),
+ std::numeric_limits<double>::max(),
+ qInf()
+};
+
void tst_QmlCppCodegen::jsMathObject()
{
QQmlEngine engine;
@@ -1603,28 +1631,13 @@ void tst_QmlCppCodegen::jsMathObject()
QScopedPointer<QObject> o(c.create());
QVERIFY(o);
- const double inputs[] = {
- qQNaN(), -qInf(),
- std::numeric_limits<double>::min(),
- std::numeric_limits<float>::min(),
- std::numeric_limits<qint32>::min(),
- -1000.2, -100, -2, -1.333, -1, -0.84, -0.5,
- std::copysign(0.0, -1), 0.0,
- 0.5, 0.77, 1, 1.4545, 2, 199, 2002.13,
- std::numeric_limits<qint32>::max(),
- std::numeric_limits<quint32>::max(),
- std::numeric_limits<float>::max(),
- std::numeric_limits<double>::max(),
- qInf()
- };
-
QJSManagedValue math(engine.globalObject().property(QStringLiteral("Math")), &engine);
const QMetaObject *metaObject = o->metaObject();
QString name;
- for (double a : inputs) {
- for (double b : inputs) {
+ for (double a : numbers) {
+ for (double b : numbers) {
o->setProperty("a", a);
o->setProperty("b", b);
for (int i = 0, end = metaObject->propertyCount(); i != end; ++i) {
@@ -2484,27 +2497,199 @@ void tst_QmlCppCodegen::notNotString()
QCOMPARE(o->property("notNotString").value<bool>(), true);
}
-void tst_QmlCppCodegen::runInterpreted()
+template<typename T>
+QString toOperand(double arg);
+
+template<>
+QString toOperand<double>(double arg)
{
-#ifdef Q_OS_ANDROID
- QSKIP("Can't start QProcess to run a custom user binary on Android");
-#endif
+ if (qIsNull(arg))
+ return std::signbit(arg) ? QStringLiteral("(-0)") : QStringLiteral("(0)");
- if (qEnvironmentVariableIsSet("QV4_FORCE_INTERPRETER"))
- QSKIP("Already running in interpreted mode");
+ return u'(' + QJSPrimitiveValue(arg).toString() + u')';
+}
-#if QT_CONFIG(process)
- QProcess process;
- process.setProgram(QCoreApplication::applicationFilePath());
- process.setEnvironment(QProcess::systemEnvironment()
- + QStringList(u"QV4_FORCE_INTERPRETER=1"_s));
- process.start();
- QVERIFY(process.waitForFinished());
- QCOMPARE(process.exitStatus(), QProcess::NormalExit);
- QCOMPARE(process.exitCode(), 0);
-#else
- QSKIP("Test needs QProcess");
-#endif
+template<>
+QString toOperand<int>(double arg)
+{
+ const int iArg = QJSPrimitiveValue(arg).toInteger();
+ return u'(' + QJSPrimitiveValue(iArg).toString() + u')';
+}
+
+template<>
+QString toOperand<bool>(double arg)
+{
+ const bool bArg = QJSPrimitiveValue(arg).toBoolean();
+ return u'(' + QJSPrimitiveValue(bArg).toString() + u')';
+}
+
+template<typename T1, typename T2>
+double jsEval(double arg1, double arg2, const QString &op, QJSEngine *engine)
+{
+ auto evalBinary = [&](const QString &jsOp) {
+ return engine->evaluate(toOperand<T1>(arg1) + jsOp + toOperand<T2>(arg2)).toNumber();
+ };
+
+ auto evalBinaryConst = [&](const QString &jsOp) {
+ return engine->evaluate(toOperand<T1>(arg1) + jsOp + u'9').toNumber();
+ };
+
+ auto evalUnary = [&](const QString &jsOp) {
+ return engine->evaluate(jsOp + toOperand<T1>(arg1)).toNumber();
+ };
+
+ auto evalInPlace = [&](const QString &jsOp) {
+ return engine->evaluate(
+ u"(function() {var a = "_s + toOperand<T1>(arg1)+ u"; return "_s
+ + jsOp + u"a;})()"_s).toNumber();
+ };
+
+ if (op == u"unot")
+ return evalUnary(u"!"_s);
+ if (op == u"uplus")
+ return evalUnary(u"+"_s);
+ if (op == u"uminus")
+ return evalUnary(u"-"_s);
+ if (op == u"ucompl")
+ return evalUnary(u"~"_s);
+
+ if (op == u"increment")
+ return evalInPlace(u"++"_s);
+ if (op == u"decrement")
+ return evalInPlace(u"--"_s);
+
+ if (op == u"add")
+ return evalBinary(u"+"_s);
+ if (op == u"sub")
+ return evalBinary(u"-"_s);
+ if (op == u"mul")
+ return evalBinary(u"*"_s);
+ if (op == u"div")
+ return evalBinary(u"/"_s);
+ if (op == u"exp")
+ return evalBinary(u"**"_s);
+ if (op == u"mod")
+ return evalBinary(u"%"_s);
+
+ if (op == u"bitAnd")
+ return evalBinary(u"&"_s);
+ if (op == u"bitOr")
+ return evalBinary(u"|"_s);
+ if (op == u"bitXor")
+ return evalBinary(u"^"_s);
+
+ if (op == u"bitAndConst")
+ return evalBinaryConst(u"&"_s);
+ if (op == u"bitOrConst")
+ return evalBinaryConst(u"|"_s);
+ if (op == u"bitXorConst")
+ return evalBinaryConst(u"^"_s);
+
+ if (op == u"ushr")
+ return evalBinary(u">>>"_s);
+ if (op == u"shr")
+ return evalBinary(u">>"_s);
+ if (op == u"shl")
+ return evalBinary(u"<<"_s);
+
+ if (op == u"ushrConst")
+ return evalBinaryConst(u">>>"_s);
+ if (op == u"shrConst")
+ return evalBinaryConst(u">>"_s);
+ if (op == u"shlConst")
+ return evalBinaryConst(u"<<"_s);
+
+ qDebug() << op;
+ Q_UNREACHABLE();
+ return 0;
+}
+
+void tst_QmlCppCodegen::mathOperations()
+{
+ QQmlEngine engine;
+ QQmlComponent c(&engine, QUrl(u"qrc:/qt/qml/TestTypes/mathOperations.qml"_s));
+ QVERIFY2(c.isReady(), qPrintable(c.errorString()));
+ QScopedPointer<QObject> o(c.create());
+
+ const QMetaObject *metaObject = o->metaObject();
+
+ char t1;
+ char t2;
+ QString name;
+ const auto guard = qScopeGuard([&]() {
+ if (QTest::currentTestFailed()) {
+ qDebug() << t1 << t2 << name << "failed on:";
+ qDebug() << "doubles" << o->property("a").toDouble() << o->property("b").toDouble();
+ qDebug() << "integers" << o->property("ia").toInt() << o->property("ib").toInt();
+ qDebug() << "booleans" << o->property("ba").toBool() << o->property("bb").toBool();
+ }
+ });
+
+ for (double a : numbers) {
+ for (double b : numbers) {
+ o->setProperty("a", a);
+ o->setProperty("b", b);
+ for (int i = 0, end = metaObject->propertyCount(); i != end; ++i) {
+ const QMetaProperty prop = metaObject->property(i);
+ const QByteArray propName = prop.name();
+
+ if (propName.length() < 3 || propName == "objectName")
+ continue;
+
+ t1 = propName[0];
+ t2 = propName[1];
+ name = QString::fromUtf8(propName.mid(2));
+
+ double expected;
+
+ switch (t2) {
+ case 'd':
+ case '_':
+ switch (t1) {
+ case 'd':
+ expected = jsEval<double, double>(a, b, name, &engine);
+ break;
+ case 'i':
+ expected = jsEval<int, double>(a, b, name, &engine);
+ break;
+ case 'b':
+ expected = jsEval<bool, double>(a, b, name, &engine);
+ break;
+ }
+ break;
+ case 'i':
+ switch (t1) {
+ case 'd':
+ expected = jsEval<double, int>(a, b, name, &engine);
+ break;
+ case 'i':
+ expected = jsEval<int, int>(a, b, name, &engine);
+ break;
+ case 'b':
+ expected = jsEval<bool, int>(a, b, name, &engine);
+ break;
+ }
+ break;
+ case 'b':
+ switch (t1) {
+ case 'd':
+ expected = jsEval<double, bool>(a, b, name, &engine);
+ break;
+ case 'i':
+ expected = jsEval<int, bool>(a, b, name, &engine);
+ break;
+ case 'b':
+ expected = jsEval<bool, bool>(a, b, name, &engine);
+ break;
+ }
+ break;
+ }
+
+ const double result = prop.read(o.data()).toDouble();
+ QCOMPARE(result, expected);
+ }
+ }
+ }
}
QTEST_MAIN(tst_QmlCppCodegen)