summaryrefslogtreecommitdiffstats
path: root/tests/auto/corelib/text/qregularexpression/tst_qregularexpression.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tests/auto/corelib/text/qregularexpression/tst_qregularexpression.cpp')
-rw-r--r--tests/auto/corelib/text/qregularexpression/tst_qregularexpression.cpp513
1 files changed, 338 insertions, 175 deletions
diff --git a/tests/auto/corelib/text/qregularexpression/tst_qregularexpression.cpp b/tests/auto/corelib/text/qregularexpression/tst_qregularexpression.cpp
index f2fe382521..ad41ae331e 100644
--- a/tests/auto/corelib/text/qregularexpression/tst_qregularexpression.cpp
+++ b/tests/auto/corelib/text/qregularexpression/tst_qregularexpression.cpp
@@ -1,31 +1,6 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// 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 <qstring.h>
@@ -37,6 +12,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,6 +23,9 @@ class tst_QRegularExpression : public QObject
{
Q_OBJECT
+public:
+ static void initMain();
+
private slots:
void defaultConstructors();
void moveSemantics();
@@ -83,6 +64,7 @@ private slots:
void threadSafety_data();
void threadSafety();
+ void returnsViewsIntoOriginalString();
void wildcard_data();
void wildcard();
void testInvalidWildcard_data();
@@ -92,6 +74,8 @@ private:
void provideRegularExpressions();
};
+using CapturedList = QVector<std::optional<QString>>;
+
struct Match
{
Match()
@@ -111,8 +95,8 @@ 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_RELOCATABLE_TYPE);
@@ -129,27 +113,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;
@@ -252,8 +262,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());
}
@@ -380,6 +393,7 @@ static void testMatch(const QRegularExpression &regexp,
result);
}
+// ### 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;
@@ -436,6 +450,16 @@ 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::defaultConstructors()
{
QRegularExpression re;
@@ -664,18 +688,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);
}
@@ -800,7 +829,7 @@ void tst_QRegularExpression::normalMatch_data()
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"
<< qsizetype(0)
@@ -860,15 +889,33 @@ void tst_QRegularExpression::normalMatch_data()
<< 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;
+
// non existing names for capturing groups
m.clear();
m.isValid = true; m.hasMatch = true;
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"
<< qsizetype(0)
@@ -879,7 +926,7 @@ 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"
<< qsizetype(0)
@@ -901,6 +948,56 @@ void tst_QRegularExpression::normalMatch_data()
// ***
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"
@@ -1000,7 +1097,7 @@ void tst_QRegularExpression::normalMatch()
testMatch<QRegularExpressionMatch>(regexp,
static_cast<QREMatchStringPMF>(&QRegularExpression::match),
- static_cast<QREMatchStringViewPMF>(&QRegularExpression::match),
+ static_cast<QREMatchStringViewPMF>(&QRegularExpression::matchView),
subject,
offset,
QRegularExpression::NormalMatch,
@@ -1272,7 +1369,7 @@ void tst_QRegularExpression::partialMatch()
testMatch<QRegularExpressionMatch>(regexp,
static_cast<QREMatchStringPMF>(&QRegularExpression::match),
- static_cast<QREMatchStringViewPMF>(&QRegularExpression::match),
+ static_cast<QREMatchStringViewPMF>(&QRegularExpression::matchView),
subject,
offset,
matchType,
@@ -1295,11 +1392,11 @@ 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"
@@ -1311,11 +1408,11 @@ 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"
@@ -1327,13 +1424,13 @@ 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"
@@ -1352,19 +1449,19 @@ 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")
@@ -1377,17 +1474,17 @@ 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(".*")
@@ -1400,19 +1497,19 @@ 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(".*")
@@ -1425,17 +1522,17 @@ 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).*")
@@ -1448,19 +1545,19 @@ 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).*")
@@ -1473,21 +1570,21 @@ 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).*")
@@ -1500,17 +1597,17 @@ 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")
@@ -1522,13 +1619,13 @@ 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")
@@ -1549,7 +1646,7 @@ void tst_QRegularExpression::globalMatch()
testMatch<QRegularExpressionMatchIterator>(regexp,
static_cast<QREGlobalMatchStringPMF>(&QRegularExpression::globalMatch),
- static_cast<QREGlobalMatchStringViewPMF>(&QRegularExpression::globalMatch),
+ static_cast<QREGlobalMatchStringViewPMF>(&QRegularExpression::globalMatchView),
subject,
offset,
matchType,
@@ -1889,7 +1986,7 @@ void tst_QRegularExpression::QStringAndQStringViewEquivalence()
QCOMPARE(match.capturedEnd(), 4);
}
{
- const QRegularExpressionMatch match = re.match(QStringView(subject));
+ const QRegularExpressionMatch match = re.matchView(QStringView(subject));
consistencyCheck(match);
QVERIFY(match.isValid());
QVERIFY(match.hasMatch());
@@ -1907,7 +2004,7 @@ void tst_QRegularExpression::QStringAndQStringViewEquivalence()
QCOMPARE(match.capturedEnd(), 4);
}
{
- const QRegularExpressionMatch match = re.match(QStringView(subject), 1);
+ const QRegularExpressionMatch match = re.matchView(QStringView(subject), 1);
consistencyCheck(match);
QVERIFY(match.isValid());
QVERIFY(match.hasMatch());
@@ -1925,7 +2022,7 @@ void tst_QRegularExpression::QStringAndQStringViewEquivalence()
QCOMPARE(match.capturedEnd(), 6);
}
{
- const QRegularExpressionMatch match = re.match(QStringView(subject).mid(1));
+ const QRegularExpressionMatch match = re.matchView(QStringView(subject).mid(1));
consistencyCheck(match);
QVERIFY(match.isValid());
QVERIFY(match.hasMatch());
@@ -1943,7 +2040,7 @@ void tst_QRegularExpression::QStringAndQStringViewEquivalence()
QCOMPARE(match.capturedEnd(), 6);
}
{
- const QRegularExpressionMatch match = re.match(QStringView(subject).mid(1), 1);
+ const QRegularExpressionMatch match = re.matchView(QStringView(subject).mid(1), 1);
consistencyCheck(match);
QVERIFY(match.isValid());
QVERIFY(match.hasMatch());
@@ -1961,7 +2058,7 @@ void tst_QRegularExpression::QStringAndQStringViewEquivalence()
QCOMPARE(match.capturedEnd(), 7);
}
{
- const QRegularExpressionMatch match = re.match(QStringView(subject), 4);
+ const QRegularExpressionMatch match = re.matchView(QStringView(subject), 4);
consistencyCheck(match);
QVERIFY(match.isValid());
QVERIFY(match.hasMatch());
@@ -1976,7 +2073,7 @@ void tst_QRegularExpression::QStringAndQStringViewEquivalence()
QVERIFY(!match.hasMatch());
}
{
- const QRegularExpressionMatch match = re.match(QStringView(subject).mid(4));
+ const QRegularExpressionMatch match = re.matchView(QStringView(subject).mid(4));
consistencyCheck(match);
QVERIFY(match.isValid());
QVERIFY(!match.hasMatch());
@@ -2009,7 +2106,7 @@ void tst_QRegularExpression::QStringAndQStringViewEquivalence()
QVERIFY(!i.hasNext());
}
{
- QRegularExpressionMatchIterator i = re.globalMatch(QStringView(subject));
+ QRegularExpressionMatchIterator i = re.globalMatchView(QStringView(subject));
QVERIFY(i.isValid());
consistencyCheck(i);
@@ -2061,7 +2158,7 @@ void tst_QRegularExpression::QStringAndQStringViewEquivalence()
QVERIFY(!i.hasNext());
}
{
- QRegularExpressionMatchIterator i = re.globalMatch(QStringView(subject), 1);
+ QRegularExpressionMatchIterator i = re.globalMatchView(QStringView(subject), 1);
QVERIFY(i.isValid());
consistencyCheck(i);
@@ -2103,7 +2200,7 @@ void tst_QRegularExpression::QStringAndQStringViewEquivalence()
QVERIFY(!i.hasNext());
}
{
- QRegularExpressionMatchIterator i = re.globalMatch(QStringView(subject).mid(1));
+ QRegularExpressionMatchIterator i = re.globalMatchView(QStringView(subject).mid(1));
QVERIFY(i.isValid());
consistencyCheck(i);
@@ -2135,7 +2232,7 @@ void tst_QRegularExpression::QStringAndQStringViewEquivalence()
QVERIFY(!i.hasNext());
}
{
- QRegularExpressionMatchIterator i = re.globalMatch(QStringView(subject).mid(1), 1);
+ QRegularExpressionMatchIterator i = re.globalMatchView(QStringView(subject).mid(1), 1);
QVERIFY(i.isValid());
consistencyCheck(i);
@@ -2167,7 +2264,7 @@ void tst_QRegularExpression::QStringAndQStringViewEquivalence()
QVERIFY(!i.hasNext());
}
{
- QRegularExpressionMatchIterator i = re.globalMatch(QStringView(subject).mid(1), 1);
+ QRegularExpressionMatchIterator i = re.globalMatchView(QStringView(subject).mid(1), 1);
QVERIFY(i.isValid());
consistencyCheck(i);
@@ -2200,7 +2297,7 @@ void tst_QRegularExpression::QStringAndQStringViewEquivalence()
QVERIFY(!i.hasNext());
}
{
- QRegularExpressionMatchIterator i = re.globalMatch(QStringView(subject), 4);
+ QRegularExpressionMatchIterator i = re.globalMatchView(QStringView(subject), 4);
QVERIFY(i.isValid());
consistencyCheck(i);
@@ -2222,7 +2319,7 @@ void tst_QRegularExpression::QStringAndQStringViewEquivalence()
QVERIFY(!i.hasNext());
}
{
- QRegularExpressionMatchIterator i = re.globalMatch(QStringView(subject).mid(4));
+ QRegularExpressionMatchIterator i = re.globalMatchView(QStringView(subject).mid(4));
consistencyCheck(i);
QVERIFY(i.isValid());
QVERIFY(!i.hasNext());
@@ -2292,6 +2389,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);
@@ -2317,59 +2418,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<qsizetype>("foundIndex");
+ QTest::addColumn<bool>("matchesPathGlob");
+ QTest::addColumn<bool>("matchesNonPathGlob");
+ QTest::addColumn<bool>("anchored");
- auto addRow = [](const char *pattern, const char *string, qsizetype 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
}
@@ -2377,12 +2530,22 @@ void tst_QRegularExpression::wildcard()
{
QFETCH(QString, pattern);
QFETCH(QString, string);
- QFETCH(qsizetype, 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()