From d13a416d0004aa12cda642dee2c4735ae25c79c7 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Fri, 14 Feb 2025 22:59:55 +0100 Subject: [PATCH] tst_QStringTokenizer: check when the lazy range may be empty Only when using SkipEmptyParts... Pick-to: 6.5 Change-Id: I7dd67b801fa0deaab14eb7bb7e9905f60891ec48 Reviewed-by: Fabian Kosmale (cherry picked from commit cef7892135b4fccc85512629e8bee76ddfbc3240) Reviewed-by: Qt Cherry-pick Bot (cherry picked from commit 0e7f52c8726c3c5b53d7dc9133a82e551fe830a7) --- .../qstringtokenizer/tst_qstringtokenizer.cpp | 78 +++++++++++++++++++ 1 file changed, 78 insertions(+) diff --git a/tests/auto/corelib/text/qstringtokenizer/tst_qstringtokenizer.cpp b/tests/auto/corelib/text/qstringtokenizer/tst_qstringtokenizer.cpp index 0101c74a7b..49dadf229c 100644 --- a/tests/auto/corelib/text/qstringtokenizer/tst_qstringtokenizer.cpp +++ b/tests/auto/corelib/text/qstringtokenizer/tst_qstringtokenizer.cpp @@ -9,16 +9,30 @@ #include Q_DECLARE_METATYPE(Qt::SplitBehavior) + namespace { class tst_QStringTokenizer : public QObject { Q_OBJECT +public: + enum class Content : bool { Null, Empty }; + Q_ENUM(Content) + private Q_SLOTS: void constExpr() const; void basics_data() const; void basics() const; void toContainer() const; + + void emptyResult_L1_data() const { emptyResult_data_impl(); } + void emptyResult_L1() const { emptyResult_impl(); } + void emptyResult_U16_data() const { emptyResult_data_impl(); } + void emptyResult_U16() const { emptyResult_impl(); } +private: + template + void emptyResult_impl() const; + void emptyResult_data_impl() const; }; static QStringList skipped(const QStringList &sl) @@ -136,5 +150,69 @@ void tst_QStringTokenizer::toContainer() const } } +void tst_QStringTokenizer::emptyResult_data_impl() const +{ + // try really hard to get an empty result... + + QTest::addColumn("haystack"); + QTest::addColumn("needle"); + QTest::addColumn("behavior"); + + const auto str = [] (auto e) { + using E = decltype(e); + const auto me = QMetaEnum::fromType(); + if constexpr (std::is_enum_v) + return me.valueToKey(qToUnderlying(e)); + else + return me.valueToKey(e.toInt()); // QFlags + }; + + for (auto haystack : {Content::Null, Content::Empty}) { + for (auto needle : {Content::Null, Content::Empty}) { + for (auto behavior : {Qt::KeepEmptyParts, Qt::SkipEmptyParts}) { + QTest::addRow("%s/%s (%s)", + str(haystack), + str(needle), + str(Qt::SplitBehavior{behavior})) + << haystack << needle << Qt::SplitBehavior{behavior}; + } + } + } +} + +template +void tst_QStringTokenizer::emptyResult_impl() const +{ + QFETCH(const Content, haystack); + QFETCH(const Content, needle); + QFETCH(const Qt::SplitBehavior, behavior); + + auto select = [](Content c, View null, View empty) { + switch (c) { + case Content::Empty: return empty; + case Content::Null: return null; + } + Q_UNREACHABLE_RETURN(null); + }; + + const auto null = View{nullptr}; + QVERIFY(null.isNull()); + + using Char = typename View::value_type; + const Char ch{0}; + const auto empty = View{&ch, qsizetype{0}}; + QVERIFY(empty.isEmpty()); + + { + const auto tok = qTokenize(select(haystack, null, empty), + select(needle, null, empty), + behavior); + if (behavior & Qt::SkipEmptyParts) + QCOMPARE_EQ(tok.begin(), tok.end()); // iow: empty + else + QCOMPARE_NE(tok.begin(), tok.end()); // iow: not empty + } +} + QTEST_APPLESS_MAIN(tst_QStringTokenizer) #include "tst_qstringtokenizer.moc"