| 1 | /**************************************************************************** | 
| 2 | ** | 
| 3 | ** Copyright (C) 2015 Giuseppe D'Angelo <dangelog@gmail.com>. | 
| 4 | ** Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Giuseppe D'Angelo <giuseppe.dangelo@kdab.com> | 
| 5 | ** Contact: https://www.qt.io/licensing/ | 
| 6 | ** | 
| 7 | ** This file is part of the test suite of the Qt Toolkit. | 
| 8 | ** | 
| 9 | ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ | 
| 10 | ** Commercial License Usage | 
| 11 | ** Licensees holding valid commercial Qt licenses may use this file in | 
| 12 | ** accordance with the commercial license agreement provided with the | 
| 13 | ** Software or, alternatively, in accordance with the terms contained in | 
| 14 | ** a written agreement between you and The Qt Company. For licensing terms | 
| 15 | ** and conditions see https://www.qt.io/terms-conditions. For further | 
| 16 | ** information use the contact form at https://www.qt.io/contact-us. | 
| 17 | ** | 
| 18 | ** GNU General Public License Usage | 
| 19 | ** Alternatively, this file may be used under the terms of the GNU | 
| 20 | ** General Public License version 3 as published by the Free Software | 
| 21 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT | 
| 22 | ** included in the packaging of this file. Please review the following | 
| 23 | ** information to ensure the GNU General Public License requirements will | 
| 24 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html. | 
| 25 | ** | 
| 26 | ** $QT_END_LICENSE$ | 
| 27 | ** | 
| 28 | ****************************************************************************/ | 
| 29 |  | 
| 30 | #include <QtTest/QtTest> | 
| 31 | #include <qstring.h> | 
| 32 | #include <qlist.h> | 
| 33 | #include <qstringlist.h> | 
| 34 | #include <qhash.h> | 
| 35 |  | 
| 36 | #include <qobject.h> | 
| 37 | #include <qregularexpression.h> | 
| 38 | #include <qthread.h> | 
| 39 |  | 
| 40 | Q_DECLARE_METATYPE(QRegularExpression::PatternOptions) | 
| 41 | Q_DECLARE_METATYPE(QRegularExpression::MatchType) | 
| 42 | Q_DECLARE_METATYPE(QRegularExpression::MatchOptions) | 
| 43 |  | 
| 44 | class tst_QRegularExpression : public QObject | 
| 45 | { | 
| 46 |     Q_OBJECT | 
| 47 |  | 
| 48 | private slots: | 
| 49 |     void defaultConstructors(); | 
| 50 |     void gettersSetters_data(); | 
| 51 |     void gettersSetters(); | 
| 52 |     void escape_data(); | 
| 53 |     void escape(); | 
| 54 |     void validity_data(); | 
| 55 |     void validity(); | 
| 56 |     void patternOptions_data(); | 
| 57 |     void patternOptions(); | 
| 58 |     void normalMatch_data(); | 
| 59 |     void normalMatch(); | 
| 60 |     void partialMatch_data(); | 
| 61 |     void partialMatch(); | 
| 62 |     void globalMatch_data(); | 
| 63 |     void globalMatch(); | 
| 64 |     void serialize_data(); | 
| 65 |     void serialize(); | 
| 66 |     void operatoreq_data(); | 
| 67 |     void operatoreq(); | 
| 68 |     void captureCount_data(); | 
| 69 |     void captureCount(); | 
| 70 |     void captureNames_data(); | 
| 71 |     void captureNames(); | 
| 72 |     void captureNamesNul(); | 
| 73 |     void pcreJitStackUsage_data(); | 
| 74 |     void pcreJitStackUsage(); | 
| 75 |     void regularExpressionMatch_data(); | 
| 76 |     void regularExpressionMatch(); | 
| 77 |     void JOptionUsage_data(); | 
| 78 |     void JOptionUsage(); | 
| 79 |     void QStringAndQStringRefEquivalence(); | 
| 80 |     void threadSafety_data(); | 
| 81 |     void threadSafety(); | 
| 82 |  | 
| 83 |     void returnsViewsIntoOriginalString(); | 
| 84 |     void wildcard_data(); | 
| 85 |     void wildcard(); | 
| 86 |     void testInvalidWildcard_data(); | 
| 87 |     void testInvalidWildcard(); | 
| 88 |  | 
| 89 | private: | 
| 90 |     void provideRegularExpressions(); | 
| 91 | }; | 
| 92 |  | 
| 93 | struct Match | 
| 94 | { | 
| 95 |     Match() | 
| 96 |     { | 
| 97 |         clear(); | 
| 98 |     } | 
| 99 |  | 
| 100 |     void clear() | 
| 101 |     { | 
| 102 |         isValid = false; | 
| 103 |         hasMatch = false; | 
| 104 |         hasPartialMatch = false; | 
| 105 |         captured.clear(); | 
| 106 |         namedCaptured.clear(); | 
| 107 |     } | 
| 108 |  | 
| 109 |     bool isValid; | 
| 110 |     bool hasMatch; | 
| 111 |     bool hasPartialMatch; | 
| 112 |     QStringList captured; | 
| 113 |     QHash<QString, QString> namedCaptured; | 
| 114 | }; | 
| 115 | QT_BEGIN_NAMESPACE | 
| 116 | Q_DECLARE_TYPEINFO(Match, Q_MOVABLE_TYPE); | 
| 117 | QT_END_NAMESPACE | 
| 118 |  | 
| 119 | Q_DECLARE_METATYPE(Match) | 
| 120 |  | 
| 121 | bool operator==(const QRegularExpressionMatch &rem, const Match &m) | 
| 122 | { | 
| 123 |     if (rem.isValid() != m.isValid) | 
| 124 |         return false; | 
| 125 |     if (!rem.isValid()) | 
| 126 |         return true; | 
| 127 |     if ((rem.hasMatch() != m.hasMatch) || (rem.hasPartialMatch() != m.hasPartialMatch)) | 
| 128 |         return false; | 
| 129 |     if (rem.hasMatch() || rem.hasPartialMatch()) { | 
| 130 |         if (rem.lastCapturedIndex() != (m.captured.size() - 1)) | 
| 131 |             return false; | 
| 132 |         for (int i = 0; i <= rem.lastCapturedIndex(); ++i) { | 
| 133 |             QString remCaptured = rem.captured(nth: i); | 
| 134 |             QString mCaptured = m.captured.at(i); | 
| 135 |             if (remCaptured != mCaptured | 
| 136 |                 || remCaptured.isNull() != mCaptured.isNull() | 
| 137 |                 || remCaptured.isEmpty() != mCaptured.isEmpty()) { | 
| 138 |                 return false; | 
| 139 |             } | 
| 140 |         } | 
| 141 |  | 
| 142 |         for (auto it = m.namedCaptured.begin(), end = m.namedCaptured.end(); it != end; ++it) { | 
| 143 |             const QString remCaptured = rem.captured(name: it.key()); | 
| 144 |             const QString mCaptured = it.value(); | 
| 145 |             if (remCaptured != mCaptured | 
| 146 |                 || remCaptured.isNull() != mCaptured.isNull() | 
| 147 |                 || remCaptured.isEmpty() != mCaptured.isEmpty()) { | 
| 148 |                 return false; | 
| 149 |             } | 
| 150 |         } | 
| 151 |     } | 
| 152 |  | 
| 153 |     return true; | 
| 154 | } | 
| 155 |  | 
| 156 | bool operator==(const Match &m, const QRegularExpressionMatch &rem) | 
| 157 | { | 
| 158 |     return operator==(rem, m); | 
| 159 | } | 
| 160 |  | 
| 161 | bool operator!=(const QRegularExpressionMatch &rem, const Match &m) | 
| 162 | { | 
| 163 |     return !operator==(rem, m); | 
| 164 | } | 
| 165 |  | 
| 166 | bool operator!=(const Match &m, const QRegularExpressionMatch &rem) | 
| 167 | { | 
| 168 |     return !operator==(m, rem); | 
| 169 | } | 
| 170 |  | 
| 171 |  | 
| 172 | bool operator==(const QRegularExpressionMatchIterator &iterator, const QVector<Match> &expectedMatchList) | 
| 173 | { | 
| 174 |     QRegularExpressionMatchIterator i = iterator; | 
| 175 |  | 
| 176 |     for (const Match &expectedMatch : expectedMatchList) { | 
| 177 |         if (!i.hasNext()) | 
| 178 |             return false; | 
| 179 |  | 
| 180 |         QRegularExpressionMatch match = i.next(); | 
| 181 |         if (match != expectedMatch) | 
| 182 |             return false; | 
| 183 |     } | 
| 184 |  | 
| 185 |     if (i.hasNext()) | 
| 186 |         return false; | 
| 187 |  | 
| 188 |     return true; | 
| 189 | } | 
| 190 |  | 
| 191 | bool operator==(const QVector<Match> &expectedMatchList, const QRegularExpressionMatchIterator &iterator) | 
| 192 | { | 
| 193 |     return operator==(iterator, expectedMatchList); | 
| 194 | } | 
| 195 |  | 
| 196 | bool operator!=(const QRegularExpressionMatchIterator &iterator, const QVector<Match> &expectedMatchList) | 
| 197 | { | 
| 198 |     return !operator==(iterator, expectedMatchList); | 
| 199 | } | 
| 200 |  | 
| 201 | bool operator!=(const QVector<Match> &expectedMatchList, const QRegularExpressionMatchIterator &iterator) | 
| 202 | { | 
| 203 |     return !operator==(expectedMatchList, iterator); | 
| 204 | } | 
| 205 |  | 
| 206 | void consistencyCheck(const QRegularExpressionMatch &match) | 
| 207 | { | 
| 208 |     if (match.isValid()) { | 
| 209 |         QVERIFY(match.regularExpression().isValid()); | 
| 210 |         QVERIFY(!(match.hasMatch() && match.hasPartialMatch())); | 
| 211 |  | 
| 212 |         if (match.hasMatch() || match.hasPartialMatch()) { | 
| 213 |             QVERIFY(match.lastCapturedIndex() >= 0); | 
| 214 |             if (match.hasPartialMatch()) | 
| 215 |                 QVERIFY(match.lastCapturedIndex() == 0); | 
| 216 |  | 
| 217 |             for (int i = 0; i <= match.lastCapturedIndex(); ++i) { | 
| 218 |                 int startPos = match.capturedStart(nth: i); | 
| 219 |                 int endPos = match.capturedEnd(nth: i); | 
| 220 |                 int length = match.capturedLength(nth: i); | 
| 221 |                 QString captured = match.captured(nth: i); | 
| 222 |                 QStringRef capturedRef = match.capturedRef(nth: i); | 
| 223 |                 QStringView capturedView = match.capturedView(nth: i); | 
| 224 |  | 
| 225 |                 if (!captured.isNull()) { | 
| 226 |                     QVERIFY(startPos >= 0); | 
| 227 |                     QVERIFY(endPos >= 0); | 
| 228 |                     QVERIFY(length >= 0); | 
| 229 |                     QVERIFY(endPos >= startPos); | 
| 230 |                     QVERIFY((endPos - startPos) == length); | 
| 231 |                     QVERIFY(captured == capturedRef); | 
| 232 |                     QVERIFY(captured == capturedView); | 
| 233 |                 } else { | 
| 234 |                     QVERIFY(startPos == -1); | 
| 235 |                     QVERIFY(endPos == -1); | 
| 236 |                     QVERIFY((endPos - startPos) == length); | 
| 237 |                     QVERIFY(capturedRef.isNull()); | 
| 238 |                     QVERIFY(capturedView.isNull()); | 
| 239 |                 } | 
| 240 |             } | 
| 241 |         } | 
| 242 |     } else { | 
| 243 |         QVERIFY(!match.hasMatch()); | 
| 244 |         QVERIFY(!match.hasPartialMatch()); | 
| 245 |         QVERIFY(match.captured(0).isNull()); | 
| 246 |         QVERIFY(match.capturedStart(0) == -1); | 
| 247 |         QVERIFY(match.capturedEnd(0) == -1); | 
| 248 |         QVERIFY(match.capturedLength(0) == 0); | 
| 249 |     } | 
| 250 | } | 
| 251 |  | 
| 252 | void consistencyCheck(const QRegularExpressionMatchIterator &iterator) | 
| 253 | { | 
| 254 |     QRegularExpressionMatchIterator i(iterator); // make a copy, we modify it | 
| 255 |     if (i.isValid()) { | 
| 256 |         while (i.hasNext()) { | 
| 257 |             QRegularExpressionMatch peeked = i.peekNext(); | 
| 258 |             QRegularExpressionMatch match = i.next(); | 
| 259 |             consistencyCheck(match: peeked); | 
| 260 |             consistencyCheck(match); | 
| 261 |             QVERIFY(match.isValid()); | 
| 262 |             QVERIFY(match.hasMatch() || match.hasPartialMatch()); | 
| 263 |             QCOMPARE(i.regularExpression(), match.regularExpression()); | 
| 264 |             QCOMPARE(i.matchOptions(), match.matchOptions()); | 
| 265 |             QCOMPARE(i.matchType(), match.matchType()); | 
| 266 |  | 
| 267 |             QVERIFY(peeked.isValid() == match.isValid()); | 
| 268 |             QVERIFY(peeked.hasMatch() == match.hasMatch()); | 
| 269 |             QVERIFY(peeked.hasPartialMatch() == match.hasPartialMatch()); | 
| 270 |             QVERIFY(peeked.lastCapturedIndex() == match.lastCapturedIndex()); | 
| 271 |             for (int i = 0; i <= peeked.lastCapturedIndex(); ++i) { | 
| 272 |                 QVERIFY(peeked.captured(i) == match.captured(i)); | 
| 273 |                 QVERIFY(peeked.capturedStart(i) == match.capturedStart(i)); | 
| 274 |                 QVERIFY(peeked.capturedEnd(i) == match.capturedEnd(i)); | 
| 275 |             } | 
| 276 |         } | 
| 277 |     } else { | 
| 278 |         QVERIFY(!i.hasNext()); | 
| 279 |         QTest::ignoreMessage(type: QtWarningMsg, message: "QRegularExpressionMatchIterator::peekNext() called on an iterator already at end" ); | 
| 280 |         QRegularExpressionMatch peeked = i.peekNext(); | 
| 281 |         QTest::ignoreMessage(type: QtWarningMsg, message: "QRegularExpressionMatchIterator::next() called on an iterator already at end" ); | 
| 282 |         QRegularExpressionMatch match = i.next(); | 
| 283 |         consistencyCheck(match: peeked); | 
| 284 |         consistencyCheck(match); | 
| 285 |         QVERIFY(!match.isValid()); | 
| 286 |         QVERIFY(!peeked.isValid()); | 
| 287 |     } | 
| 288 |  | 
| 289 | } | 
| 290 |  | 
| 291 | template<typename Result> | 
| 292 | static void prepareResultForNoMatchType(Result *r, const Result &orig) | 
| 293 | { | 
| 294 |     Q_UNUSED(r); | 
| 295 |     Q_UNUSED(orig); | 
| 296 | } | 
| 297 |  | 
| 298 | static void prepareResultForNoMatchType(Match *m, const Match &orig) | 
| 299 | { | 
| 300 |     m->isValid = orig.isValid; | 
| 301 | } | 
| 302 |  | 
| 303 | template<typename QREMatch, typename QREMatchFunc, typename Subject, typename Result> | 
| 304 | static void testMatchImpl(const QRegularExpression ®exp, | 
| 305 |                           QREMatchFunc matchingMethod, | 
| 306 |                           const Subject &subject, | 
| 307 |                           int offset, | 
| 308 |                           QRegularExpression::MatchType matchType, | 
| 309 |                           QRegularExpression::MatchOptions matchOptions, | 
| 310 |                           const Result &result) | 
| 311 | { | 
| 312 |     { | 
| 313 |         const QREMatch m = (regexp.*matchingMethod)(subject, offset, matchType, matchOptions); | 
| 314 |         consistencyCheck(m); | 
| 315 |         QVERIFY(m == result); | 
| 316 |         QCOMPARE(m.regularExpression(), regexp); | 
| 317 |         QCOMPARE(m.matchType(), matchType); | 
| 318 |         QCOMPARE(m.matchOptions(), matchOptions); | 
| 319 |     } | 
| 320 |     { | 
| 321 |         // ignore the expected results provided by the match object -- | 
| 322 |         // we'll never get any result when testing the NoMatch type. | 
| 323 |         // Just check the validity of the match here. | 
| 324 |         Result realMatch; | 
| 325 |         prepareResultForNoMatchType(&realMatch, result); | 
| 326 |  | 
| 327 |         const QREMatch m = (regexp.*matchingMethod)(subject, offset, QRegularExpression::NoMatch, matchOptions); | 
| 328 |         consistencyCheck(m); | 
| 329 |         QVERIFY(m == realMatch); | 
| 330 |         QCOMPARE(m.regularExpression(), regexp); | 
| 331 |         QCOMPARE(m.matchType(), QRegularExpression::NoMatch); | 
| 332 |         QCOMPARE(m.matchOptions(), matchOptions); | 
| 333 |     } | 
| 334 | } | 
| 335 |  | 
| 336 | template<typename QREMatch, typename QREMatchFuncForString, typename QREMatchFuncForStringRef, typename Result> | 
| 337 | static void testMatch(const QRegularExpression ®exp, | 
| 338 |                       QREMatchFuncForString matchingMethodForString, | 
| 339 |                       QREMatchFuncForStringRef matchingMethodForStringRef, | 
| 340 |                       const QString &subject, | 
| 341 |                       int offset, | 
| 342 |                       QRegularExpression::MatchType matchType, | 
| 343 |                       QRegularExpression::MatchOptions matchOptions, | 
| 344 |                       const Result &result) | 
| 345 | { | 
| 346 |     // test with QString as subject type | 
| 347 |     testMatchImpl<QREMatch>(regexp, matchingMethodForString, subject, offset, matchType, matchOptions, result); | 
| 348 |  | 
| 349 |     // test with QStringRef as subject type | 
| 350 |     testMatchImpl<QREMatch>(regexp, | 
| 351 |                             matchingMethodForStringRef, | 
| 352 |                             QStringRef(&subject, 0, subject.length()), | 
| 353 |                             offset, | 
| 354 |                             matchType, | 
| 355 |                             matchOptions, | 
| 356 |                             result); | 
| 357 | } | 
| 358 |  | 
| 359 | typedef QRegularExpressionMatch (QRegularExpression::*QREMatchStringPMF)(const QString &, int, QRegularExpression::MatchType, QRegularExpression::MatchOptions) const; | 
| 360 | typedef QRegularExpressionMatch (QRegularExpression::*QREMatchStringRefPMF)(const QStringRef &, int, QRegularExpression::MatchType, QRegularExpression::MatchOptions) const; | 
| 361 | typedef QRegularExpressionMatchIterator (QRegularExpression::*QREGlobalMatchStringPMF)(const QString &, int, QRegularExpression::MatchType, QRegularExpression::MatchOptions) const; | 
| 362 | typedef QRegularExpressionMatchIterator (QRegularExpression::*QREGlobalMatchStringRefPMF)(const QStringRef &, int, QRegularExpression::MatchType, QRegularExpression::MatchOptions) const; | 
| 363 |  | 
| 364 | void tst_QRegularExpression::provideRegularExpressions() | 
| 365 | { | 
| 366 |     QTest::addColumn<QString>(name: "pattern" ); | 
| 367 |     QTest::addColumn<QRegularExpression::PatternOptions>(name: "patternOptions" ); | 
| 368 |  | 
| 369 |     QTest::newRow(dataTag: "emptynull01" ) << QString() | 
| 370 |                                  << QRegularExpression::PatternOptions{}; | 
| 371 |     QTest::newRow(dataTag: "emptynull02" ) << QString() | 
| 372 |                                  << QRegularExpression::PatternOptions(QRegularExpression::CaseInsensitiveOption | 
| 373 |                                                                        | QRegularExpression::DotMatchesEverythingOption | 
| 374 |                                                                        | QRegularExpression::MultilineOption); | 
| 375 |     QTest::newRow(dataTag: "emptynull03" ) << ""  | 
| 376 |                                  << QRegularExpression::PatternOptions{}; | 
| 377 |     QTest::newRow(dataTag: "emptynull04" ) << ""  | 
| 378 |                                  << QRegularExpression::PatternOptions(QRegularExpression::CaseInsensitiveOption | 
| 379 |                                                                        | QRegularExpression::DotMatchesEverythingOption | 
| 380 |                                                                        | QRegularExpression::MultilineOption); | 
| 381 |  | 
| 382 |     QTest::newRow(dataTag: "regexp01" ) << "a pattern"  | 
| 383 |                               << QRegularExpression::PatternOptions{}; | 
| 384 |     QTest::newRow(dataTag: "regexp02" ) << "^a (.*) more complicated(?<P>pattern)$"  | 
| 385 |                               << QRegularExpression::PatternOptions{}; | 
| 386 |     QTest::newRow(dataTag: "regexp03" ) << "(?:a) pAttErN"  | 
| 387 |                               << QRegularExpression::PatternOptions(QRegularExpression::CaseInsensitiveOption); | 
| 388 |     QTest::newRow(dataTag: "regexp04" ) << "a\nmultiline\npattern"  | 
| 389 |                               << QRegularExpression::PatternOptions(QRegularExpression::MultilineOption); | 
| 390 |     QTest::newRow(dataTag: "regexp05" ) << "an extended # IGNOREME\npattern"  | 
| 391 |                               << QRegularExpression::PatternOptions(QRegularExpression::ExtendedPatternSyntaxOption); | 
| 392 |     QTest::newRow(dataTag: "regexp06" ) << "a [sS]ingleline .* match"  | 
| 393 |                               << QRegularExpression::PatternOptions(QRegularExpression::DotMatchesEverythingOption); | 
| 394 |     QTest::newRow(dataTag: "regexp07" ) << "multiple.*options"  | 
| 395 |                               << QRegularExpression::PatternOptions(QRegularExpression::CaseInsensitiveOption | 
| 396 |                                                                     | QRegularExpression::DotMatchesEverythingOption | 
| 397 |                                                                     | QRegularExpression::MultilineOption | 
| 398 |                                                                     | QRegularExpression::DontCaptureOption | 
| 399 |                                                                     | QRegularExpression::InvertedGreedinessOption); | 
| 400 |  | 
| 401 |     QTest::newRow(dataTag: "unicode01" ) << QString::fromUtf8(str: "^s[ome] latin-1 \xc3\x80\xc3\x88\xc3\x8c\xc3\x92\xc3\x99 chars$" ) | 
| 402 |                                << QRegularExpression::PatternOptions{}; | 
| 403 |     QTest::newRow(dataTag: "unicode02" ) << QString::fromUtf8(str: "^s[ome] latin-1 \xc3\x80\xc3\x88\xc3\x8c\xc3\x92\xc3\x99 chars$" ) | 
| 404 |                                << QRegularExpression::PatternOptions(QRegularExpression::CaseInsensitiveOption | 
| 405 |                                                                      | QRegularExpression::DotMatchesEverythingOption | 
| 406 |                                                                      | QRegularExpression::InvertedGreedinessOption); | 
| 407 |     QTest::newRow(dataTag: "unicode03" ) << QString::fromUtf8(str: "Unicode \xf0\x9d\x85\x9d \xf0\x9d\x85\x9e\xf0\x9d\x85\x9f" ) | 
| 408 |                                << QRegularExpression::PatternOptions{}; | 
| 409 |     QTest::newRow(dataTag: "unicode04" ) << QString::fromUtf8(str: "Unicode \xf0\x9d\x85\x9d \xf0\x9d\x85\x9e\xf0\x9d\x85\x9f" ) | 
| 410 |                                << QRegularExpression::PatternOptions(QRegularExpression::CaseInsensitiveOption | 
| 411 |                                                                      | QRegularExpression::DotMatchesEverythingOption | 
| 412 |                                                                      | QRegularExpression::InvertedGreedinessOption); | 
| 413 | } | 
| 414 |  | 
| 415 | void tst_QRegularExpression::defaultConstructors() | 
| 416 | { | 
| 417 |     QRegularExpression re; | 
| 418 |     QCOMPARE(re.pattern(), QString()); | 
| 419 |     QCOMPARE(re.patternOptions(), QRegularExpression::NoPatternOption); | 
| 420 |  | 
| 421 |     QRegularExpressionMatch match; | 
| 422 |     QCOMPARE(match.regularExpression(), QRegularExpression()); | 
| 423 |     QCOMPARE(match.regularExpression(), re); | 
| 424 |     QCOMPARE(match.matchType(), QRegularExpression::NoMatch); | 
| 425 |     QCOMPARE(match.matchOptions(), QRegularExpression::NoMatchOption); | 
| 426 |     QCOMPARE(match.hasMatch(), false); | 
| 427 |     QCOMPARE(match.hasPartialMatch(), false); | 
| 428 |     QCOMPARE(match.isValid(), true); | 
| 429 |     QCOMPARE(match.lastCapturedIndex(), -1); | 
| 430 |  | 
| 431 |     QRegularExpressionMatchIterator iterator; | 
| 432 |     QCOMPARE(iterator.regularExpression(), QRegularExpression()); | 
| 433 |     QCOMPARE(iterator.regularExpression(), re); | 
| 434 |     QCOMPARE(iterator.matchType(), QRegularExpression::NoMatch); | 
| 435 |     QCOMPARE(iterator.matchOptions(), QRegularExpression::NoMatchOption); | 
| 436 |     QCOMPARE(iterator.isValid(), true); | 
| 437 |     QCOMPARE(iterator.hasNext(), false); | 
| 438 | } | 
| 439 |  | 
| 440 | void tst_QRegularExpression::() | 
| 441 | { | 
| 442 |     provideRegularExpressions(); | 
| 443 | } | 
| 444 |  | 
| 445 | void tst_QRegularExpression::() | 
| 446 | { | 
| 447 |     QFETCH(QString, pattern); | 
| 448 |     QFETCH(QRegularExpression::PatternOptions, patternOptions); | 
| 449 |     { | 
| 450 |         QRegularExpression re; | 
| 451 |         re.setPattern(pattern); | 
| 452 |         QCOMPARE(re.pattern(), pattern); | 
| 453 |         QCOMPARE(re.patternOptions(), QRegularExpression::NoPatternOption); | 
| 454 |     } | 
| 455 |     { | 
| 456 |         QRegularExpression re; | 
| 457 |         re.setPatternOptions(patternOptions); | 
| 458 |         QCOMPARE(re.pattern(), QString()); | 
| 459 |         QCOMPARE(re.patternOptions(), patternOptions); | 
| 460 |     } | 
| 461 |     { | 
| 462 |         QRegularExpression re(pattern); | 
| 463 |         QCOMPARE(re.pattern(), pattern); | 
| 464 |         QCOMPARE(re.patternOptions(), QRegularExpression::NoPatternOption); | 
| 465 |     } | 
| 466 |     { | 
| 467 |         QRegularExpression re(pattern, patternOptions); | 
| 468 |         QCOMPARE(re.pattern(), pattern); | 
| 469 |         QCOMPARE(re.patternOptions(), patternOptions); | 
| 470 |     } | 
| 471 | } | 
| 472 |  | 
| 473 | void tst_QRegularExpression::escape_data() | 
| 474 | { | 
| 475 |     QTest::addColumn<QString>(name: "string" ); | 
| 476 |     QTest::addColumn<QString>(name: "escaped" ); | 
| 477 |     QTest::newRow(dataTag: "escape01" ) << "a normal pattern"  | 
| 478 |                               << "a\\ normal\\ pattern" ; | 
| 479 |  | 
| 480 |     QTest::newRow(dataTag: "escape02" ) << "abcdefghijklmnopqrstuvzABCDEFGHIJKLMNOPQRSTUVZ1234567890_"  | 
| 481 |                               << "abcdefghijklmnopqrstuvzABCDEFGHIJKLMNOPQRSTUVZ1234567890_" ; | 
| 482 |  | 
| 483 |     QTest::newRow(dataTag: "escape03" ) << "^\\ba\\b.*(?<NAME>reg|exp)$"  | 
| 484 |                               << "\\^\\\\ba\\\\b\\.\\*\\(\\?\\<NAME\\>reg\\|exp\\)\\$" ; | 
| 485 |  | 
| 486 |     QString nulString("abcXabcXXabc" ); | 
| 487 |     nulString[3] = nulString[7] = nulString[8] = QChar(0, 0); | 
| 488 |     QTest::newRow(dataTag: "NUL" ) << nulString | 
| 489 |                          << "abc\\0abc\\0\\0abc" ; | 
| 490 |  | 
| 491 |     QTest::newRow(dataTag: "unicode01" ) << QString::fromUtf8(str: "^s[ome] latin-1 \xc3\x80\xc3\x88\xc3\x8c\xc3\x92\xc3\x99 chars$" ) | 
| 492 |                                << QString::fromUtf8(str: "\\^s\\[ome\\]\\ latin\\-1\\ \\\xc3\x80\\\xc3\x88\\\xc3\x8c\\\xc3\x92\\\xc3\x99\\ chars\\$" ); | 
| 493 |     QTest::newRow(dataTag: "unicode02" ) << QString::fromUtf8(str: "Unicode \xf0\x9d\x85\x9d \xf0\x9d\x85\x9e\xf0\x9d\x85\x9f" ) | 
| 494 |                                << QString::fromUtf8(str: "Unicode\\ \\\xf0\x9d\x85\x9d\\ \\\xf0\x9d\x85\x9e\\\xf0\x9d\x85\x9f" ); | 
| 495 |  | 
| 496 |     QString unicodeAndNulString = QString::fromUtf8(str: "^\xc3\x80\xc3\x88\xc3\x8cN\xc3\x92NN\xc3\x99 chars$" ); | 
| 497 |     unicodeAndNulString[4] = unicodeAndNulString[6] = unicodeAndNulString[7] = QChar(0, 0); | 
| 498 |     QTest::newRow(dataTag: "unicode03" ) << unicodeAndNulString | 
| 499 |                                << QString::fromUtf8(str: "\\^\\\xc3\x80\\\xc3\x88\\\xc3\x8c\\0\\\xc3\x92\\0\\0\\\xc3\x99\\ chars\\$" ); | 
| 500 | } | 
| 501 |  | 
| 502 | void tst_QRegularExpression::escape() | 
| 503 | { | 
| 504 |     QFETCH(QString, string); | 
| 505 |     QFETCH(QString, escaped); | 
| 506 |     QCOMPARE(QRegularExpression::escape(string), escaped); | 
| 507 |     QRegularExpression re(escaped); | 
| 508 |     QCOMPARE(re.isValid(), true); | 
| 509 | } | 
| 510 |  | 
| 511 | void tst_QRegularExpression::validity_data() | 
| 512 | { | 
| 513 |     QTest::addColumn<QString>(name: "pattern" ); | 
| 514 |     QTest::addColumn<bool>(name: "validity" ); | 
| 515 |  | 
| 516 |     QTest::newRow(dataTag: "valid01" ) << "a pattern"  << true; | 
| 517 |     QTest::newRow(dataTag: "valid02" ) << "(a|pattern)"  << true; | 
| 518 |     QTest::newRow(dataTag: "valid03" ) << "a [pP]attern"  << true; | 
| 519 |     QTest::newRow(dataTag: "valid04" ) << "^(?<article>a).*(?<noun>pattern)$"  << true; | 
| 520 |     QTest::newRow(dataTag: "valid05" ) << "a \\P{Ll}attern"  << true; | 
| 521 |  | 
| 522 |     QTest::newRow(dataTag: "invalid01" ) << "a pattern\\"  << false; | 
| 523 |     QTest::newRow(dataTag: "invalid02" ) << "(a|pattern"  << false; | 
| 524 |     QTest::newRow(dataTag: "invalid03" ) << "a \\P{BLAH}attern"  << false; | 
| 525 |  | 
| 526 |     QString pattern; | 
| 527 |     // 0xD800 (high surrogate) not followed by a low surrogate | 
| 528 |     pattern = "abcdef" ; | 
| 529 |     pattern[3] = QChar(0x00, 0xD8); | 
| 530 |     QTest::newRow(dataTag: "invalidUnicode01" ) << pattern << false; | 
| 531 | } | 
| 532 |  | 
| 533 | void tst_QRegularExpression::validity() | 
| 534 | { | 
| 535 |     QFETCH(QString, pattern); | 
| 536 |     QFETCH(bool, validity); | 
| 537 |     QRegularExpression re(pattern); | 
| 538 |     QCOMPARE(re.isValid(), validity); | 
| 539 |     if (!validity) | 
| 540 |         QTest::ignoreMessage(type: QtWarningMsg, message: "QRegularExpressionPrivate::doMatch(): called on an invalid QRegularExpression object" ); | 
| 541 |     QRegularExpressionMatch match = re.match(subject: "a pattern" ); | 
| 542 |     QCOMPARE(match.isValid(), validity); | 
| 543 |     consistencyCheck(match); | 
| 544 |  | 
| 545 |     if (!validity) | 
| 546 |         QTest::ignoreMessage(type: QtWarningMsg, message: "QRegularExpressionPrivate::doMatch(): called on an invalid QRegularExpression object" ); | 
| 547 |     QRegularExpressionMatchIterator iterator = re.globalMatch(subject: "a pattern" ); | 
| 548 |     QCOMPARE(iterator.isValid(), validity); | 
| 549 | } | 
| 550 |  | 
| 551 | void tst_QRegularExpression::patternOptions_data() | 
| 552 | { | 
| 553 |     QTest::addColumn<QRegularExpression>(name: "regexp" ); | 
| 554 |     QTest::addColumn<QString>(name: "subject" ); | 
| 555 |     QTest::addColumn<Match>(name: "match" ); | 
| 556 |  | 
| 557 |     // none of these would successfully match if the respective | 
| 558 |     // pattern option is not set | 
| 559 |  | 
| 560 |     Match m; | 
| 561 |  | 
| 562 |     m.clear(); | 
| 563 |     m.isValid = true; m.hasMatch = true; | 
| 564 |     m.captured << QString::fromUtf8(str: "AbC\xc3\xa0" ); | 
| 565 |     QTest::newRow(dataTag: "/i" ) << QRegularExpression(QString::fromUtf8(str: "abc\xc3\x80" ), QRegularExpression::CaseInsensitiveOption) | 
| 566 |                         << QString::fromUtf8(str: "AbC\xc3\xa0" ) | 
| 567 |                         << m; | 
| 568 |  | 
| 569 |     m.clear(); | 
| 570 |     m.isValid = true; m.hasMatch = true; | 
| 571 |     m.captured << "abc123\n678def" ; | 
| 572 |     QTest::newRow(dataTag: "/s" ) << QRegularExpression("\\Aabc.*def\\z" , QRegularExpression::DotMatchesEverythingOption) | 
| 573 |                         << "abc123\n678def"  | 
| 574 |                         << m; | 
| 575 |  | 
| 576 |     m.clear(); | 
| 577 |     m.isValid = true; m.hasMatch = true; | 
| 578 |     m.captured << "jumped over" ; | 
| 579 |     QTest::newRow(dataTag: "/m" ) << QRegularExpression("^\\w+ \\w+$" , QRegularExpression::MultilineOption) | 
| 580 |                         << "the quick fox\njumped over\nthe lazy\ndog"  | 
| 581 |                         << m; | 
| 582 |  | 
| 583 |     m.clear(); | 
| 584 |     m.isValid = true; m.hasMatch = true; | 
| 585 |     m.captured << "abc 123456" ; | 
| 586 |     QTest::newRow(dataTag: "/x" ) << QRegularExpression("\\w+  # a word\n"  | 
| 587 |                                               "\\ # a space\n"  | 
| 588 |                                               "\\w+ # another word" , | 
| 589 |                                               QRegularExpression::ExtendedPatternSyntaxOption) | 
| 590 |                         << "abc 123456 def"  | 
| 591 |                         << m; | 
| 592 |  | 
| 593 |     m.clear(); | 
| 594 |     m.isValid = true; m.hasMatch = true; | 
| 595 |     m.captured << "the quick fox"  << "the"  << "quick fox" ; | 
| 596 |     QTest::newRow(dataTag: "/U" ) << QRegularExpression("(.+) (.+?)" , QRegularExpression::InvertedGreedinessOption) | 
| 597 |                         << "the quick fox"  | 
| 598 |                         << m; | 
| 599 |  | 
| 600 |     m.clear(); | 
| 601 |     m.isValid = true; m.hasMatch = true; | 
| 602 |     m.captured << "the quick fox"  << "quick" ; | 
| 603 |     m.namedCaptured["named" ] = "quick" ; | 
| 604 |     QTest::newRow(dataTag: "no cap" ) << QRegularExpression("(\\w+) (?<named>\\w+) (\\w+)" , QRegularExpression::DontCaptureOption) | 
| 605 |                             << "the quick fox"  | 
| 606 |                             << m; | 
| 607 |  | 
| 608 |     m.clear(); | 
| 609 |     m.isValid = true; m.hasMatch = true; | 
| 610 |     m.captured << QString::fromUtf8(str: "abc\xc3\x80\xc3\xa0 12\xdb\xb1\xdb\xb2\xf0\x9d\x9f\x98" ) | 
| 611 |                << QString::fromUtf8(str: "abc\xc3\x80\xc3\xa0" ) | 
| 612 |                << QString::fromUtf8(str: "12\xdb\xb1\xdb\xb2\xf0\x9d\x9f\x98" ); | 
| 613 |     QTest::newRow(dataTag: "unicode properties" ) << QRegularExpression("(\\w+) (\\d+)" , QRegularExpression::UseUnicodePropertiesOption) | 
| 614 |                             << QString::fromUtf8(str: "abc\xc3\x80\xc3\xa0 12\xdb\xb1\xdb\xb2\xf0\x9d\x9f\x98" ) | 
| 615 |                             << m; | 
| 616 | } | 
| 617 |  | 
| 618 | void tst_QRegularExpression::patternOptions() | 
| 619 | { | 
| 620 |     QFETCH(QRegularExpression, regexp); | 
| 621 |     QFETCH(QString, subject); | 
| 622 |     QFETCH(Match, match); | 
| 623 |  | 
| 624 |     QRegularExpressionMatch m = regexp.match(subject); | 
| 625 |     consistencyCheck(match: m); | 
| 626 |     QVERIFY(m == match); | 
| 627 | } | 
| 628 |  | 
| 629 | void tst_QRegularExpression::normalMatch_data() | 
| 630 | { | 
| 631 |     QTest::addColumn<QRegularExpression>(name: "regexp" ); | 
| 632 |     QTest::addColumn<QString>(name: "subject" ); | 
| 633 |     QTest::addColumn<int>(name: "offset" ); | 
| 634 |     QTest::addColumn<QRegularExpression::MatchOptions>(name: "matchOptions" ); | 
| 635 |     QTest::addColumn<Match>(name: "match" ); | 
| 636 |  | 
| 637 |     Match m; | 
| 638 |     int offset = 0; | 
| 639 |  | 
| 640 |     m.clear(); | 
| 641 |     m.isValid = true; m.hasMatch = true; | 
| 642 |     m.captured << "string"  << "string" ; | 
| 643 |     QTest::newRow(dataTag: "match01" ) << QRegularExpression("(\\bstring\\b)" ) | 
| 644 |                              << "a string"  | 
| 645 |                              << 0 | 
| 646 |                              << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) | 
| 647 |                              << m; | 
| 648 |  | 
| 649 |     m.clear(); | 
| 650 |     m.isValid = true; m.hasMatch = true; | 
| 651 |     m.captured << "a string"  << "a"  << "string" ; | 
| 652 |     QTest::newRow(dataTag: "match02" ) << QRegularExpression("(\\w+) (\\w+)" ) | 
| 653 |                              << "a string"  | 
| 654 |                              << 0 | 
| 655 |                              << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) | 
| 656 |                              << m; | 
| 657 |  | 
| 658 |     m.clear(); | 
| 659 |     m.isValid = true; m.hasMatch = true; | 
| 660 |     m.captured << "a string"  << "a"  << "string" ; | 
| 661 |     m.namedCaptured["article" ] = "a" ; | 
| 662 |     m.namedCaptured["noun" ] = "string" ; | 
| 663 |     QTest::newRow(dataTag: "match03" ) << QRegularExpression("(?<article>\\w+) (?<noun>\\w+)" ) | 
| 664 |                              << "a string"  | 
| 665 |                              << 0 | 
| 666 |                              << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) | 
| 667 |                              << m; | 
| 668 |  | 
| 669 |     m.clear(); | 
| 670 |     m.isValid = true; m.hasMatch = true; | 
| 671 |     m.captured << " string"  << QString() << "string" ; | 
| 672 |     QTest::newRow(dataTag: "match04" ) << QRegularExpression("(\\w+)? (\\w+)" ) | 
| 673 |                              << " string"  | 
| 674 |                              << 0 | 
| 675 |                              << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) | 
| 676 |                              << m; | 
| 677 |  | 
| 678 |     m.clear(); | 
| 679 |     m.isValid = true; m.hasMatch = true; | 
| 680 |     m.captured << " string"  << QString("" ) << "string" ; | 
| 681 |     QTest::newRow(dataTag: "match05" ) << QRegularExpression("(\\w*) (\\w+)" ) | 
| 682 |                              << " string"  | 
| 683 |                              << 0 | 
| 684 |                              << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) | 
| 685 |                              << m; | 
| 686 |  | 
| 687 |     m.clear(); | 
| 688 |     m.isValid = true; m.hasMatch = true; | 
| 689 |     m.captured << "c123def"  << "c12"  << "3"  << "def" ; | 
| 690 |     offset = 2; | 
| 691 |     for (int i = 0; i <= offset; ++i) { | 
| 692 |         QTest::newRow(dataTag: ("match06-offset"  + QByteArray::number(i)).constData()) | 
| 693 |                 << QRegularExpression("(\\w*)(\\d+)(\\w*)" ) | 
| 694 |                 << QStringLiteral("abc123def" ).mid(position: offset - i) | 
| 695 |                 << i | 
| 696 |                 << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) | 
| 697 |                 << m; | 
| 698 |     } | 
| 699 |  | 
| 700 |     m.clear(); | 
| 701 |     m.isValid = true; m.hasMatch = true; | 
| 702 |     m.captured << QString("" ); | 
| 703 |     offset = 9; | 
| 704 |     for (int i = 0; i <= offset; ++i) { | 
| 705 |         QTest::newRow(dataTag: ("match07-offset"  + QByteArray::number(i)).constData()) | 
| 706 |                 << QRegularExpression("\\w*" ) | 
| 707 |                 << QStringLiteral("abc123def" ).mid(position: offset - i) | 
| 708 |                 << i | 
| 709 |                 << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) | 
| 710 |                 << m; | 
| 711 |     } | 
| 712 |  | 
| 713 |     m.clear(); | 
| 714 |     m.isValid = true; m.hasMatch = true; | 
| 715 |     m.captured << QString("a string" ) << QString("a string" ) << QString("" ); | 
| 716 |     QTest::newRow(dataTag: "match08" ) << QRegularExpression("(.*)(.*)" ) | 
| 717 |                              << "a string"  | 
| 718 |                              << 0 | 
| 719 |                              << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) | 
| 720 |                              << m; | 
| 721 |  | 
| 722 |     m.clear(); | 
| 723 |     m.isValid = true; m.hasMatch = true; | 
| 724 |     m.captured << QString("a string" ) << QString("" ) << QString("a string" ); | 
| 725 |     QTest::newRow(dataTag: "match09" ) << QRegularExpression("(.*?)(.*)" ) | 
| 726 |                              << "a string"  | 
| 727 |                              << 0 | 
| 728 |                              << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) | 
| 729 |                              << m; | 
| 730 |  | 
| 731 |     // non existing names for capturing groups | 
| 732 |     m.clear(); | 
| 733 |     m.isValid = true; m.hasMatch = true; | 
| 734 |     m.captured << "a string"  << "a"  << "string" ; | 
| 735 |     m.namedCaptured["article" ] = "a" ; | 
| 736 |     m.namedCaptured["noun" ] = "string" ; | 
| 737 |     m.namedCaptured["nonexisting1" ] = QString(); | 
| 738 |     m.namedCaptured["nonexisting2" ] = QString(); | 
| 739 |     m.namedCaptured["nonexisting3" ] = QString(); | 
| 740 |     QTest::newRow(dataTag: "match10" ) << QRegularExpression("(?<article>\\w+) (?<noun>\\w+)" ) | 
| 741 |                              << "a string"  | 
| 742 |                              << 0 | 
| 743 |                              << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) | 
| 744 |                              << m; | 
| 745 |  | 
| 746 |     m.clear(); | 
| 747 |     m.isValid = true; m.hasMatch = true; | 
| 748 |     m.captured << ""  << "" ; | 
| 749 |     m.namedCaptured["digits" ] = "" ; // empty VS null | 
| 750 |     m.namedCaptured["nonexisting" ] = QString(); | 
| 751 |     QTest::newRow(dataTag: "match11" ) << QRegularExpression("(?<digits>\\d*)" ) | 
| 752 |                              << "abcde"  | 
| 753 |                              << 0 | 
| 754 |                              << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) | 
| 755 |                              << m; | 
| 756 |  | 
| 757 |     // *** | 
| 758 |  | 
| 759 |     m.clear(); | 
| 760 |     m.isValid = true; m.hasMatch = true; | 
| 761 |     m.captured << "bcd" ; | 
| 762 |     QTest::newRow(dataTag: "match12" ) | 
| 763 |             << QRegularExpression("\\Bbcd\\B" ) | 
| 764 |             << "abcde"  | 
| 765 |             << 1 | 
| 766 |             << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) | 
| 767 |             << m; | 
| 768 |  | 
| 769 |     // *** | 
| 770 |  | 
| 771 |     m.clear(); | 
| 772 |     m.isValid = true; | 
| 773 |     QTest::newRow(dataTag: "nomatch01" ) << QRegularExpression("\\d+" ) | 
| 774 |                                << "a string"  | 
| 775 |                                << 0 | 
| 776 |                                << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) | 
| 777 |                                << m; | 
| 778 |  | 
| 779 |     m.clear(); | 
| 780 |     m.isValid = true; | 
| 781 |     offset = 1; | 
| 782 |     for (int i = 0; i <= offset; ++i) { | 
| 783 |         QTest::newRow(dataTag: ("nomatch02-offset"  + QByteArray::number(i)).constData()) | 
| 784 |             << QRegularExpression("(\\w+) (\\w+)" ) | 
| 785 |             << QStringLiteral("a string" ).mid(position: offset - i) | 
| 786 |             << i | 
| 787 |             << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) | 
| 788 |             << m; | 
| 789 |     } | 
| 790 |  | 
| 791 |     m.clear(); | 
| 792 |     m.isValid = true; | 
| 793 |     offset = 9; | 
| 794 |     for (int i = 0; i <= offset; ++i) { | 
| 795 |         QTest::newRow(dataTag: ("nomatch03-offset"  + QByteArray::number(i)).constData()) | 
| 796 |                 << QRegularExpression("\\w+" ) | 
| 797 |                 << QStringLiteral("abc123def" ).mid(position: offset - i) | 
| 798 |                 << i | 
| 799 |                 << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) | 
| 800 |                 << m; | 
| 801 |     } | 
| 802 |  | 
| 803 |     // *** | 
| 804 |  | 
| 805 |     m.clear(); | 
| 806 |     m.isValid = true; | 
| 807 |     QTest::newRow(dataTag: "anchoredmatch01" ) << QRegularExpression("\\d+" ) | 
| 808 |                                      << "abc123def"  | 
| 809 |                                      << 0 | 
| 810 |                                      << QRegularExpression::MatchOptions(QRegularExpression::AnchoredMatchOption) | 
| 811 |                                      << m; | 
| 812 |  | 
| 813 |     // *** | 
| 814 |  | 
| 815 |     m.clear(); | 
| 816 |     m.isValid = true; m.hasMatch = true; | 
| 817 |     m.captured << "678" ; | 
| 818 |     QTest::newRow(dataTag: "negativeoffset01" ) << QRegularExpression("\\d+" ) | 
| 819 |                                       << "abc123def678ghi"  | 
| 820 |                                       << -6 | 
| 821 |                                       << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) | 
| 822 |                                       << m; | 
| 823 |  | 
| 824 |     m.clear(); | 
| 825 |     m.isValid = true; m.hasMatch = true; | 
| 826 |     m.captured << "678" ; | 
| 827 |     QTest::newRow(dataTag: "negativeoffset02" ) << QRegularExpression("\\d+" ) | 
| 828 |                                       << "abc123def678ghi"  | 
| 829 |                                       << -8 | 
| 830 |                                       << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) | 
| 831 |                                       << m; | 
| 832 |  | 
| 833 |     m.clear(); | 
| 834 |     m.isValid = true; m.hasMatch = true; | 
| 835 |     m.captured << "678ghi"  << "678"  << "ghi" ; | 
| 836 |     QTest::newRow(dataTag: "negativeoffset03" ) << QRegularExpression("(\\d+)(\\w+)" ) | 
| 837 |                                       << "abc123def678ghi"  | 
| 838 |                                       << -8 | 
| 839 |                                       << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) | 
| 840 |                                       << m; | 
| 841 |  | 
| 842 |     m.clear(); | 
| 843 |     m.isValid = true; | 
| 844 |     QTest::newRow(dataTag: "negativeoffset04" ) << QRegularExpression("\\d+" ) | 
| 845 |                                       << "abc123def678ghi"  | 
| 846 |                                       << -3 | 
| 847 |                                       << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) | 
| 848 |                                       << m; | 
| 849 |  | 
| 850 |     m.clear(); | 
| 851 |     m.isValid = true; m.hasMatch =  true; | 
| 852 |     m.captured << "678" ; | 
| 853 |     QTest::newRow(dataTag: "negativeoffset05" ) << QRegularExpression("^\\d+" , QRegularExpression::MultilineOption) | 
| 854 |                                       << "a\nbc123\ndef\n678gh\ni"  | 
| 855 |                                       << -10 | 
| 856 |                                       << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) | 
| 857 |                                       << m; | 
| 858 | } | 
| 859 |  | 
| 860 |  | 
| 861 | void tst_QRegularExpression::normalMatch() | 
| 862 | { | 
| 863 |     QFETCH(QRegularExpression, regexp); | 
| 864 |     QFETCH(QString, subject); | 
| 865 |     QFETCH(int, offset); | 
| 866 |     QFETCH(QRegularExpression::MatchOptions, matchOptions); | 
| 867 |     QFETCH(Match, match); | 
| 868 |  | 
| 869 |     testMatch<QRegularExpressionMatch>(regexp, | 
| 870 |                                        matchingMethodForString: static_cast<QREMatchStringPMF>(&QRegularExpression::match), | 
| 871 |                                        matchingMethodForStringRef: static_cast<QREMatchStringRefPMF>(&QRegularExpression::match), | 
| 872 |                                        subject, | 
| 873 |                                        offset, | 
| 874 |                                        matchType: QRegularExpression::NormalMatch, | 
| 875 |                                        matchOptions, | 
| 876 |                                        result: match); | 
| 877 | } | 
| 878 |  | 
| 879 | void tst_QRegularExpression::partialMatch_data() | 
| 880 | { | 
| 881 |     QTest::addColumn<QRegularExpression>(name: "regexp" ); | 
| 882 |     QTest::addColumn<QString>(name: "subject" ); | 
| 883 |     QTest::addColumn<int>(name: "offset" ); | 
| 884 |     QTest::addColumn<QRegularExpression::MatchType>(name: "matchType" ); | 
| 885 |     QTest::addColumn<QRegularExpression::MatchOptions>(name: "matchOptions" ); | 
| 886 |     QTest::addColumn<Match>(name: "match" ); | 
| 887 |  | 
| 888 |     Match m; | 
| 889 |     int offset = 0; | 
| 890 |  | 
| 891 |     m.clear(); | 
| 892 |     m.isValid = true; m.hasPartialMatch = true; | 
| 893 |     m.captured << "str" ; | 
| 894 |     QTest::newRow(dataTag: "softmatch01" ) << QRegularExpression("string" ) | 
| 895 |                                     << "a str"  | 
| 896 |                                     << 0 | 
| 897 |                                     << QRegularExpression::PartialPreferCompleteMatch | 
| 898 |                                     << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) | 
| 899 |                                     << m; | 
| 900 |  | 
| 901 |     m.clear(); | 
| 902 |     m.isValid = true; m.hasPartialMatch = true; | 
| 903 |     m.captured << " str" ; | 
| 904 |     QTest::newRow(dataTag: "softmatch02" ) << QRegularExpression("\\bstring\\b" ) | 
| 905 |                                     << "a str"  | 
| 906 |                                     << 0 | 
| 907 |                                     << QRegularExpression::PartialPreferCompleteMatch | 
| 908 |                                     << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) | 
| 909 |                                     << m; | 
| 910 |  | 
| 911 |     m.clear(); | 
| 912 |     m.isValid = true; m.hasPartialMatch = true; | 
| 913 |     m.captured << " str" ; | 
| 914 |     QTest::newRow(dataTag: "softmatch03" ) << QRegularExpression("(\\bstring\\b)" ) | 
| 915 |                                     << "a str"  | 
| 916 |                                     << 0 | 
| 917 |                                     << QRegularExpression::PartialPreferCompleteMatch | 
| 918 |                                     << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) | 
| 919 |                                     << m; | 
| 920 |  | 
| 921 |     m.clear(); | 
| 922 |     m.isValid = true; m.hasPartialMatch = true; | 
| 923 |     m.captured << "8 Dec 19" ; | 
| 924 |     QTest::newRow(dataTag: "softmatch04" ) << QRegularExpression("^(\\d{1,2}) (\\w{3}) (\\d{4})$" ) | 
| 925 |                                     << "8 Dec 19"  | 
| 926 |                                     << 0 | 
| 927 |                                     << QRegularExpression::PartialPreferCompleteMatch | 
| 928 |                                     << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) | 
| 929 |                                     << m; | 
| 930 |  | 
| 931 |     m.clear(); | 
| 932 |     m.isValid = true; m.hasMatch = true; | 
| 933 |     m.captured << "8 Dec 1985"  << "8"  << "Dec"  << "1985" ; | 
| 934 |     QTest::newRow(dataTag: "softmatch05" ) << QRegularExpression("^(\\d{1,2}) (\\w{3}) (\\d{4})$" ) | 
| 935 |                                     << "8 Dec 1985"  | 
| 936 |                                     << 0 | 
| 937 |                                     << QRegularExpression::PartialPreferCompleteMatch | 
| 938 |                                     << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) | 
| 939 |                                     << m; | 
| 940 |  | 
| 941 |     m.clear(); | 
| 942 |     m.isValid = true; m.hasMatch = true; | 
| 943 |     m.captured << "def" ; | 
| 944 |     QTest::newRow(dataTag: "softmatch06" ) << QRegularExpression("abc\\w+X|def" ) | 
| 945 |                                     << "abcdef"  | 
| 946 |                                     << 0 | 
| 947 |                                     << QRegularExpression::PartialPreferCompleteMatch | 
| 948 |                                     << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) | 
| 949 |                                     << m; | 
| 950 |  | 
| 951 |     m.clear(); | 
| 952 |     m.isValid = true; m.hasPartialMatch = true; | 
| 953 |     m.captured << "abcdef" ; | 
| 954 |     QTest::newRow(dataTag: "softmatch07" ) << QRegularExpression("abc\\w+X|defY" ) | 
| 955 |                                     << "abcdef"  | 
| 956 |                                     << 0 | 
| 957 |                                     << QRegularExpression::PartialPreferCompleteMatch | 
| 958 |                                     << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) | 
| 959 |                                     << m; | 
| 960 |  | 
| 961 |     m.clear(); | 
| 962 |     m.isValid = true; m.hasPartialMatch = true; | 
| 963 |     m.captured << "def" ; | 
| 964 |     offset = 1; | 
| 965 |     for (int i = 0; i <= offset; ++i) { | 
| 966 |         QTest::newRow(dataTag: ("softmatch08-offset"  + QByteArray::number(i)).constData()) | 
| 967 |                 << QRegularExpression("abc\\w+X|defY" ) | 
| 968 |                 << QStringLiteral("abcdef" ).mid(position: offset - i) | 
| 969 |                 << i | 
| 970 |                 << QRegularExpression::PartialPreferCompleteMatch | 
| 971 |                 << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) | 
| 972 |                 << m; | 
| 973 |     } | 
| 974 |  | 
| 975 |     // *** | 
| 976 |  | 
| 977 |     m.clear(); | 
| 978 |     m.isValid = true; m.hasPartialMatch = true; | 
| 979 |     m.captured << "str" ; | 
| 980 |     QTest::newRow(dataTag: "hardmatch01" ) << QRegularExpression("string" ) | 
| 981 |                                     << "a str"  | 
| 982 |                                     << 0 | 
| 983 |                                     << QRegularExpression::PartialPreferFirstMatch | 
| 984 |                                     << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) | 
| 985 |                                     << m; | 
| 986 |  | 
| 987 |     m.clear(); | 
| 988 |     m.isValid = true; m.hasPartialMatch = true; | 
| 989 |     m.captured << " str" ; | 
| 990 |     QTest::newRow(dataTag: "hardmatch02" ) << QRegularExpression("\\bstring\\b" ) | 
| 991 |                                     << "a str"  | 
| 992 |                                     << 0 | 
| 993 |                                     << QRegularExpression::PartialPreferFirstMatch | 
| 994 |                                     << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) | 
| 995 |                                     << m; | 
| 996 |  | 
| 997 |     m.clear(); | 
| 998 |     m.isValid = true; m.hasPartialMatch = true; | 
| 999 |     m.captured << " str" ; | 
| 1000 |     QTest::newRow(dataTag: "hardmatch03" ) << QRegularExpression("(\\bstring\\b)" ) | 
| 1001 |                                     << "a str"  | 
| 1002 |                                     << 0 | 
| 1003 |                                     << QRegularExpression::PartialPreferFirstMatch | 
| 1004 |                                     << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) | 
| 1005 |                                     << m; | 
| 1006 |  | 
| 1007 |     m.clear(); | 
| 1008 |     m.isValid = true; m.hasPartialMatch = true; | 
| 1009 |     m.captured << "8 Dec 19" ; | 
| 1010 |     QTest::newRow(dataTag: "hardmatch04" ) << QRegularExpression("^(\\d{1,2}) (\\w{3}) (\\d{4})$" ) | 
| 1011 |                                     << "8 Dec 19"  | 
| 1012 |                                     << 0 | 
| 1013 |                                     << QRegularExpression::PartialPreferFirstMatch | 
| 1014 |                                     << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) | 
| 1015 |                                     << m; | 
| 1016 |  | 
| 1017 |     m.clear(); | 
| 1018 |     m.isValid = true; m.hasPartialMatch = true; | 
| 1019 |     m.captured << "8 Dec 1985" ; | 
| 1020 |     QTest::newRow(dataTag: "hardmatch05" ) << QRegularExpression("^(\\d{1,2}) (\\w{3}) (\\d{4})$" ) | 
| 1021 |                                     << "8 Dec 1985"  | 
| 1022 |                                     << 0 | 
| 1023 |                                     << QRegularExpression::PartialPreferFirstMatch | 
| 1024 |                                     << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) | 
| 1025 |                                     << m; | 
| 1026 |  | 
| 1027 |     m.clear(); | 
| 1028 |     m.isValid = true; m.hasPartialMatch = true; | 
| 1029 |     m.captured << "abcdef" ; | 
| 1030 |     QTest::newRow(dataTag: "hardmatch06" ) << QRegularExpression("abc\\w+X|def" ) | 
| 1031 |                                     << "abcdef"  | 
| 1032 |                                     << 0 | 
| 1033 |                                     << QRegularExpression::PartialPreferFirstMatch | 
| 1034 |                                     << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) | 
| 1035 |                                     << m; | 
| 1036 |  | 
| 1037 |     m.clear(); | 
| 1038 |     m.isValid = true; m.hasPartialMatch = true; | 
| 1039 |     m.captured << "abcdef" ; | 
| 1040 |     QTest::newRow(dataTag: "hardmatch07" ) << QRegularExpression("abc\\w+X|defY" ) | 
| 1041 |                                     << "abcdef"  | 
| 1042 |                                     << 0 | 
| 1043 |                                     << QRegularExpression::PartialPreferFirstMatch | 
| 1044 |                                     << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) | 
| 1045 |                                     << m; | 
| 1046 |  | 
| 1047 |     m.clear(); | 
| 1048 |     m.isValid = true; m.hasPartialMatch = true; | 
| 1049 |     m.captured << "def" ; | 
| 1050 |     offset = 1; | 
| 1051 |     for (int i = 0; i <= offset; ++i) { | 
| 1052 |         QTest::newRow(dataTag: ("hardmatch08-offset"  + QByteArray::number(i)).constData()) | 
| 1053 |                 << QRegularExpression("abc\\w+X|defY" ) | 
| 1054 |                 << QStringLiteral("abcdef" ).mid(position: offset - i) | 
| 1055 |                 << i | 
| 1056 |                 << QRegularExpression::PartialPreferFirstMatch | 
| 1057 |                 << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) | 
| 1058 |                 << m; | 
| 1059 |     } | 
| 1060 |  | 
| 1061 |     m.clear(); | 
| 1062 |     m.isValid = true; m.hasPartialMatch = true; | 
| 1063 |     m.captured << "ab" ; | 
| 1064 |     QTest::newRow(dataTag: "hardmatch09" ) << QRegularExpression("abc|ab" ) | 
| 1065 |                                     << "ab"  | 
| 1066 |                                     << 0 | 
| 1067 |                                     << QRegularExpression::PartialPreferFirstMatch | 
| 1068 |                                     << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) | 
| 1069 |                                     << m; | 
| 1070 |  | 
| 1071 |     m.clear(); | 
| 1072 |     m.isValid = true; m.hasPartialMatch = true; | 
| 1073 |     m.captured << "abc" ; | 
| 1074 |     QTest::newRow(dataTag: "hardmatch10" ) << QRegularExpression("abc(def)?" ) | 
| 1075 |                                     << "abc"  | 
| 1076 |                                     << 0 | 
| 1077 |                                     << QRegularExpression::PartialPreferFirstMatch | 
| 1078 |                                     << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) | 
| 1079 |                                     << m; | 
| 1080 |  | 
| 1081 |     m.clear(); | 
| 1082 |     m.isValid = true; m.hasPartialMatch = true; | 
| 1083 |     m.captured << "abc" ; | 
| 1084 |     QTest::newRow(dataTag: "hardmatch11" ) << QRegularExpression("(abc)*" ) | 
| 1085 |                                     << "abc"  | 
| 1086 |                                     << 0 | 
| 1087 |                                     << QRegularExpression::PartialPreferFirstMatch | 
| 1088 |                                     << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) | 
| 1089 |                                     << m; | 
| 1090 |  | 
| 1091 |  | 
| 1092 |     // *** | 
| 1093 |  | 
| 1094 |     m.clear(); | 
| 1095 |     m.isValid = true; | 
| 1096 |     QTest::newRow(dataTag: "nomatch01" ) << QRegularExpression("abc\\w+X|defY" ) | 
| 1097 |                                << "123456"  | 
| 1098 |                                << 0 | 
| 1099 |                                << QRegularExpression::PartialPreferCompleteMatch | 
| 1100 |                                << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) | 
| 1101 |                                << m; | 
| 1102 |  | 
| 1103 |     m.clear(); | 
| 1104 |     m.isValid = true; | 
| 1105 |     QTest::newRow(dataTag: "nomatch02" ) << QRegularExpression("abc\\w+X|defY" ) | 
| 1106 |                                << "123456"  | 
| 1107 |                                << 0 | 
| 1108 |                                << QRegularExpression::PartialPreferFirstMatch | 
| 1109 |                                << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) | 
| 1110 |                                << m; | 
| 1111 |  | 
| 1112 |     m.clear(); | 
| 1113 |     m.isValid = true; | 
| 1114 |     QTest::newRow(dataTag: "nomatch03" ) << QRegularExpression("abc\\w+X|defY" ) | 
| 1115 |                                << "ab123"  | 
| 1116 |                                << 0 | 
| 1117 |                                << QRegularExpression::PartialPreferCompleteMatch | 
| 1118 |                                << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) | 
| 1119 |                                << m; | 
| 1120 |  | 
| 1121 |     m.clear(); | 
| 1122 |     m.isValid = true; | 
| 1123 |     QTest::newRow(dataTag: "nomatch04" ) << QRegularExpression("abc\\w+X|defY" ) | 
| 1124 |                                << "ab123"  | 
| 1125 |                                << 0 | 
| 1126 |                                << QRegularExpression::PartialPreferFirstMatch | 
| 1127 |                                << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) | 
| 1128 |                                << m; | 
| 1129 |  | 
| 1130 | } | 
| 1131 |  | 
| 1132 | void tst_QRegularExpression::partialMatch() | 
| 1133 | { | 
| 1134 |     QFETCH(QRegularExpression, regexp); | 
| 1135 |     QFETCH(QString, subject); | 
| 1136 |     QFETCH(int, offset); | 
| 1137 |     QFETCH(QRegularExpression::MatchType, matchType); | 
| 1138 |     QFETCH(QRegularExpression::MatchOptions, matchOptions); | 
| 1139 |     QFETCH(Match, match); | 
| 1140 |  | 
| 1141 |     testMatch<QRegularExpressionMatch>(regexp, | 
| 1142 |                                        matchingMethodForString: static_cast<QREMatchStringPMF>(&QRegularExpression::match), | 
| 1143 |                                        matchingMethodForStringRef: static_cast<QREMatchStringRefPMF>(&QRegularExpression::match), | 
| 1144 |                                        subject, | 
| 1145 |                                        offset, | 
| 1146 |                                        matchType, | 
| 1147 |                                        matchOptions, | 
| 1148 |                                        result: match); | 
| 1149 | } | 
| 1150 |  | 
| 1151 | void tst_QRegularExpression::globalMatch_data() | 
| 1152 | { | 
| 1153 |     QTest::addColumn<QRegularExpression>(name: "regexp" ); | 
| 1154 |     QTest::addColumn<QString>(name: "subject" ); | 
| 1155 |     QTest::addColumn<int>(name: "offset" ); | 
| 1156 |     QTest::addColumn<QRegularExpression::MatchType>(name: "matchType" ); | 
| 1157 |     QTest::addColumn<QRegularExpression::MatchOptions>(name: "matchOptions" ); | 
| 1158 |     QTest::addColumn<QVector<Match> >(name: "matchList" ); | 
| 1159 |  | 
| 1160 |     QVector<Match> matchList; | 
| 1161 |     Match m; | 
| 1162 |  | 
| 1163 |     matchList.clear(); | 
| 1164 |     m.clear(); | 
| 1165 |     m.isValid = true; m.hasMatch = true; | 
| 1166 |     m.captured = QStringList() << "the" ; | 
| 1167 |     matchList << m; | 
| 1168 |     m.captured = QStringList() << "quick" ; | 
| 1169 |     matchList << m; | 
| 1170 |     m.captured = QStringList() << "fox" ; | 
| 1171 |     matchList << m; | 
| 1172 |     QTest::newRow(dataTag: "globalmatch01" ) << QRegularExpression("\\w+" ) | 
| 1173 |                                    << "the quick fox"  | 
| 1174 |                                    << 0 | 
| 1175 |                                    << QRegularExpression::NormalMatch | 
| 1176 |                                    << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) | 
| 1177 |                                    << matchList; | 
| 1178 |  | 
| 1179 |     matchList.clear(); | 
| 1180 |     m.clear(); | 
| 1181 |     m.isValid = true; m.hasMatch = true; | 
| 1182 |     m.captured = QStringList() << "the"  << "t"  << "he" ; | 
| 1183 |     matchList << m; | 
| 1184 |     m.captured = QStringList() << "quick"  << "q"  << "uick" ; | 
| 1185 |     matchList << m; | 
| 1186 |     m.captured = QStringList() << "fox"  << "f"  << "ox" ; | 
| 1187 |     matchList << m; | 
| 1188 |     QTest::newRow(dataTag: "globalmatch02" ) << QRegularExpression("(\\w+?)(\\w+)" ) | 
| 1189 |                                    << "the quick fox"  | 
| 1190 |                                    << 0 | 
| 1191 |                                    << QRegularExpression::NormalMatch | 
| 1192 |                                    << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) | 
| 1193 |                                    << matchList; | 
| 1194 |  | 
| 1195 |     matchList.clear(); | 
| 1196 |     m.clear(); | 
| 1197 |     m.isValid = true; m.hasMatch = true; | 
| 1198 |     m.captured = QStringList() << "ACA" "GTG" "CGA" "AAA" ; | 
| 1199 |     matchList << m; | 
| 1200 |     m.captured = QStringList() << "AAA" ; | 
| 1201 |     matchList << m; | 
| 1202 |     m.captured = QStringList() << "AAG" "GAA" "AAG" "AAA" ; | 
| 1203 |     matchList << m; | 
| 1204 |     m.captured = QStringList() << "AAA" ; | 
| 1205 |     matchList << m; | 
| 1206 |     QTest::newRow(dataTag: "globalmatch03" ) << QRegularExpression("\\G(?:\\w\\w\\w)*?AAA" ) | 
| 1207 |                                    << "ACA" "GTG" "CGA" "AAA" "AAA" "AAG" "GAA" "AAG" "AAA" "AAA"  | 
| 1208 |                                    << 0 | 
| 1209 |                                    << QRegularExpression::NormalMatch | 
| 1210 |                                    << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) | 
| 1211 |                                    << matchList; | 
| 1212 |  | 
| 1213 |     QTest::newRow(dataTag: "globalmatch04" ) << QRegularExpression("(?:\\w\\w\\w)*?AAA" ) | 
| 1214 |                                    << "ACA" "GTG" "CGA" "AAA" "AAA" "AAG" "GAA" "AAG" "AAA" "AAA"  | 
| 1215 |                                    << 0 | 
| 1216 |                                    << QRegularExpression::NormalMatch | 
| 1217 |                                    << QRegularExpression::MatchOptions(QRegularExpression::AnchoredMatchOption) | 
| 1218 |                                    << matchList; | 
| 1219 |  | 
| 1220 |     matchList.clear(); | 
| 1221 |     m.clear(); | 
| 1222 |     m.isValid = true; m.hasMatch = true; | 
| 1223 |     m.captured = QStringList() << "" ; | 
| 1224 |     matchList << m; | 
| 1225 |     m.captured = QStringList() << "c" ; | 
| 1226 |     matchList << m; | 
| 1227 |     m.captured = QStringList() << "" ; | 
| 1228 |     matchList << m; | 
| 1229 |     m.captured = QStringList() << "c" ; | 
| 1230 |     matchList << m; | 
| 1231 |     m.captured = QStringList() << "aabb" ; | 
| 1232 |     matchList << m; | 
| 1233 |     m.captured = QStringList() << "" ; | 
| 1234 |     matchList << m; | 
| 1235 |     m.captured = QStringList() << "" ; | 
| 1236 |     matchList << m; | 
| 1237 |  | 
| 1238 |     QTest::newRow(dataTag: "globalmatch_emptycaptures01" ) << QRegularExpression("a*b*|c" ) | 
| 1239 |                                                  << "ccaabbd"  | 
| 1240 |                                                  << 0 | 
| 1241 |                                                  << QRegularExpression::NormalMatch | 
| 1242 |                                                  << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) | 
| 1243 |                                                  << matchList; | 
| 1244 |  | 
| 1245 |     matchList.clear(); | 
| 1246 |     m.clear(); | 
| 1247 |     m.isValid = true; m.hasMatch = true; | 
| 1248 |     m.captured = QStringList() << "the" ; | 
| 1249 |     matchList << m; | 
| 1250 |     m.captured = QStringList() << "" ; | 
| 1251 |     matchList << m; | 
| 1252 |     m.captured = QStringList() << "quick" ; | 
| 1253 |     matchList << m; | 
| 1254 |     m.captured = QStringList() << "" ; | 
| 1255 |     matchList << m; | 
| 1256 |     m.captured = QStringList() << "fox" ; | 
| 1257 |     matchList << m; | 
| 1258 |     m.captured = QStringList() << "" ; | 
| 1259 |     matchList << m; | 
| 1260 |  | 
| 1261 |     QTest::newRow(dataTag: "globalmatch_emptycaptures02" ) << QRegularExpression(".*" ) | 
| 1262 |                                                  << "the\nquick\nfox"  | 
| 1263 |                                                  << 0 | 
| 1264 |                                                  << QRegularExpression::NormalMatch | 
| 1265 |                                                  << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) | 
| 1266 |                                                  << matchList; | 
| 1267 |  | 
| 1268 |     matchList.clear(); | 
| 1269 |     m.clear(); | 
| 1270 |     m.isValid = true; m.hasMatch = true; | 
| 1271 |     m.captured = QStringList() << "the" ; | 
| 1272 |     matchList << m; | 
| 1273 |     m.captured = QStringList() << "" ; | 
| 1274 |     matchList << m; | 
| 1275 |     m.captured = QStringList() << "quick" ; | 
| 1276 |     matchList << m; | 
| 1277 |     m.captured = QStringList() << "" ; | 
| 1278 |     matchList << m; | 
| 1279 |     m.captured = QStringList() << "fox" ; | 
| 1280 |     matchList << m; | 
| 1281 |     m.captured = QStringList() << "" ; | 
| 1282 |     matchList << m; | 
| 1283 |     m.captured = QStringList() << "" ; | 
| 1284 |     matchList << m; | 
| 1285 |  | 
| 1286 |     QTest::newRow(dataTag: "globalmatch_emptycaptures03" ) << QRegularExpression(".*" ) | 
| 1287 |                                                  << "the\nquick\nfox\n"  | 
| 1288 |                                                  << 0 | 
| 1289 |                                                  << QRegularExpression::NormalMatch | 
| 1290 |                                                  << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) | 
| 1291 |                                                  << matchList; | 
| 1292 |  | 
| 1293 |     matchList.clear(); | 
| 1294 |     m.clear(); | 
| 1295 |     m.isValid = true; m.hasMatch = true; | 
| 1296 |     m.captured = QStringList() << "the" ; | 
| 1297 |     matchList << m; | 
| 1298 |     m.captured = QStringList() << "" ; | 
| 1299 |     matchList << m; | 
| 1300 |     m.captured = QStringList() << "quick" ; | 
| 1301 |     matchList << m; | 
| 1302 |     m.captured = QStringList() << "" ; | 
| 1303 |     matchList << m; | 
| 1304 |     m.captured = QStringList() << "fox" ; | 
| 1305 |     matchList << m; | 
| 1306 |     m.captured = QStringList() << "" ; | 
| 1307 |     matchList << m; | 
| 1308 |  | 
| 1309 |     QTest::newRow(dataTag: "globalmatch_emptycaptures04" ) << QRegularExpression("(*CRLF).*" ) | 
| 1310 |                                                  << "the\r\nquick\r\nfox"  | 
| 1311 |                                                  << 0 | 
| 1312 |                                                  << QRegularExpression::NormalMatch | 
| 1313 |                                                  << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) | 
| 1314 |                                                  << matchList; | 
| 1315 |  | 
| 1316 |     matchList.clear(); | 
| 1317 |     m.clear(); | 
| 1318 |     m.isValid = true; m.hasMatch = true; | 
| 1319 |     m.captured = QStringList() << "the" ; | 
| 1320 |     matchList << m; | 
| 1321 |     m.captured = QStringList() << "" ; | 
| 1322 |     matchList << m; | 
| 1323 |     m.captured = QStringList() << "quick" ; | 
| 1324 |     matchList << m; | 
| 1325 |     m.captured = QStringList() << "" ; | 
| 1326 |     matchList << m; | 
| 1327 |     m.captured = QStringList() << "fox" ; | 
| 1328 |     matchList << m; | 
| 1329 |     m.captured = QStringList() << "" ; | 
| 1330 |     matchList << m; | 
| 1331 |     m.captured = QStringList() << "" ; | 
| 1332 |     matchList << m; | 
| 1333 |  | 
| 1334 |     QTest::newRow(dataTag: "globalmatch_emptycaptures05" ) << QRegularExpression("(*CRLF).*" ) | 
| 1335 |                                                  << "the\r\nquick\r\nfox\r\n"  | 
| 1336 |                                                  << 0 | 
| 1337 |                                                  << QRegularExpression::NormalMatch | 
| 1338 |                                                  << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) | 
| 1339 |                                                  << matchList; | 
| 1340 |  | 
| 1341 |     matchList.clear(); | 
| 1342 |     m.clear(); | 
| 1343 |     m.isValid = true; m.hasMatch = true; | 
| 1344 |     m.captured = QStringList() << "the" ; | 
| 1345 |     matchList << m; | 
| 1346 |     m.captured = QStringList() << "" ; | 
| 1347 |     matchList << m; | 
| 1348 |     m.captured = QStringList() << "quick" ; | 
| 1349 |     matchList << m; | 
| 1350 |     m.captured = QStringList() << "" ; | 
| 1351 |     matchList << m; | 
| 1352 |     m.captured = QStringList() << "fox" ; | 
| 1353 |     matchList << m; | 
| 1354 |     m.captured = QStringList() << "" ; | 
| 1355 |     matchList << m; | 
| 1356 |     m.captured = QStringList() << "jumped" ; | 
| 1357 |     matchList << m; | 
| 1358 |     m.captured = QStringList() << "" ; | 
| 1359 |     matchList << m; | 
| 1360 |  | 
| 1361 |     QTest::newRow(dataTag: "globalmatch_emptycaptures06" ) << QRegularExpression("(*ANYCRLF).*" ) | 
| 1362 |                                                  << "the\r\nquick\nfox\rjumped"  | 
| 1363 |                                                  << 0 | 
| 1364 |                                                  << QRegularExpression::NormalMatch | 
| 1365 |                                                  << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) | 
| 1366 |                                                  << matchList; | 
| 1367 |  | 
| 1368 |     matchList.clear(); | 
| 1369 |     m.clear(); | 
| 1370 |     m.isValid = true; m.hasMatch = true; | 
| 1371 |     m.captured = QStringList() << "ABC" ; | 
| 1372 |     matchList << m; | 
| 1373 |     m.captured = QStringList() << "" ; | 
| 1374 |     matchList << m; | 
| 1375 |     m.captured = QStringList() << "DEF" ; | 
| 1376 |     matchList << m; | 
| 1377 |     m.captured = QStringList() << "" ; | 
| 1378 |     matchList << m; | 
| 1379 |     m.captured = QStringList() << "GHI" ; | 
| 1380 |     matchList << m; | 
| 1381 |     m.captured = QStringList() << "" ; | 
| 1382 |     matchList << m; | 
| 1383 |     QTest::newRow(dataTag: "globalmatch_emptycaptures07" ) << QRegularExpression("[\\x{0000}-\\x{FFFF}]*" ) | 
| 1384 |                                                  << QString::fromUtf8(str: "ABC" "\xf0\x9d\x85\x9d" "DEF" "\xf0\x9d\x85\x9e" "GHI" ) | 
| 1385 |                                                  << 0 | 
| 1386 |                                                  << QRegularExpression::NormalMatch | 
| 1387 |                                                  << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) | 
| 1388 |                                                  << matchList; | 
| 1389 |  | 
| 1390 |     matchList.clear(); | 
| 1391 |     m.clear(); | 
| 1392 |     m.isValid = true; m.hasMatch = true; | 
| 1393 |     m.captured = QStringList() << QString::fromUtf8(str: "ABC" "\xc3\x80" ); | 
| 1394 |     matchList << m; | 
| 1395 |     m.captured = QStringList() << "" ; | 
| 1396 |     matchList << m; | 
| 1397 |     m.captured = QStringList() << QString::fromUtf8(str: "\xc3\x80" "DEF" "\xc3\x80" ); | 
| 1398 |     matchList << m; | 
| 1399 |     m.captured = QStringList() << "" ; | 
| 1400 |     matchList << m; | 
| 1401 |     QTest::newRow(dataTag: "globalmatch_emptycaptures08" ) << QRegularExpression("[\\x{0000}-\\x{FFFF}]*" ) | 
| 1402 |                                                  << QString::fromUtf8(str: "ABC" "\xc3\x80" "\xf0\x9d\x85\x9d" "\xc3\x80" "DEF" "\xc3\x80" ) | 
| 1403 |                                                  << 0 | 
| 1404 |                                                  << QRegularExpression::NormalMatch | 
| 1405 |                                                  << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) | 
| 1406 |                                                  << matchList; | 
| 1407 | } | 
| 1408 |  | 
| 1409 | void tst_QRegularExpression::globalMatch() | 
| 1410 | { | 
| 1411 |     QFETCH(QRegularExpression, regexp); | 
| 1412 |     QFETCH(QString, subject); | 
| 1413 |     QFETCH(int, offset); | 
| 1414 |     QFETCH(QRegularExpression::MatchType, matchType); | 
| 1415 |     QFETCH(QRegularExpression::MatchOptions, matchOptions); | 
| 1416 |     QFETCH(QVector<Match>, matchList); | 
| 1417 |  | 
| 1418 |     testMatch<QRegularExpressionMatchIterator>(regexp, | 
| 1419 |                                                matchingMethodForString: static_cast<QREGlobalMatchStringPMF>(&QRegularExpression::globalMatch), | 
| 1420 |                                                matchingMethodForStringRef: static_cast<QREGlobalMatchStringRefPMF>(&QRegularExpression::globalMatch), | 
| 1421 |                                                subject, | 
| 1422 |                                                offset, | 
| 1423 |                                                matchType, | 
| 1424 |                                                matchOptions, | 
| 1425 |                                                result: matchList); | 
| 1426 | } | 
| 1427 |  | 
| 1428 | void tst_QRegularExpression::serialize_data() | 
| 1429 | { | 
| 1430 |     provideRegularExpressions(); | 
| 1431 | } | 
| 1432 |  | 
| 1433 | void tst_QRegularExpression::serialize() | 
| 1434 | { | 
| 1435 |     QFETCH(QString, pattern); | 
| 1436 |     QFETCH(QRegularExpression::PatternOptions, patternOptions); | 
| 1437 |     QRegularExpression outRe(pattern, patternOptions); | 
| 1438 |  | 
| 1439 |     QByteArray buffer; | 
| 1440 |     { | 
| 1441 |         QDataStream out(&buffer, QIODevice::WriteOnly); | 
| 1442 |         out << outRe; | 
| 1443 |     } | 
| 1444 |     QRegularExpression inRe; | 
| 1445 |     { | 
| 1446 |         QDataStream in(&buffer, QIODevice::ReadOnly); | 
| 1447 |         in >> inRe; | 
| 1448 |     } | 
| 1449 |     QCOMPARE(inRe, outRe); | 
| 1450 | } | 
| 1451 |  | 
| 1452 | static void verifyEquality(const QRegularExpression &re1, const QRegularExpression &re2) | 
| 1453 | { | 
| 1454 |     QVERIFY(re1 == re2); | 
| 1455 |     QVERIFY(re2 == re1); | 
| 1456 |     QCOMPARE(qHash(re1), qHash(re2)); | 
| 1457 |     QVERIFY(!(re1 != re2)); | 
| 1458 |     QVERIFY(!(re2 != re1)); | 
| 1459 |  | 
| 1460 |     QRegularExpression re3(re1); | 
| 1461 |  | 
| 1462 |     QVERIFY(re1 == re3); | 
| 1463 |     QVERIFY(re3 == re1); | 
| 1464 |     QCOMPARE(qHash(re1), qHash(re3)); | 
| 1465 |     QVERIFY(!(re1 != re3)); | 
| 1466 |     QVERIFY(!(re3 != re1)); | 
| 1467 |  | 
| 1468 |     QVERIFY(re2 == re3); | 
| 1469 |     QVERIFY(re3 == re2); | 
| 1470 |     QCOMPARE(qHash(re2), qHash(re3)); | 
| 1471 |     QVERIFY(!(re2 != re3)); | 
| 1472 |     QVERIFY(!(re3 != re2)); | 
| 1473 |  | 
| 1474 |     re3 = re2; | 
| 1475 |     QVERIFY(re1 == re3); | 
| 1476 |     QVERIFY(re3 == re1); | 
| 1477 |     QCOMPARE(qHash(re1), qHash(re3)); | 
| 1478 |     QVERIFY(!(re1 != re3)); | 
| 1479 |     QVERIFY(!(re3 != re1)); | 
| 1480 |  | 
| 1481 |     QVERIFY(re2 == re3); | 
| 1482 |     QVERIFY(re3 == re2); | 
| 1483 |     QCOMPARE(qHash(re2), qHash(re3)); | 
| 1484 |     QVERIFY(!(re2 != re3)); | 
| 1485 |     QVERIFY(!(re3 != re2)); | 
| 1486 | } | 
| 1487 |  | 
| 1488 | void tst_QRegularExpression::operatoreq_data() | 
| 1489 | { | 
| 1490 |     provideRegularExpressions(); | 
| 1491 | } | 
| 1492 |  | 
| 1493 | void tst_QRegularExpression::operatoreq() | 
| 1494 | { | 
| 1495 |     QFETCH(QString, pattern); | 
| 1496 |     QFETCH(QRegularExpression::PatternOptions, patternOptions); | 
| 1497 |     { | 
| 1498 |         QRegularExpression re1(pattern); | 
| 1499 |         QRegularExpression re2(pattern); | 
| 1500 |  | 
| 1501 |         verifyEquality(re1, re2); | 
| 1502 |     } | 
| 1503 |     { | 
| 1504 |         QRegularExpression re1(QString(), patternOptions); | 
| 1505 |         QRegularExpression re2(QString(), patternOptions); | 
| 1506 |  | 
| 1507 |         verifyEquality(re1, re2); | 
| 1508 |     } | 
| 1509 |     { | 
| 1510 |         QRegularExpression re1(pattern, patternOptions); | 
| 1511 |         QRegularExpression re2(pattern, patternOptions); | 
| 1512 |  | 
| 1513 |         verifyEquality(re1, re2); | 
| 1514 |     } | 
| 1515 | } | 
| 1516 |  | 
| 1517 | void tst_QRegularExpression::captureCount_data() | 
| 1518 | { | 
| 1519 |     QTest::addColumn<QString>(name: "pattern" ); | 
| 1520 |     QTest::addColumn<int>(name: "captureCount" ); | 
| 1521 |     QTest::newRow(dataTag: "captureCount01" ) << "a pattern"  << 0; | 
| 1522 |     QTest::newRow(dataTag: "captureCount02" ) << "a.*pattern"  << 0; | 
| 1523 |     QTest::newRow(dataTag: "captureCount03" ) << "(a) pattern"  << 1; | 
| 1524 |     QTest::newRow(dataTag: "captureCount04" ) << "(a).*(pattern)"  << 2; | 
| 1525 |     QTest::newRow(dataTag: "captureCount05" ) << "^(?<article>\\w+) (?<noun>\\w+)$"  << 2; | 
| 1526 |     QTest::newRow(dataTag: "captureCount06" ) << "^(\\w+) (?<word>\\w+) (.)$"  << 3; | 
| 1527 |     QTest::newRow(dataTag: "captureCount07" ) << "(?:non capturing) (capturing) (?<n>named) (?:non (capturing))"  << 3; | 
| 1528 |     QTest::newRow(dataTag: "captureCount08" ) << "(?|(a)(b)|(c)(d))"  << 2; | 
| 1529 |     QTest::newRow(dataTag: "captureCount09" ) << "(?|(a)(b)|(c)(d)(?:e))"  << 2; | 
| 1530 |     QTest::newRow(dataTag: "captureCount10" ) << "(?|(a)(b)|(c)(d)(e)) (f)(g)"  << 5; | 
| 1531 |     QTest::newRow(dataTag: "captureCount11" ) << "(?|(a)(b)|(c)(d)(e)) (f)(?:g)"  << 4; | 
| 1532 |     QTest::newRow(dataTag: "captureCount_invalid01" ) << "(.*"  << -1; | 
| 1533 |     QTest::newRow(dataTag: "captureCount_invalid02" ) << "\\"  << -1; | 
| 1534 |     QTest::newRow(dataTag: "captureCount_invalid03" ) << "(?<noun)"  << -1; | 
| 1535 | } | 
| 1536 |  | 
| 1537 | void tst_QRegularExpression::captureCount() | 
| 1538 | { | 
| 1539 |     QFETCH(QString, pattern); | 
| 1540 |     QRegularExpression re(pattern); | 
| 1541 |  | 
| 1542 |     QTEST(re.captureCount(), "captureCount" ); | 
| 1543 |     if (!re.isValid()) | 
| 1544 |         QCOMPARE(re.captureCount(), -1); | 
| 1545 | } | 
| 1546 |  | 
| 1547 | // the comma in the template breaks QFETCH... | 
| 1548 | typedef QMultiHash<QString, int> StringToIntMap; | 
| 1549 | Q_DECLARE_METATYPE(StringToIntMap) | 
| 1550 |  | 
| 1551 | void tst_QRegularExpression::captureNames_data() | 
| 1552 | { | 
| 1553 |     QTest::addColumn<QString>(name: "pattern" ); | 
| 1554 |     QTest::addColumn<StringToIntMap>(name: "namedCapturesIndexMap" ); | 
| 1555 |     StringToIntMap map; | 
| 1556 |  | 
| 1557 |     QTest::newRow(dataTag: "captureNames01" ) << "a pattern"  << map; | 
| 1558 |     QTest::newRow(dataTag: "captureNames02" ) << "a.*pattern"  << map; | 
| 1559 |     QTest::newRow(dataTag: "captureNames03" ) << "(a) pattern"  << map; | 
| 1560 |     QTest::newRow(dataTag: "captureNames04" ) << "(a).*(pattern)"  << map; | 
| 1561 |  | 
| 1562 |     map.clear(); | 
| 1563 |     map.replace(key: "named" , value: 1); | 
| 1564 |     QTest::newRow(dataTag: "captureNames05" ) << "a.*(?<named>pattern)"  << map; | 
| 1565 |  | 
| 1566 |     map.clear(); | 
| 1567 |     map.replace(key: "named" , value: 2); | 
| 1568 |     QTest::newRow(dataTag: "captureNames06" ) << "(a).*(?<named>pattern)"  << map; | 
| 1569 |  | 
| 1570 |     map.clear(); | 
| 1571 |     map.replace(key: "name1" , value: 1); | 
| 1572 |     map.replace(key: "name2" , value: 2); | 
| 1573 |     QTest::newRow(dataTag: "captureNames07" ) << "(?<name1>a).*(?<name2>pattern)"  << map; | 
| 1574 |  | 
| 1575 |     map.clear(); | 
| 1576 |     map.replace(key: "name1" , value: 2); | 
| 1577 |     map.replace(key: "name2" , value: 1); | 
| 1578 |     QTest::newRow(dataTag: "captureNames08" ) << "(?<name2>a).*(?<name1>pattern)"  << map; | 
| 1579 |  | 
| 1580 |     map.clear(); | 
| 1581 |     map.replace(key: "date" , value: 1); | 
| 1582 |     map.replace(key: "month" , value: 2); | 
| 1583 |     map.replace(key: "year" , value: 3); | 
| 1584 |     QTest::newRow(dataTag: "captureNames09" ) << "^(?<date>\\d\\d)/(?<month>\\d\\d)/(?<year>\\d\\d\\d\\d)$"  << map; | 
| 1585 |  | 
| 1586 |     map.clear(); | 
| 1587 |     map.replace(key: "date" , value: 2); | 
| 1588 |     map.replace(key: "month" , value: 1); | 
| 1589 |     map.replace(key: "year" , value: 3); | 
| 1590 |     QTest::newRow(dataTag: "captureNames10" ) << "^(?<month>\\d\\d)/(?<date>\\d\\d)/(?<year>\\d\\d\\d\\d)$"  << map; | 
| 1591 |  | 
| 1592 |     map.clear(); | 
| 1593 |     map.replace(key: "noun" , value: 2); | 
| 1594 |     QTest::newRow(dataTag: "captureNames11" ) << "(a)(?|(?<noun>b)|(?<noun>c))(d)"  << map; | 
| 1595 |  | 
| 1596 |     map.clear(); | 
| 1597 |     QTest::newRow(dataTag: "captureNames_invalid01" ) << "(.*"  << map; | 
| 1598 |     QTest::newRow(dataTag: "captureNames_invalid02" ) << "\\"  << map; | 
| 1599 |     QTest::newRow(dataTag: "captureNames_invalid03" ) << "(?<noun)"  << map; | 
| 1600 |     QTest::newRow(dataTag: "captureNames_invalid04" ) << "(?|(?<noun1>a)|(?<noun2>b))"  << map; | 
| 1601 | } | 
| 1602 |  | 
| 1603 | void tst_QRegularExpression::captureNames() | 
| 1604 | { | 
| 1605 |     QFETCH(QString, pattern); | 
| 1606 |     QFETCH(StringToIntMap, namedCapturesIndexMap); | 
| 1607 |  | 
| 1608 |     QRegularExpression re(pattern); | 
| 1609 |  | 
| 1610 |     QStringList namedCaptureGroups = re.namedCaptureGroups(); | 
| 1611 |     int namedCaptureGroupsCount = namedCaptureGroups.size(); | 
| 1612 |  | 
| 1613 |     QCOMPARE(namedCaptureGroupsCount, re.captureCount() + 1); | 
| 1614 |  | 
| 1615 |     for (int i = 0; i < namedCaptureGroupsCount; ++i) { | 
| 1616 |         const QString &name = namedCaptureGroups.at(i); | 
| 1617 |  | 
| 1618 |         if (name.isEmpty()) { | 
| 1619 |             QVERIFY(!namedCapturesIndexMap.contains(name)); | 
| 1620 |         } else { | 
| 1621 |             QVERIFY(namedCapturesIndexMap.contains(name)); | 
| 1622 |             QCOMPARE(i, namedCapturesIndexMap.value(name)); | 
| 1623 |         } | 
| 1624 |     } | 
| 1625 |  | 
| 1626 | } | 
| 1627 |  | 
| 1628 | void tst_QRegularExpression::captureNamesNul() | 
| 1629 | { | 
| 1630 |     QRegularExpression re("a(\\d+)b(?<name>\\d+)c(?<anotherName>\\d+)d(\\d+)e$" ); | 
| 1631 |     QVERIFY(re.isValid()); | 
| 1632 |  | 
| 1633 |     QCOMPARE(re.captureCount(), 4); | 
| 1634 |  | 
| 1635 |     QStringList namedCaptureGroups = re.namedCaptureGroups(); | 
| 1636 |     QCOMPARE(namedCaptureGroups[0], QString()); | 
| 1637 |     QCOMPARE(namedCaptureGroups[1], QString()); | 
| 1638 |     QCOMPARE(namedCaptureGroups[2], "name" ); | 
| 1639 |     QCOMPARE(namedCaptureGroups[3], "anotherName" ); | 
| 1640 |     QCOMPARE(namedCaptureGroups[4], QString()); | 
| 1641 |  | 
| 1642 |     QRegularExpressionMatch m = re.match(subject: "a12b456c789d0e" ); | 
| 1643 |     QVERIFY(m.hasMatch()); | 
| 1644 |  | 
| 1645 |     QString captureName("name" ); | 
| 1646 |     QCOMPARE(m.captured(captureName), "456" ); | 
| 1647 |     QCOMPARE(m.captured(QStringView(captureName)), "456" ); | 
| 1648 |     QCOMPARE(m.captured(qToStringViewIgnoringNull(captureName)), "456" ); | 
| 1649 |     QCOMPARE(m.captured(u"name" ), "456" ); | 
| 1650 |  | 
| 1651 |     captureName = "anotherName" ; | 
| 1652 |     QCOMPARE(m.captured(captureName), "789" ); | 
| 1653 |     QCOMPARE(m.captured(QStringView(captureName)), "789" ); | 
| 1654 |     QCOMPARE(m.captured(qToStringViewIgnoringNull(captureName)), "789" ); | 
| 1655 |     QCOMPARE(m.captured(u"anotherName" ), "789" ); | 
| 1656 | } | 
| 1657 |  | 
| 1658 | void tst_QRegularExpression::pcreJitStackUsage_data() | 
| 1659 | { | 
| 1660 |     QTest::addColumn<QString>(name: "pattern" ); | 
| 1661 |     QTest::addColumn<QString>(name: "subject" ); | 
| 1662 |     // these patterns cause enough backtrack (or even infinite recursion) | 
| 1663 |     // in the regexp engine, so that JIT requests more memory. | 
| 1664 |     QTest::newRow(dataTag: "jitstack01" ) << "(?(R)a*(?1)|((?R))b)"  << "aaaabcde" ; | 
| 1665 |     QTest::newRow(dataTag: "jitstack02" ) << "(?(R)a*(?1)|((?R))b)"  << "aaaaaaabcde" ; | 
| 1666 | } | 
| 1667 |  | 
| 1668 | void tst_QRegularExpression::pcreJitStackUsage() | 
| 1669 | { | 
| 1670 |     QFETCH(QString, pattern); | 
| 1671 |     QFETCH(QString, subject); | 
| 1672 |  | 
| 1673 |     QRegularExpression re(pattern); | 
| 1674 |  | 
| 1675 |     QVERIFY(re.isValid()); | 
| 1676 |     QRegularExpressionMatch match = re.match(subject); | 
| 1677 |     consistencyCheck(match); | 
| 1678 |     QRegularExpressionMatchIterator iterator = re.globalMatch(subject); | 
| 1679 |     consistencyCheck(iterator); | 
| 1680 |     while (iterator.hasNext()) { | 
| 1681 |         match = iterator.next(); | 
| 1682 |         consistencyCheck(match); | 
| 1683 |     } | 
| 1684 | } | 
| 1685 |  | 
| 1686 | void tst_QRegularExpression::regularExpressionMatch_data() | 
| 1687 | { | 
| 1688 |     QTest::addColumn<QString>(name: "pattern" ); | 
| 1689 |     QTest::addColumn<QString>(name: "subject" ); | 
| 1690 |  | 
| 1691 |     QTest::newRow(dataTag: "validity01" ) << "(?<digits>\\d+)"  << "1234 abcd" ; | 
| 1692 |     QTest::newRow(dataTag: "validity02" ) << "(?<digits>\\d+) (?<alpha>\\w+)"  << "1234 abcd" ; | 
| 1693 | } | 
| 1694 |  | 
| 1695 | void tst_QRegularExpression::regularExpressionMatch() | 
| 1696 | { | 
| 1697 |     QFETCH(QString, pattern); | 
| 1698 |     QFETCH(QString, subject); | 
| 1699 |  | 
| 1700 |     QRegularExpression re(pattern); | 
| 1701 |  | 
| 1702 |     QVERIFY(re.isValid()); | 
| 1703 |     QRegularExpressionMatch match = re.match(subject); | 
| 1704 |     consistencyCheck(match); | 
| 1705 |     QCOMPARE(match.captured("non-existing" ).isNull(), true); | 
| 1706 |     QTest::ignoreMessage(type: QtWarningMsg, message: "QRegularExpressionMatch::captured: empty capturing group name passed" ); | 
| 1707 |     QCOMPARE(match.captured("" ).isNull(), true); | 
| 1708 |     QTest::ignoreMessage(type: QtWarningMsg, message: "QRegularExpressionMatch::captured: empty capturing group name passed" ); | 
| 1709 |     QCOMPARE(match.captured(QString()).isNull(), true); | 
| 1710 | } | 
| 1711 |  | 
| 1712 | void tst_QRegularExpression::JOptionUsage_data() | 
| 1713 | { | 
| 1714 |     QTest::addColumn<QString>(name: "pattern" ); | 
| 1715 |     QTest::addColumn<bool>(name: "isValid" ); | 
| 1716 |     QTest::addColumn<bool>(name: "JOptionUsed" ); | 
| 1717 |  | 
| 1718 |     QTest::newRow(dataTag: "joption-notused-01" ) << "a.*b"  << true << false; | 
| 1719 |     QTest::newRow(dataTag: "joption-notused-02" ) << "^a(b)(c)$"  << true << false; | 
| 1720 |     QTest::newRow(dataTag: "joption-notused-03" ) << "a(b)(?<c>d)|e"  << true << false; | 
| 1721 |     QTest::newRow(dataTag: "joption-notused-04" ) << "(?<a>.)(?<a>.)"  << false << false; | 
| 1722 |  | 
| 1723 |     QTest::newRow(dataTag: "joption-used-01" ) << "(?J)a.*b"  << true << true; | 
| 1724 |     QTest::newRow(dataTag: "joption-used-02" ) << "(?-J)a.*b"  << true << true; | 
| 1725 |     QTest::newRow(dataTag: "joption-used-03" ) << "(?J)(?<a>.)(?<a>.)"  << true << true; | 
| 1726 |     QTest::newRow(dataTag: "joption-used-04" ) << "(?-J)(?<a>.)(?<a>.)"  << false << true; | 
| 1727 |  | 
| 1728 | } | 
| 1729 |  | 
| 1730 | void tst_QRegularExpression::JOptionUsage() | 
| 1731 | { | 
| 1732 |     QFETCH(QString, pattern); | 
| 1733 |     QFETCH(bool, isValid); | 
| 1734 |     QFETCH(bool, JOptionUsed); | 
| 1735 |  | 
| 1736 |     const QString warningMessage = QStringLiteral("QRegularExpressionPrivate::getPatternInfo(): the pattern '%1'\n    is using the (?J) option; duplicate capturing group names are not supported by Qt" ); | 
| 1737 |  | 
| 1738 |     QRegularExpression re(pattern); | 
| 1739 |     if (isValid && JOptionUsed) | 
| 1740 |         QTest::ignoreMessage(type: QtWarningMsg, qPrintable(warningMessage.arg(pattern))); | 
| 1741 |     QCOMPARE(re.isValid(), isValid); | 
| 1742 | } | 
| 1743 |  | 
| 1744 | void tst_QRegularExpression::QStringAndQStringRefEquivalence() | 
| 1745 | { | 
| 1746 |     const QString subject = QStringLiteral("Mississippi" ); | 
| 1747 |     { | 
| 1748 |         const QRegularExpression re("\\Biss\\B" ); | 
| 1749 |         QVERIFY(re.isValid()); | 
| 1750 |         { | 
| 1751 |             const QRegularExpressionMatch match = re.match(subject); | 
| 1752 |             consistencyCheck(match); | 
| 1753 |             QVERIFY(match.isValid()); | 
| 1754 |             QVERIFY(match.hasMatch()); | 
| 1755 |             QCOMPARE(match.captured(), QStringLiteral("iss" )); | 
| 1756 |             QCOMPARE(match.capturedStart(), 1); | 
| 1757 |             QCOMPARE(match.capturedEnd(), 4); | 
| 1758 |         } | 
| 1759 |         { | 
| 1760 |             const QRegularExpressionMatch match = re.match(subjectRef: QStringRef(&subject)); | 
| 1761 |             consistencyCheck(match); | 
| 1762 |             QVERIFY(match.isValid()); | 
| 1763 |             QVERIFY(match.hasMatch()); | 
| 1764 |             QCOMPARE(match.captured(), QStringLiteral("iss" )); | 
| 1765 |             QCOMPARE(match.capturedStart(), 1); | 
| 1766 |             QCOMPARE(match.capturedEnd(), 4); | 
| 1767 |         } | 
| 1768 |         { | 
| 1769 |             const QRegularExpressionMatch match = re.match(subject, offset: 1); | 
| 1770 |             consistencyCheck(match); | 
| 1771 |             QVERIFY(match.isValid()); | 
| 1772 |             QVERIFY(match.hasMatch()); | 
| 1773 |             QCOMPARE(match.captured(), QStringLiteral("iss" )); | 
| 1774 |             QCOMPARE(match.capturedStart(), 1); | 
| 1775 |             QCOMPARE(match.capturedEnd(), 4); | 
| 1776 |         } | 
| 1777 |         { | 
| 1778 |             const QRegularExpressionMatch match = re.match(subjectRef: QStringRef(&subject), offset: 1); | 
| 1779 |             consistencyCheck(match); | 
| 1780 |             QVERIFY(match.isValid()); | 
| 1781 |             QVERIFY(match.hasMatch()); | 
| 1782 |             QCOMPARE(match.captured(), QStringLiteral("iss" )); | 
| 1783 |             QCOMPARE(match.capturedStart(), 1); | 
| 1784 |             QCOMPARE(match.capturedEnd(), 4); | 
| 1785 |         } | 
| 1786 |         { | 
| 1787 |             const QRegularExpressionMatch match = re.match(subject: subject.mid(position: 1)); | 
| 1788 |             consistencyCheck(match); | 
| 1789 |             QVERIFY(match.isValid()); | 
| 1790 |             QVERIFY(match.hasMatch()); | 
| 1791 |             QCOMPARE(match.captured(), QStringLiteral("iss" )); | 
| 1792 |             QCOMPARE(match.capturedStart(), 3); | 
| 1793 |             QCOMPARE(match.capturedEnd(), 6); | 
| 1794 |         } | 
| 1795 |         { | 
| 1796 |             const QRegularExpressionMatch match = re.match(subjectRef: subject.midRef(position: 1)); | 
| 1797 |             consistencyCheck(match); | 
| 1798 |             QVERIFY(match.isValid()); | 
| 1799 |             QVERIFY(match.hasMatch()); | 
| 1800 |             QCOMPARE(match.captured(), QStringLiteral("iss" )); | 
| 1801 |             QCOMPARE(match.capturedStart(), 3); | 
| 1802 |             QCOMPARE(match.capturedEnd(), 6); | 
| 1803 |         } | 
| 1804 |         { | 
| 1805 |             const QRegularExpressionMatch match = re.match(subject: subject.mid(position: 1), offset: 1); | 
| 1806 |             consistencyCheck(match); | 
| 1807 |             QVERIFY(match.isValid()); | 
| 1808 |             QVERIFY(match.hasMatch()); | 
| 1809 |             QCOMPARE(match.captured(), QStringLiteral("iss" )); | 
| 1810 |             QCOMPARE(match.capturedStart(), 3); | 
| 1811 |             QCOMPARE(match.capturedEnd(), 6); | 
| 1812 |         } | 
| 1813 |         { | 
| 1814 |             const QRegularExpressionMatch match = re.match(subjectRef: subject.midRef(position: 1), offset: 1); | 
| 1815 |             consistencyCheck(match); | 
| 1816 |             QVERIFY(match.isValid()); | 
| 1817 |             QVERIFY(match.hasMatch()); | 
| 1818 |             QCOMPARE(match.captured(), QStringLiteral("iss" )); | 
| 1819 |             QCOMPARE(match.capturedStart(), 3); | 
| 1820 |             QCOMPARE(match.capturedEnd(), 6); | 
| 1821 |         } | 
| 1822 |         { | 
| 1823 |             const QRegularExpressionMatch match = re.match(subject, offset: 4); | 
| 1824 |             consistencyCheck(match); | 
| 1825 |             QVERIFY(match.isValid()); | 
| 1826 |             QVERIFY(match.hasMatch()); | 
| 1827 |             QCOMPARE(match.captured(), QStringLiteral("iss" )); | 
| 1828 |             QCOMPARE(match.capturedStart(), 4); | 
| 1829 |             QCOMPARE(match.capturedEnd(), 7); | 
| 1830 |         } | 
| 1831 |         { | 
| 1832 |             const QRegularExpressionMatch match = re.match(subjectRef: QStringRef(&subject), offset: 4); | 
| 1833 |             consistencyCheck(match); | 
| 1834 |             QVERIFY(match.isValid()); | 
| 1835 |             QVERIFY(match.hasMatch()); | 
| 1836 |             QCOMPARE(match.captured(), QStringLiteral("iss" )); | 
| 1837 |             QCOMPARE(match.capturedStart(), 4); | 
| 1838 |             QCOMPARE(match.capturedEnd(), 7); | 
| 1839 |         } | 
| 1840 |         { | 
| 1841 |             const QRegularExpressionMatch match = re.match(subject: subject.mid(position: 4)); | 
| 1842 |             consistencyCheck(match); | 
| 1843 |             QVERIFY(match.isValid()); | 
| 1844 |             QVERIFY(!match.hasMatch()); | 
| 1845 |         } | 
| 1846 |         { | 
| 1847 |             const QRegularExpressionMatch match = re.match(subjectRef: subject.midRef(position: 4)); | 
| 1848 |             consistencyCheck(match); | 
| 1849 |             QVERIFY(match.isValid()); | 
| 1850 |             QVERIFY(!match.hasMatch()); | 
| 1851 |         } | 
| 1852 |  | 
| 1853 |         { | 
| 1854 |             QRegularExpressionMatchIterator i = re.globalMatch(subject); | 
| 1855 |             QVERIFY(i.isValid()); | 
| 1856 |  | 
| 1857 |             consistencyCheck(iterator: i); | 
| 1858 |             QVERIFY(i.hasNext()); | 
| 1859 |             const QRegularExpressionMatch match1 = i.next(); | 
| 1860 |             consistencyCheck(match: match1); | 
| 1861 |             QVERIFY(match1.isValid()); | 
| 1862 |             QVERIFY(match1.hasMatch()); | 
| 1863 |             QCOMPARE(match1.captured(), QStringLiteral("iss" )); | 
| 1864 |             QCOMPARE(match1.capturedStart(), 1); | 
| 1865 |             QCOMPARE(match1.capturedEnd(), 4); | 
| 1866 |  | 
| 1867 |             consistencyCheck(iterator: i); | 
| 1868 |             QVERIFY(i.hasNext()); | 
| 1869 |             const QRegularExpressionMatch match2 = i.next(); | 
| 1870 |             consistencyCheck(match: match2); | 
| 1871 |             QVERIFY(match2.isValid()); | 
| 1872 |             QVERIFY(match2.hasMatch()); | 
| 1873 |             QCOMPARE(match2.captured(), QStringLiteral("iss" )); | 
| 1874 |             QCOMPARE(match2.capturedStart(), 4); | 
| 1875 |             QCOMPARE(match2.capturedEnd(), 7); | 
| 1876 |  | 
| 1877 |             QVERIFY(!i.hasNext()); | 
| 1878 |         } | 
| 1879 |         { | 
| 1880 |             QRegularExpressionMatchIterator i = re.globalMatch(subjectRef: QStringRef(&subject)); | 
| 1881 |             QVERIFY(i.isValid()); | 
| 1882 |  | 
| 1883 |             consistencyCheck(iterator: i); | 
| 1884 |             QVERIFY(i.hasNext()); | 
| 1885 |             const QRegularExpressionMatch match1 = i.next(); | 
| 1886 |             consistencyCheck(match: match1); | 
| 1887 |             QVERIFY(match1.isValid()); | 
| 1888 |             QVERIFY(match1.hasMatch()); | 
| 1889 |             QCOMPARE(match1.captured(), QStringLiteral("iss" )); | 
| 1890 |             QCOMPARE(match1.capturedStart(), 1); | 
| 1891 |             QCOMPARE(match1.capturedEnd(), 4); | 
| 1892 |  | 
| 1893 |             consistencyCheck(iterator: i); | 
| 1894 |             QVERIFY(i.hasNext()); | 
| 1895 |             const QRegularExpressionMatch match2 = i.next(); | 
| 1896 |             consistencyCheck(match: match2); | 
| 1897 |             QVERIFY(match2.isValid()); | 
| 1898 |             QVERIFY(match2.hasMatch()); | 
| 1899 |             QCOMPARE(match2.captured(), QStringLiteral("iss" )); | 
| 1900 |             QCOMPARE(match2.capturedStart(), 4); | 
| 1901 |             QCOMPARE(match2.capturedEnd(), 7); | 
| 1902 |  | 
| 1903 |             QVERIFY(!i.hasNext()); | 
| 1904 |         } | 
| 1905 |         { | 
| 1906 |             QRegularExpressionMatchIterator i = re.globalMatch(subject, offset: 1); | 
| 1907 |             QVERIFY(i.isValid()); | 
| 1908 |  | 
| 1909 |             consistencyCheck(iterator: i); | 
| 1910 |             QVERIFY(i.hasNext()); | 
| 1911 |             const QRegularExpressionMatch match1 = i.next(); | 
| 1912 |             consistencyCheck(match: match1); | 
| 1913 |             QVERIFY(match1.isValid()); | 
| 1914 |             QVERIFY(match1.hasMatch()); | 
| 1915 |             QCOMPARE(match1.captured(), QStringLiteral("iss" )); | 
| 1916 |             QCOMPARE(match1.capturedStart(), 1); | 
| 1917 |             QCOMPARE(match1.capturedEnd(), 4); | 
| 1918 |  | 
| 1919 |             consistencyCheck(iterator: i); | 
| 1920 |             QVERIFY(i.hasNext()); | 
| 1921 |             const QRegularExpressionMatch match2 = i.next(); | 
| 1922 |             consistencyCheck(match: match2); | 
| 1923 |             QVERIFY(match2.isValid()); | 
| 1924 |             QVERIFY(match2.hasMatch()); | 
| 1925 |             QCOMPARE(match2.captured(), QStringLiteral("iss" )); | 
| 1926 |             QCOMPARE(match2.capturedStart(), 4); | 
| 1927 |             QCOMPARE(match2.capturedEnd(), 7); | 
| 1928 |  | 
| 1929 |             QVERIFY(!i.hasNext()); | 
| 1930 |         } | 
| 1931 |         { | 
| 1932 |             QRegularExpressionMatchIterator i = re.globalMatch(subjectRef: QStringRef(&subject), offset: 1); | 
| 1933 |             QVERIFY(i.isValid()); | 
| 1934 |  | 
| 1935 |             consistencyCheck(iterator: i); | 
| 1936 |             QVERIFY(i.hasNext()); | 
| 1937 |             const QRegularExpressionMatch match1 = i.next(); | 
| 1938 |             consistencyCheck(match: match1); | 
| 1939 |             QVERIFY(match1.isValid()); | 
| 1940 |             QVERIFY(match1.hasMatch()); | 
| 1941 |             QCOMPARE(match1.captured(), QStringLiteral("iss" )); | 
| 1942 |             QCOMPARE(match1.capturedStart(), 1); | 
| 1943 |             QCOMPARE(match1.capturedEnd(), 4); | 
| 1944 |  | 
| 1945 |             consistencyCheck(iterator: i); | 
| 1946 |             QVERIFY(i.hasNext()); | 
| 1947 |             const QRegularExpressionMatch match2 = i.next(); | 
| 1948 |             consistencyCheck(match: match2); | 
| 1949 |             QVERIFY(match2.isValid()); | 
| 1950 |             QVERIFY(match2.hasMatch()); | 
| 1951 |             QCOMPARE(match2.captured(), QStringLiteral("iss" )); | 
| 1952 |             QCOMPARE(match2.capturedStart(), 4); | 
| 1953 |             QCOMPARE(match2.capturedEnd(), 7); | 
| 1954 |  | 
| 1955 |             QVERIFY(!i.hasNext()); | 
| 1956 |         } | 
| 1957 |         { | 
| 1958 |             QRegularExpressionMatchIterator i = re.globalMatch(subject: subject.mid(position: 1)); | 
| 1959 |             QVERIFY(i.isValid()); | 
| 1960 |  | 
| 1961 |             consistencyCheck(iterator: i); | 
| 1962 |             QVERIFY(i.hasNext()); | 
| 1963 |             const QRegularExpressionMatch match = i.next(); | 
| 1964 |             consistencyCheck(match); | 
| 1965 |             QVERIFY(match.isValid()); | 
| 1966 |             QVERIFY(match.hasMatch()); | 
| 1967 |             QCOMPARE(match.captured(), QStringLiteral("iss" )); | 
| 1968 |             QCOMPARE(match.capturedStart(), 3); | 
| 1969 |             QCOMPARE(match.capturedEnd(), 6); | 
| 1970 |  | 
| 1971 |             QVERIFY(!i.hasNext()); | 
| 1972 |         } | 
| 1973 |         { | 
| 1974 |             QRegularExpressionMatchIterator i = re.globalMatch(subjectRef: subject.midRef(position: 1)); | 
| 1975 |             QVERIFY(i.isValid()); | 
| 1976 |  | 
| 1977 |             consistencyCheck(iterator: i); | 
| 1978 |             QVERIFY(i.hasNext()); | 
| 1979 |             const QRegularExpressionMatch match = i.next(); | 
| 1980 |             consistencyCheck(match); | 
| 1981 |             QVERIFY(match.isValid()); | 
| 1982 |             QVERIFY(match.hasMatch()); | 
| 1983 |             QCOMPARE(match.captured(), QStringLiteral("iss" )); | 
| 1984 |             QCOMPARE(match.capturedStart(), 3); | 
| 1985 |             QCOMPARE(match.capturedEnd(), 6); | 
| 1986 |  | 
| 1987 |             QVERIFY(!i.hasNext()); | 
| 1988 |         } | 
| 1989 |         { | 
| 1990 |             QRegularExpressionMatchIterator i = re.globalMatch(subject: subject.mid(position: 1), offset: 1); | 
| 1991 |             QVERIFY(i.isValid()); | 
| 1992 |  | 
| 1993 |             consistencyCheck(iterator: i); | 
| 1994 |             QVERIFY(i.hasNext()); | 
| 1995 |             const QRegularExpressionMatch match = i.next(); | 
| 1996 |             consistencyCheck(match); | 
| 1997 |             QVERIFY(match.isValid()); | 
| 1998 |             QVERIFY(match.hasMatch()); | 
| 1999 |             QCOMPARE(match.captured(), QStringLiteral("iss" )); | 
| 2000 |             QCOMPARE(match.capturedStart(), 3); | 
| 2001 |             QCOMPARE(match.capturedEnd(), 6); | 
| 2002 |  | 
| 2003 |             QVERIFY(!i.hasNext()); | 
| 2004 |         } | 
| 2005 |         { | 
| 2006 |             QRegularExpressionMatchIterator i = re.globalMatch(subjectRef: subject.midRef(position: 1), offset: 1); | 
| 2007 |             QVERIFY(i.isValid()); | 
| 2008 |  | 
| 2009 |             consistencyCheck(iterator: i); | 
| 2010 |             QVERIFY(i.hasNext()); | 
| 2011 |             const QRegularExpressionMatch match = i.next(); | 
| 2012 |             consistencyCheck(match); | 
| 2013 |             QVERIFY(match.isValid()); | 
| 2014 |             QVERIFY(match.hasMatch()); | 
| 2015 |             QCOMPARE(match.captured(), QStringLiteral("iss" )); | 
| 2016 |             QCOMPARE(match.capturedStart(), 3); | 
| 2017 |             QCOMPARE(match.capturedEnd(), 6); | 
| 2018 |  | 
| 2019 |             QVERIFY(!i.hasNext()); | 
| 2020 |         } | 
| 2021 |         { | 
| 2022 |             QRegularExpressionMatchIterator i = re.globalMatch(subject: subject.mid(position: 1), offset: 1); | 
| 2023 |             QVERIFY(i.isValid()); | 
| 2024 |  | 
| 2025 |             consistencyCheck(iterator: i); | 
| 2026 |             QVERIFY(i.hasNext()); | 
| 2027 |             const QRegularExpressionMatch match = i.next(); | 
| 2028 |             consistencyCheck(match); | 
| 2029 |             QVERIFY(match.isValid()); | 
| 2030 |             QVERIFY(match.hasMatch()); | 
| 2031 |             QCOMPARE(match.captured(), QStringLiteral("iss" )); | 
| 2032 |             QCOMPARE(match.capturedStart(), 3); | 
| 2033 |             QCOMPARE(match.capturedEnd(), 6); | 
| 2034 |  | 
| 2035 |             QVERIFY(!i.hasNext()); | 
| 2036 |         } | 
| 2037 |         { | 
| 2038 |             QRegularExpressionMatchIterator i = re.globalMatch(subjectRef: subject.midRef(position: 1), offset: 1); | 
| 2039 |             QVERIFY(i.isValid()); | 
| 2040 |  | 
| 2041 |             consistencyCheck(iterator: i); | 
| 2042 |             QVERIFY(i.hasNext()); | 
| 2043 |             const QRegularExpressionMatch match = i.next(); | 
| 2044 |             consistencyCheck(match); | 
| 2045 |             QVERIFY(match.isValid()); | 
| 2046 |             QVERIFY(match.hasMatch()); | 
| 2047 |             QCOMPARE(match.captured(), QStringLiteral("iss" )); | 
| 2048 |             QCOMPARE(match.capturedStart(), 3); | 
| 2049 |             QCOMPARE(match.capturedEnd(), 6); | 
| 2050 |  | 
| 2051 |             QVERIFY(!i.hasNext()); | 
| 2052 |         } | 
| 2053 |  | 
| 2054 |         { | 
| 2055 |             QRegularExpressionMatchIterator i = re.globalMatch(subject, offset: 4); | 
| 2056 |             QVERIFY(i.isValid()); | 
| 2057 |  | 
| 2058 |             consistencyCheck(iterator: i); | 
| 2059 |             QVERIFY(i.hasNext()); | 
| 2060 |             const QRegularExpressionMatch match = i.next(); | 
| 2061 |             consistencyCheck(match); | 
| 2062 |             QVERIFY(match.isValid()); | 
| 2063 |             QVERIFY(match.hasMatch()); | 
| 2064 |             QCOMPARE(match.captured(), QStringLiteral("iss" )); | 
| 2065 |             QCOMPARE(match.capturedStart(), 4); | 
| 2066 |             QCOMPARE(match.capturedEnd(), 7); | 
| 2067 |  | 
| 2068 |             QVERIFY(!i.hasNext()); | 
| 2069 |         } | 
| 2070 |         { | 
| 2071 |             QRegularExpressionMatchIterator i = re.globalMatch(subjectRef: QStringRef(&subject), offset: 4); | 
| 2072 |             QVERIFY(i.isValid()); | 
| 2073 |  | 
| 2074 |             consistencyCheck(iterator: i); | 
| 2075 |             QVERIFY(i.hasNext()); | 
| 2076 |             const QRegularExpressionMatch match = i.next(); | 
| 2077 |             consistencyCheck(match); | 
| 2078 |             QVERIFY(match.isValid()); | 
| 2079 |             QVERIFY(match.hasMatch()); | 
| 2080 |             QCOMPARE(match.captured(), QStringLiteral("iss" )); | 
| 2081 |             QCOMPARE(match.capturedStart(), 4); | 
| 2082 |             QCOMPARE(match.capturedEnd(), 7); | 
| 2083 |  | 
| 2084 |             QVERIFY(!i.hasNext()); | 
| 2085 |         } | 
| 2086 |         { | 
| 2087 |             QRegularExpressionMatchIterator i = re.globalMatch(subject: subject.mid(position: 4)); | 
| 2088 |             consistencyCheck(iterator: i); | 
| 2089 |             QVERIFY(i.isValid()); | 
| 2090 |             QVERIFY(!i.hasNext()); | 
| 2091 |         } | 
| 2092 |         { | 
| 2093 |             QRegularExpressionMatchIterator i = re.globalMatch(subjectRef: subject.midRef(position: 4)); | 
| 2094 |             consistencyCheck(iterator: i); | 
| 2095 |             QVERIFY(i.isValid()); | 
| 2096 |             QVERIFY(!i.hasNext()); | 
| 2097 |         } | 
| 2098 |     } | 
| 2099 | } | 
| 2100 |  | 
| 2101 | class MatcherThread : public QThread | 
| 2102 | { | 
| 2103 | public: | 
| 2104 |     explicit MatcherThread(const QRegularExpression &re, const QString &subject, QObject *parent = nullptr) | 
| 2105 |         : QThread(parent), | 
| 2106 |           m_re(re), | 
| 2107 |           m_subject(subject) | 
| 2108 |     { | 
| 2109 |     } | 
| 2110 |  | 
| 2111 | private: | 
| 2112 |     static const int MATCH_ITERATIONS = 50; | 
| 2113 |  | 
| 2114 |     void run() override | 
| 2115 |     { | 
| 2116 |         yieldCurrentThread(); | 
| 2117 |         for (int i = 0; i < MATCH_ITERATIONS; ++i) | 
| 2118 |             m_re.match(subject: m_subject); | 
| 2119 |     } | 
| 2120 |  | 
| 2121 |     const QRegularExpression &m_re; | 
| 2122 |     const QString &m_subject; | 
| 2123 | }; | 
| 2124 |  | 
| 2125 | void tst_QRegularExpression::threadSafety_data() | 
| 2126 | { | 
| 2127 |     QTest::addColumn<QString>(name: "pattern" ); | 
| 2128 |     QTest::addColumn<QString>(name: "subject" ); | 
| 2129 |  | 
| 2130 |     int i = 0; | 
| 2131 |     QTest::addRow(format: "pattern%d" , ++i) << "ab.*cd"  << "abcd" ; | 
| 2132 |     QTest::addRow(format: "pattern%d" , ++i) << "ab.*cd"  << "abd" ; | 
| 2133 |     QTest::addRow(format: "pattern%d" , ++i) << "ab.*cd"  << "abbbbcccd" ; | 
| 2134 |     QTest::addRow(format: "pattern%d" , ++i) << "ab.*cd"  << "abababcd" ; | 
| 2135 |     QTest::addRow(format: "pattern%d" , ++i) << "ab.*cd"  << "abcabcd" ; | 
| 2136 |     QTest::addRow(format: "pattern%d" , ++i) << "ab.*cd"  << "abccccccababd" ; | 
| 2137 |  | 
| 2138 |     { | 
| 2139 |         QString subject(512*1024, QLatin1Char('x')); | 
| 2140 |         QTest::addRow(format: "pattern%d" , ++i) << "ab.*cd"  << subject; | 
| 2141 |     } | 
| 2142 |  | 
| 2143 |     // pcre2 does not support JIT for winrt. As this test row takes a long time without JIT we skip | 
| 2144 |     // it for winrt as it might time out in COIN. | 
| 2145 | #ifndef Q_OS_WINRT | 
| 2146 |     { | 
| 2147 |         QString subject = "ab" ; | 
| 2148 |         subject.append(s: QString(512*1024, QLatin1Char('x'))); | 
| 2149 |         subject.append(s: "c" ); | 
| 2150 |         QTest::addRow(format: "pattern%d" , ++i) << "ab.*cd"  << subject; | 
| 2151 |     } | 
| 2152 | #endif // Q_OS_WINRT | 
| 2153 |  | 
| 2154 |     { | 
| 2155 |         QString subject = "ab" ; | 
| 2156 |         subject.append(s: QString(512*1024, QLatin1Char('x'))); | 
| 2157 |         subject.append(s: "cd" ); | 
| 2158 |         QTest::addRow(format: "pattern%d" , ++i) << "ab.*cd"  << subject; | 
| 2159 |     } | 
| 2160 |  | 
| 2161 |     QTest::addRow(format: "pattern%d" , ++i) << "(?(R)a*(?1)|((?R))b)"  << "aaaabcde" ; | 
| 2162 |     QTest::addRow(format: "pattern%d" , ++i) << "(?(R)a*(?1)|((?R))b)"  << "aaaaaaabcde" ; | 
| 2163 | } | 
| 2164 |  | 
| 2165 | void tst_QRegularExpression::threadSafety() | 
| 2166 | { | 
| 2167 |     QFETCH(QString, pattern); | 
| 2168 |     QFETCH(QString, subject); | 
| 2169 |  | 
| 2170 |     QElapsedTimer time; | 
| 2171 |     time.start(); | 
| 2172 |     static const int THREAD_SAFETY_ITERATIONS = 50; | 
| 2173 |     const int threadCount = qMax(a: QThread::idealThreadCount(), b: 4); | 
| 2174 |  | 
| 2175 |     for (int threadSafetyIteration = 0; threadSafetyIteration < THREAD_SAFETY_ITERATIONS && time.elapsed() < 2000; ++threadSafetyIteration) { | 
| 2176 |         QRegularExpression re(pattern); | 
| 2177 |  | 
| 2178 |         QVector<MatcherThread *> threads; | 
| 2179 |         for (int i = 0; i < threadCount; ++i) { | 
| 2180 |             MatcherThread *thread = new MatcherThread(re, subject); | 
| 2181 |             thread->start(); | 
| 2182 |             threads.push_back(t: thread); | 
| 2183 |         } | 
| 2184 |  | 
| 2185 |         for (int i = 0; i < threadCount; ++i) | 
| 2186 |             threads[i]->wait(); | 
| 2187 |  | 
| 2188 |         qDeleteAll(c: threads); | 
| 2189 |     } | 
| 2190 | } | 
| 2191 |  | 
| 2192 | void tst_QRegularExpression::returnsViewsIntoOriginalString() | 
| 2193 | { | 
| 2194 |     // https://bugreports.qt.io/browse/QTBUG-98653 | 
| 2195 |  | 
| 2196 |     auto to_void = [](const QChar *p) -> const void* { return p; }; | 
| 2197 |  | 
| 2198 |     // GIVEN | 
| 2199 |     //  a QString with dynamically-allocated data: | 
| 2200 |     const QString string = QLatin1String("A\nA\nB\nB\n\nC\nC" ); // NOT QStringLiteral! | 
| 2201 |     const auto stringDataAddress = to_void(string.data()); | 
| 2202 |  | 
| 2203 |     //  and a view over said QString: | 
| 2204 |     QStringView view(string); | 
| 2205 |     const auto viewDataAddress = to_void(view.data()); | 
| 2206 |     QCOMPARE(stringDataAddress, viewDataAddress); | 
| 2207 |  | 
| 2208 |     // WHEN | 
| 2209 |     //  we call view.split() with a temporary QRegularExpression object | 
| 2210 |     const auto split = view.split(sep: QRegularExpression( "(\r\n|\n|\r)"  ), behavior: Qt::KeepEmptyParts); | 
| 2211 |  | 
| 2212 |     // THEN | 
| 2213 |     //  the returned views should point into the underlying string: | 
| 2214 |     QCOMPARE(to_void(split.front().data()), stringDataAddress); | 
| 2215 | } | 
| 2216 |  | 
| 2217 | void tst_QRegularExpression::wildcard_data() | 
| 2218 | { | 
| 2219 |     QTest::addColumn<QString>(name: "pattern" ); | 
| 2220 |     QTest::addColumn<QString>(name: "string" ); | 
| 2221 |     QTest::addColumn<int>(name: "foundIndex" ); | 
| 2222 |  | 
| 2223 |     auto addRow = [](const char *pattern, const char *string, int foundIndex) { | 
| 2224 |         QTest::newRow(dataTag: pattern) << pattern << string << foundIndex; | 
| 2225 |     }; | 
| 2226 |  | 
| 2227 |     addRow("*.html" , "test.html" , 0); | 
| 2228 |     addRow("*.html" , "test.htm" , -1); | 
| 2229 |     addRow("*bar*" , "foobarbaz" , 0); | 
| 2230 |     addRow("*" , "Qt Rocks!" , 0); | 
| 2231 |     addRow("*.html" , "test.html" , 0); | 
| 2232 |     addRow("*.h" , "test.cpp" , -1); | 
| 2233 |     addRow("*.???l" , "test.html" , 0); | 
| 2234 |     addRow("*?" , "test.html" , 0); | 
| 2235 |     addRow("*?ml" , "test.html" , 0); | 
| 2236 |     addRow("*[*]" , "test.html" , -1); | 
| 2237 |     addRow("*[?]" ,"test.html" , -1); | 
| 2238 |     addRow("*[?]ml" ,"test.h?ml" , 0); | 
| 2239 |     addRow("*[[]ml" ,"test.h[ml" , 0); | 
| 2240 |     addRow("*[]]ml" ,"test.h]ml" , 0); | 
| 2241 |     addRow("*.h[a-z]ml" , "test.html" , 0); | 
| 2242 |     addRow("*.h[A-Z]ml" , "test.html" , -1); | 
| 2243 |     addRow("*.h[A-Z]ml" , "test.hTml" , 0); | 
| 2244 |     addRow("*.h[!A-Z]ml" , "test.hTml" , -1); | 
| 2245 |     addRow("*.h[!A-Z]ml" , "test.html" , 0); | 
| 2246 |     addRow("*.h[!T]ml" , "test.hTml" , -1); | 
| 2247 |     addRow("*.h[!T]ml" , "test.html" , 0); | 
| 2248 |     addRow("*.h[!T]m[!L]" , "test.htmL" , -1); | 
| 2249 |     addRow("*.h[!T]m[!L]" , "test.html" , 0); | 
| 2250 |     addRow("*.h[][!]ml" , "test.h]ml" , 0); | 
| 2251 |     addRow("*.h[][!]ml" , "test.h[ml" , 0); | 
| 2252 |     addRow("*.h[][!]ml" , "test.h!ml" , 0); | 
| 2253 |  | 
| 2254 |     addRow("foo/*/bar" , "foo/baz/bar" , 0); | 
| 2255 |     addRow("foo/(*)/bar" , "foo/baz/bar" , -1); | 
| 2256 |     addRow("foo/(*)/bar" , "foo/(baz)/bar" , 0); | 
| 2257 |     addRow("foo/?/bar" , "foo/Q/bar" , 0); | 
| 2258 |     addRow("foo/?/bar" , "foo/Qt/bar" , -1); | 
| 2259 |     addRow("foo/(?)/bar" , "foo/Q/bar" , -1); | 
| 2260 |     addRow("foo/(?)/bar" , "foo/(Q)/bar" , 0); | 
| 2261 |  | 
| 2262 | #ifdef Q_OS_WIN | 
| 2263 |     addRow("foo\\*\\bar" , "foo\\baz\\bar" , 0); | 
| 2264 |     addRow("foo\\(*)\\bar" , "foo\\baz\\bar" , -1); | 
| 2265 |     addRow("foo\\(*)\\bar" , "foo\\(baz)\\bar" , 0); | 
| 2266 |     addRow("foo\\?\\bar" , "foo\\Q\\bar" , 0); | 
| 2267 |     addRow("foo\\?\\bar" , "foo\\Qt\\bar" , -1); | 
| 2268 |     addRow("foo\\(?)\\bar" , "foo\\Q\\bar" , -1); | 
| 2269 |     addRow("foo\\(?)\\bar" , "foo\\(Q)\\bar" , 0); | 
| 2270 | #endif | 
| 2271 | } | 
| 2272 |  | 
| 2273 | void tst_QRegularExpression::wildcard() | 
| 2274 | { | 
| 2275 |     QFETCH(QString, pattern); | 
| 2276 |     QFETCH(QString, string); | 
| 2277 |     QFETCH(int, foundIndex); | 
| 2278 |  | 
| 2279 |     QRegularExpression re(QRegularExpression::wildcardToRegularExpression(str: pattern)); | 
| 2280 |     QRegularExpressionMatch match = re.match(subject: string); | 
| 2281 |  | 
| 2282 |     QCOMPARE(match.capturedStart(), foundIndex); | 
| 2283 | } | 
| 2284 |  | 
| 2285 | void tst_QRegularExpression::testInvalidWildcard_data() | 
| 2286 | { | 
| 2287 |     QTest::addColumn<QString>(name: "pattern" ); | 
| 2288 |     QTest::addColumn<bool>(name: "isValid" ); | 
| 2289 |  | 
| 2290 |     QTest::newRow(dataTag: "valid []" ) << "[abc]"  << true; | 
| 2291 |     QTest::newRow(dataTag: "valid ending ]" ) << "abc]"  << true; | 
| 2292 |     QTest::newRow(dataTag: "invalid [" ) << "[abc"  << false; | 
| 2293 |     QTest::newRow(dataTag: "ending [" ) << "abc["  << false; | 
| 2294 |     QTest::newRow(dataTag: "ending [^" ) << "abc[^"  << false; | 
| 2295 |     QTest::newRow(dataTag: "ending [\\" ) << "abc[\\"  << false; | 
| 2296 |     QTest::newRow(dataTag: "ending []" ) << "abc[]"  << false; | 
| 2297 |     QTest::newRow(dataTag: "ending [[" ) << "abc[["  << false; | 
| 2298 | } | 
| 2299 |  | 
| 2300 | void tst_QRegularExpression::testInvalidWildcard() | 
| 2301 | { | 
| 2302 |     QFETCH(QString, pattern); | 
| 2303 |     QFETCH(bool, isValid); | 
| 2304 |  | 
| 2305 |     QRegularExpression re(QRegularExpression::wildcardToRegularExpression(str: pattern)); | 
| 2306 |     QCOMPARE(re.isValid(), isValid); | 
| 2307 | } | 
| 2308 |  | 
| 2309 | QTEST_APPLESS_MAIN(tst_QRegularExpression) | 
| 2310 |  | 
| 2311 | #include "tst_qregularexpression.moc" | 
| 2312 |  |