diff -r 000000000000 -r 7f656887cf89 libraries/spcre/test/src/spcreconsole.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libraries/spcre/test/src/spcreconsole.cpp Wed Jun 23 15:52:26 2010 +0100 @@ -0,0 +1,2101 @@ +// spcreconsole.cpp +// +// Copyright (c) 2005 - 2006, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: Sanjay Ghemawat +// +// Heavily refactored for Symbian OS by Accenture. + + +#include +#include +#include +#include // Console +#include +#include +#include +#include + +// Constants +_LIT(KTextConsoleTitle, "Console"); +_LIT(KTextFailed, " failed, leave code = %d\n"); +_LIT(KTextPressAnyKey, "[press any key]\n"); +// Global Variables +LOCAL_D CConsoleBase* console; // write all messages to this +TBool verboseMode = EFalse; + +// Local Functions + +// CHECK dies with a fatal error if condition is not true. It is *not* +// controlled by NDEBUG, so the check will be executed regardless of +// compilation mode. Therefore, it is safe to do things like: +// CHECK_EQ(fp->Write(x), 4) +#define CHECK(condition) \ + { \ + if (!(condition)) \ + { \ + _LIT(KCondition, #condition); \ + console->Printf(_L("%d: Check failed: %S\n"), \ + __LINE__, &KCondition()); \ + User::Leave(KErrGeneral); \ + } \ + } + +#define CHECK_EQ(a, b) CHECK(a == b) + +static void Timing1L(TInt aNumIters) + { + console->Printf(_L("Test Timing 1, %d iterations.\n"), aNumIters); + + // Same pattern lots of times + _LIT8(KPattern, "ruby:\\d+"); + _LIT8(KString,"ruby:1234"); + CRegEx* pattern = CRegEx::NewLC(KPattern()); + + for (TInt j = aNumIters; j > 0; j--) + { + CHECK(pattern->FullMatchL(KString())); + } + CleanupStack::PopAndDestroy(pattern); + } + +static void Timing2L(TInt aNumIters) + { + console->Printf(_L("Test Timing 2, %d iterations.\n"), aNumIters); + // Same pattern lots of times + _LIT8(KPattern, "ruby:(\\d+)"); + _LIT8(KString,"ruby:1234"); + CRegEx* pattern = CRegEx::NewLC(KPattern()); + + TInt i; + for (TInt j = aNumIters; j > 0; j--) + { + CHECK(pattern->FullMatchL(KString(), &i)); + CHECK_EQ(i, 1234); + } + CleanupStack::PopAndDestroy(pattern); + } + +static void Timing3L(TInt aNumIters) + { + console->Printf(_L("Test Timing 3, %d iterations.\n"), aNumIters); + _LIT8(KLine, "this is another line\n"); + HBufC8* text = HBufC8::NewLC(KLine().Length() * aNumIters); + TPtr8 pText = text->Des(); + + for (int j = aNumIters; j > 0; j--) + { + pText.Append(KLine()); + } + + CRegEx* lineMatcher = CRegEx::NewLC(_L8(".*\n")); + + TInt counter = 0; + while (lineMatcher->ConsumeL(pText)) + { + counter++; + } + CleanupStack::PopAndDestroy(2, text); + CHECK_EQ(counter, aNumIters); + console->Printf(_L("Matched %d lines\n"), counter); + } + + +static void RadixTestsL() + { + console->Write(_L("Testing hex\n")); + + #define CHECK_HEX(type, value) \ + { \ + type v; \ + CRegEx* re = CRegEx::NewLC(_L8("([0-9a-fA-F]+)[uUlL]*")); \ + CHECK(re->FullMatchL(_L8(#value), Hex(&v))); \ + CHECK_EQ(v, 0x ## value); \ + CleanupStack::PopAndDestroy(re); \ + re = NULL; \ + } + + CHECK_HEX(TInt64, 2baddeadbeefLL); + CHECK_HEX(TUint8, abU); + CHECK_HEX(TUint16, 2badU); + CHECK_HEX(TUint32, deadbeefUL); + CHECK_HEX(TUint, cafebabeU); + #undef CHECK_HEX + + console->Write(_L("Testing octal\n")); + + #define CHECK_OCTAL(type, value) \ + { \ + type v; \ + CRegEx* re = CRegEx::NewLC(_L8("([0-7]+)[uUlL]*")); \ + CHECK(re->FullMatchL(_L8(#value), Octal(&v))); \ + CHECK_EQ(v, 0 ## value); \ + CleanupStack::PopAndDestroy(re); \ + re = NULL; \ + } + + CHECK_OCTAL(TInt64, 777777777777LL); + CHECK_OCTAL(TUint8, 177U); + CHECK_OCTAL(TUint16, 177777U); + CHECK_OCTAL(TUint32, 3777777777UL); + CHECK_OCTAL(TUint, 3777777777U); + #undef CHECK_OCTAL + + console->Write(_L("Testing decimal\n")); + + #define CHECK_DECIMAL(type, value) \ + { \ + type v; \ + CRegEx* re = CRegEx::NewLC(_L8("(-?[0-9]+)[uUlL]*")); \ + CHECK(re->FullMatchL(_L8(#value), &v)); \ + CHECK_EQ(v, value); \ + CleanupStack::PopAndDestroy(re); \ + re = NULL; \ + } + + CHECK_DECIMAL(TInt8, -1); + CHECK_DECIMAL(TUint8, 1U); + CHECK_DECIMAL(TInt16, -9999); + CHECK_DECIMAL(TUint16, 9999U); + CHECK_DECIMAL(TInt32, -123456L); + CHECK_DECIMAL(TUint32, 123456U); + CHECK_DECIMAL(TInt64, 1234567890123456789LL); + CHECK_DECIMAL(TInt, -1234567890); + CHECK_DECIMAL(TUint, 1234567890U); + #undef CHECK_DECIMAL +} + +static void TestReplaceL() + { + console->Write(_L("Testing ReplaceL\n")); + + struct ReplaceTest + { + TBuf8<32> iRegExp; + TBuf8<32> iRewrite; + TBuf8<64> iOriginal; + TBuf8<64> iSingle; + TBuf8<64> iGlobal; + TInt iGlobalCount; // the expected return value from ReplaceAll + }; + + static const ReplaceTest tests[] = + { + // Test 1 + { + _L8("(qu|[b-df-hj-np-tv-z]*)([a-z]+)"), + _L8("\\2\\1ay"), + _L8("the quick brown fox jumps over the lazy dogs."), + _L8("ethay quick brown fox jumps over the lazy dogs."), + _L8("ethay ickquay ownbray oxfay umpsjay overay ethay azylay ogsday."), + 9 + }, + // Test 2 + { + _L8("\\w+"), + _L8("\\0-NOSPAM"), + _L8("paul.haahr@google.com"), + _L8("paul-NOSPAM.haahr@google.com"), + _L8("paul-NOSPAM.haahr-NOSPAM@google-NOSPAM.com-NOSPAM"), + 4 + }, + // Test 3 + {_L8("^"), + _L8("(START)"), + _L8("foo"), + _L8("(START)foo"), + _L8("(START)foo"), + 1 + }, + // Test 4 + { + _L8("^"), + _L8("(START)"), + _L8(""), + _L8("(START)"), + _L8("(START)"), + 1 + }, + // Test 5 + { + _L8("$"), + _L8("(END)"), + _L8(""), + _L8("(END)"), + _L8("(END)"), + 1 + }, + // Test 6 + { + _L8("b"), + _L8("bb"), + _L8("ababababab"), + _L8("abbabababab"), + _L8("abbabbabbabbabb"), + 5 + }, + // Test 7 + { + _L8("b"), + _L8("bb"), + _L8("bbbbbb"), + _L8("bbbbbbb"), + _L8("bbbbbbbbbbbb"), + 6 + }, + // Test 8 + {_L8("b+"), + _L8("bb"), + _L8("bbbbbb"), + _L8("bb"), + _L8("bb"), + 1 + }, + // Test 9 + { + _L8("b*"), + _L8("bb"), + _L8("bbbbbb"), + _L8("bb"), + _L8("bb"), + 1 + }, + // Test 10 + { + _L8("b*"), + _L8("bb"), + _L8("aaaaa"), + _L8("bbaaaaa"), + _L8("bbabbabbabbabbabb"), + 6 + }, + // Test 11 + { + _L8("b*"), + _L8("bb"), + _L8("aa\naa\n"), + _L8("bbaa\naa\n"), + _L8("bbabbabb\nbbabbabb\nbb"), + 7 + }, + // Test 12 + { + _L8("b*"), + _L8("bb"), + _L8("aa\raa\r"), + _L8("bbaa\raa\r"), + _L8("bbabbabb\rbbabbabb\rbb"), + 7 + }, + // Test 13 + { + _L8("b*"), + _L8("bb"), + _L8("aa\r\naa\r\n"), + _L8("bbaa\r\naa\r\n"), + _L8("bbabbabb\r\nbbabbabb\r\nbb"), + 7 + }, +#ifdef SUPPORT_UTF8 + // Test 14 + { + _L8("b*"), + _L8("bb"), + _L8("\xE3\x83\x9B\xE3\x83\xBC\xE3\x83\xA0\xE3\x81\xB8"), // utf8 + _L8("bb\xE3\x83\x9B\xE3\x83\xBC\xE3\x83\xA0\xE3\x81\xB8"), + _L8("bb\xE3\x83\x9B""bb""\xE3\x83\xBC""bb""\xE3\x83\xA0""bb""\xE3\x81\xB8""bb"), + 5 + }, + // Test 15 + { + _L8("b*"), + _L8("bb"), + _L8("\xE3\x83\x9B\r\n\xE3\x83\xBC\r\xE3\x83\xA0\n\xE3\x81\xB8\r\n"), // utf8 + _L8("bb\xE3\x83\x9B\r\n\xE3\x83\xBC\r\xE3\x83\xA0\n\xE3\x81\xB8\r\n"), + _L8("bb\xE3\x83\x9B""bb\r\nbb""\xE3\x83\xBC""bb\rbb""\xE3\x83\xA0""bb\nbb""\xE3\x81\xB8""bb\r\nbb"), + 9 + }, +#endif + { + KNullDesC8(), + KNullDesC8(), + KNullDesC8(), + KNullDesC8(), + KNullDesC8(), + -1 + } + }; + +#ifdef SUPPORT_UTF8 + const TBool supportUtf8 = ETrue; +#else + const TBool supportUtf8 = EFalse; +#endif + + CRegEx* re = NULL; + TRegExOptions options = TRegExOptions(EPcreNewlineCrLf); + options.SetUtf8(supportUtf8); + TInt i =0; + for (const ReplaceTest* t = tests; t->iGlobalCount > -1; ++t) + { + console->Printf(_L("Replace Test %d\n"), ++i); + re = CRegEx::NewLC(t->iRegExp, options); + CHECK_EQ(re->Error(), KErrNone); + TBuf8<64> one(t->iOriginal); + CHECK(re->ReplaceL(t->iRewrite, one)); + CHECK_EQ(one, t->iSingle); + TBuf8<64> all(t->iOriginal); + const TInt replaceCount = re->GlobalReplaceL(t->iRewrite, all); + CHECK_EQ(all, t->iGlobal); + CHECK_EQ(replaceCount, t->iGlobalCount); + CleanupStack::PopAndDestroy(re); + re = NULL; + } + + // One final test: test \r\n replacement when we're not in CRLF mode + { + TRegExOptions options2 = TRegExOptions(EPcreNewlineCr); + options2.SetUtf8(supportUtf8); + re = CRegEx::NewLC(_L8("b*"), options2); + CHECK_EQ(re->Error(), KErrNone); + TBuf8<32> all(_L8("aa\r\naa\r\n")); + CHECK_EQ(re->GlobalReplaceL(_L8("bb"), all), 9); + CHECK_EQ(all, _L8("bbabbabb\rbb\nbbabbabb\rbb\nbb")); + CleanupStack::PopAndDestroy(re); + re = NULL; + } + { + TRegExOptions options3 = TRegExOptions(EPcreNewlineLf); + options3.SetUtf8(supportUtf8); + re = CRegEx::NewLC(_L8("b*"), options3); + CHECK_EQ(re->Error(), KErrNone); + TBuf8<32> all(_L8("aa\r\naa\r\n")); + CHECK_EQ(re->GlobalReplaceL(_L8("bb"), all), 9); + CHECK_EQ(all, _L8("bbabbabb\rbb\nbbabbabb\rbb\nbb")); + CleanupStack::PopAndDestroy(re); + re = NULL; + } + + // TODO: test what happens when no PCRE_NEWLINE_* flag is set. + // Alas, the answer depends on how pcre was compiled. +} + +static void TestExtractL() + { + console->Write(_L("Testing ExtractL\n")); + + TBuf8<32> s; + CRegEx* re = NULL; + + re = CRegEx::NewLC(_L8("(.*)@([^.]*)")); + CHECK(re->ExtractL(_L8("\\2!\\1"), _L8("boris@kremvax.ru"), s)); + CHECK_EQ(s, _L8("kremvax!boris")); + CleanupStack::PopAndDestroy(re); + re = NULL; + + // check the RE interface as well + re = CRegEx::NewLC(_L8(".*")); + CHECK(re->ExtractL(_L8("'\\0'"), _L8("foo"), s)); + CHECK_EQ(s, _L8("'foo'")); + CleanupStack::PopAndDestroy(re); + re = NULL; + + re = CRegEx::NewLC(_L8("bar")); + CHECK(!re->ExtractL(_L8("'\\0'"), _L8("baz"), s)); + CHECK_EQ(s, _L8("'foo'")); + CleanupStack::PopAndDestroy(re); + } + +static void TestConsumeL() + { + console->Write(_L("Testing ConsumeL\n")); + + TBuf8<3> word; + TBuf8<24> input(_L8(" aaa b!@#$@#$cccc")); + + // matches a word, possibly proceeded by whitespace + CRegEx* re = CRegEx::NewLC(_L8("\\s*(\\w+)")); + CHECK(re->ConsumeL(input, &word)); + CHECK_EQ(word, _L8("aaa")); + CHECK(re->ConsumeL(input, &word)); + CHECK_EQ(word, _L8("b")); + CHECK(!re->ConsumeL(input, &word)); + CleanupStack::PopAndDestroy(re); + } + +static void TestFindAndConsumeL() + { + console->Write(_L("Testing FindAndConsumeL\n")); + + TBuf8<4> word; + TBuf8<24> input(_L8(" aaa b!@#$@#$cccc")); + + CRegEx* re = CRegEx::NewLC(_L8("(\\w+)")); // matches a word + CHECK(re->FindAndConsumeL(input, &word)); + CHECK_EQ(word, _L8("aaa")); + CHECK(re->FindAndConsumeL(input, &word)); + CHECK_EQ(word, _L8("b")); + CHECK(re->FindAndConsumeL(input, &word)); + CHECK_EQ(word, _L8("cccc")); + CHECK(!re->FindAndConsumeL(input, &word)); + CleanupStack::PopAndDestroy(re); + } + +static void TestMatchNumberPeculiarityL() + { + console->Write(_L("Testing match-number peculiarity\n")); + + TBuf8<3> word1; + TBuf8<3> word2; + TBuf8<3> word3; + + CRegEx* re = CRegEx::NewLC(_L8("(foo)|(bar)|(baz)")); + CHECK(re->PartialMatchL(_L8("foo"), &word1, &word2, &word3)); + CHECK_EQ(word1, _L8("foo")); + CHECK_EQ(word2, KNullDesC8()); + CHECK_EQ(word3, KNullDesC8()); + CHECK(re->PartialMatchL(_L8("bar"), &word1, &word2, &word3)); + CHECK_EQ(word1, KNullDesC8()); + CHECK_EQ(word2, _L8("bar")); + CHECK_EQ(word3, KNullDesC8()); + CHECK(re->PartialMatchL(_L8("baz"), &word1, &word2, &word3)); + CHECK_EQ(word1, KNullDesC8()); + CHECK_EQ(word2, KNullDesC8()); + CHECK_EQ(word3, _L8("baz")); + CHECK(!re->PartialMatchL(_L8("f"), &word1, &word2, &word3)); + + CleanupStack::PopAndDestroy(re); + re = NULL; + + TBuf8<12> a; + re = CRegEx::NewLC(_L8("(foo)|hello")); + CHECK(re->FullMatchL(_L8("hello"), &a)); + CHECK_EQ(a, KNullDesC8()); + CleanupStack::PopAndDestroy(re); + } + +static void TestRecursionL() + { + console->Write(_L("Testing recursion\n")); + + // Get one string that passes (sometimes), one that never does. + TBuf8<12> good(_L8("abcdefghijk")); + TBuf8<12> bad(_L8("acdefghijkl")); + + // According to pcretest, matching text_good against (\w+)*b + // requires match_limit of at least 8192, and match_recursion_limit + // of at least 37. + + TRegExOptions optionsMatchLimit; + optionsMatchLimit.SetMatchLimit(8192); + + CRegEx* re = CRegEx::NewLC(_L8("(\\w+)*b"), optionsMatchLimit); + CHECK(re->PartialMatchL(good)); + CHECK(re->PartialMatchL(bad) == EFalse); + CHECK(re->FullMatchL(good) == EFalse); + CHECK(re->FullMatchL(bad) == EFalse); + CleanupStack::PopAndDestroy(re); + re = NULL; + + optionsMatchLimit.SetMatchLimit(1024); + CRegEx* re2 = CRegEx::NewLC(_L8("(\\w+)*b"), optionsMatchLimit); + CHECK(re2->PartialMatchL(good) == EFalse); // because of match_limit + CHECK(re2->PartialMatchL(bad) == EFalse); + CHECK(re2->FullMatchL(good) == EFalse); + CHECK(re2->FullMatchL(bad) == EFalse); + CleanupStack::PopAndDestroy(re2); + re2 = NULL; + + TRegExOptions optionsMathLimitRecursion; + optionsMathLimitRecursion.SetMatchLimitRecursion(50); + CRegEx* re3 = CRegEx::NewLC(_L8("(\\w+)*b"), optionsMathLimitRecursion); + CHECK(re3->PartialMatchL(good)); + CHECK(re3->PartialMatchL(bad) == EFalse); + CHECK(re3->FullMatchL(good) == EFalse); + CHECK(re3->FullMatchL(bad) == EFalse); + CleanupStack::PopAndDestroy(re3); + re3 = NULL; + + optionsMathLimitRecursion.SetMatchLimitRecursion(10); + CRegEx* re4 = CRegEx::NewLC(_L8("(\\w+)*b"), optionsMathLimitRecursion); + CHECK(re4->PartialMatchL(good) == EFalse); + CHECK(re4->PartialMatchL(bad) == EFalse); + CHECK(re4->FullMatchL(good) == EFalse); + CHECK(re4->FullMatchL(bad) == EFalse); + CleanupStack::PopAndDestroy(re4); + re4 = NULL; + } + +// A meta-quoted string, interpreted as a pattern, should always match +// the original unquoted string. +static void TestQuoteMetaL(const TDesC8& aUnquoted, TRegExOptions aOptions = + TRegExOptions()) + { + HBufC8* quoted = CRegEx::QuoteMetaL(aUnquoted); + CleanupStack::PushL(quoted); + + CRegEx* re = CRegEx::NewLC(*quoted, aOptions); + CHECK(re->FullMatchL(aUnquoted)); + CleanupStack::PopAndDestroy(2, quoted); // re + } + +// A string containing meaningful regexp characters, which is then meta- +// quoted, should not generally match a string the unquoted string does. +static void NegativeTestQuoteMetaL(const TDesC8& aUnquoted, + const TDesC8& aNotMatch, TRegExOptions aOptions = TRegExOptions()) + { + HBufC8* quoted = CRegEx::QuoteMetaL(aUnquoted); + CleanupStack::PushL(quoted); + + CRegEx* re = CRegEx::NewLC(*quoted, aOptions); + CHECK(!re->FullMatchL(aNotMatch)); + CleanupStack::PopAndDestroy(2, quoted); // re + } + +// Tests that quoted meta characters match their original strings, +// and that a few things that shouldn't match indeed do not. +static void TestQuotaMetaSimpleL() + { + TestQuoteMetaL(_L8("foo")); + TestQuoteMetaL(_L8("foo.bar")); + TestQuoteMetaL(_L8("foo\\.bar")); + TestQuoteMetaL(_L8("[1-9]")); + TestQuoteMetaL(_L8("1.5-2.0?")); + TestQuoteMetaL(_L8("\\d")); + TestQuoteMetaL(_L8("Who doesn't like ice cream?")); + TestQuoteMetaL(_L8("((a|b)c?d*e+[f-h]i)")); + TestQuoteMetaL(_L8("((?!)xxx).*yyy")); + TestQuoteMetaL(_L8("([")); + TestQuoteMetaL(_L8("foo\0bar")); + } + +static void TestQuoteMetaSimpleNegativeL() + { + NegativeTestQuoteMetaL(_L8("foo"), _L8("bar")); + NegativeTestQuoteMetaL(_L8("..."), _L8("bar")); + NegativeTestQuoteMetaL(_L8("\\."), _L8(".")); + NegativeTestQuoteMetaL(_L8("\\."), _L8("..")); + NegativeTestQuoteMetaL(_L8("(a)"), _L8("a")); + NegativeTestQuoteMetaL(_L8("(a|b)"), _L8("a")); + NegativeTestQuoteMetaL(_L8("(a|b)"), _L8("(a)")); + NegativeTestQuoteMetaL(_L8("(a|b)"), _L8("a|b")); + NegativeTestQuoteMetaL(_L8("[0-9]"), _L8("0")); + NegativeTestQuoteMetaL(_L8("[0-9]"), _L8("0-9")); + NegativeTestQuoteMetaL(_L8("[0-9]"), _L8("[9]")); + NegativeTestQuoteMetaL(_L8("((?!)xxx)"), _L8("xxx")); + } + +static void TestQuoteMetaLatin1L() + { + TestQuoteMetaL(_L8("3\xb2 = 9")); + } + + +static void TestQuoteMetaUtf8L() + { +#ifdef SUPPORT_UTF8 + TRegExOptions options; + options.SetUtf8(ETrue); + TestQuoteMetaL(_L8("Pl\xc3\xa1\x63ido Domingo"), options); + TestQuoteMetaL(_L8("xyz"), options); // No fancy utf8 + TestQuoteMetaL(_L8("\xc2\xb0"), options); // 2-byte utf8 (degree symbol) + TestQuoteMetaL(_L8("27\xc2\xb0 degrees"), options); // As a middle character + TestQuoteMetaL(_L8("\xe2\x80\xb3"), options); // 3-byte utf8 (double prime) + TestQuoteMetaL(_L8("\xf0\x9d\x85\x9f"), options); // 4-byte utf8 (music note) + TestQuoteMetaL(_L8("27\xc2\xb0")); // Interpreted as Latin-1, but should still work + NegativeTestQuoteMetaL(_L8("27\xc2\xb0"), // 2-byte utf (degree symbol) + _L8("27\\\xc2\\\xb0"), + options); +#endif + } + + +static void TestQuoteMetaAllL() + { + console->Write(_L("Testing QuoteMeta\n")); + + TestQuotaMetaSimpleL(); + TestQuoteMetaSimpleNegativeL(); + TestQuoteMetaLatin1L(); + TestQuoteMetaUtf8L(); + } + +// +// Options tests contributed by +// Giuseppe Maxia, CTO, Stardata s.r.l. +// July 2005 +// +static void GetOneOptionResultL( + const TDesC& aOptionName, + const TDesC8& aRegEx, + const TDesC8& aString, + TRegExOptions& aOptions, + TBool aFull, + const TDesC8& aExpected) + { + console->Printf(_L("Testing Option <%S>\n"), &aOptionName); + + if(verboseMode) + { + TBuf<32> str; + str.Copy(aString); + TBuf<32> rx; + rx.Copy(aRegEx); + TBuf<32> expected; + expected.Copy(aExpected); + + console->Printf(_L("/%S/ finds \"%S\" within \"%S\" \n"), &rx, &expected, &str); + } + + TBuf8<32> captured; + CRegEx* re = CRegEx::NewLC(aRegEx, aOptions); + + if (aFull) + { + CHECK(re->FullMatchL(aString, &captured)); + } + else + { + CHECK(re->PartialMatchL(aString, &captured)); + } + CHECK_EQ(captured, aExpected); + + CleanupStack::PopAndDestroy(re); +} + +static void TestOneOptionL( + const TDesC& aOptionName, + const TDesC8& aRegEx, + const TDesC8& aString, + const TRegExOptions& aOptions, + TBool aFull, + TBool aAssertive = ETrue) + { + + console->Printf(_L("Testing Option <%S>\n"), &aOptionName); + if(verboseMode) + { + _LIT(KMatches, "matches"); + _LIT(KNoMatch, "doesn't match"); + TBuf<32> str; + str.Copy(aString); + TBuf<64> rx; + rx.Copy(aRegEx); + + console->Printf(_L("'%S' %S /%S/ \n"), + &str, + (aAssertive? &KMatches() : &KNoMatch()), + &rx); + } + + CRegEx* re = NULL; + TRAPD(err, re = CRegEx::NewLC(aRegEx, aOptions); CleanupStack::Pop()); + + if(err) + { + CHECK_EQ(aAssertive, EFalse); + return; + } + + CleanupStack::PushL(re); + + if (aAssertive) + { + if (aFull) + { + CHECK(re->FullMatchL(aString)); + } + else + { + CHECK(re->PartialMatchL(aString)); + } + } + else + { + if (aFull) + { + CHECK(!re->FullMatchL(aString)); + } + else + { + CHECK(!re->PartialMatchL(aString)); + } + } + CleanupStack::PopAndDestroy(re); + } + +static void TestCaseLessL() + { + TRegExOptions options; + TRegExOptions options2; + TRegExOptions caseless; + caseless.SetCaseless(ETrue); + + options.SetCaseless(ETrue); + TestOneOptionL(_L("CASELESS (class)"), _L8("HELLO"), _L8("hello"), options, EFalse); + TestOneOptionL(_L("CASELESS (class2)"), _L8("HELLO"), _L8("hello"), options2.SetCaseless(ETrue), EFalse); + TestOneOptionL(_L("CASELESS (class)"), _L8("^[A-Z]+$"), _L8("Hello"), options, EFalse); + + TestOneOptionL(_L("CASELESS (function)"), _L8("HELLO"), _L8("hello"), caseless, EFalse); + TestOneOptionL(_L("CASELESS (function)"), _L8("^[A-Z]+$"), _L8("Hello"), caseless, EFalse); + options.SetCaseless(EFalse); + TestOneOptionL(_L("no CASELESS"), _L8("HELLO"), _L8("hello"), options, EFalse, EFalse); + } + +static void TestMultilineL() + { + TRegExOptions options; + TRegExOptions options2; + TRegExOptions multiline; + multiline.SetMultiline(ETrue); + + TBuf8<32> str(_L8("HELLO\n" "cruel\n" "world\n")); + + options.SetMultiline(ETrue); + TestOneOptionL(_L("MULTILINE (class)"), _L8("^cruel$"), str, options, EFalse); + TestOneOptionL(_L("MULTILINE (class2)"), _L8("^cruel$"), str, options2.SetMultiline(ETrue), EFalse); + TestOneOptionL(_L("MULTILINE (function)"), _L8("^cruel$"), str, multiline, EFalse); + options.SetMultiline(EFalse); + TestOneOptionL(_L("no MULTILINE"), _L8("^cruel$"), str, options, EFalse, EFalse); + } + +static void TestDotAllL() + { + TRegExOptions options; + TRegExOptions options2; + TRegExOptions dotAll; + dotAll.SetDotAll(ETrue); + + TBuf8<32> str(_L8("HELLO\n" "cruel\n" "world")); + + options.SetDotAll(ETrue); + TestOneOptionL(_L("DOTALL (class)"), _L8("HELLO.*world"),str, options, ETrue); + TestOneOptionL(_L("DOTALL (class2)"), _L8("HELLO.*world"),str, options2.SetDotAll(ETrue), ETrue); + TestOneOptionL(_L("DOTALL (function)"), _L8("HELLO.*world"),str, dotAll, ETrue); + options.SetDotAll(EFalse); + TestOneOptionL(_L("no DOTALL"), _L8("HELLO.*world"),str, options, ETrue, EFalse); + } + +static void TestDollarEndOnlyL() + { + TRegExOptions options; + TRegExOptions options2; + TRegExOptions dollarEndOnly; + dollarEndOnly.SetDollarEndOnly(ETrue); + + TBuf8<32> str(_L8("HELLO world\n")); + + TestOneOptionL(_L("no DOLLAR_ENDONLY"), _L8("world$"), str, options, EFalse); + options.SetDollarEndOnly(ETrue); + TestOneOptionL(_L("DOLLAR_ENDONLY 1"), _L8("world$"), str, options, EFalse, EFalse); + TestOneOptionL(_L("DOLLAR_ENDONLY 2"), _L8("world$"), str, options2.SetDollarEndOnly(ETrue), EFalse, EFalse); + } + + +static void TestExtraL() + { + TRegExOptions options; + + TBuf8<32> str(_L8("HELLO")); + options.SetExtra(ETrue); + TestOneOptionL(_L("EXTRA 1"), _L8("\\HELL\\O"), str, options, ETrue, EFalse ); + TestOneOptionL(_L("EXTRA 2"), _L8("\\HELL\\O"), str, TRegExOptions().SetExtra(ETrue), ETrue, EFalse ); + options.SetExtra(EFalse); + TestOneOptionL(_L("no EXTRA"), _L8("\\HELL\\O"), str, options, ETrue ); + } + +static void TestExtendedL() + { + TRegExOptions options; + TRegExOptions options2; + TRegExOptions extended; + extended.SetExtended(ETrue); + + TBuf8<32> str(_L8("HELLO world")); + + options.SetExtended(ETrue); + TestOneOptionL(_L("EXTENDED (class)"), _L8("HELLO world"), str, options, EFalse, EFalse); + TestOneOptionL(_L("EXTENDED (class2)"), _L8("HELLO world"), str, options2.SetExtended(ETrue), EFalse, EFalse); + TestOneOptionL(_L("EXTENDED (class)"), _L8("^ HE L{2} O \\s+ \\w+ $ "), str, options, EFalse); + + TestOneOptionL(_L("EXTENDED (function)"), _L8("HELLO world"), str, extended, EFalse, EFalse); + TestOneOptionL(_L("EXTENDED (function)"), _L8("^ HE L{2} O \\s+ \\w+ $ "), str, extended, EFalse); + + options.SetExtended(EFalse); + TestOneOptionL(_L("no EXTENDED"), _L8("HELLO world"), str, options, EFalse); + } + +static void TestNoAutoCaptureL() + { + TRegExOptions options; + TBuf8<32> str(_L8("HELLO world")); + TBuf8<5> captured; + console->Write(_L("Testing Option \n")); + if (verboseMode) + { + console->Write(_L("parentheses capture text\n")); + } + + CRegEx* re = CRegEx::NewLC(_L8("(world|universe)$"), options); + CHECK(re->ExtractL(_L8("\\1"), str , captured)); + CHECK_EQ(captured, _L8("world")); + options.SetNoAutoCapture(ETrue); + console->Write(_L("testing Option \n")); + + if (verboseMode) + { + console->Write(_L("parentheses do not capture text\n")); + } + + re->ExtractL(_L8("\\1"),str, captured); + CHECK_EQ(captured, _L8("world")); + + CleanupStack::PopAndDestroy(re); + } + +static void TestUngreedyL() + { + TRegExOptions options; + TRegExOptions ungreedy; + ungreedy.SetUngreedy(ETrue); + + TBuf8<32> str(_L8("HELLO, 'this' is the 'world'")); + + options.SetUngreedy(ETrue); + GetOneOptionResultL(_L("UNGREEDY 1"), _L8("('.*')"), str, options, EFalse, _L8("'this'") ); + GetOneOptionResultL(_L("UNGREEDY 2"), _L8("('.*')"), str, ungreedy, EFalse, _L8("'this'") ); + GetOneOptionResultL(_L("UNGREEDY"), _L8("('.*?')"), str, options, EFalse, _L8("'this' is the 'world'") ); + + options.SetUngreedy(EFalse); + GetOneOptionResultL(_L("no UNGREEDY"), _L8("('.*')"), str, options, EFalse, _L8("'this' is the 'world'") ); + GetOneOptionResultL(_L("no UNGREEDY"), _L8("('.*?')"), str, options, EFalse, _L8("'this'") ); + } + +static void TestAllOptionsL() + { + TBuf8<32> str(_L8("HELLO\n" "cruel\n" "world")); + TRegExOptions options; + options.SetAllOptions(EPcreCaseless | EPcreDotAll); + + TestOneOptionL(_L("all_options (CASELESS|DOTALL)"), _L8("^hello.*WORLD"), str , options, EFalse); + options.SetAllOptions(0); + TestOneOptionL(_L("all_options (0)"), _L8("^hello.*WORLD"), str , options, EFalse, EFalse); + options.SetAllOptions(EPcreMultiline | EPcreExtended); + + TestOneOptionL(_L("all_options (MULTILINE|EXTENDED)"), _L8(" ^ c r u e l $ "), str, options, EFalse); + TestOneOptionL(_L("all_options (MULTILINE|EXTENDED) with constructor"), + _L8(" ^ c r u e l $ "), + str, + TRegExOptions(EPcreMultiline | EPcreExtended), + EFalse); + + TRegExOptions multilineExtended = TRegExOptions().SetMultiline(ETrue); + multilineExtended.SetExtended(ETrue); + + TestOneOptionL(_L("all_options (MULTILINE|EXTENDED) with concatenation"), + _L8(" ^ c r u e l $ "), + str, + multilineExtended, EFalse); + + options.SetAllOptions(0); + TestOneOptionL(_L("all_options (0)"), _L8("^ c r u e l $"), str, options, EFalse, EFalse); + } + +static void TestOptionsL() + { + console->Write(_L("Testing Options\n")); + TestCaseLessL(); + TestMultilineL(); + TestDotAllL(); + TestDollarEndOnlyL(); + TestExtendedL(); + TestNoAutoCaptureL(); + TestUngreedyL(); + TestExtraL(); + TestAllOptionsL(); + } + + +LOCAL_C void MainL() + { + + _LIT(KTimingArg1, "timing1"); + _LIT(KTimingArg2, "timing2"); + _LIT(KTimingArg3, "timing3"); + + CCommandLineArguments* args = CCommandLineArguments::NewLC(); + + // Treat any flag as --help + if(args->Count() > 1 && args->Arg(1)[0] == '-') + { + console->Printf(_L("Usage: %S [%S|%S|%S num-iters]\n"), &(args->Arg(0)), &KTimingArg1(), &KTimingArg2(), &KTimingArg3()); + console->Write(_L("If 'timingX ###' is specified, run the given timing test\n")); + console->Write(_L("with the given number of iterations, rather than running\n")); + console->Write(_L("the default corectness test.\n")); + CleanupStack::PopAndDestroy(args); + return; + } + if(args->Count() > 1) + { + if(args->Count() == 2) + { + console->Write(_L("timing mode needs a num-iters argument\n")); + CleanupStack::PopAndDestroy(args); + return; + } + + TLex lex(args->Arg(2)); + TInt iters; + TInt err = lex.Val(iters); + + if(err || iters == 0) + { + CleanupStack::PopAndDestroy(args); + return; + } + + if(args->Arg(1) == KTimingArg1) + { + Timing1L(iters); + } + else if(args->Arg(1) == KTimingArg2) + { + Timing2L(iters); + } + else if(args->Arg(1) == KTimingArg3) + { + Timing3L(iters); + } + else + { + console->Printf(_L("Unknown argument '%S'\n"), &(args->Arg(1))); + } + CleanupStack::PopAndDestroy(args); + return; + } + CleanupStack::PopAndDestroy(args); + + console->Write(_L("Testing FullMatch\n")); + + CRegEx* re = NULL; + TInt i; + TBuf8<10> s; + + /***** FullMatch with no args *****/ + re = CRegEx::NewLC(_L8("h.*o")); + CHECK(re->FullMatchL(_L8("hello"))); + CleanupStack::PopAndDestroy(re); + re = NULL; + + re = CRegEx::NewLC(_L8("h.*o")); // Must be anchored at front + CHECK(!re->FullMatchL(_L8("othello"))); + CleanupStack::PopAndDestroy(re); + re = NULL; + + re = CRegEx::NewLC(_L8("h.*o")); // Must be anchored at end + CHECK(!re->FullMatchL(_L8("hello!"))); + CleanupStack::PopAndDestroy(re); + re = NULL; + + re = CRegEx::NewLC(_L8("a*")); // Fullmatch with normal op + CHECK(re->FullMatchL(_L8("aaaa"))); + CleanupStack::PopAndDestroy(re); + re = NULL; + + re = CRegEx::NewLC(_L8("a*?")); // Fullmatch with nongreedy op + CHECK(re->FullMatchL(_L8("aaaa"))); + CleanupStack::PopAndDestroy(re); + re = NULL; + + re = CRegEx::NewLC(_L8("a*?\\z")); // Two unusual ops + CHECK(re->FullMatchL(_L8("aaaa"))); + CleanupStack::PopAndDestroy(re); + re = NULL; + + /***** FullMatch with args *****/ + + // Zero-arg + re = CRegEx::NewLC(_L8("\\d+")); + CHECK(re->FullMatchL(_L8("1001"))); + CleanupStack::PopAndDestroy(re); + re = NULL; + + // Single-arg + re = CRegEx::NewLC(_L8("(\\d+)")); + CHECK(re->FullMatchL(_L8("1001"), &i)); + CHECK_EQ(i, 1001); + CleanupStack::PopAndDestroy(re); + re = NULL; + + re = CRegEx::NewLC(_L8("(-?\\d+)")); + CHECK(re->FullMatchL(_L8("-123"), &i)); + CHECK_EQ(i, -123); + CleanupStack::PopAndDestroy(re); + re = NULL; + + re = CRegEx::NewLC(_L8("()\\d+")); + CHECK(!re->FullMatchL(_L8("10"), &i)); + CleanupStack::PopAndDestroy(re); + re = NULL; + + re = CRegEx::NewLC(_L8("(\\d+)")); + CHECK(!re->FullMatchL(_L8("1234567890123456789012345678901234567890"), &i)); + CleanupStack::PopAndDestroy(re); + re = NULL; + + // Digits surrounding integer-arg + re = CRegEx::NewLC(_L8("1(\\d*)4")); + CHECK(re->FullMatchL(_L8("1234"), &i)); + CHECK_EQ(i, 23); + CleanupStack::PopAndDestroy(re); + re = NULL; + + re = CRegEx::NewLC(_L8("(\\d)\\d+")); + CHECK(re->FullMatchL(_L8("1234"), &i)); + CHECK_EQ(i, 1); + CleanupStack::PopAndDestroy(re); + re = NULL; + + re = CRegEx::NewLC(_L8("(-\\d)\\d+")); + CHECK(re->FullMatchL(_L8("-1234"), &i)); + CHECK_EQ(i, -1); + CleanupStack::PopAndDestroy(re); + re = NULL; + + re = CRegEx::NewLC(_L8("(\\d)")); + CHECK(re->PartialMatchL(_L8("1234"), &i)); + CHECK_EQ(i, 1); + CleanupStack::PopAndDestroy(re); + re = NULL; + + re = CRegEx::NewLC(_L8("(-\\d)")); + CHECK(re->PartialMatchL(_L8("-1234"), &i)); + CHECK_EQ(i, -1); + CleanupStack::PopAndDestroy(re); + re = NULL; + + // String-arg + re = CRegEx::NewLC(_L8("h(.*)o")); + CHECK(re->PartialMatchL(_L8("hello"), &s)); + CHECK_EQ(s, _L8("ell")); + CleanupStack::PopAndDestroy(re); + re = NULL; + + // Multi-arg + re = CRegEx::NewLC(_L8("(\\w+):(\\d+)")); + CHECK(re->PartialMatchL(_L8("ruby:1234"), &s, &i)); + CHECK_EQ(s.Length(), 4); + CHECK_EQ(s, _L8("ruby")); + CHECK_EQ(i, 1234); + CleanupStack::PopAndDestroy(re); + re = NULL; + + // Ignore non-void* NULL arg + re = CRegEx::NewLC(_L8("he(.*)lo")); + CHECK(re->FullMatchL(_L8("hello"), (TDes8*)NULL)); + CleanupStack::PopAndDestroy(re); + re = NULL; + + re = CRegEx::NewLC(_L8("(.*)")); + CHECK(re->FullMatchL(_L8("123"), (TInt8*)NULL)); + CleanupStack::PopAndDestroy(re); + re = NULL; + + re = CRegEx::NewLC(_L8("(.*)")); + CHECK(re->FullMatchL(_L8("12345"), (TInt16*)NULL)); + CleanupStack::PopAndDestroy(re); + re = NULL; + + re = CRegEx::NewLC(_L8("(.*)")); + CHECK(re->FullMatchL(_L8("1234567890"), (TInt32*)NULL)); + CleanupStack::PopAndDestroy(re); + re = NULL; + + re = CRegEx::NewLC(_L8("(.*)")); + CHECK(re->FullMatchL(_L8("1234567890123456"), (TInt64*)NULL)); + CleanupStack::PopAndDestroy(re); + re = NULL; + + re = CRegEx::NewLC(_L8("(.*)")); + CHECK(re->FullMatchL(_L8("1234567890"), (TInt*)NULL)); + CleanupStack::PopAndDestroy(re); + re = NULL; + + re = CRegEx::NewLC(_L8("(.*)")); + CHECK(re->FullMatchL(_L8("123"), (TUint8*)NULL)); + CleanupStack::PopAndDestroy(re); + re = NULL; + + re = CRegEx::NewLC(_L8("(.*)")); + CHECK(re->FullMatchL(_L8("12345"), (TUint16*)NULL)); + CleanupStack::PopAndDestroy(re); + re = NULL; + + re = CRegEx::NewLC(_L8("(.*)")); + CHECK(re->FullMatchL(_L8("1234567890"), (TUint32*)NULL)); + CleanupStack::PopAndDestroy(re); + re = NULL; + + re = CRegEx::NewLC(_L8("(.*)")); + CHECK(re->FullMatchL(_L8("1234567890"), (TUint*)NULL)); + CleanupStack::PopAndDestroy(re); + re = NULL; + + re = CRegEx::NewLC(_L8("(.*)")); + CHECK(re->FullMatchL(_L8("123.4567890123456"), (TReal32*)NULL)); + CleanupStack::PopAndDestroy(re); + re = NULL; + + re = CRegEx::NewLC(_L8("(.*)")); + CHECK(re->FullMatchL(_L8("123.4567890123456"), (TReal64*)NULL)); + CleanupStack::PopAndDestroy(re); + re = NULL; + + re = CRegEx::NewLC(_L8("(.*)")); + CHECK(re->FullMatchL(_L8("123.4567890123456"), (TReal*)NULL)); + CleanupStack::PopAndDestroy(re); + re = NULL; + + // Fail on non-void* NULL arg if the match doesn't parse for the given type. + re = CRegEx::NewLC(_L8("h(.*)lo")); + CHECK(!re->FullMatchL(_L8("hello"), &s, (TDes8*)NULL)); + CleanupStack::PopAndDestroy(re); + re = NULL; + + re = CRegEx::NewLC(_L8("(.*)")); + CHECK(!re->FullMatchL(_L8("hello"), (TInt8*)NULL)); + CleanupStack::PopAndDestroy(re); + re = NULL; + + re = CRegEx::NewLC(_L8("(.*)")); + CHECK(!re->FullMatchL(_L8("hello"), (TInt16*)NULL)); + CleanupStack::PopAndDestroy(re); + re = NULL; + + re = CRegEx::NewLC(_L8("(.*)")); + CHECK(!re->FullMatchL(_L8("hello"), (TInt32*)NULL)); + CleanupStack::PopAndDestroy(re); + re = NULL; + + re = CRegEx::NewLC(_L8("(.*)")); + CHECK(!re->FullMatchL(_L8("hello"), (TInt64*)NULL)); + CleanupStack::PopAndDestroy(re); + re = NULL; + + re = CRegEx::NewLC(_L8("(.*)")); + CHECK(!re->FullMatchL(_L8("hello"), (TInt*)NULL)); + CleanupStack::PopAndDestroy(re); + re = NULL; + + re = CRegEx::NewLC(_L8("(.*)")); + CHECK(!re->FullMatchL(_L8("hello"), (TUint8*)NULL)); + CleanupStack::PopAndDestroy(re); + re = NULL; + + re = CRegEx::NewLC(_L8("(.*)")); + CHECK(!re->FullMatchL(_L8("hello"), (TUint16*)NULL)); + CleanupStack::PopAndDestroy(re); + re = NULL; + + re = CRegEx::NewLC(_L8("(.*)")); + CHECK(!re->FullMatchL(_L8("hello"), (TUint32*)NULL)); + CleanupStack::PopAndDestroy(re); + re = NULL; + + re = CRegEx::NewLC(_L8("(.*)")); + CHECK(!re->FullMatchL(_L8("hello"), (TUint*)NULL)); + CleanupStack::PopAndDestroy(re); + re = NULL; + + re = CRegEx::NewLC(_L8("(.*)")); + CHECK(!re->FullMatchL(_L8("hello"), (TReal32*)NULL)); + CleanupStack::PopAndDestroy(re); + re = NULL; + + re = CRegEx::NewLC(_L8("(.*)")); + CHECK(!re->FullMatchL(_L8("hello"), (TReal64*)NULL)); + CleanupStack::PopAndDestroy(re); + re = NULL; + + re = CRegEx::NewLC(_L8("(.*)")); + CHECK(!re->FullMatchL(_L8("hello"), (TReal*)NULL)); + CleanupStack::PopAndDestroy(re); + re = NULL; + + re = CRegEx::NewLC(_L8("(.*)")); + CHECK(!re->FullMatchL(_L8("1234"), (TInt8*)NULL)); + CleanupStack::PopAndDestroy(re); + re = NULL; + + re = CRegEx::NewLC(_L8("(.*)")); + CHECK(!re->FullMatchL(_L8("123456"), (TInt16*)NULL)); + CleanupStack::PopAndDestroy(re); + re = NULL; + + re = CRegEx::NewLC(_L8("(.*)")); + CHECK(!re->FullMatchL(_L8("12345678901"), (TInt32*)NULL)); + CleanupStack::PopAndDestroy(re); + re = NULL; + + re = CRegEx::NewLC(_L8("(.*)")); + CHECK(!re->FullMatchL(_L8("12345678901"), (TInt*)NULL)); + CleanupStack::PopAndDestroy(re); + re = NULL; + + re = CRegEx::NewLC(_L8("(.*)")); + CHECK(!re->FullMatchL(_L8("1234"), (TUint8*)NULL)); + CleanupStack::PopAndDestroy(re); + re = NULL; + + re = CRegEx::NewLC(_L8("(.*)")); + CHECK(!re->FullMatchL(_L8("123456"), (TUint16*)NULL)); + CleanupStack::PopAndDestroy(re); + re = NULL; + + re = CRegEx::NewLC(_L8("(.*)")); + CHECK(!re->FullMatchL(_L8("12345678901"), (TUint32*)NULL)); + CleanupStack::PopAndDestroy(re); + re = NULL; + + re = CRegEx::NewLC(_L8("(.*)")); + CHECK(!re->FullMatchL(_L8("12345678901"), (TUint*)NULL)); + CleanupStack::PopAndDestroy(re); + re = NULL; + + // Ignored arg + re = CRegEx::NewLC(_L8("(\\w+)(:)(\\d+)")); + CHECK(re->FullMatchL(_L8("ruby:1234"), &s, (TAny*)NULL, &i)); + CleanupStack::PopAndDestroy(re); + CHECK_EQ(s, _L8("ruby")); + CHECK_EQ(i, 1234); + re = NULL; + +// Type tests + { + TChar c; + re = CRegEx::NewLC(_L8("(H)ello")); + CHECK(re->FullMatchL(_L8("Hello"), &c)); + CHECK_EQ(c, 'H'); + CleanupStack::PopAndDestroy(re); + re = NULL; + } + { + TInt8 v; + re = CRegEx::NewLC(_L8("(-?\\d+)")); + CHECK(re->FullMatchL(_L8("100"), &v)); + CHECK_EQ(v, 100); + CleanupStack::PopAndDestroy(re); + re = NULL; + + re = CRegEx::NewLC(_L8("(-?\\d+)")); + CHECK(re->FullMatchL(_L8("-100"), &v)); + CHECK_EQ(v, -100); + CleanupStack::PopAndDestroy(re); + re = NULL; + + re = CRegEx::NewLC(_L8("(-?\\d+)")); + CHECK(re->FullMatchL(_L8("127"), &v)); + CHECK_EQ(v, KMaxTInt8); + CleanupStack::PopAndDestroy(re); + re = NULL; + + re = CRegEx::NewLC(_L8("(-?\\d+)")); + CHECK(re->FullMatchL(_L8("-128"), &v)); + CHECK_EQ(v, KMinTInt8); + CleanupStack::PopAndDestroy(re); + re = NULL; + + re = CRegEx::NewLC(_L8("(-?\\d+)")); + CHECK(!re->FullMatchL(_L8("128"), &v)); + CleanupStack::PopAndDestroy(re); + re = NULL; + + re = CRegEx::NewLC(_L8("(-?\\d+)")); + CHECK(!re->FullMatchL(_L8("-129"), &v)); + CleanupStack::PopAndDestroy(re); + re = NULL; + } + { + TUint8 v; + re = CRegEx::NewLC(_L8("(\\d+)")); + CHECK(re->FullMatchL(_L8("100"), &v)); + CHECK_EQ(v, 100); + CleanupStack::PopAndDestroy(re); + re = NULL; + + re = CRegEx::NewLC(_L8("(\\d+)")); + CHECK(re->FullMatchL(_L8("128"), &v)); + CHECK_EQ(v, KMaxTInt8 + 1); + CleanupStack::PopAndDestroy(re); + re = NULL; + + re = CRegEx::NewLC(_L8("(\\d+)")); + CHECK(re->FullMatchL(_L8("255"), &v)); + CHECK_EQ(v, KMaxTUint8); + CleanupStack::PopAndDestroy(re); + re = NULL; + + re = CRegEx::NewLC(_L8("(\\d+)")); + CHECK(!re->FullMatchL(_L8("256"), &v)); + CleanupStack::PopAndDestroy(re); + re = NULL; + + re = CRegEx::NewLC(_L8("(\\d+)")); + CHECK(!re->FullMatchL(_L8("-100"), &v)); + CleanupStack::PopAndDestroy(re); + re = NULL; + } + { + TInt16 v; + re = CRegEx::NewLC(_L8("(-?\\d+)")); + CHECK(re->FullMatchL(_L8("100"), &v)); + CHECK_EQ(v, 100); + CleanupStack::PopAndDestroy(re); + re = NULL; + + re = CRegEx::NewLC(_L8("(-?\\d+)")); + CHECK(re->FullMatchL(_L8("-100"), &v)); + CHECK_EQ(v, -100); + CleanupStack::PopAndDestroy(re); + re = NULL; + + re = CRegEx::NewLC(_L8("(-?\\d+)")); + CHECK(re->FullMatchL(_L8("32767"), &v)); + CHECK_EQ(v, KMaxTInt16); + CleanupStack::PopAndDestroy(re); + re = NULL; + + re = CRegEx::NewLC(_L8("(-?\\d+)")); + CHECK(re->FullMatchL(_L8("-32768"), &v)); + CHECK_EQ(v, KMinTInt16); + CleanupStack::PopAndDestroy(re); + re = NULL; + + re = CRegEx::NewLC(_L8("(-?\\d+)")); + CHECK(!re->FullMatchL(_L8("32768"), &v)); + CleanupStack::PopAndDestroy(re); + re = NULL; + + re = CRegEx::NewLC(_L8("(-?\\d+)")); + CHECK(!re->FullMatchL(_L8("-32769"), &v)); + CleanupStack::PopAndDestroy(re); + re = NULL; + } + { + TUint16 v; + re = CRegEx::NewLC(_L8("(\\d+)")); + CHECK(re->FullMatchL(_L8("100"), &v)); + CHECK_EQ(v, 100); + CleanupStack::PopAndDestroy(re); + re = NULL; + + re = CRegEx::NewLC(_L8("(\\d+)")); + CHECK(re->FullMatchL(_L8("32767"), &v)); + CHECK_EQ(v, KMaxTInt16); + CleanupStack::PopAndDestroy(re); + re = NULL; + + re = CRegEx::NewLC(_L8("(\\d+)")); + CHECK(re->FullMatchL(_L8("65535"), &v)); + CHECK_EQ(v, KMaxTUint16); + CleanupStack::PopAndDestroy(re); + re = NULL; + + re = CRegEx::NewLC(_L8("(\\d+)")); + CHECK(!re->FullMatchL(_L8("655356"), &v)); + CleanupStack::PopAndDestroy(re); + re = NULL; + + re = CRegEx::NewLC(_L8("(\\d+)")); + CHECK(!re->FullMatchL(_L8("-100"), &v)); + CleanupStack::PopAndDestroy(re); + re = NULL; + } + { + TInt32 v; + re = CRegEx::NewLC(_L8("(-?\\d+)")); + CHECK(re->FullMatchL(_L8("100"), &v)); + CHECK_EQ(v, 100); + CleanupStack::PopAndDestroy(re); + re = NULL; + + re = CRegEx::NewLC(_L8("(-?\\d+)")); + CHECK(re->FullMatchL(_L8("-100"), &v)); + CHECK_EQ(v, -100); + CleanupStack::PopAndDestroy(re); + re = NULL; + + re = CRegEx::NewLC(_L8("(-?\\d+)")); + CHECK(re->FullMatchL(_L8("2147483647"), &v)); + CHECK_EQ(v, KMaxTInt32); + CleanupStack::PopAndDestroy(re); + re = NULL; + + re = CRegEx::NewLC(_L8("(-?\\d+)")); + CHECK(re->FullMatchL(_L8("-2147483648"), &v)); + CHECK_EQ(v, KMinTInt32); + CleanupStack::PopAndDestroy(re); + re = NULL; + + re = CRegEx::NewLC(_L8("(-?\\d+)")); + CHECK(!re->FullMatchL(_L8("2147483648"), &v)); + CleanupStack::PopAndDestroy(re); + re = NULL; + + re = CRegEx::NewLC(_L8("(-?\\d+)")); + CHECK(!re->FullMatchL(_L8("-2147483649"), &v)); + CleanupStack::PopAndDestroy(re); + re = NULL; + } + { + TUint32 v; + re = CRegEx::NewLC(_L8("(\\d+)")); + CHECK(re->FullMatchL(_L8("100"), &v)); + CHECK_EQ(v, 100); + CleanupStack::PopAndDestroy(re); + re = NULL; + + re = CRegEx::NewLC(_L8("(\\d+)")); + CHECK(re->FullMatchL(_L8("2147483647"), &v)); + CHECK_EQ(v, KMaxTInt32); + CleanupStack::PopAndDestroy(re); + re = NULL; + + re = CRegEx::NewLC(_L8("(\\d+)")); + CHECK(re->FullMatchL(_L8("4294967295"), &v)); + CHECK_EQ(v, KMaxTUint32); + CleanupStack::PopAndDestroy(re); + re = NULL; + + re = CRegEx::NewLC(_L8("(\\d+)")); + CHECK(!re->FullMatchL(_L8("4294967296"), &v)); + CleanupStack::PopAndDestroy(re); + re = NULL; + + re = CRegEx::NewLC(_L8("(\\d+)")); + CHECK(!re->FullMatchL(_L8("-100"), &v)); + CleanupStack::PopAndDestroy(re); + re = NULL; + } + { + TInt64 v; + // Note TLex treats TInt64 as unsigned + re = CRegEx::NewLC(_L8("(-?\\d+)")); + CHECK(re->FullMatchL(_L8("100"), &v)); + CHECK_EQ(v, 100); + CleanupStack::PopAndDestroy(re); + re = NULL; + + re = CRegEx::NewLC(_L8("(-?\\d+)")); + CHECK(re->FullMatchL(_L8("9223372036854775807"), &v)); + CHECK_EQ(v, KMaxTInt64); + CleanupStack::PopAndDestroy(re); + re = NULL; + + re = CRegEx::NewLC(_L8("(-?\\d+)")); + CHECK(!re->FullMatchL(_L8("-100"), &v)); + CleanupStack::PopAndDestroy(re); + re = NULL; + + re = CRegEx::NewLC(_L8("(-?\\d+)")); + CHECK(!re->FullMatchL(_L8("-9223372036854775808"), &v)); + CleanupStack::PopAndDestroy(re); + re = NULL; + + re = CRegEx::NewLC(_L8("(-?\\d+)")); + CHECK(!re->FullMatchL(_L8("9223372036854775808"), &v)); + CleanupStack::PopAndDestroy(re); + re = NULL; + + re = CRegEx::NewLC(_L8("(-?\\d+)")); + CHECK(!re->FullMatchL(_L8("-9223372036854775809"), &v)); + CleanupStack::PopAndDestroy(re); + re = NULL; + } + { + TInt v; + re = CRegEx::NewLC(_L8("(-?\\d+)")); + CHECK(re->FullMatchL(_L8("100"), &v)); + CHECK_EQ(v, 100); + CleanupStack::PopAndDestroy(re); + re = NULL; + + re = CRegEx::NewLC(_L8("(-?\\d+)")); + CHECK(re->FullMatchL(_L8("-100"), &v)); + CHECK_EQ(v, -100); + CleanupStack::PopAndDestroy(re); + re = NULL; + + re = CRegEx::NewLC(_L8("(-?\\d+)")); + CHECK(re->FullMatchL(_L8("2147483647"), &v)); + CHECK_EQ(v, KMaxTInt); + CleanupStack::PopAndDestroy(re); + re = NULL; + + re = CRegEx::NewLC(_L8("(-?\\d+)")); + CHECK(re->FullMatchL(_L8("-2147483648"), &v)); + CHECK_EQ(v, KMinTInt); + CleanupStack::PopAndDestroy(re); + re = NULL; + + re = CRegEx::NewLC(_L8("(-?\\d+)")); + CHECK(!re->FullMatchL(_L8("2147483648"), &v)); + CleanupStack::PopAndDestroy(re); + re = NULL; + + re = CRegEx::NewLC(_L8("(-?\\d+)")); + CHECK(!re->FullMatchL(_L8("-2147483649"), &v)); + CleanupStack::PopAndDestroy(re); + re = NULL; + } + { + TUint v; + re = CRegEx::NewLC(_L8("(\\d+)")); + CHECK(re->FullMatchL(_L8("100"), &v)); + CHECK_EQ(v, 100); + CleanupStack::PopAndDestroy(re); + re = NULL; + + re = CRegEx::NewLC(_L8("(\\d+)")); + CHECK(re->FullMatchL(_L8("2147483647"), &v)); + CHECK_EQ(v, KMaxTInt); + CleanupStack::PopAndDestroy(re); + re = NULL; + + re = CRegEx::NewLC(_L8("(\\d+)")); + CHECK(re->FullMatchL(_L8("4294967295"), &v)); + CHECK_EQ(v, KMaxTUint); + CleanupStack::PopAndDestroy(re); + + re = NULL; + + re = CRegEx::NewLC(_L8("(\\d+)")); + CHECK(!re->FullMatchL(_L8("4294967296"), &v)); + CleanupStack::PopAndDestroy(re); + re = NULL; + + re = CRegEx::NewLC(_L8("(\\d+)")); + CHECK(!re->FullMatchL(_L8("-100"), &v)); + CleanupStack::PopAndDestroy(re); + re = NULL; + } + { + TReal32 v; + re = CRegEx::NewLC(_L8("(.*)")); + CHECK(re->FullMatchL(_L8("100"), &v)); + CHECK_EQ(v, 100); + CleanupStack::PopAndDestroy(re); + re = NULL; + + re = CRegEx::NewLC(_L8("(.*)")); + CHECK(re->FullMatchL(_L8("-100"), &v)); + CHECK_EQ(v, -100); + CleanupStack::PopAndDestroy(re); + re = NULL; + + re = CRegEx::NewLC(_L8("(.*)")); + CHECK(re->FullMatchL(_L8("3.4028234663852885981170418348452e+38"), &v)); + CleanupStack::PopAndDestroy(re); + re = NULL; + + re = CRegEx::NewLC(_L8("(.*)")); + CHECK(re->FullMatchL(_L8("-1.17549435E-38f"), &v)); + CleanupStack::PopAndDestroy(re); + re = NULL; + } + { + TReal64 v; + re = CRegEx::NewLC(_L8("(.*)")); + CHECK(re->FullMatchL(_L8("100"), &v)); + CHECK_EQ(v, 100); + CleanupStack::PopAndDestroy(re); + re = NULL; + + re = CRegEx::NewLC(_L8("(.*)")); + CHECK(re->FullMatchL(_L8("-100"), &v)); + CHECK_EQ(v, -100); + CleanupStack::PopAndDestroy(re); + re = NULL; + + re = CRegEx::NewLC(_L8("(.*)")); + CHECK(re->FullMatchL(_L8("1.7976931348623157E+308"), &v)); + CleanupStack::PopAndDestroy(re); + re = NULL; + + re = CRegEx::NewLC(_L8("(.*)")); + CHECK(re->FullMatchL(_L8("-2.2250738585072015E-308"), &v)); + CleanupStack::PopAndDestroy(re); + re = NULL; + } + + // Check that matching is fully anchored + re = CRegEx::NewLC(_L8("(\\d+)")); + CHECK(!re->FullMatchL(_L8("x1001"), &i)); + CleanupStack::PopAndDestroy(re); + re = NULL; + + re = CRegEx::NewLC(_L8("(\\d+)")); + CHECK(!re->FullMatchL(_L8("1001x"), &i)); + CleanupStack::PopAndDestroy(re); + re = NULL; + + re = CRegEx::NewLC(_L8("x(\\d+)")); + CHECK(re->FullMatchL(_L8("x1001"), &i)); + CleanupStack::PopAndDestroy(re); + CHECK_EQ(i, 1001); + re = NULL; + + re = CRegEx::NewLC(_L8("(\\d+)x")); + CHECK(re->FullMatchL(_L8("1001x"), &i)); + CleanupStack::PopAndDestroy(re); + CHECK_EQ(i, 1001); + re = NULL; + + // Braces + re = CRegEx::NewLC(_L8("[0-9a-f+.-]{5,}")); + CHECK(re->FullMatchL(_L8("0abcd"))); + CleanupStack::PopAndDestroy(re); + re = NULL; + + re = CRegEx::NewLC(_L8("[0-9a-f+.-]{5,}")); + CHECK(re->FullMatchL(_L8("0abcde"))); + CleanupStack::PopAndDestroy(re); + re = NULL; + + re = CRegEx::NewLC(_L8("[0-9a-f+.-]{5,}")); + CHECK(!re->FullMatchL(_L8("0abc"))); + CleanupStack::PopAndDestroy(re); + re = NULL; + + // Complicated RE + re = CRegEx::NewLC(_L8("foo|bar|[A-Z]")); + CHECK(re->FullMatchL(_L8("foo"))); + CleanupStack::PopAndDestroy(re); + re = NULL; + + re = CRegEx::NewLC(_L8("foo|bar|[A-Z]")); + CHECK(re->FullMatchL(_L8("bar"))); + CleanupStack::PopAndDestroy(re); + re = NULL; + + re = CRegEx::NewLC(_L8("foo|bar|[A-Z]")); + CHECK(re->FullMatchL(_L8("X"))); + CleanupStack::PopAndDestroy(re); + re = NULL; + + re = CRegEx::NewLC(_L8("foo|bar|[A-Z]")); + CHECK(!re->FullMatchL(_L8("XY"))); + CleanupStack::PopAndDestroy(re); + re = NULL; + + // Check full-match handling (needs '$' tacked on internally) + re = CRegEx::NewLC(_L8("fo|foo")); + CHECK(re->FullMatchL(_L8("fo"))); + CleanupStack::PopAndDestroy(re); + re = NULL; + + re = CRegEx::NewLC(_L8("fo|foo")); + CHECK(re->FullMatchL(_L8("foo"))); + CleanupStack::PopAndDestroy(re); + re = NULL; + + re = CRegEx::NewLC(_L8("fo|foo$")); + CHECK(re->FullMatchL(_L8("fo"))); + CleanupStack::PopAndDestroy(re); + re = NULL; + + re = CRegEx::NewLC(_L8("fo|foo$")); + CHECK(re->FullMatchL(_L8("foo"))); + CleanupStack::PopAndDestroy(re); + re = NULL; + + re = CRegEx::NewLC(_L8("foo$")); + CHECK(re->FullMatchL(_L8("foo"))); + CleanupStack::PopAndDestroy(re); + re = NULL; + + re = CRegEx::NewLC(_L8("foo\\$")); + CHECK(!re->FullMatchL(_L8("foo$bar"))); + CleanupStack::PopAndDestroy(re); + re = NULL; + + re = CRegEx::NewLC(_L8("fo|bar")); + CHECK(!re->FullMatchL(_L8("fox"))); + CleanupStack::PopAndDestroy(re); + re = NULL; + + // Uncomment the following if we change the handling of '$' to + // prevent it from matching a trailing newline + if (false) + { + // Check that we don't get bitten by pcre's special handling of a + // '\n' at the end of the string matching '$' + re = CRegEx::NewLC(_L8("foo$")); + CHECK(!re->PartialMatchL(_L8("foo\n"))); + CleanupStack::PopAndDestroy(re); + re = NULL; + } + + // Number of args + TInt a[16]; + + re = CRegEx::NewLC(_L8("")); + CHECK(re->FullMatchL(_L8(""))); + CleanupStack::PopAndDestroy(re); + re = NULL; + + memset(a, 0, sizeof(0)); + re = CRegEx::NewLC(_L8("(\\d){1}")); + CHECK(re->FullMatchL(_L8("1"), &a[0])); + CHECK_EQ(a[0], 1); + CleanupStack::PopAndDestroy(re); + re = NULL; + + memset(a, 0, sizeof(0)); + re = CRegEx::NewLC(_L8("(\\d)(\\d)")); + CHECK(re->FullMatchL(_L8("12"), &a[0], &a[1])); + CHECK_EQ(a[0], 1); + CHECK_EQ(a[1], 2); + CleanupStack::PopAndDestroy(re); + re = NULL; + + memset(a, 0, sizeof(0)); + re = CRegEx::NewLC(_L8("(\\d)(\\d)(\\d)")); + CHECK(re->FullMatchL(_L8("123"), &a[0], &a[1], &a[2])); + CHECK_EQ(a[0], 1); + CHECK_EQ(a[1], 2); + CHECK_EQ(a[2], 3); + CleanupStack::PopAndDestroy(re); + re = NULL; + + memset(a, 0, sizeof(0)); + re = CRegEx::NewLC(_L8("(\\d)(\\d)(\\d)(\\d)")); + CHECK(re->FullMatchL(_L8("1234"), &a[0], &a[1], &a[2], &a[3])); + CHECK_EQ(a[0], 1); + CHECK_EQ(a[1], 2); + CHECK_EQ(a[2], 3); + CHECK_EQ(a[3], 4); + CleanupStack::PopAndDestroy(re); + re = NULL; + + // Currently maximum args == 4 + /* + memset(a, 0, sizeof(0)); + re = CRegEx::NewLC(_L8("(\\d)(\\d)(\\d)(\\d)(\\d)")); + CHECK(re->FullMatchL(_L8("12345"), &a[0], &a[1], &a[2], &a[3], &a[4])); + CHECK_EQ(a[0], 1); + CHECK_EQ(a[1], 2); + CHECK_EQ(a[2], 3); + CHECK_EQ(a[3], 4); + CHECK_EQ(a[4], 5); + CleanupStack::PopAndDestroy(re); + re = NULL; + + memset(a, 0, sizeof(0)); + re = CRegEx::NewLC(_L8("(\\d)(\\d)(\\d)(\\d)(\\d)(\\d)")); + CHECK(re->FullMatchL(_L8("123456"), &a[0], &a[1], &a[2], &a[3], &a[4], &a[5])); + CHECK_EQ(a[0], 1); + CHECK_EQ(a[1], 2); + CHECK_EQ(a[2], 3); + CHECK_EQ(a[3], 4); + CHECK_EQ(a[4], 5); + CHECK_EQ(a[5], 6); + CleanupStack::PopAndDestroy(re); + re = NULL; + + memset(a, 0, sizeof(0)); + re = CRegEx::NewLC(_L8("(\\d)(\\d)(\\d)(\\d)(\\d)(\\d)(\\d)")); + CHECK(re->FullMatchL(_L8("1234567"), &a[0], &a[1], &a[2], &a[3], &a[4], &a[5], &a[6])); + CHECK_EQ(a[0], 1); + CHECK_EQ(a[1], 2); + CHECK_EQ(a[2], 3); + CHECK_EQ(a[3], 4); + CHECK_EQ(a[4], 5); + CHECK_EQ(a[5], 6); + CHECK_EQ(a[6], 7); + CleanupStack::PopAndDestroy(re); + re = NULL; + + memset(a, 0, sizeof(0)); + re + = CRegEx::NewLC( + _L8("(\\d)(\\d)(\\d)(\\d)(\\d)(\\d)(\\d)(\\d)(\\d)(\\d)(\\d)(\\d)(\\d)(\\d)(\\d)(\\d)")); + CHECK(re->FullMatchL(_L8("1234567890123456"), &a[0], &a[1], &a[2], &a[3], + &a[4], &a[5], &a[6], &a[7], + &a[8], &a[9], &a[10], &a[11], + &a[12],&a[13], &a[14], &a[15])); + CHECK_EQ(a[0], 1); + CHECK_EQ(a[1], 2); + CHECK_EQ(a[2], 3); + CHECK_EQ(a[3], 4); + CHECK_EQ(a[4], 5); + CHECK_EQ(a[5], 6); + CHECK_EQ(a[6], 7); + CHECK_EQ(a[7], 8); + CHECK_EQ(a[8], 9); + CHECK_EQ(a[9], 0); + CHECK_EQ(a[10], 1); + CHECK_EQ(a[11], 2); + CHECK_EQ(a[12], 3); + CHECK_EQ(a[13], 4); + CHECK_EQ(a[14], 5); + CHECK_EQ(a[15], 6); + CleanupStack::PopAndDestroy(re); + re = NULL; + */ + + /***** PartialMatch *****/ + console->Write(_L("Testing PartialMatch\n")); + + re = CRegEx::NewLC(_L8("h.*o")); + CHECK(re->PartialMatchL(_L8("hello"))); + CleanupStack::PopAndDestroy(re); + re = NULL; + + re = CRegEx::NewLC(_L8("h.*o")); + CHECK(re->PartialMatchL(_L8("othello"))); + CleanupStack::PopAndDestroy(re); + re = NULL; + + re = CRegEx::NewLC(_L8("h.*o")); + CHECK(re->PartialMatchL(_L8("hello!"))); + CleanupStack::PopAndDestroy(re); + re = NULL; + + re = CRegEx::NewLC(_L8("((((((((((((((((((((x))))))))))))))))))))")); + CHECK(re->PartialMatchL(_L8("x"))); + CleanupStack::PopAndDestroy(re); + re = NULL; + + /***** other tests *****/ + + RadixTestsL(); + TestReplaceL(); + TestExtractL(); + TestConsumeL(); + TestFindAndConsumeL(); + TestQuoteMetaAllL(); + TestMatchNumberPeculiarityL(); + + // Check the pattern() accessor + { + _LIT8(KPattern, "http://([^/]+)/.*"); + re = CRegEx::NewLC(KPattern()); + CHECK_EQ(KPattern(), re->Pattern()); + CleanupStack::PopAndDestroy(re); + re = NULL; + } + // Check RE error field. + { + re = CRegEx::NewLC(_L8("foo")); + CHECK_EQ(re->Error(), KErrNone); // Must have no error + CleanupStack::PopAndDestroy(re); + re = NULL; + } + +#ifdef SUPPORT_UTF8 + // Check UTF-8 handling + { + console->Write(_L("Testing UTF-8 handling\n")); + + // Three Japanese characters (nihongo) + TBuf8<9> utf8String(_L8("\xE6\x97\xA5\xE6\x9C\xAC\xE8\xAA\x9E")); + TBuf8<5> utf8Pattern(_L8(".\xE6\x9C\xAC.")); + TRegExOptions utf8Options; + utf8Options.SetUtf8(ETrue); + + // Both should match in either mode, bytes or UTF-8 + CRegEx* re_test1 = CRegEx::NewLC(_L8(".........")); + CHECK(re_test1->FullMatchL(utf8String)); + CleanupStack::PopAndDestroy(re_test1); + re_test1 = NULL; + + CRegEx* re_test2 = CRegEx::NewLC(_L8("..."), utf8Options); + CHECK(re_test2->FullMatchL(utf8String)); + CleanupStack::PopAndDestroy(re_test2); + re_test2 = NULL; + + // Check that '.' matches one byte or UTF-8 character + // according to the mode. + TBuf8<3> ss; + + CRegEx* re_test3 = CRegEx::NewLC(_L8("(.)")); + CHECK(re_test3->PartialMatchL(utf8String, &ss)); + CHECK_EQ(ss, _L8("\xE6")); + CleanupStack::PopAndDestroy(re_test3); + re_test3 = NULL; + + CRegEx* re_test4 = CRegEx::NewLC(_L8("(.)"), utf8Options); + CHECK(re_test4->PartialMatchL(utf8String, &ss)); + CHECK_EQ(ss, _L8("\xE6\x97\xA5")); + CleanupStack::PopAndDestroy(re_test4); + re_test4 = NULL; + + // Check that string matches itself in either mode + CRegEx* re_test5 = CRegEx::NewLC(utf8String); + CHECK(re_test5->FullMatchL(utf8String)); + CleanupStack::PopAndDestroy(re_test5); + re_test5 = NULL; + + CRegEx* re_test6 = CRegEx::NewLC(utf8String, utf8Options); + CHECK(re_test6->FullMatchL(utf8String)); + CleanupStack::PopAndDestroy(re_test6); + re_test6 = NULL; + + // Check that pattern matches string only in UTF8 mode + CRegEx* re_test7 = CRegEx::NewLC(utf8Pattern); + CHECK(!re_test7->FullMatchL(utf8String)); + CleanupStack::PopAndDestroy(re_test7); + re_test7 = NULL; + + CRegEx* re_test8 = CRegEx::NewLC(utf8Pattern, utf8Options); + CHECK(re_test8->FullMatchL(utf8String)); + CleanupStack::PopAndDestroy(re_test8); + re_test8 = NULL; + } + + // Check that ungreedy, UTF8 regular expressions don't match when they + // oughtn't -- see bug 82246. + { + // This code always worked. + _LIT8(KPattern, "\\w+X"); + _LIT8(KTarget, "a aX"); + + TRegExOptions utf8Options; + utf8Options.SetUtf8(ETrue); + + CRegEx* matchSentence = CRegEx::NewLC(KPattern()); + CHECK(!matchSentence->FullMatchL(KTarget())); + CleanupStack::PopAndDestroy(matchSentence); + matchSentence = NULL; + + CRegEx* matchSentenceRe = CRegEx::NewLC(KPattern(), utf8Options); + CHECK(!matchSentenceRe->FullMatchL(KTarget())); + CleanupStack::PopAndDestroy(matchSentenceRe); + matchSentenceRe = NULL; + } + { + _LIT8(KPattern, "(?U)\\w+X"); + _LIT8(KTarget, "a aX"); + + TRegExOptions utf8Options; + utf8Options.SetUtf8(ETrue); + + CRegEx* matchSentence = CRegEx::NewLC(KPattern()); + CHECK(!matchSentence->FullMatchL(KTarget())); + CleanupStack::PopAndDestroy(matchSentence); + matchSentence = NULL; + + CRegEx* matchSentenceRe = CRegEx::NewLC(KPattern(), utf8Options); + CHECK(!matchSentenceRe->FullMatchL(KTarget())); + CleanupStack::PopAndDestroy(matchSentenceRe); + matchSentenceRe = NULL; + } + +#endif /* def SUPPORT_UTF8 */ + + console->Write(_L("Testing error reporting\n")); + { + TRAPD(err, re = CRegEx::NewLC(_L8("a\\1")); CleanupStack::PopAndDestroy()); + CHECK(err != KErrNone); + re = NULL; + } + { + TRAPD(err, re = CRegEx::NewLC(_L8("a[x")); CleanupStack::PopAndDestroy()); + CHECK(err != KErrNone); + re = NULL; + } + { + TRAPD(err, re = CRegEx::NewLC(_L8("a[z-a]")); CleanupStack::PopAndDestroy()); + CHECK(err != KErrNone); + re = NULL; + } + { + TRAPD(err, re = CRegEx::NewLC(_L8("a[[:foobar:]]")); CleanupStack::PopAndDestroy()); + CHECK(err != KErrNone); + re = NULL; + } + { + TRAPD(err, re = CRegEx::NewLC(_L8("a(b")); CleanupStack::PopAndDestroy()); + CHECK(err != KErrNone); + re = NULL; + } + { + TRAPD(err, re = CRegEx::NewLC(_L8("a\\")); CleanupStack::PopAndDestroy()); + CHECK(err != KErrNone); + re = NULL; + } + + // Test that recursion is stopped + TestRecursionL(); + + // Test Options + TestOptionsL(); + + // Done + console->Write(_L("OK\n")); + } +LOCAL_C void DoStartL() + { + // Create active scheduler (to run active objects) + CActiveScheduler* scheduler = new (ELeave) CActiveScheduler(); + CleanupStack::PushL(scheduler); + CActiveScheduler::Install(scheduler); + + MainL(); + + // Delete active scheduler + CleanupStack::PopAndDestroy(scheduler); + } + +// Global Functions + +GLDEF_C TInt E32Main() + { + // Create cleanup stack + __UHEAP_MARK; + CTrapCleanup* cleanup = CTrapCleanup::New(); + // Create output console + TRAPD(createError, console = Console::NewL(KTextConsoleTitle, TSize( + KConsFullScreen, KConsFullScreen))); + if (createError) + return createError; + // Run application code inside TRAP harness, wait keypress when terminated + TRAPD(mainError, DoStartL()); + if (mainError) + console->Printf(KTextFailed, mainError); + console->Printf(KTextPressAnyKey); + console->Getch(); + + delete console; + delete cleanup; + __UHEAP_MARKEND; + return KErrNone; + }