diff options
Diffstat (limited to 'tests/auto/corelib/text/qregularexpression/tst_qregularexpression.cpp')
-rw-r--r-- | tests/auto/corelib/text/qregularexpression/tst_qregularexpression.cpp | 872 |
1 files changed, 598 insertions, 274 deletions
diff --git a/tests/auto/corelib/text/qregularexpression/tst_qregularexpression.cpp b/tests/auto/corelib/text/qregularexpression/tst_qregularexpression.cpp index 98cbd0b4a5..d0ce414095 100644 --- a/tests/auto/corelib/text/qregularexpression/tst_qregularexpression.cpp +++ b/tests/auto/corelib/text/qregularexpression/tst_qregularexpression.cpp @@ -1,33 +1,9 @@ -/**************************************************************************** -** -** Copyright (C) 2015 Giuseppe D'Angelo <dangelog@gmail.com>. -** Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Giuseppe D'Angelo <giuseppe.dangelo@kdab.com> -** 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 <QtTest/QtTest> +// Copyright (C) 2015 Giuseppe D'Angelo <dangelog@gmail.com>. +// Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Giuseppe D'Angelo <giuseppe.dangelo@kdab.com> +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#include <QTest> +#include <QtTest/private/qcomparisontesthelper_p.h> #include <qstring.h> #include <qlist.h> #include <qstringlist.h> @@ -37,6 +13,9 @@ #include <qregularexpression.h> #include <qthread.h> +#include <iostream> +#include <optional> + Q_DECLARE_METATYPE(QRegularExpression::PatternOptions) Q_DECLARE_METATYPE(QRegularExpression::MatchType) Q_DECLARE_METATYPE(QRegularExpression::MatchOptions) @@ -45,8 +24,15 @@ class tst_QRegularExpression : public QObject { Q_OBJECT +public: + static void initMain(); + private slots: + void compareCompiles(); void defaultConstructors(); + void moveSemantics(); + void moveSemanticsMatch(); + void moveSemanticsMatchIterator(); void gettersSetters_data(); void gettersSetters(); void escape_data(); @@ -69,16 +55,18 @@ private slots: void captureCount(); void captureNames_data(); void captureNames(); + void captureNamesNul(); void pcreJitStackUsage_data(); void pcreJitStackUsage(); void regularExpressionMatch_data(); void regularExpressionMatch(); void JOptionUsage_data(); void JOptionUsage(); - void QStringAndQStringRefEquivalence(); + void QStringAndQStringViewEquivalence(); void threadSafety_data(); void threadSafety(); + void returnsViewsIntoOriginalString(); void wildcard_data(); void wildcard(); void testInvalidWildcard_data(); @@ -88,6 +76,8 @@ private: void provideRegularExpressions(); }; +using CapturedList = QVector<std::optional<QString>>; + struct Match { Match() @@ -107,11 +97,11 @@ struct Match bool isValid; bool hasMatch; bool hasPartialMatch; - QStringList captured; - QHash<QString, QString> namedCaptured; + CapturedList captured; + QHash<QString, std::optional<QString>> namedCaptured; }; QT_BEGIN_NAMESPACE -Q_DECLARE_TYPEINFO(Match, Q_MOVABLE_TYPE); +Q_DECLARE_TYPEINFO(Match, Q_RELOCATABLE_TYPE); QT_END_NAMESPACE Q_DECLARE_METATYPE(Match) @@ -125,27 +115,53 @@ bool operator==(const QRegularExpressionMatch &rem, const Match &m) if ((rem.hasMatch() != m.hasMatch) || (rem.hasPartialMatch() != m.hasPartialMatch)) return false; if (rem.hasMatch() || rem.hasPartialMatch()) { + if (!rem.hasCaptured(0)) + return false; if (rem.lastCapturedIndex() != (m.captured.size() - 1)) return false; for (int i = 0; i <= rem.lastCapturedIndex(); ++i) { + auto mMaybeCaptured = m.captured.at(i); QString remCaptured = rem.captured(i); - QString mCaptured = m.captured.at(i); - if (remCaptured != mCaptured - || remCaptured.isNull() != mCaptured.isNull() - || remCaptured.isEmpty() != mCaptured.isEmpty()) { - return false; + if (!mMaybeCaptured) { + if (rem.hasCaptured(i)) + return false; + if (!remCaptured.isNull()) + return false; + } else { + if (!rem.hasCaptured(i)) + return false; + QString mCaptured = *mMaybeCaptured; + if (remCaptured != mCaptured + || remCaptured.isNull() != mCaptured.isNull() + || remCaptured.isEmpty() != mCaptured.isEmpty()) { + return false; + } } } for (auto it = m.namedCaptured.begin(), end = m.namedCaptured.end(); it != end; ++it) { - const QString remCaptured = rem.captured(it.key()); - const QString mCaptured = it.value(); - if (remCaptured != mCaptured - || remCaptured.isNull() != mCaptured.isNull() - || remCaptured.isEmpty() != mCaptured.isEmpty()) { - return false; + const QString capturedGroupName = it.key(); + const QString remCaptured = rem.captured(capturedGroupName); + const auto mMaybeCaptured = it.value(); + if (!mMaybeCaptured) { + if (rem.hasCaptured(capturedGroupName)) + return false; + if (!remCaptured.isNull()) + return false; + } else { + if (!rem.hasCaptured(capturedGroupName)) + return false; + const auto mCaptured = *mMaybeCaptured; + if (remCaptured != mCaptured + || remCaptured.isNull() != mCaptured.isNull() + || remCaptured.isEmpty() != mCaptured.isEmpty()) { + return false; + } } } + } else { + if (rem.hasCaptured(0)) + return false; } return true; @@ -183,6 +199,27 @@ bool operator==(const QRegularExpressionMatchIterator &iterator, const QList<Mat if (i.hasNext()) return false; + i = iterator; + + int index = 0; + for (const QRegularExpressionMatch &match : i) { + if (match != expectedMatchList[index++]) + return false; + } + + if (index != expectedMatchList.size()) + return false; + + // do it again + index = 0; + for (const QRegularExpressionMatch &match : i) { + if (match != expectedMatchList[index++]) + return false; + } + + if (index != expectedMatchList.size()) + return false; + return true; } @@ -213,9 +250,9 @@ void consistencyCheck(const QRegularExpressionMatch &match) QVERIFY(match.lastCapturedIndex() == 0); for (int i = 0; i <= match.lastCapturedIndex(); ++i) { - int startPos = match.capturedStart(i); - int endPos = match.capturedEnd(i); - int length = match.capturedLength(i); + qsizetype startPos = match.capturedStart(i); + qsizetype endPos = match.capturedEnd(i); + qsizetype length = match.capturedLength(i); QString captured = match.captured(i); QStringView capturedView = match.capturedView(i); @@ -227,8 +264,11 @@ void consistencyCheck(const QRegularExpressionMatch &match) QVERIFY((endPos - startPos) == length); QVERIFY(captured == capturedView); } else { - QVERIFY(startPos == -1); - QVERIFY(endPos == -1); + // A null capture can either mean no capture at all, + // or capture of length 0 over a null subject. + QVERIFY(startPos == endPos); + QVERIFY(((startPos == -1) && (endPos == -1)) // no capture + || ((startPos == 0) && (endPos == 0))); // null subject QVERIFY((endPos - startPos) == length); QVERIFY(capturedView.isNull()); } @@ -252,7 +292,11 @@ void consistencyCheck(const QRegularExpressionMatchIterator &iterator) QRegularExpressionMatch peeked = i.peekNext(); QRegularExpressionMatch match = i.next(); consistencyCheck(peeked); + if (QTest::currentTestFailed()) + return; consistencyCheck(match); + if (QTest::currentTestFailed()) + return; QVERIFY(match.isValid()); QVERIFY(match.hasMatch() || match.hasPartialMatch()); QCOMPARE(i.regularExpression(), match.regularExpression()); @@ -299,7 +343,7 @@ template<typename QREMatch, typename QREMatchFunc, typename Subject, typename Re static void testMatchImpl(const QRegularExpression ®exp, QREMatchFunc matchingMethod, const Subject &subject, - int offset, + qsizetype offset, QRegularExpression::MatchType matchType, QRegularExpression::MatchOptions matchOptions, const Result &result) @@ -333,7 +377,7 @@ static void testMatch(const QRegularExpression ®exp, QREMatchFuncForString matchingMethodForString, QREMatchFuncForStringRef matchingMethodForStringRef, const QString &subject, - int offset, + qsizetype offset, QRegularExpression::MatchType matchType, QRegularExpression::MatchOptions matchOptions, const Result &result) @@ -351,10 +395,11 @@ static void testMatch(const QRegularExpression ®exp, result); } -typedef QRegularExpressionMatch (QRegularExpression::*QREMatchStringPMF)(const QString &, int, QRegularExpression::MatchType, QRegularExpression::MatchOptions) const; -typedef QRegularExpressionMatch (QRegularExpression::*QREMatchStringViewPMF)(QStringView, int, QRegularExpression::MatchType, QRegularExpression::MatchOptions) const; -typedef QRegularExpressionMatchIterator (QRegularExpression::*QREGlobalMatchStringPMF)(const QString &, int, QRegularExpression::MatchType, QRegularExpression::MatchOptions) const; -typedef QRegularExpressionMatchIterator (QRegularExpression::*QREGlobalMatchStringViewPMF)(QStringView, int, QRegularExpression::MatchType, QRegularExpression::MatchOptions) const; +// ### Qt 7: there should no longer be the need for these +typedef QRegularExpressionMatch (QRegularExpression::*QREMatchStringPMF)(const QString &, qsizetype, QRegularExpression::MatchType, QRegularExpression::MatchOptions) const; +typedef QRegularExpressionMatch (QRegularExpression::*QREMatchStringViewPMF)(QStringView, qsizetype, QRegularExpression::MatchType, QRegularExpression::MatchOptions) const; +typedef QRegularExpressionMatchIterator (QRegularExpression::*QREGlobalMatchStringPMF)(const QString &, qsizetype, QRegularExpression::MatchType, QRegularExpression::MatchOptions) const; +typedef QRegularExpressionMatchIterator (QRegularExpression::*QREGlobalMatchStringViewPMF)(QStringView, qsizetype, QRegularExpression::MatchType, QRegularExpression::MatchOptions) const; void tst_QRegularExpression::provideRegularExpressions() { @@ -407,11 +452,30 @@ void tst_QRegularExpression::provideRegularExpressions() | QRegularExpression::InvertedGreedinessOption); } +static const char enableJitEnvironmentVariable[] = "QT_ENABLE_REGEXP_JIT"; + +void tst_QRegularExpression::initMain() +{ + if (!qEnvironmentVariableIsSet(enableJitEnvironmentVariable)) { + std::cerr << "Enabling QRegularExpression JIT for testing; set QT_ENABLE_REGEXP_JIT to 0 to disable it.\n"; + qputenv(enableJitEnvironmentVariable, "1"); + } +} + +void tst_QRegularExpression::compareCompiles() +{ + QTestPrivate::testEqualityOperatorsCompile<QRegularExpression>(); +} + void tst_QRegularExpression::defaultConstructors() { QRegularExpression re; QCOMPARE(re.pattern(), QString()); QCOMPARE(re.patternOptions(), QRegularExpression::NoPatternOption); + QCOMPARE(re.isValid(), true); + QCOMPARE(re.patternErrorOffset(), -1); + QCOMPARE(re.captureCount(), 0); + QCOMPARE(re.namedCaptureGroups(), QStringList { QString() }); QRegularExpressionMatch match; QCOMPARE(match.regularExpression(), QRegularExpression()); @@ -422,6 +486,15 @@ void tst_QRegularExpression::defaultConstructors() QCOMPARE(match.hasPartialMatch(), false); QCOMPARE(match.isValid(), true); QCOMPARE(match.lastCapturedIndex(), -1); + QCOMPARE(match.captured(), QString()); + QCOMPARE(match.captured("test"), QString()); + QCOMPARE(match.capturedTexts(), QStringList()); + QCOMPARE(match.capturedStart(), -1); + QCOMPARE(match.capturedEnd(), -1); + QCOMPARE(match.capturedLength(), 0); + QCOMPARE(match.capturedStart("test"), -1); + QCOMPARE(match.capturedEnd("test"), -1); + QCOMPARE(match.capturedLength("test"), 0); QRegularExpressionMatchIterator iterator; QCOMPARE(iterator.regularExpression(), QRegularExpression()); @@ -432,6 +505,101 @@ void tst_QRegularExpression::defaultConstructors() QCOMPARE(iterator.hasNext(), false); } +void tst_QRegularExpression::moveSemantics() +{ + const QString pattern = "pattern"; + const QRegularExpression::PatternOptions options = QRegularExpression::CaseInsensitiveOption; + QRegularExpression expr1(pattern, options); + QCOMPARE(expr1.pattern(), pattern); + QCOMPARE(expr1.patternOptions(), options); + + QRegularExpression expr2(std::move(expr1)); + QCOMPARE(expr2.pattern(), pattern); + QCOMPARE(expr2.patternOptions(), options); + + const QString pattern2 = "pattern2"; + QRegularExpression expr3(pattern2); + QCOMPARE(expr3.pattern(), pattern2); + QCOMPARE(expr3.patternOptions(), QRegularExpression::NoPatternOption); + + // check that (move)assigning to the moved-from object is ok + expr1 = std::move(expr3); + QCOMPARE(expr1.pattern(), pattern2); + QCOMPARE(expr1.patternOptions(), QRegularExpression::NoPatternOption); + + // here expr3 is in the moved-from state, so destructor call for moved-from + // object is also checked +} + +void tst_QRegularExpression::moveSemanticsMatch() +{ + QRegularExpression re("test"); + QRegularExpressionMatch match1 = re.match("abctestdef"); + QCOMPARE(match1.hasMatch(), true); + QCOMPARE(match1.capturedStart(), 3); + QCOMPARE(match1.capturedEnd(), 7); + + QRegularExpressionMatch match2(std::move(match1)); + QCOMPARE(match2.hasMatch(), true); + QCOMPARE(match2.capturedStart(), 3); + QCOMPARE(match2.capturedEnd(), 7); + consistencyCheck(match2); + if (QTest::currentTestFailed()) + return; + + QRegularExpressionMatch match3 = re.match("test1"); + QCOMPARE(match3.hasMatch(), true); + QCOMPARE(match3.capturedStart(), 0); + QCOMPARE(match3.capturedEnd(), 4); + + // check that (move)assigning to the moved-from object is ok + match1 = std::move(match3); + QCOMPARE(match1.hasMatch(), true); + QCOMPARE(match1.capturedStart(), 0); + QCOMPARE(match1.capturedEnd(), 4); + consistencyCheck(match1); + if (QTest::currentTestFailed()) + return; + + // here match3 is in the moved-from state, so destructor call for moved-from + // object is also checked +} + +void tst_QRegularExpression::moveSemanticsMatchIterator() +{ + QRegularExpression re("(\\w+)"); + QRegularExpressionMatchIterator it1 = re.globalMatch("some test"); + QVERIFY(it1.isValid()); + QVERIFY(it1.hasNext()); + QT_TEST_EQUALITY_OPS(it1.regularExpression(), re, true); + + QRegularExpressionMatchIterator it2(std::move(it1)); + QVERIFY(it2.isValid()); + QVERIFY(it2.hasNext()); + QT_TEST_EQUALITY_OPS(it2.regularExpression(), re, true); + consistencyCheck(it2); + if (QTest::currentTestFailed()) + return; + + QRegularExpression re2("test"); + QRegularExpressionMatchIterator it3 = re2.globalMatch("123test456"); + QVERIFY(it3.isValid()); + QVERIFY(it3.hasNext()); + QT_TEST_EQUALITY_OPS(it3.regularExpression(), re2, true); + + // check that (move)assigning to the moved-from object is ok + it1 = std::move(it3); + QVERIFY(it1.isValid()); + QVERIFY(it1.hasNext()); + QT_TEST_EQUALITY_OPS(it1.regularExpression(), re2, true); + consistencyCheck(it1); + if (QTest::currentTestFailed()) + return; + + // here it3 is in the moved-from state, so destructor call for moved-from + // object is also checked +} + void tst_QRegularExpression::gettersSetters_data() { provideRegularExpressions(); @@ -527,18 +695,23 @@ void tst_QRegularExpression::validity_data() void tst_QRegularExpression::validity() { + static const QRegularExpression ignoreMessagePattern( + "^" + QRegularExpression::escape("QRegularExpressionPrivate::doMatch(): " + "called on an invalid QRegularExpression object") + ); + QFETCH(QString, pattern); QFETCH(bool, validity); QRegularExpression re(pattern); QCOMPARE(re.isValid(), validity); if (!validity) - QTest::ignoreMessage(QtWarningMsg, "QRegularExpressionPrivate::doMatch(): called on an invalid QRegularExpression object"); + QTest::ignoreMessage(QtWarningMsg, ignoreMessagePattern); QRegularExpressionMatch match = re.match("a pattern"); QCOMPARE(match.isValid(), validity); consistencyCheck(match); if (!validity) - QTest::ignoreMessage(QtWarningMsg, "QRegularExpressionPrivate::doMatch(): called on an invalid QRegularExpression object"); + QTest::ignoreMessage(QtWarningMsg, ignoreMessagePattern); QRegularExpressionMatchIterator iterator = re.globalMatch("a pattern"); QCOMPARE(iterator.isValid(), validity); } @@ -625,19 +798,19 @@ void tst_QRegularExpression::normalMatch_data() { QTest::addColumn<QRegularExpression>("regexp"); QTest::addColumn<QString>("subject"); - QTest::addColumn<int>("offset"); + QTest::addColumn<qsizetype>("offset"); QTest::addColumn<QRegularExpression::MatchOptions>("matchOptions"); QTest::addColumn<Match>("match"); Match m; - int offset = 0; + qsizetype offset = 0; m.clear(); m.isValid = true; m.hasMatch = true; m.captured << "string" << "string"; QTest::newRow("match01") << QRegularExpression("(\\bstring\\b)") << "a string" - << 0 + << qsizetype(0) << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) << m; @@ -646,7 +819,7 @@ void tst_QRegularExpression::normalMatch_data() m.captured << "a string" << "a" << "string"; QTest::newRow("match02") << QRegularExpression("(\\w+) (\\w+)") << "a string" - << 0 + << qsizetype(0) << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) << m; @@ -657,16 +830,16 @@ void tst_QRegularExpression::normalMatch_data() m.namedCaptured["noun"] = "string"; QTest::newRow("match03") << QRegularExpression("(?<article>\\w+) (?<noun>\\w+)") << "a string" - << 0 + << qsizetype(0) << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) << m; m.clear(); m.isValid = true; m.hasMatch = true; - m.captured << " string" << QString() << "string"; + m.captured << " string" << std::nullopt << "string"; QTest::newRow("match04") << QRegularExpression("(\\w+)? (\\w+)") << " string" - << 0 + << qsizetype(0) << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) << m; @@ -675,7 +848,7 @@ void tst_QRegularExpression::normalMatch_data() m.captured << " string" << QString("") << "string"; QTest::newRow("match05") << QRegularExpression("(\\w*) (\\w+)") << " string" - << 0 + << qsizetype(0) << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) << m; @@ -683,7 +856,7 @@ void tst_QRegularExpression::normalMatch_data() m.isValid = true; m.hasMatch = true; m.captured << "c123def" << "c12" << "3" << "def"; offset = 2; - for (int i = 0; i <= offset; ++i) { + for (qsizetype i = 0; i <= offset; ++i) { QTest::newRow(("match06-offset" + QByteArray::number(i)).constData()) << QRegularExpression("(\\w*)(\\d+)(\\w*)") << QStringLiteral("abc123def").mid(offset - i) @@ -696,7 +869,7 @@ void tst_QRegularExpression::normalMatch_data() m.isValid = true; m.hasMatch = true; m.captured << QString(""); offset = 9; - for (int i = 0; i <= offset; ++i) { + for (qsizetype i = 0; i <= offset; ++i) { QTest::newRow(("match07-offset" + QByteArray::number(i)).constData()) << QRegularExpression("\\w*") << QStringLiteral("abc123def").mid(offset - i) @@ -710,7 +883,7 @@ void tst_QRegularExpression::normalMatch_data() m.captured << QString("a string") << QString("a string") << QString(""); QTest::newRow("match08") << QRegularExpression("(.*)(.*)") << "a string" - << 0 + << qsizetype(0) << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) << m; @@ -719,7 +892,25 @@ void tst_QRegularExpression::normalMatch_data() m.captured << QString("a string") << QString("") << QString("a string"); QTest::newRow("match09") << QRegularExpression("(.*?)(.*)") << "a string" - << 0 + << qsizetype(0) + << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) + << m; + + m.clear(); + m.isValid = true; m.hasMatch = true; + m.captured << QString(); + QTest::newRow("empty-in-null-string") << QRegularExpression("") + << QString() + << qsizetype(0) + << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) + << m; + + m.clear(); + m.isValid = true; m.hasMatch = true; + m.captured << QString(""); + QTest::newRow("empty-in-empty-string") << QRegularExpression("") + << QString("") + << qsizetype(0) << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) << m; @@ -729,12 +920,12 @@ void tst_QRegularExpression::normalMatch_data() m.captured << "a string" << "a" << "string"; m.namedCaptured["article"] = "a"; m.namedCaptured["noun"] = "string"; - m.namedCaptured["nonexisting1"] = QString(); - m.namedCaptured["nonexisting2"] = QString(); - m.namedCaptured["nonexisting3"] = QString(); + m.namedCaptured["nonexisting1"] = std::nullopt; + m.namedCaptured["nonexisting2"] = std::nullopt; + m.namedCaptured["nonexisting3"] = std::nullopt; QTest::newRow("match10") << QRegularExpression("(?<article>\\w+) (?<noun>\\w+)") << "a string" - << 0 + << qsizetype(0) << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) << m; @@ -742,10 +933,10 @@ void tst_QRegularExpression::normalMatch_data() m.isValid = true; m.hasMatch = true; m.captured << "" << ""; m.namedCaptured["digits"] = ""; // empty VS null - m.namedCaptured["nonexisting"] = QString(); + m.namedCaptured["nonexisting"] = std::nullopt; QTest::newRow("match11") << QRegularExpression("(?<digits>\\d*)") << "abcde" - << 0 + << qsizetype(0) << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) << m; @@ -757,24 +948,74 @@ void tst_QRegularExpression::normalMatch_data() QTest::newRow("match12") << QRegularExpression("\\Bbcd\\B") << "abcde" - << 1 + << qsizetype(1) << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) << m; // *** m.clear(); + m.isValid = true; m.hasMatch = true; + m.captured << QString() << QString(); + QTest::newRow("capture-in-null-string") + << QRegularExpression("(a*)") + << QString() + << qsizetype(0) + << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) + << m; + + m.clear(); + m.isValid = true; m.hasMatch = true; + m.captured << QString() << QString() << QString(); + QTest::newRow("capture-in-null-string-2") + << QRegularExpression("(a*)(b*)") + << QString() + << qsizetype(0) + << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) + << m; + + m.clear(); + m.isValid = true; m.hasMatch = true; + m.captured << QString(); + QTest::newRow("no-capture-in-null-string") + << QRegularExpression("(a+)?") + << QString() + << qsizetype(0) + << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) + << m; + + m.clear(); + m.isValid = true; m.hasMatch = true; + m.captured << "bb" << QString("") << "bb"; + QTest::newRow("empty-capture-in-non-null-string") + << QRegularExpression("(a*)(b*)") + << QString("bbc") + << qsizetype(0) + << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) + << m; + + m.clear(); + m.isValid = true; m.hasMatch = true; + m.captured << "bb" << std::nullopt << "bb"; + QTest::newRow("no-capture-in-non-null-string") + << QRegularExpression("(a+)?(b+)?") + << QString("bbc") + << qsizetype(0) + << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) + << m; + + m.clear(); m.isValid = true; QTest::newRow("nomatch01") << QRegularExpression("\\d+") << "a string" - << 0 + << qsizetype(0) << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) << m; m.clear(); m.isValid = true; offset = 1; - for (int i = 0; i <= offset; ++i) { + for (qsizetype i = 0; i <= offset; ++i) { QTest::newRow(("nomatch02-offset" + QByteArray::number(i)).constData()) << QRegularExpression("(\\w+) (\\w+)") << QStringLiteral("a string").mid(offset - i) @@ -786,7 +1027,7 @@ void tst_QRegularExpression::normalMatch_data() m.clear(); m.isValid = true; offset = 9; - for (int i = 0; i <= offset; ++i) { + for (qsizetype i = 0; i <= offset; ++i) { QTest::newRow(("nomatch03-offset" + QByteArray::number(i)).constData()) << QRegularExpression("\\w+") << QStringLiteral("abc123def").mid(offset - i) @@ -801,7 +1042,7 @@ void tst_QRegularExpression::normalMatch_data() m.isValid = true; QTest::newRow("anchoredmatch01") << QRegularExpression("\\d+") << "abc123def" - << 0 + << qsizetype(0) << QRegularExpression::MatchOptions(QRegularExpression::AnchorAtOffsetMatchOption) << m; @@ -812,7 +1053,7 @@ void tst_QRegularExpression::normalMatch_data() m.captured << "678"; QTest::newRow("negativeoffset01") << QRegularExpression("\\d+") << "abc123def678ghi" - << -6 + << qsizetype(-6) << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) << m; @@ -821,7 +1062,7 @@ void tst_QRegularExpression::normalMatch_data() m.captured << "678"; QTest::newRow("negativeoffset02") << QRegularExpression("\\d+") << "abc123def678ghi" - << -8 + << qsizetype(-8) << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) << m; @@ -830,7 +1071,7 @@ void tst_QRegularExpression::normalMatch_data() m.captured << "678ghi" << "678" << "ghi"; QTest::newRow("negativeoffset03") << QRegularExpression("(\\d+)(\\w+)") << "abc123def678ghi" - << -8 + << qsizetype(-8) << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) << m; @@ -838,7 +1079,7 @@ void tst_QRegularExpression::normalMatch_data() m.isValid = true; QTest::newRow("negativeoffset04") << QRegularExpression("\\d+") << "abc123def678ghi" - << -3 + << qsizetype(-3) << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) << m; @@ -847,7 +1088,7 @@ void tst_QRegularExpression::normalMatch_data() m.captured << "678"; QTest::newRow("negativeoffset05") << QRegularExpression("^\\d+", QRegularExpression::MultilineOption) << "a\nbc123\ndef\n678gh\ni" - << -10 + << qsizetype(-10) << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) << m; } @@ -857,13 +1098,13 @@ void tst_QRegularExpression::normalMatch() { QFETCH(QRegularExpression, regexp); QFETCH(QString, subject); - QFETCH(int, offset); + QFETCH(qsizetype, offset); QFETCH(QRegularExpression::MatchOptions, matchOptions); QFETCH(Match, match); testMatch<QRegularExpressionMatch>(regexp, static_cast<QREMatchStringPMF>(&QRegularExpression::match), - static_cast<QREMatchStringViewPMF>(&QRegularExpression::match), + static_cast<QREMatchStringViewPMF>(&QRegularExpression::matchView), subject, offset, QRegularExpression::NormalMatch, @@ -875,20 +1116,20 @@ void tst_QRegularExpression::partialMatch_data() { QTest::addColumn<QRegularExpression>("regexp"); QTest::addColumn<QString>("subject"); - QTest::addColumn<int>("offset"); + QTest::addColumn<qsizetype>("offset"); QTest::addColumn<QRegularExpression::MatchType>("matchType"); QTest::addColumn<QRegularExpression::MatchOptions>("matchOptions"); QTest::addColumn<Match>("match"); Match m; - int offset = 0; + qsizetype offset = 0; m.clear(); m.isValid = true; m.hasPartialMatch = true; m.captured << "str"; QTest::newRow("softmatch01") << QRegularExpression("string") << "a str" - << 0 + << qsizetype(0) << QRegularExpression::PartialPreferCompleteMatch << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) << m; @@ -898,7 +1139,7 @@ void tst_QRegularExpression::partialMatch_data() m.captured << " str"; QTest::newRow("softmatch02") << QRegularExpression("\\bstring\\b") << "a str" - << 0 + << qsizetype(0) << QRegularExpression::PartialPreferCompleteMatch << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) << m; @@ -908,7 +1149,7 @@ void tst_QRegularExpression::partialMatch_data() m.captured << " str"; QTest::newRow("softmatch03") << QRegularExpression("(\\bstring\\b)") << "a str" - << 0 + << qsizetype(0) << QRegularExpression::PartialPreferCompleteMatch << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) << m; @@ -918,7 +1159,7 @@ void tst_QRegularExpression::partialMatch_data() m.captured << "8 Dec 19"; QTest::newRow("softmatch04") << QRegularExpression("^(\\d{1,2}) (\\w{3}) (\\d{4})$") << "8 Dec 19" - << 0 + << qsizetype(0) << QRegularExpression::PartialPreferCompleteMatch << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) << m; @@ -928,7 +1169,7 @@ void tst_QRegularExpression::partialMatch_data() m.captured << "8 Dec 1985" << "8" << "Dec" << "1985"; QTest::newRow("softmatch05") << QRegularExpression("^(\\d{1,2}) (\\w{3}) (\\d{4})$") << "8 Dec 1985" - << 0 + << qsizetype(0) << QRegularExpression::PartialPreferCompleteMatch << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) << m; @@ -938,7 +1179,7 @@ void tst_QRegularExpression::partialMatch_data() m.captured << "def"; QTest::newRow("softmatch06") << QRegularExpression("abc\\w+X|def") << "abcdef" - << 0 + << qsizetype(0) << QRegularExpression::PartialPreferCompleteMatch << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) << m; @@ -948,7 +1189,7 @@ void tst_QRegularExpression::partialMatch_data() m.captured << "abcdef"; QTest::newRow("softmatch07") << QRegularExpression("abc\\w+X|defY") << "abcdef" - << 0 + << qsizetype(0) << QRegularExpression::PartialPreferCompleteMatch << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) << m; @@ -957,7 +1198,7 @@ void tst_QRegularExpression::partialMatch_data() m.isValid = true; m.hasPartialMatch = true; m.captured << "def"; offset = 1; - for (int i = 0; i <= offset; ++i) { + for (qsizetype i = 0; i <= offset; ++i) { QTest::newRow(("softmatch08-offset" + QByteArray::number(i)).constData()) << QRegularExpression("abc\\w+X|defY") << QStringLiteral("abcdef").mid(offset - i) @@ -974,7 +1215,7 @@ void tst_QRegularExpression::partialMatch_data() m.captured << "str"; QTest::newRow("hardmatch01") << QRegularExpression("string") << "a str" - << 0 + << qsizetype(0) << QRegularExpression::PartialPreferFirstMatch << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) << m; @@ -984,7 +1225,7 @@ void tst_QRegularExpression::partialMatch_data() m.captured << " str"; QTest::newRow("hardmatch02") << QRegularExpression("\\bstring\\b") << "a str" - << 0 + << qsizetype(0) << QRegularExpression::PartialPreferFirstMatch << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) << m; @@ -994,7 +1235,7 @@ void tst_QRegularExpression::partialMatch_data() m.captured << " str"; QTest::newRow("hardmatch03") << QRegularExpression("(\\bstring\\b)") << "a str" - << 0 + << qsizetype(0) << QRegularExpression::PartialPreferFirstMatch << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) << m; @@ -1004,7 +1245,7 @@ void tst_QRegularExpression::partialMatch_data() m.captured << "8 Dec 19"; QTest::newRow("hardmatch04") << QRegularExpression("^(\\d{1,2}) (\\w{3}) (\\d{4})$") << "8 Dec 19" - << 0 + << qsizetype(0) << QRegularExpression::PartialPreferFirstMatch << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) << m; @@ -1014,7 +1255,7 @@ void tst_QRegularExpression::partialMatch_data() m.captured << "8 Dec 1985"; QTest::newRow("hardmatch05") << QRegularExpression("^(\\d{1,2}) (\\w{3}) (\\d{4})$") << "8 Dec 1985" - << 0 + << qsizetype(0) << QRegularExpression::PartialPreferFirstMatch << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) << m; @@ -1024,7 +1265,7 @@ void tst_QRegularExpression::partialMatch_data() m.captured << "abcdef"; QTest::newRow("hardmatch06") << QRegularExpression("abc\\w+X|def") << "abcdef" - << 0 + << qsizetype(0) << QRegularExpression::PartialPreferFirstMatch << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) << m; @@ -1034,7 +1275,7 @@ void tst_QRegularExpression::partialMatch_data() m.captured << "abcdef"; QTest::newRow("hardmatch07") << QRegularExpression("abc\\w+X|defY") << "abcdef" - << 0 + << qsizetype(0) << QRegularExpression::PartialPreferFirstMatch << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) << m; @@ -1043,7 +1284,7 @@ void tst_QRegularExpression::partialMatch_data() m.isValid = true; m.hasPartialMatch = true; m.captured << "def"; offset = 1; - for (int i = 0; i <= offset; ++i) { + for (qsizetype i = 0; i <= offset; ++i) { QTest::newRow(("hardmatch08-offset" + QByteArray::number(i)).constData()) << QRegularExpression("abc\\w+X|defY") << QStringLiteral("abcdef").mid(offset - i) @@ -1058,7 +1299,7 @@ void tst_QRegularExpression::partialMatch_data() m.captured << "ab"; QTest::newRow("hardmatch09") << QRegularExpression("abc|ab") << "ab" - << 0 + << qsizetype(0) << QRegularExpression::PartialPreferFirstMatch << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) << m; @@ -1068,7 +1309,7 @@ void tst_QRegularExpression::partialMatch_data() m.captured << "abc"; QTest::newRow("hardmatch10") << QRegularExpression("abc(def)?") << "abc" - << 0 + << qsizetype(0) << QRegularExpression::PartialPreferFirstMatch << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) << m; @@ -1078,7 +1319,7 @@ void tst_QRegularExpression::partialMatch_data() m.captured << "abc"; QTest::newRow("hardmatch11") << QRegularExpression("(abc)*") << "abc" - << 0 + << qsizetype(0) << QRegularExpression::PartialPreferFirstMatch << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) << m; @@ -1090,7 +1331,7 @@ void tst_QRegularExpression::partialMatch_data() m.isValid = true; QTest::newRow("nomatch01") << QRegularExpression("abc\\w+X|defY") << "123456" - << 0 + << qsizetype(0) << QRegularExpression::PartialPreferCompleteMatch << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) << m; @@ -1099,7 +1340,7 @@ void tst_QRegularExpression::partialMatch_data() m.isValid = true; QTest::newRow("nomatch02") << QRegularExpression("abc\\w+X|defY") << "123456" - << 0 + << qsizetype(0) << QRegularExpression::PartialPreferFirstMatch << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) << m; @@ -1108,7 +1349,7 @@ void tst_QRegularExpression::partialMatch_data() m.isValid = true; QTest::newRow("nomatch03") << QRegularExpression("abc\\w+X|defY") << "ab123" - << 0 + << qsizetype(0) << QRegularExpression::PartialPreferCompleteMatch << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) << m; @@ -1117,7 +1358,7 @@ void tst_QRegularExpression::partialMatch_data() m.isValid = true; QTest::newRow("nomatch04") << QRegularExpression("abc\\w+X|defY") << "ab123" - << 0 + << qsizetype(0) << QRegularExpression::PartialPreferFirstMatch << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) << m; @@ -1128,14 +1369,14 @@ void tst_QRegularExpression::partialMatch() { QFETCH(QRegularExpression, regexp); QFETCH(QString, subject); - QFETCH(int, offset); + QFETCH(qsizetype, offset); QFETCH(QRegularExpression::MatchType, matchType); QFETCH(QRegularExpression::MatchOptions, matchOptions); QFETCH(Match, match); testMatch<QRegularExpressionMatch>(regexp, static_cast<QREMatchStringPMF>(&QRegularExpression::match), - static_cast<QREMatchStringViewPMF>(&QRegularExpression::match), + static_cast<QREMatchStringViewPMF>(&QRegularExpression::matchView), subject, offset, matchType, @@ -1147,7 +1388,7 @@ void tst_QRegularExpression::globalMatch_data() { QTest::addColumn<QRegularExpression>("regexp"); QTest::addColumn<QString>("subject"); - QTest::addColumn<int>("offset"); + QTest::addColumn<qsizetype>("offset"); QTest::addColumn<QRegularExpression::MatchType>("matchType"); QTest::addColumn<QRegularExpression::MatchOptions>("matchOptions"); QTest::addColumn<QList<Match> >("matchList"); @@ -1158,15 +1399,15 @@ void tst_QRegularExpression::globalMatch_data() matchList.clear(); m.clear(); m.isValid = true; m.hasMatch = true; - m.captured = QStringList() << "the"; + m.captured = CapturedList() << "the"; matchList << m; - m.captured = QStringList() << "quick"; + m.captured = CapturedList() << "quick"; matchList << m; - m.captured = QStringList() << "fox"; + m.captured = CapturedList() << "fox"; matchList << m; QTest::newRow("globalmatch01") << QRegularExpression("\\w+") << "the quick fox" - << 0 + << qsizetype(0) << QRegularExpression::NormalMatch << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) << matchList; @@ -1174,15 +1415,15 @@ void tst_QRegularExpression::globalMatch_data() matchList.clear(); m.clear(); m.isValid = true; m.hasMatch = true; - m.captured = QStringList() << "the" << "t" << "he"; + m.captured = CapturedList() << "the" << "t" << "he"; matchList << m; - m.captured = QStringList() << "quick" << "q" << "uick"; + m.captured = CapturedList() << "quick" << "q" << "uick"; matchList << m; - m.captured = QStringList() << "fox" << "f" << "ox"; + m.captured = CapturedList() << "fox" << "f" << "ox"; matchList << m; QTest::newRow("globalmatch02") << QRegularExpression("(\\w+?)(\\w+)") << "the quick fox" - << 0 + << qsizetype(0) << QRegularExpression::NormalMatch << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) << matchList; @@ -1190,24 +1431,24 @@ void tst_QRegularExpression::globalMatch_data() matchList.clear(); m.clear(); m.isValid = true; m.hasMatch = true; - m.captured = QStringList() << "ACA""GTG""CGA""AAA"; + m.captured = CapturedList() << "ACA""GTG""CGA""AAA"; matchList << m; - m.captured = QStringList() << "AAA"; + m.captured = CapturedList() << "AAA"; matchList << m; - m.captured = QStringList() << "AAG""GAA""AAG""AAA"; + m.captured = CapturedList() << "AAG""GAA""AAG""AAA"; matchList << m; - m.captured = QStringList() << "AAA"; + m.captured = CapturedList() << "AAA"; matchList << m; QTest::newRow("globalmatch03") << QRegularExpression("\\G(?:\\w\\w\\w)*?AAA") << "ACA""GTG""CGA""AAA""AAA""AAG""GAA""AAG""AAA""AAA" - << 0 + << qsizetype(0) << QRegularExpression::NormalMatch << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) << matchList; QTest::newRow("globalmatch04") << QRegularExpression("(?:\\w\\w\\w)*?AAA") << "ACA""GTG""CGA""AAA""AAA""AAG""GAA""AAG""AAA""AAA" - << 0 + << qsizetype(0) << QRegularExpression::NormalMatch << QRegularExpression::MatchOptions(QRegularExpression::AnchorAtOffsetMatchOption) << matchList; @@ -1215,24 +1456,24 @@ void tst_QRegularExpression::globalMatch_data() matchList.clear(); m.clear(); m.isValid = true; m.hasMatch = true; - m.captured = QStringList() << ""; + m.captured = CapturedList() << ""; matchList << m; - m.captured = QStringList() << "c"; + m.captured = CapturedList() << "c"; matchList << m; - m.captured = QStringList() << ""; + m.captured = CapturedList() << ""; matchList << m; - m.captured = QStringList() << "c"; + m.captured = CapturedList() << "c"; matchList << m; - m.captured = QStringList() << "aabb"; + m.captured = CapturedList() << "aabb"; matchList << m; - m.captured = QStringList() << ""; + m.captured = CapturedList() << ""; matchList << m; - m.captured = QStringList() << ""; + m.captured = CapturedList() << ""; matchList << m; QTest::newRow("globalmatch_emptycaptures01") << QRegularExpression("a*b*|c") << "ccaabbd" - << 0 + << qsizetype(0) << QRegularExpression::NormalMatch << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) << matchList; @@ -1240,22 +1481,22 @@ void tst_QRegularExpression::globalMatch_data() matchList.clear(); m.clear(); m.isValid = true; m.hasMatch = true; - m.captured = QStringList() << "the"; + m.captured = CapturedList() << "the"; matchList << m; - m.captured = QStringList() << ""; + m.captured = CapturedList() << ""; matchList << m; - m.captured = QStringList() << "quick"; + m.captured = CapturedList() << "quick"; matchList << m; - m.captured = QStringList() << ""; + m.captured = CapturedList() << ""; matchList << m; - m.captured = QStringList() << "fox"; + m.captured = CapturedList() << "fox"; matchList << m; - m.captured = QStringList() << ""; + m.captured = CapturedList() << ""; matchList << m; QTest::newRow("globalmatch_emptycaptures02") << QRegularExpression(".*") << "the\nquick\nfox" - << 0 + << qsizetype(0) << QRegularExpression::NormalMatch << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) << matchList; @@ -1263,24 +1504,24 @@ void tst_QRegularExpression::globalMatch_data() matchList.clear(); m.clear(); m.isValid = true; m.hasMatch = true; - m.captured = QStringList() << "the"; + m.captured = CapturedList() << "the"; matchList << m; - m.captured = QStringList() << ""; + m.captured = CapturedList() << ""; matchList << m; - m.captured = QStringList() << "quick"; + m.captured = CapturedList() << "quick"; matchList << m; - m.captured = QStringList() << ""; + m.captured = CapturedList() << ""; matchList << m; - m.captured = QStringList() << "fox"; + m.captured = CapturedList() << "fox"; matchList << m; - m.captured = QStringList() << ""; + m.captured = CapturedList() << ""; matchList << m; - m.captured = QStringList() << ""; + m.captured = CapturedList() << ""; matchList << m; QTest::newRow("globalmatch_emptycaptures03") << QRegularExpression(".*") << "the\nquick\nfox\n" - << 0 + << qsizetype(0) << QRegularExpression::NormalMatch << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) << matchList; @@ -1288,22 +1529,22 @@ void tst_QRegularExpression::globalMatch_data() matchList.clear(); m.clear(); m.isValid = true; m.hasMatch = true; - m.captured = QStringList() << "the"; + m.captured = CapturedList() << "the"; matchList << m; - m.captured = QStringList() << ""; + m.captured = CapturedList() << ""; matchList << m; - m.captured = QStringList() << "quick"; + m.captured = CapturedList() << "quick"; matchList << m; - m.captured = QStringList() << ""; + m.captured = CapturedList() << ""; matchList << m; - m.captured = QStringList() << "fox"; + m.captured = CapturedList() << "fox"; matchList << m; - m.captured = QStringList() << ""; + m.captured = CapturedList() << ""; matchList << m; QTest::newRow("globalmatch_emptycaptures04") << QRegularExpression("(*CRLF).*") << "the\r\nquick\r\nfox" - << 0 + << qsizetype(0) << QRegularExpression::NormalMatch << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) << matchList; @@ -1311,24 +1552,24 @@ void tst_QRegularExpression::globalMatch_data() matchList.clear(); m.clear(); m.isValid = true; m.hasMatch = true; - m.captured = QStringList() << "the"; + m.captured = CapturedList() << "the"; matchList << m; - m.captured = QStringList() << ""; + m.captured = CapturedList() << ""; matchList << m; - m.captured = QStringList() << "quick"; + m.captured = CapturedList() << "quick"; matchList << m; - m.captured = QStringList() << ""; + m.captured = CapturedList() << ""; matchList << m; - m.captured = QStringList() << "fox"; + m.captured = CapturedList() << "fox"; matchList << m; - m.captured = QStringList() << ""; + m.captured = CapturedList() << ""; matchList << m; - m.captured = QStringList() << ""; + m.captured = CapturedList() << ""; matchList << m; QTest::newRow("globalmatch_emptycaptures05") << QRegularExpression("(*CRLF).*") << "the\r\nquick\r\nfox\r\n" - << 0 + << qsizetype(0) << QRegularExpression::NormalMatch << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) << matchList; @@ -1336,26 +1577,26 @@ void tst_QRegularExpression::globalMatch_data() matchList.clear(); m.clear(); m.isValid = true; m.hasMatch = true; - m.captured = QStringList() << "the"; + m.captured = CapturedList() << "the"; matchList << m; - m.captured = QStringList() << ""; + m.captured = CapturedList() << ""; matchList << m; - m.captured = QStringList() << "quick"; + m.captured = CapturedList() << "quick"; matchList << m; - m.captured = QStringList() << ""; + m.captured = CapturedList() << ""; matchList << m; - m.captured = QStringList() << "fox"; + m.captured = CapturedList() << "fox"; matchList << m; - m.captured = QStringList() << ""; + m.captured = CapturedList() << ""; matchList << m; - m.captured = QStringList() << "jumped"; + m.captured = CapturedList() << "jumped"; matchList << m; - m.captured = QStringList() << ""; + m.captured = CapturedList() << ""; matchList << m; QTest::newRow("globalmatch_emptycaptures06") << QRegularExpression("(*ANYCRLF).*") << "the\r\nquick\nfox\rjumped" - << 0 + << qsizetype(0) << QRegularExpression::NormalMatch << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) << matchList; @@ -1363,21 +1604,21 @@ void tst_QRegularExpression::globalMatch_data() matchList.clear(); m.clear(); m.isValid = true; m.hasMatch = true; - m.captured = QStringList() << "ABC"; + m.captured = CapturedList() << "ABC"; matchList << m; - m.captured = QStringList() << ""; + m.captured = CapturedList() << ""; matchList << m; - m.captured = QStringList() << "DEF"; + m.captured = CapturedList() << "DEF"; matchList << m; - m.captured = QStringList() << ""; + m.captured = CapturedList() << ""; matchList << m; - m.captured = QStringList() << "GHI"; + m.captured = CapturedList() << "GHI"; matchList << m; - m.captured = QStringList() << ""; + m.captured = CapturedList() << ""; matchList << m; QTest::newRow("globalmatch_emptycaptures07") << QRegularExpression("[\\x{0000}-\\x{FFFF}]*") << QString::fromUtf8("ABC""\xf0\x9d\x85\x9d""DEF""\xf0\x9d\x85\x9e""GHI") - << 0 + << qsizetype(0) << QRegularExpression::NormalMatch << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) << matchList; @@ -1385,17 +1626,17 @@ void tst_QRegularExpression::globalMatch_data() matchList.clear(); m.clear(); m.isValid = true; m.hasMatch = true; - m.captured = QStringList() << QString::fromUtf8("ABC""\xc3\x80"); + m.captured = CapturedList() << QString::fromUtf8("ABC""\xc3\x80"); matchList << m; - m.captured = QStringList() << ""; + m.captured = CapturedList() << ""; matchList << m; - m.captured = QStringList() << QString::fromUtf8("\xc3\x80""DEF""\xc3\x80"); + m.captured = CapturedList() << QString::fromUtf8("\xc3\x80""DEF""\xc3\x80"); matchList << m; - m.captured = QStringList() << ""; + m.captured = CapturedList() << ""; matchList << m; QTest::newRow("globalmatch_emptycaptures08") << QRegularExpression("[\\x{0000}-\\x{FFFF}]*") << QString::fromUtf8("ABC""\xc3\x80""\xf0\x9d\x85\x9d""\xc3\x80""DEF""\xc3\x80") - << 0 + << qsizetype(0) << QRegularExpression::NormalMatch << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) << matchList; @@ -1405,14 +1646,14 @@ void tst_QRegularExpression::globalMatch() { QFETCH(QRegularExpression, regexp); QFETCH(QString, subject); - QFETCH(int, offset); + QFETCH(qsizetype, offset); QFETCH(QRegularExpression::MatchType, matchType); QFETCH(QRegularExpression::MatchOptions, matchOptions); QFETCH(QList<Match>, matchList); testMatch<QRegularExpressionMatchIterator>(regexp, static_cast<QREGlobalMatchStringPMF>(&QRegularExpression::globalMatch), - static_cast<QREGlobalMatchStringViewPMF>(&QRegularExpression::globalMatch), + static_cast<QREGlobalMatchStringViewPMF>(&QRegularExpression::globalMatchView), subject, offset, matchType, @@ -1446,38 +1687,23 @@ void tst_QRegularExpression::serialize() static void verifyEquality(const QRegularExpression &re1, const QRegularExpression &re2) { - QVERIFY(re1 == re2); - QVERIFY(re2 == re1); + QT_TEST_EQUALITY_OPS(re1, re2, true); QCOMPARE(qHash(re1), qHash(re2)); - QVERIFY(!(re1 != re2)); - QVERIFY(!(re2 != re1)); QRegularExpression re3(re1); - QVERIFY(re1 == re3); - QVERIFY(re3 == re1); QCOMPARE(qHash(re1), qHash(re3)); - QVERIFY(!(re1 != re3)); - QVERIFY(!(re3 != re1)); + QT_TEST_EQUALITY_OPS(re1, re3, true); - QVERIFY(re2 == re3); - QVERIFY(re3 == re2); QCOMPARE(qHash(re2), qHash(re3)); - QVERIFY(!(re2 != re3)); - QVERIFY(!(re3 != re2)); + QT_TEST_EQUALITY_OPS(re2, re3, true); re3 = re2; - QVERIFY(re1 == re3); - QVERIFY(re3 == re1); QCOMPARE(qHash(re1), qHash(re3)); - QVERIFY(!(re1 != re3)); - QVERIFY(!(re3 != re1)); + QT_TEST_EQUALITY_OPS(re1, re3, true); - QVERIFY(re2 == re3); - QVERIFY(re3 == re2); QCOMPARE(qHash(re2), qHash(re3)); - QVERIFY(!(re2 != re3)); - QVERIFY(!(re3 != re2)); + QT_TEST_EQUALITY_OPS(re2, re3, true); } void tst_QRegularExpression::operatoreq_data() @@ -1620,6 +1846,38 @@ void tst_QRegularExpression::captureNames() } +void tst_QRegularExpression::captureNamesNul() +{ + QRegularExpression re("a(\\d+)b(?<name>\\d+)c(?<anotherName>\\d+)d(\\d+)e$"); + QVERIFY(re.isValid()); + + QCOMPARE(re.captureCount(), 4); + + QStringList namedCaptureGroups = re.namedCaptureGroups(); + QCOMPARE(namedCaptureGroups[0], QString()); + QCOMPARE(namedCaptureGroups[1], QString()); + QCOMPARE(namedCaptureGroups[2], "name"); + QCOMPARE(namedCaptureGroups[3], "anotherName"); + QCOMPARE(namedCaptureGroups[4], QString()); + + QRegularExpressionMatch m = re.match("a12b456c789d0e"); + QVERIFY(m.hasMatch()); + + QString captureName("name"); + QCOMPARE(m.captured(captureName), "456"); + QCOMPARE(m.captured(QStringView(captureName)), "456"); + QCOMPARE(m.captured(QAnyStringView(captureName)), "456"); + QCOMPARE(m.captured(qToStringViewIgnoringNull(captureName)), "456"); + QCOMPARE(m.captured(u"name"), "456"); + + captureName = "anotherName"; + QCOMPARE(m.captured(captureName), "789"); + QCOMPARE(m.captured(QStringView(captureName)), "789"); + QCOMPARE(m.captured(QAnyStringView(captureName)), "789"); + QCOMPARE(m.captured(qToStringViewIgnoringNull(captureName)), "789"); + QCOMPARE(m.captured(u"anotherName"), "789"); +} + void tst_QRegularExpression::pcreJitStackUsage_data() { QTest::addColumn<QString>("pattern"); @@ -1706,7 +1964,7 @@ void tst_QRegularExpression::JOptionUsage() QCOMPARE(re.isValid(), isValid); } -void tst_QRegularExpression::QStringAndQStringRefEquivalence() +void tst_QRegularExpression::QStringAndQStringViewEquivalence() { const QString subject = QStringLiteral("Mississippi"); { @@ -1722,7 +1980,7 @@ void tst_QRegularExpression::QStringAndQStringRefEquivalence() QCOMPARE(match.capturedEnd(), 4); } { - const QRegularExpressionMatch match = re.match(QStringRef(&subject)); + const QRegularExpressionMatch match = re.matchView(QStringView(subject)); consistencyCheck(match); QVERIFY(match.isValid()); QVERIFY(match.hasMatch()); @@ -1740,7 +1998,7 @@ void tst_QRegularExpression::QStringAndQStringRefEquivalence() QCOMPARE(match.capturedEnd(), 4); } { - const QRegularExpressionMatch match = re.match(QStringRef(&subject), 1); + const QRegularExpressionMatch match = re.matchView(QStringView(subject), 1); consistencyCheck(match); QVERIFY(match.isValid()); QVERIFY(match.hasMatch()); @@ -1758,7 +2016,7 @@ void tst_QRegularExpression::QStringAndQStringRefEquivalence() QCOMPARE(match.capturedEnd(), 6); } { - const QRegularExpressionMatch match = re.match(subject.midRef(1)); + const QRegularExpressionMatch match = re.matchView(QStringView(subject).mid(1)); consistencyCheck(match); QVERIFY(match.isValid()); QVERIFY(match.hasMatch()); @@ -1776,7 +2034,7 @@ void tst_QRegularExpression::QStringAndQStringRefEquivalence() QCOMPARE(match.capturedEnd(), 6); } { - const QRegularExpressionMatch match = re.match(subject.midRef(1), 1); + const QRegularExpressionMatch match = re.matchView(QStringView(subject).mid(1), 1); consistencyCheck(match); QVERIFY(match.isValid()); QVERIFY(match.hasMatch()); @@ -1794,7 +2052,7 @@ void tst_QRegularExpression::QStringAndQStringRefEquivalence() QCOMPARE(match.capturedEnd(), 7); } { - const QRegularExpressionMatch match = re.match(QStringRef(&subject), 4); + const QRegularExpressionMatch match = re.matchView(QStringView(subject), 4); consistencyCheck(match); QVERIFY(match.isValid()); QVERIFY(match.hasMatch()); @@ -1809,7 +2067,7 @@ void tst_QRegularExpression::QStringAndQStringRefEquivalence() QVERIFY(!match.hasMatch()); } { - const QRegularExpressionMatch match = re.match(subject.midRef(4)); + const QRegularExpressionMatch match = re.matchView(QStringView(subject).mid(4)); consistencyCheck(match); QVERIFY(match.isValid()); QVERIFY(!match.hasMatch()); @@ -1842,7 +2100,7 @@ void tst_QRegularExpression::QStringAndQStringRefEquivalence() QVERIFY(!i.hasNext()); } { - QRegularExpressionMatchIterator i = re.globalMatch(QStringRef(&subject)); + QRegularExpressionMatchIterator i = re.globalMatchView(QStringView(subject)); QVERIFY(i.isValid()); consistencyCheck(i); @@ -1894,7 +2152,7 @@ void tst_QRegularExpression::QStringAndQStringRefEquivalence() QVERIFY(!i.hasNext()); } { - QRegularExpressionMatchIterator i = re.globalMatch(QStringRef(&subject), 1); + QRegularExpressionMatchIterator i = re.globalMatchView(QStringView(subject), 1); QVERIFY(i.isValid()); consistencyCheck(i); @@ -1936,7 +2194,7 @@ void tst_QRegularExpression::QStringAndQStringRefEquivalence() QVERIFY(!i.hasNext()); } { - QRegularExpressionMatchIterator i = re.globalMatch(subject.midRef(1)); + QRegularExpressionMatchIterator i = re.globalMatchView(QStringView(subject).mid(1)); QVERIFY(i.isValid()); consistencyCheck(i); @@ -1968,7 +2226,7 @@ void tst_QRegularExpression::QStringAndQStringRefEquivalence() QVERIFY(!i.hasNext()); } { - QRegularExpressionMatchIterator i = re.globalMatch(subject.midRef(1), 1); + QRegularExpressionMatchIterator i = re.globalMatchView(QStringView(subject).mid(1), 1); QVERIFY(i.isValid()); consistencyCheck(i); @@ -2000,7 +2258,7 @@ void tst_QRegularExpression::QStringAndQStringRefEquivalence() QVERIFY(!i.hasNext()); } { - QRegularExpressionMatchIterator i = re.globalMatch(subject.midRef(1), 1); + QRegularExpressionMatchIterator i = re.globalMatchView(QStringView(subject).mid(1), 1); QVERIFY(i.isValid()); consistencyCheck(i); @@ -2033,7 +2291,7 @@ void tst_QRegularExpression::QStringAndQStringRefEquivalence() QVERIFY(!i.hasNext()); } { - QRegularExpressionMatchIterator i = re.globalMatch(QStringRef(&subject), 4); + QRegularExpressionMatchIterator i = re.globalMatchView(QStringView(subject), 4); QVERIFY(i.isValid()); consistencyCheck(i); @@ -2055,7 +2313,7 @@ void tst_QRegularExpression::QStringAndQStringRefEquivalence() QVERIFY(!i.hasNext()); } { - QRegularExpressionMatchIterator i = re.globalMatch(subject.midRef(4)); + QRegularExpressionMatchIterator i = re.globalMatchView(QStringView(subject).mid(4)); consistencyCheck(i); QVERIFY(i.isValid()); QVERIFY(!i.hasNext()); @@ -2080,7 +2338,7 @@ private: { yieldCurrentThread(); for (int i = 0; i < MATCH_ITERATIONS; ++i) - m_re.match(m_subject); + (void)m_re.match(m_subject); } const QRegularExpression &m_re; @@ -2125,6 +2383,10 @@ void tst_QRegularExpression::threadSafety_data() void tst_QRegularExpression::threadSafety() { +#if defined(Q_OS_WASM) + QSKIP("This test misbehaves on WASM. Investigation needed (QTBUG-110067)"); +#endif + QFETCH(QString, pattern); QFETCH(QString, subject); @@ -2150,59 +2412,111 @@ void tst_QRegularExpression::threadSafety() } } +void tst_QRegularExpression::returnsViewsIntoOriginalString() +{ + // https://bugreports.qt.io/browse/QTBUG-98653 + + auto to_void = [](const auto *p) -> const void* { return p; }; + + // GIVEN + // a QString with dynamically-allocated data: + const QString string = QLatin1String("A\nA\nB\nB\n\nC\nC"); // NOT QStringLiteral! + const auto stringDataAddress = to_void(string.data()); + + // and a view over said QString: + QStringView view(string); + const auto viewDataAddress = to_void(view.data()); + QCOMPARE(stringDataAddress, viewDataAddress); + + // WHEN + // we call view.split() with a temporary QRegularExpression object + const auto split = view.split(QRegularExpression( "(\r\n|\n|\r)" ), Qt::KeepEmptyParts); + + // THEN + // the returned views should point into the underlying string: +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) + QEXPECT_FAIL("", "QTBUG-98653", Continue); +#endif + QCOMPARE(to_void(split.front().data()), stringDataAddress); +} + void tst_QRegularExpression::wildcard_data() { QTest::addColumn<QString>("pattern"); QTest::addColumn<QString>("string"); - QTest::addColumn<int>("foundIndex"); + QTest::addColumn<bool>("matchesPathGlob"); + QTest::addColumn<bool>("matchesNonPathGlob"); + QTest::addColumn<bool>("anchored"); - auto addRow = [](const char *pattern, const char *string, int foundIndex) { - QTest::newRow(pattern) << pattern << string << foundIndex; + auto addRow = [](const char *pattern, const char *string, bool matchesPathGlob, bool matchesNonPathGlob, bool anchored = true) { + QTest::addRow("%s@%s", pattern, string) << pattern << string << matchesPathGlob << matchesNonPathGlob << anchored; }; - addRow("*.html", "test.html", 0); - addRow("*.html", "test.htm", -1); - addRow("*bar*", "foobarbaz", 0); - addRow("*", "Qt Rocks!", 0); - addRow("*.html", "test.html", 0); - addRow("*.h", "test.cpp", -1); - addRow("*.???l", "test.html", 0); - addRow("*?", "test.html", 0); - addRow("*?ml", "test.html", 0); - addRow("*[*]", "test.html", -1); - addRow("*[?]","test.html", -1); - addRow("*[?]ml","test.h?ml", 0); - addRow("*[[]ml","test.h[ml", 0); - addRow("*[]]ml","test.h]ml", 0); - addRow("*.h[a-z]ml", "test.html", 0); - addRow("*.h[A-Z]ml", "test.html", -1); - addRow("*.h[A-Z]ml", "test.hTml", 0); - addRow("*.h[!A-Z]ml", "test.hTml", -1); - addRow("*.h[!A-Z]ml", "test.html", 0); - addRow("*.h[!T]ml", "test.hTml", -1); - addRow("*.h[!T]ml", "test.html", 0); - addRow("*.h[!T]m[!L]", "test.htmL", -1); - addRow("*.h[!T]m[!L]", "test.html", 0); - addRow("*.h[][!]ml", "test.h]ml", 0); - addRow("*.h[][!]ml", "test.h[ml", 0); - addRow("*.h[][!]ml", "test.h!ml", 0); - - addRow("foo/*/bar", "foo/baz/bar", 0); - addRow("foo/(*)/bar", "foo/baz/bar", -1); - addRow("foo/(*)/bar", "foo/(baz)/bar", 0); - addRow("foo/?/bar", "foo/Q/bar", 0); - addRow("foo/?/bar", "foo/Qt/bar", -1); - addRow("foo/(?)/bar", "foo/Q/bar", -1); - addRow("foo/(?)/bar", "foo/(Q)/bar", 0); + addRow("*.html", "test.html", true, true); + addRow("*.html", "test.htm", false, false); + addRow("*bar*", "foobarbaz", true, true); + addRow("*", "Qt Rocks!", true, true); + addRow("*.h", "test.cpp", false, false); + addRow("*.???l", "test.html", true, true); + addRow("*?", "test.html", true, true); + addRow("*?ml", "test.html", true, true); + addRow("*[*]", "test.html", false, false); + addRow("*[?]","test.html", false, false); + addRow("*[?]ml","test.h?ml", true, true); + addRow("*[[]ml","test.h[ml", true, true); + addRow("*[]]ml","test.h]ml", true, true); + addRow("*.h[a-z]ml", "test.html", true, true); + addRow("*.h[A-Z]ml", "test.html", false, false); + addRow("*.h[A-Z]ml", "test.hTml", true, true); + addRow("*.h[!A-Z]ml", "test.hTml", false, false); + addRow("*.h[!A-Z]ml", "test.html", true, true); + addRow("*.h[!T]ml", "test.hTml", false, false); + addRow("*.h[!T]ml", "test.html", true, true); + addRow("*.h[!T]m[!L]", "test.htmL", false, false); + addRow("*.h[!T]m[!L]", "test.html", true, true); + addRow("*.h[][!]ml", "test.h]ml", true, true); + addRow("*.h[][!]ml", "test.h[ml", true, true); + addRow("*.h[][!]ml", "test.h!ml", true, true); + + addRow("foo/*/bar", "foo/baz/bar", true, true); + addRow("foo/*/bar", "foo/fie/baz/bar", false, true); + addRow("foo?bar", "foo/bar", false, true); + addRow("foo/(*)/bar", "foo/baz/bar", false, false); + addRow("foo/(*)/bar", "foo/(baz)/bar", true, true); + addRow("foo/?/bar", "foo/Q/bar", true, true); + addRow("foo/?/bar", "foo/Qt/bar", false, false); + addRow("foo/(?)/bar", "foo/Q/bar", false, false); + addRow("foo/(?)/bar", "foo/(Q)/bar", true, true); + + addRow("foo*bar", "foo/fie/baz/bar", false, true); + addRow("foo*bar", "foo bar", true, true); + addRow("foo*bar", "foo\tbar", true, true); + addRow("foo*bar", "foo\nbar", true, true); + addRow("foo*bar", "foo\r\nbar", true, true); + + // different anchor modes + addRow("foo", "afoob", false, false, true); + addRow("foo", "afoob", true, true, false); + + addRow("fie*bar", "foo/fie/baz/bar", false, false, true); + addRow("fie*bar", "foo/fie/baz/bar", false, true, false); #ifdef Q_OS_WIN - addRow("foo\\*\\bar", "foo\\baz\\bar", 0); - addRow("foo\\(*)\\bar", "foo\\baz\\bar", -1); - addRow("foo\\(*)\\bar", "foo\\(baz)\\bar", 0); - addRow("foo\\?\\bar", "foo\\Q\\bar", 0); - addRow("foo\\?\\bar", "foo\\Qt\\bar", -1); - addRow("foo\\(?)\\bar", "foo\\Q\\bar", -1); - addRow("foo\\(?)\\bar", "foo\\(Q)\\bar", 0); + addRow("foo\\*\\bar", "foo\\baz\\bar", true, true); + addRow("foo\\*\\bar", "foo/baz/bar", true, false); + addRow("foo\\*\\bar", "foo/baz\\bar", true, false); + addRow("foo\\*\\bar", "foo\\fie\\baz\\bar", false, true); + addRow("foo\\*\\bar", "foo/fie/baz/bar", false, false); + addRow("foo/*/bar", "foo\\baz\\bar", true, false); + addRow("foo/*/bar", "foo/baz/bar", true, true); + addRow("foo/*/bar", "foo\\fie\\baz\\bar", false, false); + addRow("foo/*/bar", "foo/fie/baz/bar", false, true); + addRow("foo\\(*)\\bar", "foo\\baz\\bar", false, false); + addRow("foo\\(*)\\bar", "foo\\(baz)\\bar", true, true); + addRow("foo\\?\\bar", "foo\\Q\\bar", true, true); + addRow("foo\\?\\bar", "foo\\Qt\\bar", false, false); + addRow("foo\\(?)\\bar", "foo\\Q\\bar", false, false); + addRow("foo\\(?)\\bar", "foo\\(Q)\\bar", true, true); #endif } @@ -2210,12 +2524,22 @@ void tst_QRegularExpression::wildcard() { QFETCH(QString, pattern); QFETCH(QString, string); - QFETCH(int, foundIndex); + QFETCH(bool, matchesPathGlob); + QFETCH(bool, matchesNonPathGlob); + QFETCH(bool, anchored); - QRegularExpression re(QRegularExpression::wildcardToRegularExpression(pattern)); - QRegularExpressionMatch match = re.match(string); + QRegularExpression::WildcardConversionOptions options = {}; + if (!anchored) + options |= QRegularExpression::UnanchoredWildcardConversion; - QCOMPARE(match.capturedStart(), foundIndex); + { + QRegularExpression re(QRegularExpression::wildcardToRegularExpression(pattern, options)); + QCOMPARE(string.contains(re), matchesPathGlob); + } + { + QRegularExpression re(QRegularExpression::wildcardToRegularExpression(pattern, options | QRegularExpression::NonPathWildcardConversion)); + QCOMPARE(string.contains(re), matchesNonPathGlob); + } } void tst_QRegularExpression::testInvalidWildcard_data() |