+
+ // UText C++ API, length of match is 0 for non-participating matches.
+ UText ut = UTEXT_INITIALIZER;
+ utext_openUnicodeString(&ut, &text, &status);
+ RegexMatcher matcher(UnicodeString("(A)|(B)"), 0, status);
+ REGEX_CHECK_STATUS;
+ matcher.reset(&ut);
+ REGEX_ASSERT(matcher.lookingAt(0, status));
+
+ // UText C++ API, Capture group 1 matches "A", position 0, length 1.
+ int64_t groupLen = -666;
+ UText group = UTEXT_INITIALIZER;
+ matcher.group(1, &group, groupLen, status);
+ REGEX_CHECK_STATUS;
+ REGEX_ASSERT(groupLen == 1);
+ REGEX_ASSERT(utext_getNativeIndex(&group) == 0);
+
+ // Capture group 2, the (B), does not participate in the match.
+ matcher.group(2, &group, groupLen, status);
+ REGEX_CHECK_STATUS;
+ REGEX_ASSERT(groupLen == 0);
+ REGEX_ASSERT(matcher.start(2, status) == -1);
+ REGEX_CHECK_STATUS;
+}
+
+void RegexTest::TestBug12884() {
+ // setTimeLimit() was not effective for empty sub-patterns with large {minimum counts}
+ UnicodeString pattern(u"(((((((){120}){11}){11}){11}){80}){11}){4}");
+ UnicodeString text(u"hello");
+ UErrorCode status = U_ZERO_ERROR;
+ RegexMatcher m(pattern, text, 0, status);
+ REGEX_CHECK_STATUS;
+ m.setTimeLimit(5, status);
+ m.find(status);
+ REGEX_ASSERT(status == U_REGEX_TIME_OUT);
+
+ // Non-greedy loops. They take a different code path during matching.
+ UnicodeString ngPattern(u"(((((((){120}?){11}?){11}?){11}?){80}?){11}?){4}?");
+ status = U_ZERO_ERROR;
+ RegexMatcher ngM(ngPattern, text, 0, status);
+ REGEX_CHECK_STATUS;
+ ngM.setTimeLimit(5, status);
+ ngM.find(status);
+ REGEX_ASSERT(status == U_REGEX_TIME_OUT);
+
+ // UText, wrapping non-UTF-16 text, also takes a different execution path.
+ const char *text8 = u8"¿Qué es Unicode? Unicode proporciona un número único para cada"
+ "carácter, sin importar la plataforma, sin importar el programa,"
+ "sin importar el idioma.";
+ status = U_ZERO_ERROR;
+ LocalUTextPointer ut(utext_openUTF8(NULL, text8, -1, &status));
+ REGEX_CHECK_STATUS;
+ m.reset(ut.getAlias());
+ m.find(status);
+ REGEX_ASSERT(status == U_REGEX_TIME_OUT);
+
+ status = U_ZERO_ERROR;
+ ngM.reset(ut.getAlias());
+ ngM.find(status);
+ REGEX_ASSERT(status == U_REGEX_TIME_OUT);
+}
+
+// Bug 13631. A find() of a pattern with a zero length look-behind assertions
+// can cause a read past the end of the input text.
+// The failure is seen when running this test with Clang's Addresss Sanitizer.
+
+void RegexTest::TestBug13631() {
+ const UChar *pats[] = { u"(?<!^)",
+ u"(?<=^)",
+ nullptr
+ };
+ for (const UChar **pat=pats; *pat; ++pat) {
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeString upat(*pat);
+ RegexMatcher matcher(upat, 0, status);
+ const UChar s =u'a';
+ UText *ut = utext_openUChars(nullptr, &s, 1, &status);
+ REGEX_CHECK_STATUS;
+ matcher.reset(ut);
+ while (matcher.find()) {
+ }
+ utext_close(ut);
+ }