From bf65c277892f6f322fa689c06d81ba9b1d9a8038 Mon Sep 17 00:00:00 2001 From: Edward Welbourne Date: Mon, 2 Dec 2019 16:15:14 +0100 Subject: Fix more mis-handling of spaces in ISO date format strings ISO date format doesn't allow spaces within a date, although 3339 does allow a space to replace the T between date and time. Sixteen tests added to check this all failed. So clean up the handling of spaces in the parsing of ISO date-time strings. [ChangeLog][QtCore][QDateTime] ISO 8601: parsing of dates now requires a punctuator as separator (it previously allowed any non-digit; officially only a dash should be allowed) and parsing of date-times no longer tolerates spaces in the numeric fields: an internal space is only allowed in an ISO 8601 date-time as replacement for the T between date and time. Change-Id: I24d110e71d416ecef74e196d5ee270b59d1bd813 Reviewed-by: Thiago Macieira --- .../auto/corelib/time/qdatetime/tst_qdatetime.cpp | 38 ++++++++++++++++++++++ 1 file changed, 38 insertions(+) (limited to 'tests/auto/corelib') diff --git a/tests/auto/corelib/time/qdatetime/tst_qdatetime.cpp b/tests/auto/corelib/time/qdatetime/tst_qdatetime.cpp index 7778542736..c03d112560 100644 --- a/tests/auto/corelib/time/qdatetime/tst_qdatetime.cpp +++ b/tests/auto/corelib/time/qdatetime/tst_qdatetime.cpp @@ -2213,8 +2213,46 @@ void tst_QDateTime::fromStringDateFormat_data() QTest::newRow("trailing space") // QTBUG-80445 << QString("2000-01-02 03:04:05.678 ") << Qt::ISODate << QDateTime(QDate(2000, 1, 2), QTime(3, 4, 5, 678)); + + // Invalid spaces (but keeping field widths correct): QTest::newRow("space before millis") << QString("2000-01-02 03:04:05. 678") << Qt::ISODate << QDateTime(); + QTest::newRow("space after seconds") + << QString("2000-01-02 03:04:5 .678") << Qt::ISODate << QDateTime(); + QTest::newRow("space before seconds") + << QString("2000-01-02 03:04: 5.678") << Qt::ISODate << QDateTime(); + QTest::newRow("space after minutes") + << QString("2000-01-02 03:4 :05.678") << Qt::ISODate << QDateTime(); + QTest::newRow("space before minutes") + << QString("2000-01-02 03: 4:05.678") << Qt::ISODate << QDateTime(); + QTest::newRow("space after hour") + << QString("2000-01-02 3 :04:05.678") << Qt::ISODate << QDateTime(); + QTest::newRow("space before hour") + << QString("2000-01-02 3:04:05.678") << Qt::ISODate << QDateTime(); + QTest::newRow("space after day") + << QString("2000-01-2 03:04:05.678") << Qt::ISODate << QDateTime(); + QTest::newRow("space before day") + << QString("2000-01- 2 03:04:05.678") << Qt::ISODate << QDateTime(); + QTest::newRow("space after month") + << QString("2000-1 -02 03:04:05.678") << Qt::ISODate << QDateTime(); + QTest::newRow("space before month") + << QString("2000- 1-02 03:04:05.678") << Qt::ISODate << QDateTime(); + QTest::newRow("space after year") + << QString("200 -01-02 03:04:05.678") << Qt::ISODate << QDateTime(); + + // Spaces as separators: + QTest::newRow("sec-milli space") + << QString("2000-01-02 03:04:05 678") << Qt::ISODate + // Should be invalid, but we ignore trailing cruft (in some cases) + << QDateTime(QDate(2000, 1, 2), QTime(3, 4, 5)); + QTest::newRow("min-sec space") + << QString("2000-01-02 03:04 05.678") << Qt::ISODate << QDateTime(); + QTest::newRow("hour-min space") + << QString("2000-01-02 03 04:05.678") << Qt::ISODate << QDateTime(); + QTest::newRow("mon-day space") + << QString("2000-01 02 03:04:05.678") << Qt::ISODate << QDateTime(); + QTest::newRow("year-mon space") + << QString("2000 01-02 03:04:05.678") << Qt::ISODate << QDateTime(); // Normal usage: QTest::newRow("ISO +01:00") << QString::fromLatin1("1987-02-13T13:24:51+01:00") -- cgit v1.2.3 From c15d6a155c6121bad68a3ec60be62181fb92d0f8 Mon Sep 17 00:00:00 2001 From: Fabian Kosmale Date: Tue, 10 Dec 2019 14:55:14 +0100 Subject: QVariant: introduce ShouldDeleteVariantData flag This flag is used in QSequentialIterable and QAssociativeIterable to indicate that the data pointer in VariantData should be deleted after the variant has been constructed. The use case for this is https://codereview.qt-project.org/c/qt/qtdeclarative/+/284151, where we have a proxy iterator and cannot easily return a pointer to already owned data, as it is hard to manage its lifetime in the iterator. In contrast, it is clear that we can release the memory in the QSequentialIterable functions, as it has already been copied into the QVariant there. Change-Id: I2b33497d991cd4f752153e0ebda767b82e4bb851 Reviewed-by: Olivier Goffart (Woboq GmbH) --- .../auto/corelib/kernel/qvariant/tst_qvariant.cpp | 97 +++++++++++++++++++++- 1 file changed, 96 insertions(+), 1 deletion(-) (limited to 'tests/auto/corelib') diff --git a/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp b/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp index edb15a8db2..e719871128 100644 --- a/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp +++ b/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp @@ -31,6 +31,7 @@ #include #include +#include #include #include #include @@ -276,7 +277,8 @@ private slots: void nullConvert(); void accessSequentialContainerKey(); - + void shouldDeleteVariantDataWorksForSequential(); + void shouldDeleteVariantDataWorksForAssociative(); void fromStdVariant(); void qt4UuidDataStream(); @@ -4990,6 +4992,99 @@ void tst_QVariant::accessSequentialContainerKey() QCOMPARE(nameResult, QStringLiteral("Seven")); } +void tst_QVariant::shouldDeleteVariantDataWorksForSequential() +{ + QCOMPARE(instanceCount, 0); + { + QtMetaTypePrivate::QSequentialIterableImpl iterator {}; + iterator._iteratorCapabilities = QtMetaTypePrivate::RandomAccessCapability | + QtMetaTypePrivate::BiDirectionalCapability | + QtMetaTypePrivate::ForwardCapability; + iterator._metaType_flags = QVariantConstructionFlags::ShouldDeleteVariantData; + + iterator._size = [](const void *) {return 1;}; + iterator._metaType_id = qMetaTypeId(); + iterator._moveToBegin = [](const void *, void **) {}; + iterator._moveToEnd = [](const void *, void **) {}; + iterator._advance = [](void **, int) {}; + iterator._destroyIter = [](void **){}; + iterator._equalIter = [](void * const *, void * const *){return true; /*all iterators are nullptr*/}; + iterator._destroyIter = [](void **){}; + iterator._at = [](const void *, int ) -> void const * { + MyType mytype {1, "eins"}; + return QMetaType::create(qMetaTypeId(), &mytype); + }; + iterator._get = [](void * const *, int, uint) -> QtMetaTypePrivate::VariantData { + MyType mytype {2, "zwei"}; + return {qMetaTypeId(), QMetaType::create(qMetaTypeId(), &mytype), QVariantConstructionFlags::ShouldDeleteVariantData}; + }; + QSequentialIterable iterable {iterator}; + QVariant value1 = iterable.at(0); + QVERIFY(value1.canConvert()); + QCOMPARE(value1.value().number, 1); + QVariant value2 = *iterable.begin(); + QVERIFY(value2.canConvert()); + QCOMPARE(value2.value().number, 2); + } + QCOMPARE(instanceCount, 0); +} + +void tst_QVariant::shouldDeleteVariantDataWorksForAssociative() +{ + QCOMPARE(instanceCount, 0); + { + QtMetaTypePrivate::QAssociativeIterableImpl iterator {}; + iterator._metaType_flags_key = QVariantConstructionFlags::ShouldDeleteVariantData; + iterator._metaType_flags_value = QVariantConstructionFlags::ShouldDeleteVariantData; + + iterator._size = [](const void *) {return 1;}; + iterator._metaType_id_value = qMetaTypeId(); + iterator._metaType_id_key = qMetaTypeId(); + iterator._begin = [](const void *, void **) {}; + iterator._end = [](const void *, void **) {}; + iterator._advance = [](void **, int) {}; + iterator._destroyIter = [](void **){}; + iterator._equalIter = [](void * const *, void * const *){return true; /*all iterators are nullptr*/}; + iterator._destroyIter = [](void **){}; + iterator._find = [](const void *, const void *, void **iterator ) -> void { + (*iterator) = reinterpret_cast(quintptr(42)); + }; + iterator._getKey = [](void * const *iterator, int, uint) -> QtMetaTypePrivate::VariantData { + MyType mytype {1, "key"}; + if (reinterpret_cast(*iterator) == 42) { + mytype.number = 42; + mytype.text = "find_key"; + } + return {qMetaTypeId(), QMetaType::create(qMetaTypeId(), &mytype), QVariantConstructionFlags::ShouldDeleteVariantData}; + }; + iterator._getValue = [](void * const *iterator, int, uint) -> QtMetaTypePrivate::VariantData { + MyType mytype {2, "value"}; + if (reinterpret_cast(*iterator) == 42) { + mytype.number = 42; + mytype.text = "find_value"; + } + return {qMetaTypeId(), QMetaType::create(qMetaTypeId(), &mytype), QVariantConstructionFlags::ShouldDeleteVariantData}; + }; + QAssociativeIterable iterable {iterator}; + auto it = iterable.begin(); + QVariant value1 = it.key(); + QVERIFY(value1.canConvert()); + QCOMPARE(value1.value().number, 1); + QCOMPARE(value1.value().text, "key"); + QVariant value2 = it.value(); + QVERIFY(value2.canConvert()); + QCOMPARE(value2.value().number, 2); + auto findIt = iterable.find(QVariant::fromValue(MyType {})); + value1 = findIt.key(); + QCOMPARE(value1.value().number, 42); + QCOMPARE(value1.value().text, "find_key"); + value2 = findIt.value(); + QCOMPARE(value2.value().number, 42); + QCOMPARE(value2.value().text, "find_value"); + } + QCOMPARE(instanceCount, 0); +} + void tst_QVariant::fromStdVariant() { #if __has_include() && __cplusplus >= 201703L -- cgit v1.2.3