aboutsummaryrefslogtreecommitdiffstats
path: root/tests/auto/qml
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@qt.io>2020-12-10 18:07:26 +0100
committerUlf Hermann <ulf.hermann@qt.io>2020-12-18 14:23:29 +0100
commitd2e331dfa02475e773e51af6e7532951f4d1a233 (patch)
treed16f2ef9cfd363ff09d06fed70b226ccb212f3ca /tests/auto/qml
parent31211f1415f221ed1a974663fdde117fd6de357d (diff)
Allow JavaScript primitive type transformations inline in C++
We don't want to call into the engine just for adding two numbers. This implements the most common operators on primitive JavaScript values. More are to follow in the future. Change-Id: Id51a5af59a3af9fec78a2d8f293e59e6567e9204 Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Diffstat (limited to 'tests/auto/qml')
-rw-r--r--tests/auto/qml/.prev_CMakeLists.txt1
-rw-r--r--tests/auto/qml/CMakeLists.txt1
-rw-r--r--tests/auto/qml/qjsprimitivevalue/CMakeLists.txt15
-rw-r--r--tests/auto/qml/qjsprimitivevalue/qjsprimitivevalue.pro5
-rw-r--r--tests/auto/qml/qjsprimitivevalue/tst_qjsprimitivevalue.cpp226
-rw-r--r--tests/auto/qml/qml.pro1
6 files changed, 249 insertions, 0 deletions
diff --git a/tests/auto/qml/.prev_CMakeLists.txt b/tests/auto/qml/.prev_CMakeLists.txt
index 9e9d8299e2..40fd5a3795 100644
--- a/tests/auto/qml/.prev_CMakeLists.txt
+++ b/tests/auto/qml/.prev_CMakeLists.txt
@@ -6,6 +6,7 @@ qt_exclude_tool_directories_from_default_target(
)
add_subdirectory(parserstress)
+add_subdirectory(qjsprimitivevalue)
add_subdirectory(qjsvalueiterator)
add_subdirectory(qjsonbinding)
add_subdirectory(qqmlfile)
diff --git a/tests/auto/qml/CMakeLists.txt b/tests/auto/qml/CMakeLists.txt
index 3021a3201e..ed3706d760 100644
--- a/tests/auto/qml/CMakeLists.txt
+++ b/tests/auto/qml/CMakeLists.txt
@@ -6,6 +6,7 @@ qt_exclude_tool_directories_from_default_target(
)
add_subdirectory(parserstress)
+add_subdirectory(qjsprimitivevalue)
add_subdirectory(qjsvalueiterator)
add_subdirectory(qjsonbinding)
add_subdirectory(qqmlfile)
diff --git a/tests/auto/qml/qjsprimitivevalue/CMakeLists.txt b/tests/auto/qml/qjsprimitivevalue/CMakeLists.txt
new file mode 100644
index 0000000000..b2a1b8050c
--- /dev/null
+++ b/tests/auto/qml/qjsprimitivevalue/CMakeLists.txt
@@ -0,0 +1,15 @@
+# Generated from qjsprimitivevalue.pro.
+
+#####################################################################
+## tst_qjsprimitivevalue Test:
+#####################################################################
+
+qt_internal_add_test(tst_qjsprimitivevalue
+ SOURCES
+ tst_qjsprimitivevalue.cpp
+ PUBLIC_LIBRARIES
+ Qt::Qml
+)
+
+## Scopes:
+#####################################################################
diff --git a/tests/auto/qml/qjsprimitivevalue/qjsprimitivevalue.pro b/tests/auto/qml/qjsprimitivevalue/qjsprimitivevalue.pro
new file mode 100644
index 0000000000..c62bbe7b07
--- /dev/null
+++ b/tests/auto/qml/qjsprimitivevalue/qjsprimitivevalue.pro
@@ -0,0 +1,5 @@
+CONFIG += testcase
+TARGET = tst_qjsprimitivevalue
+macos:CONFIG -= app_bundle
+QT += qml
+SOURCES += tst_qjsprimitivevalue.cpp
diff --git a/tests/auto/qml/qjsprimitivevalue/tst_qjsprimitivevalue.cpp b/tests/auto/qml/qjsprimitivevalue/tst_qjsprimitivevalue.cpp
new file mode 100644
index 0000000000..b957e7a18b
--- /dev/null
+++ b/tests/auto/qml/qjsprimitivevalue/tst_qjsprimitivevalue.cpp
@@ -0,0 +1,226 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtCore/qobject.h>
+#include <QtQml/qjsengine.h>
+#include <QtQml/qjsprimitivevalue.h>
+
+#include <QtTest/qtest.h>
+
+class tst_QJSPrimitiveValue : public QObject
+{
+ Q_OBJECT
+
+private slots:
+ void operators_data();
+ void operators();
+
+private:
+ QJSEngine engine;
+
+ const QList<QJSPrimitiveValue> operands = {
+ QJSPrimitiveNull(), QJSPrimitiveUndefined(), true, false,
+ std::numeric_limits<int>::min(), -10, -1, 0, 1, 10, std::numeric_limits<int>::max(),
+ -std::numeric_limits<double>::infinity(), -100.1, -1.2, -0.0, 0.0, 1.2, 100.1,
+ std::numeric_limits<double>::infinity(), std::numeric_limits<double>::quiet_NaN()
+ };
+};
+
+template<typename T>
+QString toScriptString(T value)
+{
+ if constexpr (std::is_same_v<T, QString>) {
+ return u'"' + value + u'"';
+ } else {
+ if (value.type() == QJSPrimitiveValue::Double) {
+ // -0 is rendered as "0" in QJSValue's "toString()".
+ // However, we need the sign when constructing an expression to be evaluated.
+ const double result = value.toDouble();
+ if (qIsNull(result)) {
+ if (std::signbit(result))
+ return QStringLiteral("-0.0");
+ else
+ return QStringLiteral("0.0");
+ }
+ }
+ return value.toString();
+ }
+}
+
+void tst_QJSPrimitiveValue::operators_data()
+{
+ QTest::addColumn<QJSPrimitiveValue>("lhs");
+ QTest::addColumn<QJSPrimitiveValue>("rhs");
+
+ for (QJSPrimitiveValue l : operands) {
+ for (QJSPrimitiveValue r : operands)
+ QTest::newRow(qPrintable(toScriptString(l) + " x " + toScriptString(r))) << l << r ;
+ }
+}
+
+#define VERBOSECOMPARE(actual, expected) \
+do {\
+ if (!QTest::qCompare(actual, expected, #actual, #expected, __FILE__, __LINE__)) { \
+ qDebug() << "In" << Q_FUNC_INFO; \
+ return;\
+ } \
+} while (false)
+
+#define VERBOSEVERIFY(condition, expression, js) \
+ QVERIFY2(condition, qPrintable(expression + " -> " + js.toString()))
+
+enum Operator {
+ Add, Sub, Mul, Div, Eq, SEq, NEq, SNEq, GT, LT, GEq, LEq
+};
+
+QString toString(Operator op) {
+ switch (op) {
+ case Add: return "+";
+ case Sub: return "-";
+ case Mul: return "*";
+ case Div: return "/";
+ case Eq: return "==";
+ case SEq: return "===";
+ case NEq: return "!=";
+ case SNEq: return "!==";
+ case GT: return ">";
+ case LT: return "<";
+ case GEq: return ">=";
+ case LEq: return "<=";
+ }
+
+ Q_UNREACHABLE();
+ return QString();
+}
+
+template<typename LHS, typename RHS, typename Result, Operator op>
+void doTestOperator(QJSEngine *engine, LHS lhs, RHS rhs)
+{
+ Result result;
+
+ if constexpr (op == Add)
+ result = lhs + rhs;
+ else if constexpr (op == Sub)
+ result = lhs - rhs;
+ else if constexpr (op == Mul)
+ result = lhs * rhs;
+ else if constexpr (op == Div)
+ result = lhs / rhs;
+ else if constexpr (op == Eq)
+ result = QJSPrimitiveValue(lhs).equals(rhs);
+ else if constexpr (op == SEq)
+ result = lhs == rhs;
+ else if constexpr (op == NEq)
+ result = !QJSPrimitiveValue(lhs).equals(rhs);
+ else if constexpr (op == SNEq)
+ result = lhs != rhs;
+ else if constexpr (op == GT)
+ result = lhs > rhs;
+ else if constexpr (op == LT)
+ result = lhs < rhs;
+ else if constexpr (op == GEq)
+ result = lhs >= rhs;
+ else if constexpr (op == LEq)
+ result = lhs <= rhs;
+ else
+ QFAIL("Unkonwn operator");
+
+ const QString expression = toScriptString(lhs) + " " + toString(op) + " " + toScriptString(rhs);
+ const QJSValue js = engine->evaluate(expression);
+
+ if constexpr (std::is_same_v<Result, bool>) {
+ VERBOSEVERIFY(js.isBool(), expression, js);
+ VERBOSECOMPARE(js.toBool(), result);
+ } else if constexpr (std::is_same_v<Result, QString>) {
+ VERBOSEVERIFY(js.isString(), expression, js);
+ VERBOSECOMPARE(result, js.toString());
+ } else {
+ switch (result.type()) {
+ case QJSPrimitiveValue::Undefined:
+ VERBOSEVERIFY(js.isUndefined(), expression, js);
+ break;
+ case QJSPrimitiveValue::Null:
+ VERBOSEVERIFY(js.isNull(), expression, js);
+ break;
+ case QJSPrimitiveValue::Boolean:
+ VERBOSEVERIFY(js.isBool(), expression, js);
+ break;
+ case QJSPrimitiveValue::Integer:
+ VERBOSEVERIFY(js.isNumber(), expression, js);
+ break;
+ case QJSPrimitiveValue::Double:
+ VERBOSEVERIFY(js.isNumber(), expression, js);
+ break;
+ case QJSPrimitiveValue::String:
+ VERBOSEVERIFY(js.isString(), expression, js);
+ break;
+ default:
+ QFAIL("unexpected type");
+ }
+
+ VERBOSECOMPARE(result.toBoolean(), js.toBool());
+ VERBOSECOMPARE(result.toInteger(), js.toInt());
+ VERBOSECOMPARE(result.toDouble(), js.toNumber());
+ VERBOSECOMPARE(result.toString(), js.toString());
+ }
+}
+
+template<typename LHS, typename RHS>
+void doTestForAllOperators(QJSEngine *engine, LHS lhs, RHS rhs)
+{
+ doTestOperator<LHS, RHS, QJSPrimitiveValue, Add>(engine, lhs, rhs);
+ doTestOperator<LHS, RHS, QJSPrimitiveValue, Sub>(engine, lhs, rhs);
+ doTestOperator<LHS, RHS, QJSPrimitiveValue, Mul>(engine, lhs, rhs);
+ doTestOperator<LHS, RHS, QJSPrimitiveValue, Div>(engine, lhs, rhs);
+ doTestOperator<LHS, RHS, bool, Eq>(engine, lhs, rhs);
+ doTestOperator<LHS, RHS, bool, SEq>(engine, lhs, rhs);
+ doTestOperator<LHS, RHS, bool, NEq>(engine, lhs, rhs);
+ doTestOperator<LHS, RHS, bool, SNEq>(engine, lhs, rhs);
+ doTestOperator<LHS, RHS, bool, GT>(engine, lhs, rhs);
+ doTestOperator<LHS, RHS, bool, LT>(engine, lhs, rhs);
+ doTestOperator<LHS, RHS, bool, GEq>(engine, lhs, rhs);
+ doTestOperator<LHS, RHS, bool, LEq>(engine, lhs, rhs);
+}
+
+void tst_QJSPrimitiveValue::operators()
+{
+ QFETCH(QJSPrimitiveValue, lhs);
+ QFETCH(QJSPrimitiveValue, rhs);
+
+ doTestForAllOperators(&engine, lhs, rhs);
+ doTestForAllOperators(&engine, lhs.toString(), rhs);
+ doTestForAllOperators(&engine, lhs, rhs.toString());
+ doTestForAllOperators(&engine, lhs.toString() + " bar", rhs);
+ doTestForAllOperators(&engine, lhs, rhs.toString() + " bar");
+ doTestForAllOperators(&engine, "foo" + lhs.toString(), rhs);
+ doTestForAllOperators(&engine, lhs, "foo" + rhs.toString());
+}
+
+QTEST_MAIN(tst_QJSPrimitiveValue)
+
+#include "tst_qjsprimitivevalue.moc"
diff --git a/tests/auto/qml/qml.pro b/tests/auto/qml/qml.pro
index 5409361142..abbc786ee9 100644
--- a/tests/auto/qml/qml.pro
+++ b/tests/auto/qml/qml.pro
@@ -6,6 +6,7 @@ METATYPETESTS += \
PUBLICTESTS += \
parserstress \
+ qjsprimitivevalue \
qjsvalueiterator \
qjsonbinding \
qqmlfile \