diff options
Diffstat (limited to 'tests/auto/corelib/serialization')
5 files changed, 459 insertions, 82 deletions
diff --git a/tests/auto/corelib/serialization/CMakeLists.txt b/tests/auto/corelib/serialization/CMakeLists.txt index 3792336255..45965114cc 100644 --- a/tests/auto/corelib/serialization/CMakeLists.txt +++ b/tests/auto/corelib/serialization/CMakeLists.txt @@ -3,7 +3,9 @@ add_subdirectory(json) add_subdirectory(qcborstreamreader) -add_subdirectory(qcborstreamwriter) +if(QT_FEATURE_cborstreamwriter) + add_subdirectory(qcborstreamwriter) +endif() if(NOT WASM) add_subdirectory(qcborvalue) endif() diff --git a/tests/auto/corelib/serialization/json/tst_qtjson.cpp b/tests/auto/corelib/serialization/json/tst_qtjson.cpp index 5046478547..54ef9be4f2 100644 --- a/tests/auto/corelib/serialization/json/tst_qtjson.cpp +++ b/tests/auto/corelib/serialization/json/tst_qtjson.cpp @@ -182,14 +182,20 @@ void tst_QtJson::compareCompiles() QJsonArray::const_iterator>(); QTestPrivate::testEqualityOperatorsCompile<QJsonDocument>(); QTestPrivate::testEqualityOperatorsCompile<QJsonObject>(); + QTestPrivate::testEqualityOperatorsCompile<QJsonObject::iterator>(); + QTestPrivate::testEqualityOperatorsCompile<QJsonObject::const_iterator>(); QTestPrivate::testEqualityOperatorsCompile<QJsonValue>(); QTestPrivate::testEqualityOperatorsCompile<QJsonValueConstRef>(); QTestPrivate::testEqualityOperatorsCompile<QJsonValueRef>(); QTestPrivate::testEqualityOperatorsCompile<QJsonArray, QJsonValue>(); QTestPrivate::testEqualityOperatorsCompile<QJsonObject, QJsonValue>(); + QTestPrivate::testEqualityOperatorsCompile<QJsonObject, QJsonValueConstRef>(); + QTestPrivate::testEqualityOperatorsCompile<QJsonObject, QJsonValueRef>(); QTestPrivate::testEqualityOperatorsCompile<QJsonValueConstRef, QJsonValue>(); QTestPrivate::testEqualityOperatorsCompile<QJsonValueRef, QJsonValue>(); QTestPrivate::testEqualityOperatorsCompile<QJsonValueRef, QJsonValueConstRef>(); + QTestPrivate::testEqualityOperatorsCompile<QJsonObject::iterator, + QJsonObject::const_iterator>(); } void tst_QtJson::testValueSimple() @@ -670,6 +676,7 @@ void tst_QtJson::testObjectInsertCopies() QCOMPARE(obj.size(), 2); QCOMPARE(obj.value("value"), "TEST"); QCOMPARE(obj.value("prop2"), "TEST"); + QT_TEST_EQUALITY_OPS(rv, obj["value"].toObject(), true); } { QJsonObject obj; @@ -1105,6 +1112,7 @@ void tst_QtJson::testObjectIteration() for (QJsonObject::iterator it = object.begin(); it != object.end(); ++it) { QJsonValue value = it.value(); QCOMPARE((double)it.key().toInt(), value.toDouble()); + QT_TEST_EQUALITY_OPS(it, QJsonObject::iterator(), false); } { @@ -1117,6 +1125,7 @@ void tst_QtJson::testObjectIteration() QCOMPARE(object.size(), 10); QCOMPARE(object2.size(), 9); QVERIFY(next == object2.begin()); + QT_TEST_EQUALITY_OPS(next, object2.begin(), true); double d = 1; // we erased the first item for (auto it = object2.constBegin(); it != object2.constEnd(); ++it, d += 1) { @@ -1175,6 +1184,7 @@ void tst_QtJson::testObjectIteration() { QJsonObject::Iterator it = object.begin(); it += 5; + QT_TEST_ALL_COMPARISON_OPS(it, object.begin(), Qt::strong_ordering::greater); QCOMPARE(QJsonValue(it.value()).toDouble(), 5.); it -= 3; QCOMPARE(QJsonValue(it.value()).toDouble(), 2.); @@ -1189,10 +1199,14 @@ void tst_QtJson::testObjectIteration() it += 5; QCOMPARE(QJsonValue(it.value()).toDouble(), 5.); it -= 3; + QT_TEST_ALL_COMPARISON_OPS(object.constBegin(), it, Qt::strong_ordering::less); QCOMPARE(QJsonValue(it.value()).toDouble(), 2.); QJsonObject::ConstIterator it2 = it + 5; + QT_TEST_EQUALITY_OPS(it, it2, false); QCOMPARE(QJsonValue(it2.value()).toDouble(), 7.); it2 = it - 1; + QT_TEST_ALL_COMPARISON_OPS(it2, it, Qt::strong_ordering::less); + QT_TEST_ALL_COMPARISON_OPS(it2, it - 2, Qt::strong_ordering::greater); QCOMPARE(QJsonValue(it2.value()).toDouble(), 1.); } @@ -1201,6 +1215,17 @@ void tst_QtJson::testObjectIteration() it = object.erase(it); QCOMPARE(object.size() , 0); QCOMPARE(it, object.end()); + QT_TEST_ALL_COMPARISON_OPS(it, object.end(), Qt::strong_ordering::equal); + QT_TEST_ALL_COMPARISON_OPS(it, object.constEnd(), Qt::strong_ordering::equal); + QT_TEST_ALL_COMPARISON_OPS(it, object.begin(), + Qt::strong_ordering::equal); // because object is empty + QT_TEST_ALL_COMPARISON_OPS(it, object.constBegin(), Qt::strong_ordering::equal); + QT_TEST_ALL_COMPARISON_OPS(QJsonObject::Iterator(), + QJsonObject::Iterator(), Qt::strong_ordering::equal); + QT_TEST_ALL_COMPARISON_OPS(QJsonObject::ConstIterator(), + QJsonObject::Iterator(), Qt::strong_ordering::equal); + QT_TEST_ALL_COMPARISON_OPS(QJsonObject::ConstIterator(), + QJsonObject::ConstIterator(), Qt::strong_ordering::equal); } void tst_QtJson::testArrayIteration() diff --git a/tests/auto/corelib/serialization/qcborvalue/tst_qcborvalue.cpp b/tests/auto/corelib/serialization/qcborvalue/tst_qcborvalue.cpp index 37f1569bbc..e480b033e1 100644 --- a/tests/auto/corelib/serialization/qcborvalue/tst_qcborvalue.cpp +++ b/tests/auto/corelib/serialization/qcborvalue/tst_qcborvalue.cpp @@ -7,7 +7,9 @@ #include <QBuffer> #include <QCborStreamReader> +#if QT_CONFIG(cborstreamwriter) #include <QCborStreamWriter> +#endif #include <QDateTime> #include <QtEndian> #include <QTimeZone> @@ -16,6 +18,8 @@ Q_DECLARE_METATYPE(QCborKnownTags) Q_DECLARE_METATYPE(QCborValue) Q_DECLARE_METATYPE(QCborValue::EncodingOptions) +using namespace Qt::StringLiterals; + class tst_QCborValue : public QObject { Q_OBJECT @@ -78,16 +82,17 @@ private slots: void mapComplexKeys(); void mapNested(); + void sorting_data(); void sorting(); - void comparison_data(); - void comparison(); void comparisonMap_data(); void comparisonMap(); void toCbor_data(); +#if QT_CONFIG(cborstreamwriter) void toCbor(); void toCborStreamWriter_data() { toCbor_data(); } void toCborStreamWriter(); +#endif void fromCbor_data(); void fromCbor(); void fromCborStreamReaderByteArray_data() { fromCbor_data(); } @@ -457,7 +462,11 @@ void tst_QCborValue::compareCompiles() QTestPrivate::testAllComparisonOperatorsCompile<QCborValueRef>(); QTestPrivate::testAllComparisonOperatorsCompile<QCborValueConstRef>(); QTestPrivate::testAllComparisonOperatorsCompile<QCborArray>(); + QTestPrivate::testAllComparisonOperatorsCompile<QCborArray::Iterator>(); + QTestPrivate::testAllComparisonOperatorsCompile<QCborArray::ConstIterator>(); QTestPrivate::testAllComparisonOperatorsCompile<QCborMap>(); + QTestPrivate::testAllComparisonOperatorsCompile<QCborMap::Iterator>(); + QTestPrivate::testAllComparisonOperatorsCompile<QCborMap::ConstIterator>(); // QCborValue, Ref and ConstRef QTestPrivate::testAllComparisonOperatorsCompile<QCborValueRef, QCborValueConstRef>(); @@ -471,6 +480,8 @@ void tst_QCborValue::compareCompiles() QTestPrivate::testAllComparisonOperatorsCompile<QCborMap, QCborValue>(); QTestPrivate::testAllComparisonOperatorsCompile<QCborMap, QCborValueRef>(); QTestPrivate::testAllComparisonOperatorsCompile<QCborMap, QCborValueConstRef>(); + QTestPrivate::testAllComparisonOperatorsCompile<QCborArray::Iterator, + QCborArray::ConstIterator>(); } void tst_QCborValue::extendedTypes() @@ -739,6 +750,13 @@ void tst_QCborValue::mapNonEmptyDetach() { QCborMap copy(m); auto it = m.find(QLatin1String("3")); QVERIFY(it == m.end()); } { QCborMap copy(m); auto it = m.find(QString("3")); QVERIFY(it == m.end()); } { QCborMap copy(m); auto it = m.find(QCborValue(3)); QVERIFY(it == m.end()); } + + QT_TEST_EQUALITY_OPS(m.constBegin(), m.constEnd(), false); + QT_TEST_EQUALITY_OPS(m.begin(), m.end(), false); + QT_TEST_EQUALITY_OPS(m.constFind(3), m.constEnd(), true); + QT_TEST_EQUALITY_OPS(m.find(3), m.end(), true); + QT_TEST_EQUALITY_OPS(m.find(3), m.constEnd(), true); + QT_TEST_EQUALITY_OPS(m.constFind(3), m.end(), true); } void tst_QCborValue::arrayInitializerList() @@ -785,12 +803,17 @@ void tst_QCborValue::arrayInitializerList() // iterators auto it = a.constBegin(); auto end = a.constEnd(); + QT_TEST_ALL_COMPARISON_OPS(it, end, Qt::strong_ordering::less); QCOMPARE(end - it, 7); QCOMPARE(it + 7, end); + QT_TEST_EQUALITY_OPS(it + 7, end, true); QVERIFY(it->isInteger()); QCOMPARE(*it, QCborValue(0)); QCOMPARE(it[1], QCborValue(-1)); QCOMPARE(*(it + 2), QCborValue(false)); + QT_TEST_EQUALITY_OPS(*it, QCborValue(0), true); + QT_TEST_EQUALITY_OPS(it[1], QCborValue(-1), true); + QT_TEST_EQUALITY_OPS(*(it + 2), QCborValue(false), true); it += 3; QCOMPARE(*it, QCborValue(true)); ++it; @@ -801,6 +824,24 @@ void tst_QCborValue::arrayInitializerList() QCOMPARE(*end, QCborValue(1.0)); end--; QCOMPARE(it, end); + QT_TEST_EQUALITY_OPS(it, end, true); + QT_TEST_EQUALITY_OPS(it, QCborArray::ConstIterator(), false); + QT_TEST_EQUALITY_OPS(QCborArray::ConstIterator(), end, false); + QT_TEST_EQUALITY_OPS(QCborArray::ConstIterator(), QCborArray::ConstIterator(), true); + QT_TEST_EQUALITY_OPS(QCborArray::ConstIterator(), QCborArray::Iterator(), true); + + { + auto it = a.begin(); + auto it1 = a.constBegin(); + auto end = a.end(); + QT_TEST_ALL_COMPARISON_OPS(it, end, Qt::strong_ordering::less); + QT_TEST_ALL_COMPARISON_OPS(it1, end, Qt::strong_ordering::less); + QT_TEST_EQUALITY_OPS(it + 7, end, true); + QT_TEST_EQUALITY_OPS(it1 + 7, end, true); + QT_TEST_EQUALITY_OPS(it, QCborArray::Iterator(), false); + QT_TEST_EQUALITY_OPS(QCborArray::Iterator(), end, false); + QT_TEST_EQUALITY_OPS(QCborArray::Iterator(), QCborArray::ConstIterator(), true); + } // range for int i = 0; @@ -1151,8 +1192,18 @@ void tst_QCborValue::mapMutation() m2 = m; auto it = m.begin(); // detaches again auto end = m.end(); + auto it1 = m.constBegin(); // detaches again + auto end2 = m.constEnd(); QCOMPARE(end - it, 2); + QT_TEST_ALL_COMPARISON_OPS(it, it + 1, Qt::strong_ordering::less); + QT_TEST_ALL_COMPARISON_OPS(it, it1 + 1, Qt::strong_ordering::less); + QT_TEST_ALL_COMPARISON_OPS(it, it - 1, Qt::strong_ordering::greater); + QT_TEST_ALL_COMPARISON_OPS(it, it1 - 1, Qt::strong_ordering::greater); + QT_TEST_EQUALITY_OPS(it, it1, true); QCOMPARE(it + 2, end); + QT_TEST_EQUALITY_OPS(it + 2, end, true); + QT_TEST_EQUALITY_OPS(it + 2, end2, true); + QT_TEST_EQUALITY_OPS(it1 + 2, end2, true); QT_TEST_EQUALITY_OPS(it.key(), QCborValue(42), true); QT_TEST_EQUALITY_OPS(it.value(), QCborValue(2.5), true); QT_TEST_EQUALITY_OPS((++it).value(), QCborValue(nullptr), true); @@ -1287,6 +1338,8 @@ void tst_QCborValue::arrayValueRef() QVERIFY(v == a.first()); QVERIFY(v == a.last()); QVERIFY(v == a[0]); + QT_TEST_EQUALITY_OPS(a.first(), v, true); + QT_TEST_EQUALITY_OPS(a.last(), v, true); auto iteratorCheck = [&v](auto it) { QT_TEST_EQUALITY_OPS(*it, v, true); @@ -1819,8 +1872,24 @@ void tst_QCborValue::mapNested() } } -void tst_QCborValue::sorting() +void tst_QCborValue::sorting_data() { + // CBOR data comparisons are done as if we were comparing their canonically + // (deterministic) encoded forms in the byte stream, including the Major + // Type. That has a few surprises noted below: + // 1) because the length of a string precedes it, effectively strings are + // sorted by their UTF-8 length before their contents + // 2) because negative integers are stored in negated form, they sort in + // descending order (i.e. by absolute value) + // 3) negative integers (Major Type 1) sort after all positive integers + // (Major Type 0) + // Effectively, this means integers are sorted as sign+magnitude. + // 4) floating point types (Major Type 7) sort after all integers + + QTest::addColumn<QCborValue>("lhs"); + QTest::addColumn<QCborValue>("rhs"); + QTest::addColumn<Qt::strong_ordering>("expectedOrdering"); + QCborValue vundef, vnull(nullptr); QCborValue vtrue(true), vfalse(false); QCborValue vint1(1), vint2(2); @@ -1839,97 +1908,213 @@ void tst_QCborValue::sorting() QCborValue vurl1(QUrl("https://example.net")), vurl2(QUrl("https://example.com/")); QCborValue vuuid1{QUuid()}, vuuid2(QUuid::createUuid()); QCborValue vsimple1(QCborSimpleType(1)), vsimple32(QCborSimpleType(32)), vsimple255(QCborSimpleType(255)); - QCborValue vdouble1(1.5), vdouble2(qInf()); + QCborValue vdouble1(1.5), vdouble2(qInf()), vdouble3(qQNaN()); QCborValue vndouble1(-1.5), vndouble2(-qInf()); + auto addRow = [](QCborValue lhs, QCborValue rhs, Qt::strong_ordering order) { + QTest::addRow("%s-cmp-%s", qPrintable(lhs.toDiagnosticNotation()), + qPrintable(rhs.toDiagnosticNotation())) + << lhs << rhs << order; + }; + auto addSelfCmp = [](QCborValue v) { + QTest::addRow("self-%s", qPrintable(v.toDiagnosticNotation())) + << v << v << Qt::strong_ordering::equal; + }; + + // self compares + addSelfCmp(vundef); + addSelfCmp(vnull); + addSelfCmp(vfalse); + addSelfCmp(vtrue); + addSelfCmp(vint1); + addSelfCmp(vint2); + addSelfCmp(vneg1); + addSelfCmp(vneg2); + addSelfCmp(vba1); + addSelfCmp(vba2); + addSelfCmp(vba3); + addSelfCmp(vs1); + addSelfCmp(vs2); + addSelfCmp(vs3); + addSelfCmp(va1); + addSelfCmp(va2); + addSelfCmp(va3); + addSelfCmp(vm1); + addSelfCmp(vm2); + addSelfCmp(vm3); + addSelfCmp(vdt1); + addSelfCmp(vdt2); + addSelfCmp(vtagged1); + addSelfCmp(vtagged2); + addSelfCmp(vtagged3); + addSelfCmp(vtagged4); + addSelfCmp(vtagged5); + addSelfCmp(vurl1); + addSelfCmp(vurl2); + addSelfCmp(vuuid1); + addSelfCmp(vuuid2); + addSelfCmp(vsimple1); + addSelfCmp(vsimple32); + addSelfCmp(vsimple255); + addSelfCmp(vdouble1); + addSelfCmp(vdouble2); + addSelfCmp(vdouble3); // surprise: NaNs do compare + addSelfCmp(vndouble1); + addSelfCmp(vndouble2); + // intra-type comparisons - QT_TEST_ALL_COMPARISON_OPS(vfalse, vtrue, Qt::strong_ordering::less); - QT_TEST_ALL_COMPARISON_OPS(vsimple1, vsimple32, Qt::strong_ordering::less); - QT_TEST_ALL_COMPARISON_OPS(vsimple32, vsimple255, Qt::strong_ordering::less); - QT_TEST_ALL_COMPARISON_OPS(vint1, vint2, Qt::strong_ordering::less); - QT_TEST_ALL_COMPARISON_OPS(vdouble1, vdouble2, Qt::strong_ordering::less); - QT_TEST_ALL_COMPARISON_OPS(vndouble1, vndouble2, Qt::strong_ordering::less); - // note: shorter length sorts first - QT_TEST_ALL_COMPARISON_OPS(vba1, vba2, Qt::strong_ordering::less); - QT_TEST_ALL_COMPARISON_OPS(vba2, vba3, Qt::strong_ordering::less); - QT_TEST_ALL_COMPARISON_OPS(vs1, vs2, Qt::strong_ordering::less); - QT_TEST_ALL_COMPARISON_OPS(vs2, vs3, Qt::strong_ordering::less); - QT_TEST_ALL_COMPARISON_OPS(va1, va2, Qt::strong_ordering::less); - QT_TEST_ALL_COMPARISON_OPS(va2, va3, Qt::strong_ordering::less); - QT_TEST_ALL_COMPARISON_OPS(vm1, vm2, Qt::strong_ordering::less); - QT_TEST_ALL_COMPARISON_OPS(vm2, vm3, Qt::strong_ordering::less); - QT_TEST_ALL_COMPARISON_OPS(vdt1, vdt2, Qt::strong_ordering::less); - QT_TEST_ALL_COMPARISON_OPS(vtagged1, vtagged2, Qt::strong_ordering::less); - QT_TEST_ALL_COMPARISON_OPS(vtagged2, vtagged3, Qt::strong_ordering::less); - QT_TEST_ALL_COMPARISON_OPS(vtagged3, vtagged4, Qt::strong_ordering::less); - QT_TEST_ALL_COMPARISON_OPS(vtagged4, vtagged5, Qt::strong_ordering::less); - QT_TEST_ALL_COMPARISON_OPS(vurl1, vurl2, Qt::strong_ordering::less); - QT_TEST_ALL_COMPARISON_OPS(vuuid1, vuuid2, Qt::strong_ordering::less); - - // surprise 1: CBOR sorts integrals by absolute value - QT_TEST_ALL_COMPARISON_OPS(vneg1, vneg2, Qt::strong_ordering::less); - - // surprise 2: CBOR sorts negatives after positives (sign+magnitude) - QT_TEST_ALL_COMPARISON_OPS(vint2, vneg1, Qt::strong_ordering::less); - QVERIFY(vint2.toInteger() > vneg1.toInteger()); - QT_TEST_ALL_COMPARISON_OPS(vdouble2, vndouble1, Qt::strong_ordering::less); - QVERIFY(vdouble2.toDouble() > vndouble1.toDouble()); + addRow(vfalse, vtrue, Qt::strong_ordering::less); + addRow(vsimple1, vsimple32, Qt::strong_ordering::less); + addRow(vsimple32, vsimple255, Qt::strong_ordering::less); + addRow(vint1, vint2, Qt::strong_ordering::less); + addRow(vdouble1, vdouble2, Qt::strong_ordering::less); + addRow(vdouble2, vdouble3, Qt::strong_ordering::less); // surprise: NaNs do compare + addRow(vndouble1, vndouble2, Qt::strong_ordering::less); // surprise: -1.5 < -inf + addRow(va1, va2, Qt::strong_ordering::less); + addRow(va2, va3, Qt::strong_ordering::less); + addRow(vm1, vm2, Qt::strong_ordering::less); + addRow(vm2, vm3, Qt::strong_ordering::less); + addRow(vdt1, vdt2, Qt::strong_ordering::less); + addRow(vtagged1, vtagged2, Qt::strong_ordering::less); + addRow(vtagged2, vtagged3, Qt::strong_ordering::less); + addRow(vtagged3, vtagged4, Qt::strong_ordering::less); + addRow(vtagged4, vtagged5, Qt::strong_ordering::less); + addRow(vurl1, vurl2, Qt::strong_ordering::less); + addRow(vuuid1, vuuid2, Qt::strong_ordering::less); + + // surprise 1: CBOR sorts strings by length first + addRow(vba1, vba2, Qt::strong_ordering::less); + addRow(vba2, vba3, Qt::strong_ordering::less); + addRow(vs1, vs2, Qt::strong_ordering::less); + addRow(vs2, vs3, Qt::strong_ordering::less); + + // surprise 2: CBOR sorts integrals by absolute value + addRow(vneg1, vneg2, Qt::strong_ordering::less); + + // surprise 3: CBOR sorts negatives after positives (sign+magnitude) + addRow(vint2, vneg1, Qt::strong_ordering::less); + addRow(vdouble2, vndouble1, Qt::strong_ordering::less); // inter-type comparisons - QT_TEST_ALL_COMPARISON_OPS(vneg2, vba1, Qt::strong_ordering::less); - QT_TEST_ALL_COMPARISON_OPS(vba3, vs1, Qt::strong_ordering::less); - QT_TEST_ALL_COMPARISON_OPS(vs3, va1, Qt::strong_ordering::less); - QT_TEST_ALL_COMPARISON_OPS(va2, vm1, Qt::strong_ordering::less); - QT_TEST_ALL_COMPARISON_OPS(vm2, vdt1, Qt::strong_ordering::less); - QT_TEST_ALL_COMPARISON_OPS(vdt2, vtagged1, Qt::strong_ordering::less); - QT_TEST_ALL_COMPARISON_OPS(vtagged2, vurl1, Qt::strong_ordering::less); - QT_TEST_ALL_COMPARISON_OPS(vurl1, vuuid1, Qt::strong_ordering::less); - QT_TEST_ALL_COMPARISON_OPS(vuuid2, vtagged3, Qt::strong_ordering::less); - QT_TEST_ALL_COMPARISON_OPS(vtagged4, vsimple1, Qt::strong_ordering::less); - QT_TEST_ALL_COMPARISON_OPS(vsimple1, vfalse, Qt::strong_ordering::less); - QT_TEST_ALL_COMPARISON_OPS(vtrue, vnull, Qt::strong_ordering::less); - QT_TEST_ALL_COMPARISON_OPS(vnull, vundef, Qt::strong_ordering::less); - QT_TEST_ALL_COMPARISON_OPS(vundef, vsimple32, Qt::strong_ordering::less); - QT_TEST_ALL_COMPARISON_OPS(vsimple255, vdouble1, Qt::strong_ordering::less); + addRow(vneg2, vba1, Qt::strong_ordering::less); + addRow(vba3, vs1, Qt::strong_ordering::less); + addRow(vs3, va1, Qt::strong_ordering::less); + addRow(va2, vm1, Qt::strong_ordering::less); + addRow(vm2, vdt1, Qt::strong_ordering::less); + addRow(vdt2, vtagged1, Qt::strong_ordering::less); + addRow(vtagged2, vurl1, Qt::strong_ordering::less); + addRow(vurl1, vuuid1, Qt::strong_ordering::less); + addRow(vuuid2, vtagged3, Qt::strong_ordering::less); + addRow(vtagged4, vsimple1, Qt::strong_ordering::less); + addRow(vsimple1, vfalse, Qt::strong_ordering::less); + addRow(vtrue, vnull, Qt::strong_ordering::less); + addRow(vnull, vundef, Qt::strong_ordering::less); + addRow(vundef, vsimple32, Qt::strong_ordering::less); + addRow(vsimple255, vdouble1, Qt::strong_ordering::less); // which shows all doubles sorted after integrals - QT_TEST_ALL_COMPARISON_OPS(vint2, vdouble1, Qt::strong_ordering::less); - QVERIFY(vint2.toInteger() > vdouble1.toDouble()); -} + addRow(vint2, vdouble1, Qt::strong_ordering::less); -void tst_QCborValue::comparison_data() -{ - QTest::addColumn<QCborValue>("lhs"); - QTest::addColumn<QCborValue>("rhs"); - QTest::addColumn<Qt::strong_ordering>("expectedOrdering"); + // Add some non-US-ASCII strings. In the current implementation, QCborValue + // can store a string as either US-ASCII, UTF-8, or UTF-16, so let's exercise + // those comparisons. - auto addRow = [](QCborValue lhs, QCborValue rhs, Qt::strong_ordering order) { - QTest::addRow("%s-cmp-%s", qPrintable(lhs.toDiagnosticNotation()), - qPrintable(rhs.toDiagnosticNotation())) - << lhs << rhs << order; + // we don't have a QUtf8StringView constructor, so work around it + auto utf8string = [](QByteArray str) { + Q_ASSERT(str.size() < 24); + str.prepend(char(QCborValue::String) + str.size()); + return QCborValue::fromCbor(str); }; - // typical, sorts as expected - addRow(0, 0, Qt::strong_ordering::equivalent); - addRow(1, 0, Qt::strong_ordering::greater); - addRow(0, 1, Qt::strong_ordering::less); - addRow(10.0, 10.0, Qt::strong_ordering::equivalent); - addRow(10.5, 10.8, Qt::strong_ordering::less); - addRow(-10.5, -10.8, Qt::strong_ordering::less); - addRow("Qt","Qt", Qt::strong_ordering::equivalent); - addRow("qt","Qt", Qt::strong_ordering::greater); - // atypical gotchas - addRow(0, -1, Qt::strong_ordering::less); - addRow(10, 10.0, Qt::strong_ordering::less); - addRow(0, "Qt", Qt::strong_ordering::less); + auto addStringCmp = [&](const char *prefix, const char *tag, QUtf8StringView lhs, + QUtf8StringView rhs) { + // CBOR orders strings by UTF-8 length + auto order = Qt::compareThreeWay(lhs.size(), rhs.size()); + if (is_eq(order)) + order = compareThreeWay(lhs, rhs); + Q_ASSERT(is_eq(order) || is_lt(order)); // please keep lhs <= rhs! + + QCborValue lhs_utf8 = utf8string(QByteArrayView(lhs).toByteArray()); + QCborValue rhs_utf8 = utf8string(QByteArrayView(rhs).toByteArray()); + QCborValue lhs_utf16 = QString::fromUtf8(lhs); + QCborValue rhs_utf16 = QString::fromUtf8(rhs); + + QTest::addRow("string-%s%s:utf8-utf8", prefix, tag) << lhs_utf8 << rhs_utf8 << order; + QTest::addRow("string-%s%s:utf8-utf16", prefix, tag) << lhs_utf8 << rhs_utf16 << order; + QTest::addRow("string-%s%s:utf16-utf8", prefix, tag) << lhs_utf16 << rhs_utf8 << order; + QTest::addRow("string-%s%s:utf16-utf16", prefix, tag) << lhs_utf16 << rhs_utf16 << order; + }; + auto addStringCmpSameLength = [&](const char *tag, QUtf8StringView lhs, QUtf8StringView rhs) { + Q_ASSERT(lhs.size() == rhs.size()); + addStringCmp("samelength-", tag, lhs, rhs); + }; + auto addStringCmpShorter = [&](const char *tag, QUtf8StringView lhs, QUtf8StringView rhs) { + Q_ASSERT(lhs.size() < rhs.size()); + addStringCmp("shorter-", tag, lhs, rhs); + }; + + // ascii-only is already tested + addStringCmp("equal-", "1continuation", "ab\u00A0c", "ab\u00A0c"); + addStringCmp("equal-", "2continuation", "ab\u0800", "ab\u0800"); + addStringCmp("equal-", "3continuation", "a\U00010000", "a\U00010000"); + + // these strings all have the same UTF-8 length (5 bytes) + addStringCmpSameLength("less-ascii", "abcde", "ab\u00A0c"); + addStringCmpSameLength("less-1continuation", "ab\u00A0c", "ab\u07FFc"); + addStringCmpSameLength("less-2continuation", "ab\u0800", "ab\uFFFC"); + addStringCmpSameLength("less-3continuation", "a\U00010000", "a\U0010FFFC"); + addStringCmpSameLength("less-0-vs-1continuation", "abcde", "ab\u00A0c"); + addStringCmpSameLength("less-0-vs-2continuation", "abcde", "ab\u0800"); + addStringCmpSameLength("less-0-vs-3continuation", "abcde", "a\U00010000"); + addStringCmpSameLength("less-1-vs-2continuation", "ab\u00A0c", "ab\uFFFC"); + addStringCmpSameLength("less-1-vs-3continuation", "ab\u00A0c", "a\U00010000"); + addStringCmpSameLength("less-2-vs-3continuation", "ab\u0800", "a\U00010000"); + addStringCmpSameLength("less-2-vs-3continuation_surrogate", "a\uFFFCz", "a\U00010000"); // even though U+D800 < U+FFFC + + // these strings have different lengths in UTF-8 + // (0continuation already tested) + addStringCmpShorter("1continuation", "ab\u00A0", "ab\u00A0c"); + addStringCmpShorter("2continuation", "ab\u0800", "ab\u0800c"); + addStringCmpShorter("3continuation", "ab\U00010000", "ab\U00010000c"); + // most of these have the same length in UTF-16! + addStringCmpShorter("0-vs-1continuation", "abc", "ab\u00A0"); + addStringCmpShorter("0-vs-2continuation", "abcd", "ab\u0800"); + addStringCmpShorter("0-vs-3continuation", "abcde", "ab\U00010000"); + addStringCmpShorter("1-vs-2continuation", "ab\u00A0", "ab\u0800"); + addStringCmpShorter("1-vs-3continuation", "abc\u00A0", "ab\U00010000"); + addStringCmpShorter("2-vs-3continuation", "ab\u0800", "ab\U00010000"); + + // lhs is 4xUTF-16 and 8xUTF-8; rhs is 3xUTF-16 but 9xUTF-8 + addStringCmpShorter("3x2-vs-2x3continuation", "\U00010000\U00010000", "\u0800\u0800\u0800"); + + // slight surprising because normally rhs would sort first ("aa" vs "ab" prefix) + // (0continuation_surprise already tested) + addStringCmpShorter("1continuation_surprise", "ab\u00A0", "aa\u00A0c"); + addStringCmpShorter("2continuation_surprise", "ab\u0800", "aa\u0800c"); + addStringCmpShorter("3continuation_surprise", "ab\U00010000", "aa\U00010000c"); + addStringCmpShorter("0-vs-1continuation_surprise", "abc", "aa\u00A0"); + addStringCmpShorter("0-vs-2continuation_surprise", "abcd", "aa\u0800"); + addStringCmpShorter("0-vs-3continuation_surprise", "abcde", "aa\U00010000"); + addStringCmpShorter("1-vs-2continuation_surprise", "ab\u00A0", "aa\u0800"); + addStringCmpShorter("1-vs-3continuation_surprise", "abc\u00A0", "aa\U00010000"); + addStringCmpShorter("2-vs-3continuation_surprise", "ab\u0800", "aa\U00010000"); } -void tst_QCborValue::comparison() +void tst_QCborValue::sorting() { QFETCH(QCborValue, lhs); QFETCH(QCborValue, rhs); QFETCH(Qt::strong_ordering, expectedOrdering); + // do a QCOMPARE first so we get a proper QTest error in case QCborValue is + // broken + if (expectedOrdering == Qt::strong_ordering::equal) + QCOMPARE_EQ(lhs, rhs); + else if (expectedOrdering == Qt::strong_ordering::less) + QCOMPARE_LT(lhs, rhs); + else if (expectedOrdering == Qt::strong_ordering::greater) + QCOMPARE_GT(lhs, rhs); + QCborArray array{lhs, rhs}; QCborValueConstRef lhsCRef = array.constBegin()[0]; @@ -1937,7 +2122,7 @@ void tst_QCborValue::comparison() QCborValueRef lhsRef = array[0]; QCborValueRef rhsRef = array[1]; - // QCborValue vs QCborValue + // QCborValue vs QCborValue QT_TEST_ALL_COMPARISON_OPS(lhs, rhs, expectedOrdering); // QCborValueConstRef vs QCborValueConstRef QT_TEST_ALL_COMPARISON_OPS(lhsCRef, rhsCRef, expectedOrdering); @@ -1951,7 +2136,6 @@ void tst_QCborValue::comparison() QT_TEST_ALL_COMPARISON_OPS(lhsCRef, rhsRef, expectedOrdering); } - void tst_QCborValue::comparisonMap_data() { QTest::addColumn<QCborMap>("left"); @@ -2131,6 +2315,7 @@ void tst_QCborValue::toCbor_data() QTest::newRow("UseInteger:-2^65") << QCborValue(-2 * 18446744073709551616.0) << raw("\xfb\xc4\0\0\0""\0\0\0\0") << QCborValue::EncodingOptions(QCborValue::UseIntegers); } +#if QT_CONFIG(cborstreamwriter) void tst_QCborValue::toCbor() { QFETCH(QCborValue, v); @@ -2170,6 +2355,7 @@ void tst_QCborValue::toCborStreamWriter() QCOMPARE(buffer.pos(), result.size()); QCOMPARE(output, result); } +#endif void tst_QCborValue::fromCbor_data() { @@ -2487,12 +2673,14 @@ void tst_QCborValue::extendedTypeValidation() QCOMPARE(error.offset, data.size()); QT_TEST_EQUALITY_OPS(decoded, expected, true); +#if QT_CONFIG(cborstreamwriter) QByteArray encoded = decoded.toCbor(); #if QT_VERSION < QT_VERSION_CHECK(6,0,0) // behavior change, see qdatetime.cpp:fromIsoTimeString QEXPECT_FAIL("DateTime:Null-at-19", "QDateTime parsing fixed, but only in 6.0", Abort); #endif QCOMPARE(encoded, data); +#endif } void tst_QCborValue::hugeDeviceValidation_data() @@ -2820,7 +3008,9 @@ template <typename ValueRef> static void cborValueRef_template() else QCOMPARE(ref.toVariant(), v.toVariant()); QCOMPARE(ref.toJsonValue(), v.toJsonValue()); +#if QT_CONFIG(cborstreamwriter) QCOMPARE(ref.toCbor(), v.toCbor()); +#endif QCOMPARE(ref.toDiagnosticNotation(), v.toDiagnosticNotation()); } @@ -2980,6 +3170,7 @@ void tst_QCborValue::datastreamSerialization_data() void tst_QCborValue::datastreamSerialization() { +#if QT_CONFIG(cborstreamwriter) QFETCH(QCborValue, v); QByteArray buffer; { @@ -3007,6 +3198,7 @@ void tst_QCborValue::datastreamSerialization() load >> output; QCOMPARE(output, map); } +#endif } void tst_QCborValue::streamVariantSerialization() diff --git a/tests/auto/corelib/serialization/qdatastream/tst_qdatastream.cpp b/tests/auto/corelib/serialization/qdatastream/tst_qdatastream.cpp index 77ca884897..9a227c782d 100644 --- a/tests/auto/corelib/serialization/qdatastream/tst_qdatastream.cpp +++ b/tests/auto/corelib/serialization/qdatastream/tst_qdatastream.cpp @@ -143,9 +143,11 @@ private slots: void stream_QJsonObject(); void stream_QJsonValue(); +#if QT_CONFIG(cborstreamwriter) void stream_QCborArray(); void stream_QCborMap(); void stream_QCborValue(); +#endif void setVersion_data(); void setVersion(); @@ -2326,6 +2328,7 @@ void tst_QDataStream::stream_QJsonValue() } } +#if QT_CONFIG(cborstreamwriter) void tst_QDataStream::stream_QCborArray() { QByteArray buffer; @@ -2361,6 +2364,7 @@ void tst_QDataStream::stream_QCborValue() load >> valueLoad; QCOMPARE(valueLoad, valueSave); } +#endif void tst_QDataStream::setVersion_data() { @@ -3254,11 +3258,13 @@ void tst_QDataStream::streamRealDataTypes() // Generate QPicture from pixmap. QPixmap pm(open_xpm); QVERIFY(!pm.isNull()); +#ifndef QT_NO_PICTURE QPicture picture; picture.setBoundingRect(QRect(QPoint(0, 0), pm.size())); QPainter painter(&picture); painter.drawPixmap(0, 0, pm); painter.end(); +#endif // Generate path QPainterPath path; @@ -3296,7 +3302,9 @@ void tst_QDataStream::streamRealDataTypes() stream << QPointF(3, 5) << QRectF(-1, -2, 3, 4) << (QPolygonF() << QPointF(0, 0) << QPointF(1, 2)); stream << QTransform().rotate(90).scale(2, 2).asAffineMatrix(); stream << path; +#ifndef QT_NO_PICTURE stream << picture; +#endif stream << QTextLength(QTextLength::VariableLength, 1.5); stream << color; stream << radialBrush << conicalBrush; @@ -3310,7 +3318,9 @@ void tst_QDataStream::streamRealDataTypes() QPolygonF polygon {{3, 4}, {5, 6}}; QTransform transform; QPainterPath p = otherPath; +#ifndef QT_NO_PICTURE QPicture pict; +#endif QTextLength textLength(QTextLength::FixedLength, 2.5); QColor col(128, 128, 127); QBrush rGrad(Qt::CrossPattern); @@ -3363,6 +3373,7 @@ void tst_QDataStream::streamRealDataTypes() QCOMPARE(transform, QTransform().rotate(90).scale(2, 2)); stream >> p; QCOMPARE(p, path); +#ifndef QT_NO_PICTURE if (i == 1) { stream >> pict; @@ -3376,6 +3387,7 @@ void tst_QDataStream::streamRealDataTypes() QCOMPARE(pictA, pictB); } +#endif stream >> textLength; QCOMPARE(textLength, QTextLength(QTextLength::VariableLength, 1.5)); stream >> col; diff --git a/tests/auto/corelib/serialization/qxmlstream/tst_qxmlstream.cpp b/tests/auto/corelib/serialization/qxmlstream/tst_qxmlstream.cpp index 0b7d9ab0ed..b90d05b0fa 100644 --- a/tests/auto/corelib/serialization/qxmlstream/tst_qxmlstream.cpp +++ b/tests/auto/corelib/serialization/qxmlstream/tst_qxmlstream.cpp @@ -95,8 +95,8 @@ static QByteArray makeCanonical(const QString &filename, bool testIncremental = false) { QFile file(filename); - file.open(QIODevice::ReadOnly); - + if (!file.open(QIODevice::ReadOnly)) + qFatal("Could not open file %s", qPrintable(filename)); QXmlStreamReader reader; QByteArray buffer; @@ -572,6 +572,14 @@ private slots: void hasAttribute() const; void writeWithUtf8Codec() const; void writeWithStandalone() const; + void writeCharacters_data() const; + void writeCharacters() const; + void writeAttribute_data() const; + void writeAttribute() const; + void writeBadCharactersUtf8_data() const; + void writeBadCharactersUtf8() const; + void writeBadCharactersUtf16_data() const; + void writeBadCharactersUtf16() const; void entitiesAndWhitespace_1() const; void entitiesAndWhitespace_2() const; void testFalsePrematureError() const; @@ -747,7 +755,8 @@ void tst_QXmlStream::reportSuccess_data() const QByteArray tst_QXmlStream::readFile(const QString &filename) { QFile file(filename); - file.open(QIODevice::ReadOnly); + if (!file.open(QIODevice::ReadOnly)) + qFatal("Could not open file %s", qPrintable(filename)); QXmlStreamReader reader; @@ -1406,6 +1415,143 @@ void tst_QXmlStream::writeWithStandalone() const } } +static void writeCharacters_data_common() +{ + QTest::addColumn<QString>("input"); + QTest::addColumn<QString>("output"); + + QTest::newRow("empty") << QString() << QString(); + + // invalid content + QTest::newRow("null-character") << u"\0"_s << QString(); + QTest::newRow("vertical-tab") << "\v" << QString(); + QTest::newRow("form-feed") << "\f" << QString(); + QTest::newRow("esc") << "\x1f" << QString(); + QTest::newRow("U+FFFE") << u"\xfffe"_s << QString(); + QTest::newRow("U+FFFF") << u"\xffff"_s << QString(); + + // simple strings + QTest::newRow("us-ascii") << "Hello, world" << "Hello, world"; + QTest::newRow("latin1") << "Bokmål" << "Bokmål"; + QTest::newRow("nonlatin1") << "Ελληνικά" << "Ελληνικά"; + QTest::newRow("nonbmp") << u"\U00010000"_s << u"\U00010000"_s; + + // escaped content + QTest::newRow("less-than") << "<" << "<"; + QTest::newRow("greater-than") << ">" << ">"; + QTest::newRow("ampersand") << "&" << "&"; + QTest::newRow("quote") << "\"" << """; +} + +template <typename Execute, typename Transform> +static void writeCharacters_common(Execute &&exec, Transform &&transform) +{ + QFETCH(QString, input); + QFETCH(QString, output); + QStringView utf16 = input; + QByteArray utf8ba = input.toUtf8(); + QUtf8StringView utf8(utf8ba); + + // may be invalid if input is not Latin1 + QByteArray l1ba = input.toLatin1(); + QLatin1StringView l1(l1ba); + if (l1 != input) + l1 = {}; + + auto write = [&](auto input) -> std::optional<QString> { + QString result; + QXmlStreamWriter writer(&result); + writer.writeStartElement("a"); + exec(writer, input); + writer.writeEndElement(); + if (writer.hasError()) + return std::nullopt; + return result; + }; + + if (input.isNull() != output.isNull()) { + // error + QCOMPARE(write(utf16), std::nullopt); + QCOMPARE(write(utf8), std::nullopt); + if (!l1.isEmpty()) + QCOMPARE(write(l1), std::nullopt); + } else { + output = transform(output); + QCOMPARE(write(utf16), output); + QCOMPARE(write(utf8), output); + if (!l1.isEmpty()) + QCOMPARE(write(l1), output); + } +} + +void tst_QXmlStream::writeCharacters_data() const +{ + writeCharacters_data_common(); + QTest::newRow("tab") << "\t" << "\t"; + QTest::newRow("newline") << "\n" << "\n"; + QTest::newRow("carriage-return") << "\r" << "\r"; +} + +void tst_QXmlStream::writeCharacters() const +{ + auto exec = [](QXmlStreamWriter &writer, auto input) { + writer.writeCharacters(input); + }; + auto transform = [](auto output) { return "<a>" + output + "</a>"; }; + writeCharacters_common(exec, transform); +} + +void tst_QXmlStream::writeAttribute_data() const +{ + writeCharacters_data_common(); + QTest::newRow("tab") << "\t" << "	"; + QTest::newRow("newline") << "\n" << " "; + QTest::newRow("carriage-return") << "\r" << " "; +} + +void tst_QXmlStream::writeAttribute() const +{ + auto exec = [](QXmlStreamWriter &writer, auto input) { + writer.writeAttribute("b", input); + }; + auto transform = [](auto output) { return "<a b=\"" + output + "\"/>"; }; + writeCharacters_common(exec, transform); +} + +#include "../../io/qurlinternal/utf8data.cpp" +void tst_QXmlStream::writeBadCharactersUtf8_data() const +{ + QTest::addColumn<QByteArray>("input"); + loadInvalidUtf8Rows(); +} + +void tst_QXmlStream::writeBadCharactersUtf8() const +{ + QFETCH(QByteArray, input); + QString target; + QXmlStreamWriter writer(&target); + writer.writeTextElement("a", QUtf8StringView(input)); + QVERIFY(writer.hasError()); +} + +void tst_QXmlStream::writeBadCharactersUtf16_data() const +{ + QTest::addColumn<QString>("input"); + QTest::addRow("low-surrogate") << u"\xdc00"_s; + QTest::addRow("high-surrogate") << u"\xd800"_s; + QTest::addRow("inverted-surrogate-pair") << u"\xdc00\xd800"_s; + QTest::addRow("high-surrogate+non-surrogate") << u"\xd800z"_s; +} + +void tst_QXmlStream::writeBadCharactersUtf16() const +{ + QFETCH(QString, input); + QString target; + QXmlStreamWriter writer(&target); + writer.writeTextElement("a", input); + QVERIFY(writer.hasError()); +} + void tst_QXmlStream::entitiesAndWhitespace_1() const { QXmlStreamReader reader(QLatin1String("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\" \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\"><test>&extEnt;</test>")); |