summaryrefslogtreecommitdiffstats
path: root/tests/auto/corelib/text/qregularexpression/tst_qregularexpression.cpp
diff options
context:
space:
mode:
authorGiuseppe D'Angelo <giuseppe.dangelo@kdab.com>2021-08-06 10:17:50 +0200
committerGiuseppe D'Angelo <giuseppe.dangelo@kdab.com>2021-08-25 00:06:42 +0200
commitbac329a28b14ccddcdb45a4ef51cd8056eda9233 (patch)
tree06aa44b30eb36fd441be11215f73a98885d120d2 /tests/auto/corelib/text/qregularexpression/tst_qregularexpression.cpp
parent145940e1ef8fc8334ff4603a44f7896886e646cb (diff)
QRegularExpressionMatch: add a way to know if a capturing group captured
Relying on the fact that a given capturing group captured a null string doesn't allow users to distinguish whether a capturing group did not capture anything, or captured a null substring (say, from a null subject string). Perl allows for the distinction: the entries in the @- and @+ arrays are set to values in case there is a capture, but they're undef otherwise. PCRE2 gives us the information already in the results "ovector", but it was simply not exposed to QREM users. So, expose it. [ChangeLog][QtCore][QRegularExpressionMatch] Added the hasCaptured() family of functions to know if a given capturing group has captured something. Change-Id: Ic1320933d4554e2e313c0a680be1b1b9dd95af0b Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: Thiago Macieira <thiago.macieira@intel.com> Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io> Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
Diffstat (limited to 'tests/auto/corelib/text/qregularexpression/tst_qregularexpression.cpp')
-rw-r--r--tests/auto/corelib/text/qregularexpression/tst_qregularexpression.cpp238
1 files changed, 159 insertions, 79 deletions
diff --git a/tests/auto/corelib/text/qregularexpression/tst_qregularexpression.cpp b/tests/auto/corelib/text/qregularexpression/tst_qregularexpression.cpp
index 48d4de0aa4..684727758c 100644
--- a/tests/auto/corelib/text/qregularexpression/tst_qregularexpression.cpp
+++ b/tests/auto/corelib/text/qregularexpression/tst_qregularexpression.cpp
@@ -37,6 +37,8 @@
#include <qregularexpression.h>
#include <qthread.h>
+#include <optional>
+
Q_DECLARE_METATYPE(QRegularExpression::PatternOptions)
Q_DECLARE_METATYPE(QRegularExpression::MatchType)
Q_DECLARE_METATYPE(QRegularExpression::MatchOptions)
@@ -92,6 +94,8 @@ private:
void provideRegularExpressions();
};
+using CapturedList = QVector<std::optional<QString>>;
+
struct Match
{
Match()
@@ -111,8 +115,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 +133,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;
@@ -803,7 +833,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)
@@ -887,9 +917,9 @@ 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"
<< qsizetype(0)
@@ -900,7 +930,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)
@@ -922,6 +952,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"
@@ -1316,11 +1396,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"
@@ -1332,11 +1412,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"
@@ -1348,13 +1428,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"
@@ -1373,19 +1453,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")
@@ -1398,17 +1478,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(".*")
@@ -1421,19 +1501,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(".*")
@@ -1446,17 +1526,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).*")
@@ -1469,19 +1549,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).*")
@@ -1494,21 +1574,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).*")
@@ -1521,17 +1601,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")
@@ -1543,13 +1623,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")