// Copyright (C) 2020 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include #include #include #include class tst_QJSPrimitiveValue : public QObject { Q_OBJECT private slots: void binaryOperators_data(); void binaryOperators(); void unaryOperators_data(); void unaryOperators(); void toFromVariant(); void coercion(); void ctor_invalid(); void ctor_undefinedWithEngine(); void ctor_boolWithEngine(); void ctor_intWithEngine(); void ctor_stringWithEngine(); void ctor_copyAndAssignWithEngine(); void toString(); void toNumber(); void toBoolean(); void toVariant(); void equals(); void strictlyEquals(); void stringAndUrl(); void negativeNullMult(); private: QJSEngine engine; const QList operands = { QJSPrimitiveNull(), QJSPrimitiveUndefined(), true, false, std::numeric_limits::min(), -10, -1, 0, 1, 10, std::numeric_limits::max(), -std::numeric_limits::infinity(), -100.1, -1.2, -0.0, 0.0, 1.2, 100.1, std::numeric_limits::infinity(), std::numeric_limits::quiet_NaN() }; }; template QString toScriptString(T value) { if constexpr (std::is_same_v) { 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"); } } else if (value.type() == QJSPrimitiveValue::String) { return u'"' + value.toString() + u'"'; } return value.toString(); } } void tst_QJSPrimitiveValue::binaryOperators_data() { QTest::addColumn("lhs"); QTest::addColumn("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 BinaryOperator { Add, Sub, Mul, Div, Eq, SEq, NEq, SNEq, GT, LT, GEq, LEq, Mod }; QString toString(BinaryOperator 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 "<="; case Mod: return "%"; } Q_UNREACHABLE_RETURN(QString()); } template void verifyResult(Result result, QJSEngine *engine, const QString &expression) { const QJSValue js = engine->evaluate(expression); if constexpr (std::is_same_v) { VERBOSEVERIFY(js.isBool(), expression, js); VERBOSECOMPARE(js.toBool(), result); } else if constexpr (std::is_same_v) { 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 void doTestBinaryOperator(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 if constexpr (op == Mod) result = lhs % rhs; else QFAIL("Unkonwn operator"); const QString expression = toScriptString(lhs) + " " + toString(op) + " " + toScriptString(rhs); verifyResult(result, engine, expression); } template void doTestForAllBinaryOperators(QJSEngine *engine, LHS lhs, RHS rhs) { doTestBinaryOperator(engine, lhs, rhs); doTestBinaryOperator(engine, lhs, rhs); doTestBinaryOperator(engine, lhs, rhs); doTestBinaryOperator(engine, lhs, rhs); doTestBinaryOperator(engine, lhs, rhs); doTestBinaryOperator(engine, lhs, rhs); doTestBinaryOperator(engine, lhs, rhs); doTestBinaryOperator(engine, lhs, rhs); doTestBinaryOperator(engine, lhs, rhs); doTestBinaryOperator(engine, lhs, rhs); doTestBinaryOperator(engine, lhs, rhs); doTestBinaryOperator(engine, lhs, rhs); doTestBinaryOperator(engine, lhs, rhs); } void tst_QJSPrimitiveValue::binaryOperators() { QFETCH(QJSPrimitiveValue, lhs); QFETCH(QJSPrimitiveValue, rhs); doTestForAllBinaryOperators(&engine, lhs, rhs); doTestForAllBinaryOperators(&engine, lhs.toString(), rhs); doTestForAllBinaryOperators(&engine, lhs, rhs.toString()); doTestForAllBinaryOperators(&engine, lhs.toString() + " bar", rhs); doTestForAllBinaryOperators(&engine, lhs, rhs.toString() + " bar"); doTestForAllBinaryOperators(&engine, "foo" + lhs.toString(), rhs); doTestForAllBinaryOperators(&engine, lhs, "foo" + rhs.toString()); } void tst_QJSPrimitiveValue::unaryOperators_data() { QTest::addColumn("operand"); for (const QJSPrimitiveValue &o : operands) QTest::newRow(qPrintable(toScriptString(o))) << o; } enum UnaryOperator { Plus, Minus, PreIncrement, PostIncrement, PreDecrement, PostDecrement }; QString toString(UnaryOperator op) { switch (op) { case Plus: return "+"; case Minus: return "-"; case PreIncrement: case PostIncrement: return "++"; case PreDecrement: case PostDecrement: return "--"; } Q_UNREACHABLE_RETURN(QString()); } template void doTestUnaryOperator(QJSEngine *engine, QJSPrimitiveValue operand) { Result result; // Need to get the string here as the operators change the original value const QString asString = toScriptString(operand); if constexpr (Operator == Plus) result = +operand; else if constexpr (Operator == Minus) result = -operand; else if constexpr (Operator == PreIncrement) result = ++operand; else if constexpr (Operator == PostIncrement) result = operand++; else if constexpr (Operator == PreDecrement) result = --operand; else if constexpr (Operator == PostDecrement) result = operand--; else QFAIL("Unkonwn operator"); const QString decl = "var a = " + asString + "; "; const QString expression = decl + ((Operator == PostIncrement || Operator == PostDecrement) ? (u'a' + toString(Operator)) : (toString(Operator) + u'a')); verifyResult(result, engine, expression); } void doTestForAllUnaryOperators(QJSEngine *engine, QJSPrimitiveValue operand) { doTestUnaryOperator(engine, operand); doTestUnaryOperator(engine, operand); doTestUnaryOperator(engine, operand); doTestUnaryOperator(engine, operand); doTestUnaryOperator(engine, operand); } void tst_QJSPrimitiveValue::unaryOperators() { QFETCH(QJSPrimitiveValue, operand); doTestForAllUnaryOperators(&engine, operand); doTestForAllUnaryOperators(&engine, operand.toString()); doTestForAllUnaryOperators(&engine, operand.toString() + " bar"); doTestForAllUnaryOperators(&engine, "foo" + operand.toString()); } void tst_QJSPrimitiveValue::toFromVariant() { for (const auto &operand : operands) { const QVariant var = operand.toVariant(); switch (operand.type()) { case QJSPrimitiveValue::Undefined: QVERIFY(!var.isValid()); QCOMPARE(operand.metaType(), QMetaType()); QCOMPARE(operand.data(), nullptr); break; case QJSPrimitiveValue::Null: QCOMPARE(var.typeId(), QMetaType::Nullptr); QCOMPARE(operand.metaType(), QMetaType::fromType()); QCOMPARE(operand.data(), nullptr); break; case QJSPrimitiveValue::Boolean: QCOMPARE(var.typeId(), QMetaType::Bool); QCOMPARE(var.toBool(), operand.toBoolean()); QCOMPARE(operand.metaType(), QMetaType::fromType()); QCOMPARE(*static_cast(operand.data()), operand.toBoolean()); break; case QJSPrimitiveValue::Integer: QCOMPARE(var.typeId(), QMetaType::Int); QCOMPARE(var.toInt(), operand.toInteger()); QCOMPARE(operand.metaType(), QMetaType::fromType()); QCOMPARE(*static_cast(operand.data()), operand.toInteger()); break; case QJSPrimitiveValue::Double: QCOMPARE(var.typeId(), QMetaType::Double); QCOMPARE(var.toDouble(), operand.toDouble()); QCOMPARE(operand.metaType(), QMetaType::fromType()); QCOMPARE(*static_cast(operand.data()), operand.toDouble()); break; case QJSPrimitiveValue::String: QCOMPARE(var.typeId(), QMetaType::QString); QCOMPARE(var.toString(), operand.toString()); QCOMPARE(operand.metaType(), QMetaType::fromType()); QCOMPARE(*static_cast(operand.data()), operand.toString()); break; } QJSPrimitiveValue fromVar(var); QCOMPARE(fromVar.type(), operand.type()); if (operand.type() == QJSPrimitiveValue::Double && std::isnan(operand.toDouble())) QVERIFY(fromVar != operand); else QCOMPARE(fromVar, operand); } } void tst_QJSPrimitiveValue::coercion() { for (const QJSPrimitiveValue &operand : operands) { QCOMPARE(operand.to(), QJSPrimitiveUndefined()); QCOMPARE(operand.to(), QJSPrimitiveNull()); QCOMPARE(operand.to(), operand.toBoolean()); QCOMPARE(operand.to(), operand.toInteger()); QCOMPARE(operand.to(), operand.toString()); const QJSPrimitiveValue lhs = operand.to(); QCOMPARE(lhs.type(), QJSPrimitiveValue::Double); const double rhs = operand.toDouble(); if (std::isnan(rhs)) QVERIFY(std::isnan(lhs.toDouble())); else QCOMPARE(lhs.toDouble(), rhs); } } void tst_QJSPrimitiveValue::ctor_invalid() { QJSPrimitiveValue v; QCOMPARE(v.type(), QJSPrimitiveValue::Undefined); } void tst_QJSPrimitiveValue::ctor_undefinedWithEngine() { QJSEngine eng; QJSPrimitiveValue v(eng.toPrimitiveValue(QVariant())); QCOMPARE(v.type(), QJSPrimitiveValue::Undefined); } void tst_QJSPrimitiveValue::ctor_boolWithEngine() { QJSEngine eng; QJSPrimitiveValue v(eng.toPrimitiveValue(false)); QCOMPARE(v.type(), QJSPrimitiveValue::Boolean); QCOMPARE(v.toBoolean(), false); } void tst_QJSPrimitiveValue::ctor_intWithEngine() { QJSEngine eng; QJSPrimitiveValue v(eng.toPrimitiveValue(int(1))); QCOMPARE(v.type(), QJSPrimitiveValue::Integer); QCOMPARE(v.toInteger(), 1); } void tst_QJSPrimitiveValue::ctor_stringWithEngine() { QJSEngine eng; QJSPrimitiveValue v(eng.toPrimitiveValue(QStringLiteral("ciao"))); QCOMPARE(v.type(), QJSPrimitiveValue::String); QCOMPARE(v.toString(), QStringLiteral("ciao")); } void tst_QJSPrimitiveValue::ctor_copyAndAssignWithEngine() { QJSEngine eng; // copy constructor, operator= QJSPrimitiveValue v(eng.toPrimitiveValue(1.0)); QJSPrimitiveValue v2(v); QCOMPARE(v2.strictlyEquals(v), true); QJSPrimitiveValue v3(v); QCOMPARE(v3.strictlyEquals(v), true); QCOMPARE(v3.strictlyEquals(v2), true); QJSPrimitiveValue v4(eng.toPrimitiveValue(2.0)); QCOMPARE(v4.strictlyEquals(v), false); v3 = QJSPrimitiveValue(v4); QCOMPARE(v3.strictlyEquals(v), false); QCOMPARE(v3.strictlyEquals(v4), true); v2 = QJSPrimitiveValue(); QCOMPARE(v2.strictlyEquals(v), false); QCOMPARE(v.toDouble(), 1.0); QJSPrimitiveValue v5(v); QCOMPARE(v5.strictlyEquals(v), true); v = QJSPrimitiveValue(); QCOMPARE(v5.strictlyEquals(v), false); QCOMPARE(v5.toDouble(), 1.0); } void tst_QJSPrimitiveValue::toString() { QJSEngine eng; { QJSPrimitiveValue undefined(eng.toPrimitiveValue(QVariant())); QCOMPARE(undefined.toString(), QStringLiteral("undefined")); QCOMPARE(qjsvalue_cast(undefined), QStringLiteral("undefined")); } { QJSPrimitiveValue null((QJSPrimitiveNull())); QCOMPARE(null.toString(), QStringLiteral("null")); QCOMPARE(qjsvalue_cast(null), QStringLiteral("null")); } { QJSPrimitiveValue falskt(eng.toPrimitiveValue(false)); QCOMPARE(falskt.toString(), QStringLiteral("false")); QCOMPARE(qjsvalue_cast(falskt), QStringLiteral("false")); QJSPrimitiveValue sant(eng.toPrimitiveValue(true)); QCOMPARE(sant.toString(), QStringLiteral("true")); QCOMPARE(qjsvalue_cast(sant), QStringLiteral("true")); } { QJSPrimitiveValue number(eng.toPrimitiveValue(123)); QCOMPARE(number.toString(), QStringLiteral("123")); QCOMPARE(qjsvalue_cast(number), QStringLiteral("123")); } { QJSPrimitiveValue number(eng.toPrimitiveValue(6.37e-8)); QCOMPARE(number.toString(), QStringLiteral("6.37e-8")); } { QJSPrimitiveValue number(eng.toPrimitiveValue(-6.37e-8)); QCOMPARE(number.toString(), QStringLiteral("-6.37e-8")); QJSPrimitiveValue str(eng.toPrimitiveValue(QStringLiteral("ciao"))); QCOMPARE(str.toString(), QStringLiteral("ciao")); QCOMPARE(qjsvalue_cast(str), QStringLiteral("ciao")); } QJSPrimitiveValue inv((QJSPrimitiveUndefined())); QCOMPARE(inv.toString(), QStringLiteral("undefined")); // Type cannot be represented in QJSPrimitiveValue, and is converted to string. QJSPrimitiveValue variant(eng.toPrimitiveValue(QPoint(10, 20))); QCOMPARE(variant.type(), QJSPrimitiveValue::String); QCOMPARE(variant.toString(), QStringLiteral("QPoint(10, 20)")); variant = eng.toPrimitiveValue(QUrl()); QCOMPARE(variant.type(), QJSPrimitiveValue::String); QVERIFY(variant.toString().isEmpty()); { QByteArray hello = QByteArrayLiteral("Hello World"); QJSPrimitiveValue jsValue(eng.toPrimitiveValue(hello)); QCOMPARE(jsValue.toString(), QString::fromUtf8(hello)); } } void tst_QJSPrimitiveValue::toNumber() { QJSEngine eng; QJSPrimitiveValue undefined(eng.toPrimitiveValue(QVariant())); QCOMPARE(qIsNaN(undefined.toDouble()), true); QCOMPARE(qIsNaN(qjsvalue_cast(undefined)), true); QJSPrimitiveValue null((QJSPrimitiveNull())); QCOMPARE(null.toDouble(), 0.0); QCOMPARE(qjsvalue_cast(null), 0.0); { QJSPrimitiveValue falskt(eng.toPrimitiveValue(false)); QCOMPARE(falskt.toDouble(), 0.0); QCOMPARE(qjsvalue_cast(falskt), 0.0); QJSPrimitiveValue sant(eng.toPrimitiveValue(true)); QCOMPARE(sant.toDouble(), 1.0); QCOMPARE(qjsvalue_cast(sant), 1.0); QJSPrimitiveValue number(eng.toPrimitiveValue(123.0)); QCOMPARE(number.toDouble(), 123.0); QCOMPARE(qjsvalue_cast(number), 123.0); QJSPrimitiveValue str(eng.toPrimitiveValue(QStringLiteral("ciao"))); QCOMPARE(qIsNaN(str.toDouble()), true); QCOMPARE(qIsNaN(qjsvalue_cast(str)), true); QJSPrimitiveValue str2(eng.toPrimitiveValue(QStringLiteral("123"))); QCOMPARE(str2.toDouble(), 123.0); QCOMPARE(qjsvalue_cast(str2), 123.0); } QJSPrimitiveValue inv((QJSPrimitiveUndefined())); QVERIFY(qIsNaN(inv.toDouble())); QVERIFY(qIsNaN(qjsvalue_cast(inv))); // V2 constructors { QJSPrimitiveValue falskt(false); QCOMPARE(falskt.toDouble(), 0.0); QCOMPARE(qjsvalue_cast(falskt), 0.0); QJSPrimitiveValue sant(true); QCOMPARE(sant.toDouble(), 1.0); QCOMPARE(qjsvalue_cast(sant), 1.0); QJSPrimitiveValue number(123.0); QCOMPARE(number.toDouble(), 123.0); QCOMPARE(qjsvalue_cast(number), 123.0); QJSPrimitiveValue number2(int(0x43211234)); QCOMPARE(number2.toDouble(), 1126240820.0); QJSPrimitiveValue str(QStringLiteral("ciao")); QCOMPARE(qIsNaN(str.toDouble()), true); QCOMPARE(qIsNaN(qjsvalue_cast(str)), true); QJSPrimitiveValue str2(QStringLiteral("123")); QCOMPARE(str2.toDouble(), 123.0); QCOMPARE(qjsvalue_cast(str2), 123.0); } } void tst_QJSPrimitiveValue::toBoolean() { QJSEngine eng; QJSPrimitiveValue undefined(eng.toPrimitiveValue(QVariant())); QCOMPARE(undefined.type(), QJSPrimitiveValue::Undefined); QCOMPARE(undefined.toBoolean(), false); QCOMPARE(qjsvalue_cast(undefined), false); QJSPrimitiveValue null((QJSPrimitiveNull())); QCOMPARE(null.type(), QJSPrimitiveValue::Null); QCOMPARE(null.toBoolean(), false); QCOMPARE(qjsvalue_cast(null), false); { QJSPrimitiveValue falskt = eng.toPrimitiveValue(false); QCOMPARE(falskt.type(), QJSPrimitiveValue::Boolean); QCOMPARE(falskt.toBoolean(), false); QCOMPARE(qjsvalue_cast(falskt), false); QJSPrimitiveValue sant(eng.toPrimitiveValue(true)); QCOMPARE(sant.type(), QJSPrimitiveValue::Boolean); QCOMPARE(sant.toBoolean(), true); QCOMPARE(qjsvalue_cast(sant), true); QJSPrimitiveValue number(eng.toPrimitiveValue(0.0)); QCOMPARE(number.toBoolean(), false); QCOMPARE(qjsvalue_cast(number), false); QJSPrimitiveValue number2(eng.toPrimitiveValue(qQNaN())); QCOMPARE(number2.toBoolean(), false); QCOMPARE(qjsvalue_cast(number2), false); QJSPrimitiveValue number3(eng.toPrimitiveValue(123.0)); QCOMPARE(number3.toBoolean(), true); QCOMPARE(qjsvalue_cast(number3), true); QJSPrimitiveValue number4(eng.toPrimitiveValue(-456.0)); QCOMPARE(number4.toBoolean(), true); QCOMPARE(qjsvalue_cast(number4), true); QJSPrimitiveValue str(eng.toPrimitiveValue(QStringLiteral(""))); QCOMPARE(str.toBoolean(), false); QCOMPARE(qjsvalue_cast(str), false); QJSPrimitiveValue str2(eng.toPrimitiveValue(QStringLiteral("123"))); QCOMPARE(str2.toBoolean(), true); QCOMPARE(qjsvalue_cast(str2), true); } QJSPrimitiveValue inv((QJSPrimitiveUndefined())); QCOMPARE(inv.toBoolean(), false); QCOMPARE(qjsvalue_cast(inv), false); // V2 constructors { QJSPrimitiveValue falskt(false); QCOMPARE(falskt.toBoolean(), false); QCOMPARE(qjsvalue_cast(falskt), false); QJSPrimitiveValue sant(true); QCOMPARE(sant.toBoolean(), true); QCOMPARE(qjsvalue_cast(sant), true); QJSPrimitiveValue number(0.0); QCOMPARE(number.toBoolean(), false); QCOMPARE(qjsvalue_cast(number), false); QJSPrimitiveValue number2(qQNaN()); QCOMPARE(number2.toBoolean(), false); QCOMPARE(qjsvalue_cast(number2), false); QJSPrimitiveValue number3(123.0); QCOMPARE(number3.toBoolean(), true); QCOMPARE(qjsvalue_cast(number3), true); QJSPrimitiveValue number4(-456.0); QCOMPARE(number4.toBoolean(), true); QCOMPARE(qjsvalue_cast(number4), true); QJSPrimitiveValue number5(0x43211234); QCOMPARE(number5.toBoolean(), true); QJSPrimitiveValue str(QStringLiteral("")); QCOMPARE(str.toBoolean(), false); QCOMPARE(qjsvalue_cast(str), false); QJSPrimitiveValue str2(QStringLiteral("123")); QCOMPARE(str2.toBoolean(), true); QCOMPARE(qjsvalue_cast(str2), true); } } void tst_QJSPrimitiveValue::toVariant() { QJSEngine eng; { QJSPrimitiveValue undefined(eng.toPrimitiveValue(QVariant())); QCOMPARE(undefined.toVariant(), QVariant()); QCOMPARE(qjsvalue_cast(undefined), QVariant()); } { QJSPrimitiveValue null((QJSPrimitiveNull())); QCOMPARE(null.toVariant(), QVariant::fromValue(nullptr)); QCOMPARE(qjsvalue_cast(null), QVariant::fromValue(nullptr)); } { QJSPrimitiveValue number(eng.toPrimitiveValue(123.0)); QCOMPARE(number.toVariant(), QVariant(123.0)); QCOMPARE(qjsvalue_cast(number), QVariant(123.0)); QJSPrimitiveValue intNumber(eng.toPrimitiveValue(qint32(123))); QCOMPARE(intNumber.toVariant().typeId(), QVariant((qint32)123).typeId()); QCOMPARE((qjsvalue_cast(intNumber)).typeId(), QVariant(qint32(123)).typeId()); QJSPrimitiveValue falskt(eng.toPrimitiveValue(false)); QCOMPARE(falskt.toVariant(), QVariant(false)); QCOMPARE(qjsvalue_cast(falskt), QVariant(false)); QJSPrimitiveValue sant(eng.toPrimitiveValue(true)); QCOMPARE(sant.toVariant(), QVariant(true)); QCOMPARE(qjsvalue_cast(sant), QVariant(true)); QJSPrimitiveValue str(eng.toPrimitiveValue(QStringLiteral("ciao"))); QCOMPARE(str.toVariant(), QVariant(QStringLiteral("ciao"))); QCOMPARE(qjsvalue_cast(str), QVariant(QStringLiteral("ciao"))); } { QDateTime dateTime = QDate(1980, 10, 4).startOfDay(); QJSPrimitiveValue dateObject(eng.toPrimitiveValue(dateTime)); QVariant var = dateObject.toVariant(); QCOMPARE(var, (eng.coerceValue(dateTime))); QCOMPARE(dateObject.toVariant(), var); } { QRegularExpression rx = QRegularExpression(QStringLiteral("[0-9a-z]+")); QJSPrimitiveValue rxObject(eng.toPrimitiveValue(rx)); QCOMPARE(rxObject.type(), QJSPrimitiveValue::String); QVariant var = rxObject.toVariant(); QCOMPARE(var, u'/' + rx.pattern() + u'/'); } { QJSPrimitiveValue inv; QCOMPARE(inv.toVariant(), QVariant()); QCOMPARE(inv.toVariant(), QVariant()); QCOMPARE(qjsvalue_cast(inv), QVariant()); } // V2 constructors { QJSPrimitiveValue number(123.0); QCOMPARE(number.toVariant(), QVariant(123.0)); QCOMPARE(number.toVariant(), QVariant(123.0)); QCOMPARE(qjsvalue_cast(number), QVariant(123.0)); QJSPrimitiveValue falskt(false); QCOMPARE(falskt.toVariant(), QVariant(false)); QCOMPARE(falskt.toVariant(), QVariant(false)); QCOMPARE(qjsvalue_cast(falskt), QVariant(false)); QJSPrimitiveValue sant(true); QCOMPARE(sant.toVariant(), QVariant(true)); QCOMPARE(sant.toVariant(), QVariant(true)); QCOMPARE(qjsvalue_cast(sant), QVariant(true)); QJSPrimitiveValue str(QStringLiteral("ciao")); QCOMPARE(str.toVariant(), QVariant(QStringLiteral("ciao"))); QCOMPARE(str.toVariant(), QVariant(QStringLiteral("ciao"))); QCOMPARE(qjsvalue_cast(str), QVariant(QStringLiteral("ciao"))); QJSPrimitiveValue undef((QJSPrimitiveUndefined())); QCOMPARE(undef.toVariant(), QVariant()); QCOMPARE(undef.toVariant(), QVariant()); QCOMPARE(qjsvalue_cast(undef), QVariant()); QJSPrimitiveValue nil((QJSPrimitiveNull())); QCOMPARE(nil.toVariant(), QVariant::fromValue(nullptr)); QCOMPARE(nil.toVariant(), QVariant::fromValue(nullptr)); QCOMPARE(qjsvalue_cast(nil), QVariant::fromValue(nullptr)); } } void tst_QJSPrimitiveValue::equals() { QJSEngine eng; QObject temp; QVERIFY(QJSPrimitiveValue().equals(QJSPrimitiveValue())); QJSPrimitiveValue num(eng.toPrimitiveValue(123)); QVERIFY(num.equals(eng.toPrimitiveValue(123))); QVERIFY(!num.equals(eng.toPrimitiveValue(321))); QVERIFY(num.equals(eng.toPrimitiveValue(QStringLiteral("123")))); QVERIFY(!num.equals(eng.toPrimitiveValue(QStringLiteral("321")))); QVERIFY(!num.equals(QJSPrimitiveValue())); QJSPrimitiveValue str(eng.toPrimitiveValue(QStringLiteral("123"))); QVERIFY(str.equals(eng.toPrimitiveValue(QStringLiteral("123")))); QVERIFY(!str.equals(eng.toPrimitiveValue(QStringLiteral("321")))); QVERIFY(str.equals(eng.toPrimitiveValue(123))); QVERIFY(!str.equals(eng.toPrimitiveValue(321))); QCOMPARE(str.equals(QJSPrimitiveValue()), false); QJSPrimitiveValue num2(123); QVERIFY(num2.equals(QJSPrimitiveValue(123))); QVERIFY(!num2.equals(QJSPrimitiveValue(321))); QVERIFY(num2.equals(QStringLiteral("123"))); QVERIFY(!num2.equals(QStringLiteral("321"))); QVERIFY(!num2.equals(QJSPrimitiveValue())); QJSPrimitiveValue str2(QStringLiteral("123")); QVERIFY(str2.equals(QStringLiteral("123"))); QVERIFY(!str2.equals(QStringLiteral("321"))); QVERIFY(str2.equals(QJSPrimitiveValue(123))); QVERIFY(!str2.equals(QJSPrimitiveValue(321))); QVERIFY(!str2.equals(QJSPrimitiveValue())); QJSPrimitiveValue date1(eng.toPrimitiveValue(QDate(2000, 1, 1).startOfDay())); QJSPrimitiveValue date2(eng.toPrimitiveValue(QDate(1999, 1, 1).startOfDay())); QCOMPARE(date1.equals(date2), false); QCOMPARE(date1.equals(date1), true); QCOMPARE(date2.equals(date2), true); QJSPrimitiveValue undefined(eng.toPrimitiveValue(QVariant())); QJSPrimitiveValue null((QJSPrimitiveNull())); QCOMPARE(undefined.equals(undefined), true); QCOMPARE(null.equals(null), true); QCOMPARE(undefined.equals(null), true); QCOMPARE(null.equals(undefined), true); QVERIFY(undefined.equals(QJSPrimitiveValue())); QVERIFY(null.equals(QJSPrimitiveValue())); QVERIFY(!null.equals(num)); QVERIFY(!undefined.equals(num)); QJSPrimitiveValue sant(eng.toPrimitiveValue(true)); QVERIFY(sant.equals(eng.toPrimitiveValue(1))); QVERIFY(sant.equals(eng.toPrimitiveValue(QStringLiteral("1")))); QVERIFY(sant.equals(sant)); QVERIFY(!sant.equals(eng.toPrimitiveValue(0))); QVERIFY(!sant.equals(undefined)); QVERIFY(!sant.equals(null)); QJSPrimitiveValue falskt(eng.toPrimitiveValue(false)); QVERIFY(falskt.equals(eng.toPrimitiveValue(0))); QVERIFY(falskt.equals(eng.toPrimitiveValue(QStringLiteral("0")))); QVERIFY(falskt.equals(falskt)); QVERIFY(!falskt.equals(sant)); QVERIFY(!falskt.equals(undefined)); QVERIFY(!falskt.equals(null)); { QJSPrimitiveValue var1(eng.toPrimitiveValue(QVariant::fromValue(QPoint(1, 2)))); QJSPrimitiveValue var2(eng.toPrimitiveValue(QVariant::fromValue(QPoint(1, 2)))); QVERIFY(var1.equals(var2)); } { QJSPrimitiveValue var1(eng.toPrimitiveValue(QVariant::fromValue(QPoint(1, 2)))); QJSPrimitiveValue var2(eng.toPrimitiveValue(QVariant::fromValue(QPoint(3, 4)))); QVERIFY(!var1.equals(var2)); } } void tst_QJSPrimitiveValue::strictlyEquals() { QJSEngine eng; QObject temp; QVERIFY(QJSPrimitiveValue().strictlyEquals(QJSPrimitiveValue())); QJSPrimitiveValue num(eng.toPrimitiveValue(123)); QVERIFY(num.strictlyEquals(eng.toPrimitiveValue(123))); QVERIFY(!num.strictlyEquals(eng.toPrimitiveValue(321))); QVERIFY(!num.strictlyEquals(eng.toPrimitiveValue(QStringLiteral("123")))); QVERIFY(!num.strictlyEquals(eng.toPrimitiveValue(QStringLiteral("321")))); QVERIFY(!num.strictlyEquals(QJSPrimitiveValue())); QVERIFY(!QJSPrimitiveValue().strictlyEquals(num)); QJSPrimitiveValue str(eng.toPrimitiveValue(QStringLiteral("123"))); QVERIFY(str.strictlyEquals(eng.toPrimitiveValue(QStringLiteral("123")))); QVERIFY(!str.strictlyEquals(eng.toPrimitiveValue(QStringLiteral("321")))); QVERIFY(!str.strictlyEquals(eng.toPrimitiveValue(123))); QVERIFY(!str.strictlyEquals(eng.toPrimitiveValue(321))); QVERIFY(!str.strictlyEquals(QJSPrimitiveValue())); QJSPrimitiveValue num2(123); QVERIFY(num2.strictlyEquals(QJSPrimitiveValue(123))); QVERIFY(!num2.strictlyEquals(QJSPrimitiveValue(321))); QVERIFY(!num2.strictlyEquals(QStringLiteral("123"))); QVERIFY(!num2.strictlyEquals(QStringLiteral("321"))); QVERIFY(!num2.strictlyEquals(QJSPrimitiveValue())); QJSPrimitiveValue str2(QStringLiteral("123")); QVERIFY(str2.strictlyEquals(QStringLiteral("123"))); QVERIFY(!str2.strictlyEquals(QStringLiteral("321"))); QVERIFY(!str2.strictlyEquals(QJSPrimitiveValue(123))); QVERIFY(!str2.strictlyEquals(QJSPrimitiveValue(321))); QVERIFY(!str2.strictlyEquals(QJSPrimitiveValue())); QJSPrimitiveValue date1(eng.toPrimitiveValue(QDate(2000, 1, 1).startOfDay())); QJSPrimitiveValue date2(eng.toPrimitiveValue(QDate(1999, 1, 1).startOfDay())); QCOMPARE(date1.strictlyEquals(date2), false); QCOMPARE(date1.strictlyEquals(date1), true); QCOMPARE(date2.strictlyEquals(date2), true); QVERIFY(!date1.strictlyEquals(QJSPrimitiveValue())); QJSPrimitiveValue undefined(eng.toPrimitiveValue(QVariant())); QJSPrimitiveValue null((QJSPrimitiveNull())); QCOMPARE(undefined.strictlyEquals(undefined), true); QCOMPARE(null.strictlyEquals(null), true); QCOMPARE(undefined.strictlyEquals(null), false); QCOMPARE(null.strictlyEquals(undefined), false); QVERIFY(!null.strictlyEquals(QJSPrimitiveValue())); QJSPrimitiveValue sant(eng.toPrimitiveValue(true)); QVERIFY(!sant.strictlyEquals(eng.toPrimitiveValue(1))); QVERIFY(!sant.strictlyEquals(eng.toPrimitiveValue(QStringLiteral("1")))); QVERIFY(sant.strictlyEquals(sant)); QVERIFY(!sant.strictlyEquals(eng.toPrimitiveValue(0))); QVERIFY(!sant.strictlyEquals(undefined)); QVERIFY(!sant.strictlyEquals(null)); QVERIFY(!sant.strictlyEquals(QJSPrimitiveValue())); QJSPrimitiveValue falskt(eng.toPrimitiveValue(false)); QVERIFY(!falskt.strictlyEquals(eng.toPrimitiveValue(0))); QVERIFY(!falskt.strictlyEquals(eng.toPrimitiveValue(QStringLiteral("0")))); QVERIFY(falskt.strictlyEquals(falskt)); QVERIFY(!falskt.strictlyEquals(sant)); QVERIFY(!falskt.strictlyEquals(undefined)); QVERIFY(!falskt.strictlyEquals(null)); QVERIFY(!falskt.strictlyEquals(QJSPrimitiveValue())); QVERIFY(!QJSPrimitiveValue(false).strictlyEquals(QJSPrimitiveValue(123))); QVERIFY(!QJSPrimitiveValue(QJSPrimitiveUndefined()).strictlyEquals(QJSPrimitiveValue(123))); QVERIFY(!QJSPrimitiveValue(QJSPrimitiveNull()).strictlyEquals(QJSPrimitiveValue(123))); QVERIFY(!QJSPrimitiveValue(false).strictlyEquals({QStringLiteral("ciao")})); QVERIFY(!QJSPrimitiveValue(QJSPrimitiveUndefined()).strictlyEquals({QStringLiteral("ciao")})); QVERIFY(!QJSPrimitiveValue(QJSPrimitiveNull()).strictlyEquals({QStringLiteral("ciao")})); QVERIFY(eng.toPrimitiveValue(QStringLiteral("ciao")).strictlyEquals(QJSPrimitiveValue(QStringLiteral("ciao")))); QVERIFY(QJSPrimitiveValue(QStringLiteral("ciao")).strictlyEquals(eng.toPrimitiveValue(QStringLiteral("ciao")))); QVERIFY(!QJSPrimitiveValue(QStringLiteral("ciao")).strictlyEquals(QJSPrimitiveValue(123))); QVERIFY(!QJSPrimitiveValue(QStringLiteral("ciao")).strictlyEquals(eng.toPrimitiveValue(123))); QVERIFY(!QJSPrimitiveValue(123).strictlyEquals({QStringLiteral("ciao")})); QVERIFY(!QJSPrimitiveValue(123).strictlyEquals(eng.toPrimitiveValue(QStringLiteral("ciao")))); QVERIFY(!eng.toPrimitiveValue(123).strictlyEquals(QJSPrimitiveValue(QStringLiteral("ciao")))); { QJSPrimitiveValue var1(eng.toPrimitiveValue(QVariant(QStringList() << QStringLiteral("a")))); QJSPrimitiveValue var2(eng.toPrimitiveValue(QVariant(QStringList() << QStringLiteral("a")))); QVERIFY(var1.strictlyEquals(var2)); } { QJSPrimitiveValue var1(eng.toPrimitiveValue(QVariant(QStringList() << QStringLiteral("a")))); QJSPrimitiveValue var2(eng.toPrimitiveValue(QVariant(QStringList() << QStringLiteral("b")))); QVERIFY(!var1.strictlyEquals(var2)); } { QJSPrimitiveValue var1(eng.toPrimitiveValue(QVariant::fromValue(QPoint(1, 2)))); QJSPrimitiveValue var2(eng.toPrimitiveValue(QVariant::fromValue(QPoint(1, 2)))); QVERIFY(var1.strictlyEquals(var2)); } { QJSPrimitiveValue var1(eng.toPrimitiveValue(QVariant::fromValue(QPoint(1, 2)))); QJSPrimitiveValue var2(eng.toPrimitiveValue(QVariant::fromValue(QPoint(3, 4)))); QVERIFY(!var1.strictlyEquals(var2)); } } void tst_QJSPrimitiveValue::stringAndUrl() { QJSEngine engine; const QString string = QStringLiteral("http://example.com/something.html"); const QUrl url(string); const QJSPrimitiveValue urlValue(engine.toPrimitiveValue(url)); QCOMPARE(urlValue.type(), QJSPrimitiveValue::String); QCOMPARE(urlValue.toString(), string); QCOMPARE(engine.fromPrimitiveValue(urlValue), url); const QJSPrimitiveValue stringValue(engine.toPrimitiveValue(string)); QCOMPARE(stringValue.toString(), string); QCOMPARE(engine.fromPrimitiveValue(stringValue), url); const QJSPrimitiveValue immediateStringValue(string); QCOMPARE(immediateStringValue.toString(), string); QCOMPARE(engine.fromPrimitiveValue(immediateStringValue), url); } void tst_QJSPrimitiveValue::negativeNullMult() { QJSPrimitiveValue zero(0); QJSPrimitiveValue negative(-1); QJSPrimitiveValue positive(1); QCOMPARE((zero * negative).type(), QJSPrimitiveValue::Double); QCOMPARE((negative * zero).type(), QJSPrimitiveValue::Double); QCOMPARE((zero * positive).type(), QJSPrimitiveValue::Integer); QCOMPARE((positive * zero).type(), QJSPrimitiveValue::Integer); } QTEST_MAIN(tst_QJSPrimitiveValue) #include "tst_qjsprimitivevalue.moc"