tools/pcre/pcrecpp_unittest.cc
author David Anderson <dvander@alliedmods.net>
Thu Oct 29 00:06:12 2009 -0700 (2009-10-29)
changeset 2844 87f951bece2d
parent 2762 d2d467bf1b5a
child 3831 babd0eee3c5e
permissions -rw-r--r--
Fix iloop race when using AddCommandListener and SourceMod unloads (bug 4077, r=pred).
dvander@2762
     1
// -*- coding: utf-8 -*-
dvander@2762
     2
//
dvander@2762
     3
// Copyright (c) 2005 - 2006, Google Inc.
dvander@2762
     4
// All rights reserved.
dvander@2762
     5
//
dvander@2762
     6
// Redistribution and use in source and binary forms, with or without
dvander@2762
     7
// modification, are permitted provided that the following conditions are
dvander@2762
     8
// met:
dvander@2762
     9
//
dvander@2762
    10
//     * Redistributions of source code must retain the above copyright
dvander@2762
    11
// notice, this list of conditions and the following disclaimer.
dvander@2762
    12
//     * Redistributions in binary form must reproduce the above
dvander@2762
    13
// copyright notice, this list of conditions and the following disclaimer
dvander@2762
    14
// in the documentation and/or other materials provided with the
dvander@2762
    15
// distribution.
dvander@2762
    16
//     * Neither the name of Google Inc. nor the names of its
dvander@2762
    17
// contributors may be used to endorse or promote products derived from
dvander@2762
    18
// this software without specific prior written permission.
dvander@2762
    19
//
dvander@2762
    20
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
dvander@2762
    21
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
dvander@2762
    22
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
dvander@2762
    23
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
dvander@2762
    24
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
dvander@2762
    25
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
dvander@2762
    26
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
dvander@2762
    27
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
dvander@2762
    28
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
dvander@2762
    29
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
dvander@2762
    30
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
dvander@2762
    31
//
dvander@2762
    32
// Author: Sanjay Ghemawat
dvander@2762
    33
//
dvander@2762
    34
// TODO: Test extractions for PartialMatch/Consume
dvander@2762
    35
dvander@2762
    36
#ifdef HAVE_CONFIG_H
dvander@2762
    37
#include "config.h"
dvander@2762
    38
#endif
dvander@2762
    39
dvander@2762
    40
#include <stdio.h>
dvander@2762
    41
#include <cassert>
dvander@2762
    42
#include <vector>
dvander@2762
    43
#include "pcrecpp.h"
dvander@2762
    44
dvander@2762
    45
using pcrecpp::StringPiece;
dvander@2762
    46
using pcrecpp::RE;
dvander@2762
    47
using pcrecpp::RE_Options;
dvander@2762
    48
using pcrecpp::Hex;
dvander@2762
    49
using pcrecpp::Octal;
dvander@2762
    50
using pcrecpp::CRadix;
dvander@2762
    51
dvander@2762
    52
static bool VERBOSE_TEST  = false;
dvander@2762
    53
dvander@2762
    54
// CHECK dies with a fatal error if condition is not true.  It is *not*
dvander@2762
    55
// controlled by NDEBUG, so the check will be executed regardless of
dvander@2762
    56
// compilation mode.  Therefore, it is safe to do things like:
dvander@2762
    57
//    CHECK_EQ(fp->Write(x), 4)
dvander@2762
    58
#define CHECK(condition) do {                           \
dvander@2762
    59
  if (!(condition)) {                                   \
dvander@2762
    60
    fprintf(stderr, "%s:%d: Check failed: %s\n",        \
dvander@2762
    61
            __FILE__, __LINE__, #condition);            \
dvander@2762
    62
    exit(1);                                            \
dvander@2762
    63
  }                                                     \
dvander@2762
    64
} while (0)
dvander@2762
    65
dvander@2762
    66
#define CHECK_EQ(a, b)   CHECK(a == b)
dvander@2762
    67
dvander@2762
    68
static void Timing1(int num_iters) {
dvander@2762
    69
  // Same pattern lots of times
dvander@2762
    70
  RE pattern("ruby:\\d+");
dvander@2762
    71
  StringPiece p("ruby:1234");
dvander@2762
    72
  for (int j = num_iters; j > 0; j--) {
dvander@2762
    73
    CHECK(pattern.FullMatch(p));
dvander@2762
    74
  }
dvander@2762
    75
}
dvander@2762
    76
dvander@2762
    77
static void Timing2(int num_iters) {
dvander@2762
    78
  // Same pattern lots of times
dvander@2762
    79
  RE pattern("ruby:(\\d+)");
dvander@2762
    80
  int i;
dvander@2762
    81
  for (int j = num_iters; j > 0; j--) {
dvander@2762
    82
    CHECK(pattern.FullMatch("ruby:1234", &i));
dvander@2762
    83
    CHECK_EQ(i, 1234);
dvander@2762
    84
  }
dvander@2762
    85
}
dvander@2762
    86
dvander@2762
    87
static void Timing3(int num_iters) {
dvander@2762
    88
  string text_string;
dvander@2762
    89
  for (int j = num_iters; j > 0; j--) {
dvander@2762
    90
    text_string += "this is another line\n";
dvander@2762
    91
  }
dvander@2762
    92
dvander@2762
    93
  RE line_matcher(".*\n");
dvander@2762
    94
  string line;
dvander@2762
    95
  StringPiece text(text_string);
dvander@2762
    96
  int counter = 0;
dvander@2762
    97
  while (line_matcher.Consume(&text)) {
dvander@2762
    98
    counter++;
dvander@2762
    99
  }
dvander@2762
   100
  printf("Matched %d lines\n", counter);
dvander@2762
   101
}
dvander@2762
   102
dvander@2762
   103
#if 0  // uncomment this if you have a way of defining VirtualProcessSize()
dvander@2762
   104
dvander@2762
   105
static void LeakTest() {
dvander@2762
   106
  // Check for memory leaks
dvander@2762
   107
  unsigned long long initial_size = 0;
dvander@2762
   108
  for (int i = 0; i < 100000; i++) {
dvander@2762
   109
    if (i == 50000) {
dvander@2762
   110
      initial_size = VirtualProcessSize();
dvander@2762
   111
      printf("Size after 50000: %llu\n", initial_size);
dvander@2762
   112
    }
dvander@2762
   113
    char buf[100];  // definitely big enough
dvander@2762
   114
    sprintf(buf, "pat%09d", i);
dvander@2762
   115
    RE newre(buf);
dvander@2762
   116
  }
dvander@2762
   117
  uint64 final_size = VirtualProcessSize();
dvander@2762
   118
  printf("Size after 100000: %llu\n", final_size);
dvander@2762
   119
  const double growth = double(final_size - initial_size) / final_size;
dvander@2762
   120
  printf("Growth: %0.2f%%", growth * 100);
dvander@2762
   121
  CHECK(growth < 0.02);       // Allow < 2% growth
dvander@2762
   122
}
dvander@2762
   123
dvander@2762
   124
#endif
dvander@2762
   125
dvander@2762
   126
static void RadixTests() {
dvander@2762
   127
  printf("Testing hex\n");
dvander@2762
   128
dvander@2762
   129
#define CHECK_HEX(type, value) \
dvander@2762
   130
  do { \
dvander@2762
   131
    type v; \
dvander@2762
   132
    CHECK(RE("([0-9a-fA-F]+)[uUlL]*").FullMatch(#value, Hex(&v))); \
dvander@2762
   133
    CHECK_EQ(v, 0x ## value); \
dvander@2762
   134
    CHECK(RE("([0-9a-fA-FxX]+)[uUlL]*").FullMatch("0x" #value, CRadix(&v))); \
dvander@2762
   135
    CHECK_EQ(v, 0x ## value); \
dvander@2762
   136
  } while(0)
dvander@2762
   137
dvander@2762
   138
  CHECK_HEX(short,              2bad);
dvander@2762
   139
  CHECK_HEX(unsigned short,     2badU);
dvander@2762
   140
  CHECK_HEX(int,                dead);
dvander@2762
   141
  CHECK_HEX(unsigned int,       deadU);
dvander@2762
   142
  CHECK_HEX(long,               7eadbeefL);
dvander@2762
   143
  CHECK_HEX(unsigned long,      deadbeefUL);
dvander@2762
   144
#ifdef HAVE_LONG_LONG
dvander@2762
   145
  CHECK_HEX(long long,          12345678deadbeefLL);
dvander@2762
   146
#endif
dvander@2762
   147
#ifdef HAVE_UNSIGNED_LONG_LONG
dvander@2762
   148
  CHECK_HEX(unsigned long long, cafebabedeadbeefULL);
dvander@2762
   149
#endif
dvander@2762
   150
dvander@2762
   151
#undef CHECK_HEX
dvander@2762
   152
dvander@2762
   153
  printf("Testing octal\n");
dvander@2762
   154
dvander@2762
   155
#define CHECK_OCTAL(type, value) \
dvander@2762
   156
  do { \
dvander@2762
   157
    type v; \
dvander@2762
   158
    CHECK(RE("([0-7]+)[uUlL]*").FullMatch(#value, Octal(&v))); \
dvander@2762
   159
    CHECK_EQ(v, 0 ## value); \
dvander@2762
   160
    CHECK(RE("([0-9a-fA-FxX]+)[uUlL]*").FullMatch("0" #value, CRadix(&v))); \
dvander@2762
   161
    CHECK_EQ(v, 0 ## value); \
dvander@2762
   162
  } while(0)
dvander@2762
   163
dvander@2762
   164
  CHECK_OCTAL(short,              77777);
dvander@2762
   165
  CHECK_OCTAL(unsigned short,     177777U);
dvander@2762
   166
  CHECK_OCTAL(int,                17777777777);
dvander@2762
   167
  CHECK_OCTAL(unsigned int,       37777777777U);
dvander@2762
   168
  CHECK_OCTAL(long,               17777777777L);
dvander@2762
   169
  CHECK_OCTAL(unsigned long,      37777777777UL);
dvander@2762
   170
#ifdef HAVE_LONG_LONG
dvander@2762
   171
  CHECK_OCTAL(long long,          777777777777777777777LL);
dvander@2762
   172
#endif
dvander@2762
   173
#ifdef HAVE_UNSIGNED_LONG_LONG
dvander@2762
   174
  CHECK_OCTAL(unsigned long long, 1777777777777777777777ULL);
dvander@2762
   175
#endif
dvander@2762
   176
dvander@2762
   177
#undef CHECK_OCTAL
dvander@2762
   178
dvander@2762
   179
  printf("Testing decimal\n");
dvander@2762
   180
dvander@2762
   181
#define CHECK_DECIMAL(type, value) \
dvander@2762
   182
  do { \
dvander@2762
   183
    type v; \
dvander@2762
   184
    CHECK(RE("(-?[0-9]+)[uUlL]*").FullMatch(#value, &v)); \
dvander@2762
   185
    CHECK_EQ(v, value); \
dvander@2762
   186
    CHECK(RE("(-?[0-9a-fA-FxX]+)[uUlL]*").FullMatch(#value, CRadix(&v))); \
dvander@2762
   187
    CHECK_EQ(v, value); \
dvander@2762
   188
  } while(0)
dvander@2762
   189
dvander@2762
   190
  CHECK_DECIMAL(short,              -1);
dvander@2762
   191
  CHECK_DECIMAL(unsigned short,     9999);
dvander@2762
   192
  CHECK_DECIMAL(int,                -1000);
dvander@2762
   193
  CHECK_DECIMAL(unsigned int,       12345U);
dvander@2762
   194
  CHECK_DECIMAL(long,               -10000000L);
dvander@2762
   195
  CHECK_DECIMAL(unsigned long,      3083324652U);
dvander@2762
   196
#ifdef HAVE_LONG_LONG
dvander@2762
   197
  CHECK_DECIMAL(long long,          -100000000000000LL);
dvander@2762
   198
#endif
dvander@2762
   199
#ifdef HAVE_UNSIGNED_LONG_LONG
dvander@2762
   200
  CHECK_DECIMAL(unsigned long long, 1234567890987654321ULL);
dvander@2762
   201
#endif
dvander@2762
   202
dvander@2762
   203
#undef CHECK_DECIMAL
dvander@2762
   204
dvander@2762
   205
}
dvander@2762
   206
dvander@2762
   207
static void TestReplace() {
dvander@2762
   208
  printf("Testing Replace\n");
dvander@2762
   209
dvander@2762
   210
  struct ReplaceTest {
dvander@2762
   211
    const char *regexp;
dvander@2762
   212
    const char *rewrite;
dvander@2762
   213
    const char *original;
dvander@2762
   214
    const char *single;
dvander@2762
   215
    const char *global;
dvander@2762
   216
    int global_count;         // the expected return value from ReplaceAll
dvander@2762
   217
  };
dvander@2762
   218
  static const ReplaceTest tests[] = {
dvander@2762
   219
    { "(qu|[b-df-hj-np-tv-z]*)([a-z]+)",
dvander@2762
   220
      "\\2\\1ay",
dvander@2762
   221
      "the quick brown fox jumps over the lazy dogs.",
dvander@2762
   222
      "ethay quick brown fox jumps over the lazy dogs.",
dvander@2762
   223
      "ethay ickquay ownbray oxfay umpsjay overay ethay azylay ogsday.",
dvander@2762
   224
      9 },
dvander@2762
   225
    { "\\w+",
dvander@2762
   226
      "\\0-NOSPAM",
dvander@2762
   227
      "[email protected]",
dvander@2762
   228
      "[email protected]",
dvander@2762
   229
      "[email protected]",
dvander@2762
   230
      4 },
dvander@2762
   231
    { "^",
dvander@2762
   232
      "(START)",
dvander@2762
   233
      "foo",
dvander@2762
   234
      "(START)foo",
dvander@2762
   235
      "(START)foo",
dvander@2762
   236
      1 },
dvander@2762
   237
    { "^",
dvander@2762
   238
      "(START)",
dvander@2762
   239
      "",
dvander@2762
   240
      "(START)",
dvander@2762
   241
      "(START)",
dvander@2762
   242
      1 },
dvander@2762
   243
    { "$",
dvander@2762
   244
      "(END)",
dvander@2762
   245
      "",
dvander@2762
   246
      "(END)",
dvander@2762
   247
      "(END)",
dvander@2762
   248
      1 },
dvander@2762
   249
    { "b",
dvander@2762
   250
      "bb",
dvander@2762
   251
      "ababababab",
dvander@2762
   252
      "abbabababab",
dvander@2762
   253
      "abbabbabbabbabb",
dvander@2762
   254
       5 },
dvander@2762
   255
    { "b",
dvander@2762
   256
      "bb",
dvander@2762
   257
      "bbbbbb",
dvander@2762
   258
      "bbbbbbb",
dvander@2762
   259
      "bbbbbbbbbbbb",
dvander@2762
   260
      6 },
dvander@2762
   261
    { "b+",
dvander@2762
   262
      "bb",
dvander@2762
   263
      "bbbbbb",
dvander@2762
   264
      "bb",
dvander@2762
   265
      "bb",
dvander@2762
   266
      1 },
dvander@2762
   267
    { "b*",
dvander@2762
   268
      "bb",
dvander@2762
   269
      "bbbbbb",
dvander@2762
   270
      "bb",
dvander@2762
   271
      "bb",
dvander@2762
   272
      1 },
dvander@2762
   273
    { "b*",
dvander@2762
   274
      "bb",
dvander@2762
   275
      "aaaaa",
dvander@2762
   276
      "bbaaaaa",
dvander@2762
   277
      "bbabbabbabbabbabb",
dvander@2762
   278
      6 },
dvander@2762
   279
    { "b*",
dvander@2762
   280
      "bb",
dvander@2762
   281
      "aa\naa\n",
dvander@2762
   282
      "bbaa\naa\n",
dvander@2762
   283
      "bbabbabb\nbbabbabb\nbb",
dvander@2762
   284
      7 },
dvander@2762
   285
    { "b*",
dvander@2762
   286
      "bb",
dvander@2762
   287
      "aa\raa\r",
dvander@2762
   288
      "bbaa\raa\r",
dvander@2762
   289
      "bbabbabb\rbbabbabb\rbb",
dvander@2762
   290
      7 },
dvander@2762
   291
    { "b*",
dvander@2762
   292
      "bb",
dvander@2762
   293
      "aa\r\naa\r\n",
dvander@2762
   294
      "bbaa\r\naa\r\n",
dvander@2762
   295
      "bbabbabb\r\nbbabbabb\r\nbb",
dvander@2762
   296
      7 },
dvander@2762
   297
#ifdef SUPPORT_UTF8
dvander@2762
   298
    { "b*",
dvander@2762
   299
      "bb",
dvander@2762
   300
      "\xE3\x83\x9B\xE3\x83\xBC\xE3\x83\xA0\xE3\x81\xB8",   // utf8
dvander@2762
   301
      "bb\xE3\x83\x9B\xE3\x83\xBC\xE3\x83\xA0\xE3\x81\xB8",
dvander@2762
   302
      "bb\xE3\x83\x9B""bb""\xE3\x83\xBC""bb""\xE3\x83\xA0""bb""\xE3\x81\xB8""bb",
dvander@2762
   303
      5 },
dvander@2762
   304
    { "b*",
dvander@2762
   305
      "bb",
dvander@2762
   306
      "\xE3\x83\x9B\r\n\xE3\x83\xBC\r\xE3\x83\xA0\n\xE3\x81\xB8\r\n",   // utf8
dvander@2762
   307
      "bb\xE3\x83\x9B\r\n\xE3\x83\xBC\r\xE3\x83\xA0\n\xE3\x81\xB8\r\n",
dvander@2762
   308
      ("bb\xE3\x83\x9B""bb\r\nbb""\xE3\x83\xBC""bb\rbb""\xE3\x83\xA0"
dvander@2762
   309
       "bb\nbb""\xE3\x81\xB8""bb\r\nbb"),
dvander@2762
   310
      9 },
dvander@2762
   311
#endif
dvander@2762
   312
    { "", NULL, NULL, NULL, NULL, 0 }
dvander@2762
   313
  };
dvander@2762
   314
dvander@2762
   315
#ifdef SUPPORT_UTF8
dvander@2762
   316
  const bool support_utf8 = true;
dvander@2762
   317
#else
dvander@2762
   318
  const bool support_utf8 = false;
dvander@2762
   319
#endif
dvander@2762
   320
dvander@2762
   321
  for (const ReplaceTest *t = tests; t->original != NULL; ++t) {
dvander@2762
   322
    RE re(t->regexp, RE_Options(PCRE_NEWLINE_CRLF).set_utf8(support_utf8));
dvander@2762
   323
    assert(re.error().empty());
dvander@2762
   324
    string one(t->original);
dvander@2762
   325
    CHECK(re.Replace(t->rewrite, &one));
dvander@2762
   326
    CHECK_EQ(one, t->single);
dvander@2762
   327
    string all(t->original);
dvander@2762
   328
    const int replace_count = re.GlobalReplace(t->rewrite, &all);
dvander@2762
   329
    CHECK_EQ(all, t->global);
dvander@2762
   330
    CHECK_EQ(replace_count, t->global_count);
dvander@2762
   331
  }
dvander@2762
   332
dvander@2762
   333
  // One final test: test \r\n replacement when we're not in CRLF mode
dvander@2762
   334
  {
dvander@2762
   335
    RE re("b*", RE_Options(PCRE_NEWLINE_CR).set_utf8(support_utf8));
dvander@2762
   336
    assert(re.error().empty());
dvander@2762
   337
    string all("aa\r\naa\r\n");
dvander@2762
   338
    CHECK_EQ(re.GlobalReplace("bb", &all), 9);
dvander@2762
   339
    CHECK_EQ(all, string("bbabbabb\rbb\nbbabbabb\rbb\nbb"));
dvander@2762
   340
  }
dvander@2762
   341
  {
dvander@2762
   342
    RE re("b*", RE_Options(PCRE_NEWLINE_LF).set_utf8(support_utf8));
dvander@2762
   343
    assert(re.error().empty());
dvander@2762
   344
    string all("aa\r\naa\r\n");
dvander@2762
   345
    CHECK_EQ(re.GlobalReplace("bb", &all), 9);
dvander@2762
   346
    CHECK_EQ(all, string("bbabbabb\rbb\nbbabbabb\rbb\nbb"));
dvander@2762
   347
  }
dvander@2762
   348
  // TODO: test what happens when no PCRE_NEWLINE_* flag is set.
dvander@2762
   349
  //       Alas, the answer depends on how pcre was compiled.
dvander@2762
   350
}
dvander@2762
   351
dvander@2762
   352
static void TestExtract() {
dvander@2762
   353
  printf("Testing Extract\n");
dvander@2762
   354
dvander@2762
   355
  string s;
dvander@2762
   356
dvander@2762
   357
  CHECK(RE("(.*)@([^.]*)").Extract("\\2!\\1", "[email protected]", &s));
dvander@2762
   358
  CHECK_EQ(s, "kremvax!boris");
dvander@2762
   359
dvander@2762
   360
  // check the RE interface as well
dvander@2762
   361
  CHECK(RE(".*").Extract("'\\0'", "foo", &s));
dvander@2762
   362
  CHECK_EQ(s, "'foo'");
dvander@2762
   363
  CHECK(!RE("bar").Extract("'\\0'", "baz", &s));
dvander@2762
   364
  CHECK_EQ(s, "'foo'");
dvander@2762
   365
}
dvander@2762
   366
dvander@2762
   367
static void TestConsume() {
dvander@2762
   368
  printf("Testing Consume\n");
dvander@2762
   369
dvander@2762
   370
  string word;
dvander@2762
   371
dvander@2762
   372
  string s("   aaa b!@#$@#$cccc");
dvander@2762
   373
  StringPiece input(s);
dvander@2762
   374
dvander@2762
   375
  RE r("\\s*(\\w+)");    // matches a word, possibly proceeded by whitespace
dvander@2762
   376
  CHECK(r.Consume(&input, &word));
dvander@2762
   377
  CHECK_EQ(word, "aaa");
dvander@2762
   378
  CHECK(r.Consume(&input, &word));
dvander@2762
   379
  CHECK_EQ(word, "b");
dvander@2762
   380
  CHECK(! r.Consume(&input, &word));
dvander@2762
   381
}
dvander@2762
   382
dvander@2762
   383
static void TestFindAndConsume() {
dvander@2762
   384
  printf("Testing FindAndConsume\n");
dvander@2762
   385
dvander@2762
   386
  string word;
dvander@2762
   387
dvander@2762
   388
  string s("   aaa b!@#$@#$cccc");
dvander@2762
   389
  StringPiece input(s);
dvander@2762
   390
dvander@2762
   391
  RE r("(\\w+)");      // matches a word
dvander@2762
   392
  CHECK(r.FindAndConsume(&input, &word));
dvander@2762
   393
  CHECK_EQ(word, "aaa");
dvander@2762
   394
  CHECK(r.FindAndConsume(&input, &word));
dvander@2762
   395
  CHECK_EQ(word, "b");
dvander@2762
   396
  CHECK(r.FindAndConsume(&input, &word));
dvander@2762
   397
  CHECK_EQ(word, "cccc");
dvander@2762
   398
  CHECK(! r.FindAndConsume(&input, &word));
dvander@2762
   399
}
dvander@2762
   400
dvander@2762
   401
static void TestMatchNumberPeculiarity() {
dvander@2762
   402
  printf("Testing match-number peculiaraity\n");
dvander@2762
   403
dvander@2762
   404
  string word1;
dvander@2762
   405
  string word2;
dvander@2762
   406
  string word3;
dvander@2762
   407
dvander@2762
   408
  RE r("(foo)|(bar)|(baz)");
dvander@2762
   409
  CHECK(r.PartialMatch("foo", &word1, &word2, &word3));
dvander@2762
   410
  CHECK_EQ(word1, "foo");
dvander@2762
   411
  CHECK_EQ(word2, "");
dvander@2762
   412
  CHECK_EQ(word3, "");
dvander@2762
   413
  CHECK(r.PartialMatch("bar", &word1, &word2, &word3));
dvander@2762
   414
  CHECK_EQ(word1, "");
dvander@2762
   415
  CHECK_EQ(word2, "bar");
dvander@2762
   416
  CHECK_EQ(word3, "");
dvander@2762
   417
  CHECK(r.PartialMatch("baz", &word1, &word2, &word3));
dvander@2762
   418
  CHECK_EQ(word1, "");
dvander@2762
   419
  CHECK_EQ(word2, "");
dvander@2762
   420
  CHECK_EQ(word3, "baz");
dvander@2762
   421
  CHECK(!r.PartialMatch("f", &word1, &word2, &word3));
dvander@2762
   422
dvander@2762
   423
  string a;
dvander@2762
   424
  CHECK(RE("(foo)|hello").FullMatch("hello", &a));
dvander@2762
   425
  CHECK_EQ(a, "");
dvander@2762
   426
}
dvander@2762
   427
dvander@2762
   428
static void TestRecursion() {
dvander@2762
   429
  printf("Testing recursion\n");
dvander@2762
   430
dvander@2762
   431
  // Get one string that passes (sometimes), one that never does.
dvander@2762
   432
  string text_good("abcdefghijk");
dvander@2762
   433
  string text_bad("acdefghijkl");
dvander@2762
   434
dvander@2762
   435
  // According to pcretest, matching text_good against (\w+)*b
dvander@2762
   436
  // requires match_limit of at least 8192, and match_recursion_limit
dvander@2762
   437
  // of at least 37.
dvander@2762
   438
dvander@2762
   439
  RE_Options options_ml;
dvander@2762
   440
  options_ml.set_match_limit(8192);
dvander@2762
   441
  RE re("(\\w+)*b", options_ml);
dvander@2762
   442
  CHECK(re.PartialMatch(text_good) == true);
dvander@2762
   443
  CHECK(re.PartialMatch(text_bad) == false);
dvander@2762
   444
  CHECK(re.FullMatch(text_good) == false);
dvander@2762
   445
  CHECK(re.FullMatch(text_bad) == false);
dvander@2762
   446
dvander@2762
   447
  options_ml.set_match_limit(1024);
dvander@2762
   448
  RE re2("(\\w+)*b", options_ml);
dvander@2762
   449
  CHECK(re2.PartialMatch(text_good) == false);   // because of match_limit
dvander@2762
   450
  CHECK(re2.PartialMatch(text_bad) == false);
dvander@2762
   451
  CHECK(re2.FullMatch(text_good) == false);
dvander@2762
   452
  CHECK(re2.FullMatch(text_bad) == false);
dvander@2762
   453
dvander@2762
   454
  RE_Options options_mlr;
dvander@2762
   455
  options_mlr.set_match_limit_recursion(50);
dvander@2762
   456
  RE re3("(\\w+)*b", options_mlr);
dvander@2762
   457
  CHECK(re3.PartialMatch(text_good) == true);
dvander@2762
   458
  CHECK(re3.PartialMatch(text_bad) == false);
dvander@2762
   459
  CHECK(re3.FullMatch(text_good) == false);
dvander@2762
   460
  CHECK(re3.FullMatch(text_bad) == false);
dvander@2762
   461
dvander@2762
   462
  options_mlr.set_match_limit_recursion(10);
dvander@2762
   463
  RE re4("(\\w+)*b", options_mlr);
dvander@2762
   464
  CHECK(re4.PartialMatch(text_good) == false);
dvander@2762
   465
  CHECK(re4.PartialMatch(text_bad) == false);
dvander@2762
   466
  CHECK(re4.FullMatch(text_good) == false);
dvander@2762
   467
  CHECK(re4.FullMatch(text_bad) == false);
dvander@2762
   468
}
dvander@2762
   469
dvander@2762
   470
// A meta-quoted string, interpreted as a pattern, should always match
dvander@2762
   471
// the original unquoted string.
dvander@2762
   472
static void TestQuoteMeta(string unquoted, RE_Options options = RE_Options()) {
dvander@2762
   473
  string quoted = RE::QuoteMeta(unquoted);
dvander@2762
   474
  RE re(quoted, options);
dvander@2762
   475
  CHECK(re.FullMatch(unquoted));
dvander@2762
   476
}
dvander@2762
   477
dvander@2762
   478
// A string containing meaningful regexp characters, which is then meta-
dvander@2762
   479
// quoted, should not generally match a string the unquoted string does.
dvander@2762
   480
static void NegativeTestQuoteMeta(string unquoted, string should_not_match,
dvander@2762
   481
                                  RE_Options options = RE_Options()) {
dvander@2762
   482
  string quoted = RE::QuoteMeta(unquoted);
dvander@2762
   483
  RE re(quoted, options);
dvander@2762
   484
  CHECK(!re.FullMatch(should_not_match));
dvander@2762
   485
}
dvander@2762
   486
dvander@2762
   487
// Tests that quoted meta characters match their original strings,
dvander@2762
   488
// and that a few things that shouldn't match indeed do not.
dvander@2762
   489
static void TestQuotaMetaSimple() {
dvander@2762
   490
  TestQuoteMeta("foo");
dvander@2762
   491
  TestQuoteMeta("foo.bar");
dvander@2762
   492
  TestQuoteMeta("foo\\.bar");
dvander@2762
   493
  TestQuoteMeta("[1-9]");
dvander@2762
   494
  TestQuoteMeta("1.5-2.0?");
dvander@2762
   495
  TestQuoteMeta("\\d");
dvander@2762
   496
  TestQuoteMeta("Who doesn't like ice cream?");
dvander@2762
   497
  TestQuoteMeta("((a|b)c?d*e+[f-h]i)");
dvander@2762
   498
  TestQuoteMeta("((?!)xxx).*yyy");
dvander@2762
   499
  TestQuoteMeta("([");
dvander@2762
   500
  TestQuoteMeta(string("foo\0bar", 7));
dvander@2762
   501
}
dvander@2762
   502
dvander@2762
   503
static void TestQuoteMetaSimpleNegative() {
dvander@2762
   504
  NegativeTestQuoteMeta("foo", "bar");
dvander@2762
   505
  NegativeTestQuoteMeta("...", "bar");
dvander@2762
   506
  NegativeTestQuoteMeta("\\.", ".");
dvander@2762
   507
  NegativeTestQuoteMeta("\\.", "..");
dvander@2762
   508
  NegativeTestQuoteMeta("(a)", "a");
dvander@2762
   509
  NegativeTestQuoteMeta("(a|b)", "a");
dvander@2762
   510
  NegativeTestQuoteMeta("(a|b)", "(a)");
dvander@2762
   511
  NegativeTestQuoteMeta("(a|b)", "a|b");
dvander@2762
   512
  NegativeTestQuoteMeta("[0-9]", "0");
dvander@2762
   513
  NegativeTestQuoteMeta("[0-9]", "0-9");
dvander@2762
   514
  NegativeTestQuoteMeta("[0-9]", "[9]");
dvander@2762
   515
  NegativeTestQuoteMeta("((?!)xxx)", "xxx");
dvander@2762
   516
}
dvander@2762
   517
dvander@2762
   518
static void TestQuoteMetaLatin1() {
dvander@2762
   519
  TestQuoteMeta("3\xb2 = 9");
dvander@2762
   520
}
dvander@2762
   521
dvander@2762
   522
static void TestQuoteMetaUtf8() {
dvander@2762
   523
#ifdef SUPPORT_UTF8
dvander@2762
   524
  TestQuoteMeta("Pl\xc3\xa1\x63ido Domingo", pcrecpp::UTF8());
dvander@2762
   525
  TestQuoteMeta("xyz", pcrecpp::UTF8());            // No fancy utf8
dvander@2762
   526
  TestQuoteMeta("\xc2\xb0", pcrecpp::UTF8());       // 2-byte utf8 (degree symbol)
dvander@2762
   527
  TestQuoteMeta("27\xc2\xb0 degrees", pcrecpp::UTF8());  // As a middle character
dvander@2762
   528
  TestQuoteMeta("\xe2\x80\xb3", pcrecpp::UTF8());   // 3-byte utf8 (double prime)
dvander@2762
   529
  TestQuoteMeta("\xf0\x9d\x85\x9f", pcrecpp::UTF8()); // 4-byte utf8 (music note)
dvander@2762
   530
  TestQuoteMeta("27\xc2\xb0"); // Interpreted as Latin-1, but should still work
dvander@2762
   531
  NegativeTestQuoteMeta("27\xc2\xb0",               // 2-byte utf (degree symbol)
dvander@2762
   532
                        "27\\\xc2\\\xb0",
dvander@2762
   533
                        pcrecpp::UTF8());
dvander@2762
   534
#endif
dvander@2762
   535
}
dvander@2762
   536
dvander@2762
   537
static void TestQuoteMetaAll() {
dvander@2762
   538
  printf("Testing QuoteMeta\n");
dvander@2762
   539
  TestQuotaMetaSimple();
dvander@2762
   540
  TestQuoteMetaSimpleNegative();
dvander@2762
   541
  TestQuoteMetaLatin1();
dvander@2762
   542
  TestQuoteMetaUtf8();
dvander@2762
   543
}
dvander@2762
   544
dvander@2762
   545
//
dvander@2762
   546
// Options tests contributed by
dvander@2762
   547
// Giuseppe Maxia, CTO, Stardata s.r.l.
dvander@2762
   548
// July 2005
dvander@2762
   549
//
dvander@2762
   550
static void GetOneOptionResult(
dvander@2762
   551
                const char *option_name,
dvander@2762
   552
                const char *regex,
dvander@2762
   553
                const char *str,
dvander@2762
   554
                RE_Options options,
dvander@2762
   555
                bool full,
dvander@2762
   556
                string expected) {
dvander@2762
   557
dvander@2762
   558
  printf("Testing Option <%s>\n", option_name);
dvander@2762
   559
  if(VERBOSE_TEST)
dvander@2762
   560
    printf("/%s/ finds \"%s\" within \"%s\" \n",
dvander@2762
   561
                    regex,
dvander@2762
   562
                    expected.c_str(),
dvander@2762
   563
                    str);
dvander@2762
   564
  string captured("");
dvander@2762
   565
  if (full)
dvander@2762
   566
    RE(regex,options).FullMatch(str, &captured);
dvander@2762
   567
  else
dvander@2762
   568
    RE(regex,options).PartialMatch(str, &captured);
dvander@2762
   569
  CHECK_EQ(captured, expected);
dvander@2762
   570
}
dvander@2762
   571
dvander@2762
   572
static void TestOneOption(
dvander@2762
   573
                const char *option_name,
dvander@2762
   574
                const char *regex,
dvander@2762
   575
                const char *str,
dvander@2762
   576
                RE_Options options,
dvander@2762
   577
                bool full,
dvander@2762
   578
                bool assertive = true) {
dvander@2762
   579
dvander@2762
   580
  printf("Testing Option <%s>\n", option_name);
dvander@2762
   581
  if (VERBOSE_TEST)
dvander@2762
   582
    printf("'%s' %s /%s/ \n",
dvander@2762
   583
                  str,
dvander@2762
   584
                  (assertive? "matches" : "doesn't match"),
dvander@2762
   585
                  regex);
dvander@2762
   586
  if (assertive) {
dvander@2762
   587
    if (full)
dvander@2762
   588
      CHECK(RE(regex,options).FullMatch(str));
dvander@2762
   589
    else
dvander@2762
   590
      CHECK(RE(regex,options).PartialMatch(str));
dvander@2762
   591
  } else {
dvander@2762
   592
    if (full)
dvander@2762
   593
      CHECK(!RE(regex,options).FullMatch(str));
dvander@2762
   594
    else
dvander@2762
   595
      CHECK(!RE(regex,options).PartialMatch(str));
dvander@2762
   596
  }
dvander@2762
   597
}
dvander@2762
   598
dvander@2762
   599
static void Test_CASELESS() {
dvander@2762
   600
  RE_Options options;
dvander@2762
   601
  RE_Options options2;
dvander@2762
   602
dvander@2762
   603
  options.set_caseless(true);
dvander@2762
   604
  TestOneOption("CASELESS (class)",  "HELLO",    "hello", options, false);
dvander@2762
   605
  TestOneOption("CASELESS (class2)", "HELLO",    "hello", options2.set_caseless(true), false);
dvander@2762
   606
  TestOneOption("CASELESS (class)",  "^[A-Z]+$", "Hello", options, false);
dvander@2762
   607
dvander@2762
   608
  TestOneOption("CASELESS (function)", "HELLO",    "hello", pcrecpp::CASELESS(), false);
dvander@2762
   609
  TestOneOption("CASELESS (function)", "^[A-Z]+$", "Hello", pcrecpp::CASELESS(), false);
dvander@2762
   610
  options.set_caseless(false);
dvander@2762
   611
  TestOneOption("no CASELESS", "HELLO",    "hello", options, false, false);
dvander@2762
   612
}
dvander@2762
   613
dvander@2762
   614
static void Test_MULTILINE() {
dvander@2762
   615
  RE_Options options;
dvander@2762
   616
  RE_Options options2;
dvander@2762
   617
  const char *str = "HELLO\n" "cruel\n" "world\n";
dvander@2762
   618
dvander@2762
   619
  options.set_multiline(true);
dvander@2762
   620
  TestOneOption("MULTILINE (class)",    "^cruel$", str, options, false);
dvander@2762
   621
  TestOneOption("MULTILINE (class2)",   "^cruel$", str, options2.set_multiline(true), false);
dvander@2762
   622
  TestOneOption("MULTILINE (function)", "^cruel$", str, pcrecpp::MULTILINE(), false);
dvander@2762
   623
  options.set_multiline(false);
dvander@2762
   624
  TestOneOption("no MULTILINE", "^cruel$", str, options, false, false);
dvander@2762
   625
}
dvander@2762
   626
dvander@2762
   627
static void Test_DOTALL() {
dvander@2762
   628
  RE_Options options;
dvander@2762
   629
  RE_Options options2;
dvander@2762
   630
  const char *str = "HELLO\n" "cruel\n" "world";
dvander@2762
   631
dvander@2762
   632
  options.set_dotall(true);
dvander@2762
   633
  TestOneOption("DOTALL (class)",    "HELLO.*world", str, options, true);
dvander@2762
   634
  TestOneOption("DOTALL (class2)",   "HELLO.*world", str, options2.set_dotall(true), true);
dvander@2762
   635
  TestOneOption("DOTALL (function)",    "HELLO.*world", str, pcrecpp::DOTALL(), true);
dvander@2762
   636
  options.set_dotall(false);
dvander@2762
   637
  TestOneOption("no DOTALL", "HELLO.*world", str, options, true, false);
dvander@2762
   638
}
dvander@2762
   639
dvander@2762
   640
static void Test_DOLLAR_ENDONLY() {
dvander@2762
   641
  RE_Options options;
dvander@2762
   642
  RE_Options options2;
dvander@2762
   643
  const char *str = "HELLO world\n";
dvander@2762
   644
dvander@2762
   645
  TestOneOption("no DOLLAR_ENDONLY", "world$", str, options, false);
dvander@2762
   646
  options.set_dollar_endonly(true);
dvander@2762
   647
  TestOneOption("DOLLAR_ENDONLY 1",    "world$", str, options, false, false);
dvander@2762
   648
  TestOneOption("DOLLAR_ENDONLY 2",    "world$", str, options2.set_dollar_endonly(true), false, false);
dvander@2762
   649
}
dvander@2762
   650
dvander@2762
   651
static void Test_EXTRA() {
dvander@2762
   652
  RE_Options options;
dvander@2762
   653
  const char *str = "HELLO";
dvander@2762
   654
dvander@2762
   655
  options.set_extra(true);
dvander@2762
   656
  TestOneOption("EXTRA 1", "\\HELL\\O", str, options, true, false );
dvander@2762
   657
  TestOneOption("EXTRA 2", "\\HELL\\O", str, RE_Options().set_extra(true), true, false );
dvander@2762
   658
  options.set_extra(false);
dvander@2762
   659
  TestOneOption("no EXTRA", "\\HELL\\O", str, options, true );
dvander@2762
   660
}
dvander@2762
   661
dvander@2762
   662
static void Test_EXTENDED() {
dvander@2762
   663
  RE_Options options;
dvander@2762
   664
  RE_Options options2;
dvander@2762
   665
  const char *str = "HELLO world";
dvander@2762
   666
dvander@2762
   667
  options.set_extended(true);
dvander@2762
   668
  TestOneOption("EXTENDED (class)",    "HELLO world", str, options, false, false);
dvander@2762
   669
  TestOneOption("EXTENDED (class2)",   "HELLO world", str, options2.set_extended(true), false, false);
dvander@2762
   670
  TestOneOption("EXTENDED (class)",
dvander@2762
   671
                    "^ HE L{2} O "
dvander@2762
   672
                    "\\s+        "
dvander@2762
   673
                    "\\w+ $      ",
dvander@2762
   674
                    str,
dvander@2762
   675
                    options,
dvander@2762
   676
                    false);
dvander@2762
   677
dvander@2762
   678
  TestOneOption("EXTENDED (function)",    "HELLO world", str, pcrecpp::EXTENDED(), false, false);
dvander@2762
   679
  TestOneOption("EXTENDED (function)",
dvander@2762
   680
                    "^ HE L{2} O "
dvander@2762
   681
                    "\\s+        "
dvander@2762
   682
                    "\\w+ $      ",
dvander@2762
   683
                    str,
dvander@2762
   684
                    pcrecpp::EXTENDED(),
dvander@2762
   685
                    false);
dvander@2762
   686
dvander@2762
   687
  options.set_extended(false);
dvander@2762
   688
  TestOneOption("no EXTENDED", "HELLO world", str, options, false);
dvander@2762
   689
}
dvander@2762
   690
dvander@2762
   691
static void Test_NO_AUTO_CAPTURE() {
dvander@2762
   692
  RE_Options options;
dvander@2762
   693
  const char *str = "HELLO world";
dvander@2762
   694
  string captured;
dvander@2762
   695
dvander@2762
   696
  printf("Testing Option <no NO_AUTO_CAPTURE>\n");
dvander@2762
   697
  if (VERBOSE_TEST)
dvander@2762
   698
    printf("parentheses capture text\n");
dvander@2762
   699
  RE re("(world|universe)$", options);
dvander@2762
   700
  CHECK(re.Extract("\\1", str , &captured));
dvander@2762
   701
  CHECK_EQ(captured, "world");
dvander@2762
   702
  options.set_no_auto_capture(true);
dvander@2762
   703
  printf("testing Option <NO_AUTO_CAPTURE>\n");
dvander@2762
   704
  if (VERBOSE_TEST)
dvander@2762
   705
    printf("parentheses do not capture text\n");
dvander@2762
   706
  re.Extract("\\1",str, &captured );
dvander@2762
   707
  CHECK_EQ(captured, "world");
dvander@2762
   708
}
dvander@2762
   709
dvander@2762
   710
static void Test_UNGREEDY() {
dvander@2762
   711
  RE_Options options;
dvander@2762
   712
  const char *str = "HELLO, 'this' is the 'world'";
dvander@2762
   713
dvander@2762
   714
  options.set_ungreedy(true);
dvander@2762
   715
  GetOneOptionResult("UNGREEDY 1", "('.*')", str, options, false, "'this'" );
dvander@2762
   716
  GetOneOptionResult("UNGREEDY 2", "('.*')", str, RE_Options().set_ungreedy(true), false, "'this'" );
dvander@2762
   717
  GetOneOptionResult("UNGREEDY", "('.*?')", str, options, false, "'this' is the 'world'" );
dvander@2762
   718
dvander@2762
   719
  options.set_ungreedy(false);
dvander@2762
   720
  GetOneOptionResult("no UNGREEDY", "('.*')", str, options, false, "'this' is the 'world'" );
dvander@2762
   721
  GetOneOptionResult("no UNGREEDY", "('.*?')", str, options, false, "'this'" );
dvander@2762
   722
}
dvander@2762
   723
dvander@2762
   724
static void Test_all_options() {
dvander@2762
   725
  const char *str = "HELLO\n" "cruel\n" "world";
dvander@2762
   726
  RE_Options options;
dvander@2762
   727
  options.set_all_options(PCRE_CASELESS | PCRE_DOTALL);
dvander@2762
   728
dvander@2762
   729
  TestOneOption("all_options (CASELESS|DOTALL)", "^hello.*WORLD", str , options, false);
dvander@2762
   730
  options.set_all_options(0);
dvander@2762
   731
  TestOneOption("all_options (0)", "^hello.*WORLD", str , options, false, false);
dvander@2762
   732
  options.set_all_options(PCRE_MULTILINE | PCRE_EXTENDED);
dvander@2762
   733
dvander@2762
   734
  TestOneOption("all_options (MULTILINE|EXTENDED)", " ^ c r u e l $ ", str, options, false);
dvander@2762
   735
  TestOneOption("all_options (MULTILINE|EXTENDED) with constructor",
dvander@2762
   736
                  " ^ c r u e l $ ",
dvander@2762
   737
                  str,
dvander@2762
   738
                  RE_Options(PCRE_MULTILINE | PCRE_EXTENDED),
dvander@2762
   739
                  false);
dvander@2762
   740
dvander@2762
   741
  TestOneOption("all_options (MULTILINE|EXTENDED) with concatenation",
dvander@2762
   742
                  " ^ c r u e l $ ",
dvander@2762
   743
                  str,
dvander@2762
   744
                  RE_Options()
dvander@2762
   745
                       .set_multiline(true)
dvander@2762
   746
                       .set_extended(true),
dvander@2762
   747
                  false);
dvander@2762
   748
dvander@2762
   749
  options.set_all_options(0);
dvander@2762
   750
  TestOneOption("all_options (0)", "^ c r u e l $", str, options, false, false);
dvander@2762
   751
dvander@2762
   752
}
dvander@2762
   753
dvander@2762
   754
static void TestOptions() {
dvander@2762
   755
  printf("Testing Options\n");
dvander@2762
   756
  Test_CASELESS();
dvander@2762
   757
  Test_MULTILINE();
dvander@2762
   758
  Test_DOTALL();
dvander@2762
   759
  Test_DOLLAR_ENDONLY();
dvander@2762
   760
  Test_EXTENDED();
dvander@2762
   761
  Test_NO_AUTO_CAPTURE();
dvander@2762
   762
  Test_UNGREEDY();
dvander@2762
   763
  Test_EXTRA();
dvander@2762
   764
  Test_all_options();
dvander@2762
   765
}
dvander@2762
   766
dvander@2762
   767
static void TestConstructors() {
dvander@2762
   768
  printf("Testing constructors\n");
dvander@2762
   769
dvander@2762
   770
  RE_Options options;
dvander@2762
   771
  options.set_dotall(true);
dvander@2762
   772
  const char *str = "HELLO\n" "cruel\n" "world";
dvander@2762
   773
dvander@2762
   774
  RE orig("HELLO.*world", options);
dvander@2762
   775
  CHECK(orig.FullMatch(str));
dvander@2762
   776
dvander@2762
   777
  RE copy1(orig);
dvander@2762
   778
  CHECK(copy1.FullMatch(str));
dvander@2762
   779
dvander@2762
   780
  RE copy2("not a match");
dvander@2762
   781
  CHECK(!copy2.FullMatch(str));
dvander@2762
   782
  copy2 = copy1;
dvander@2762
   783
  CHECK(copy2.FullMatch(str));
dvander@2762
   784
  copy2 = orig;
dvander@2762
   785
  CHECK(copy2.FullMatch(str));
dvander@2762
   786
dvander@2762
   787
  // Make sure when we assign to ourselves, nothing bad happens
dvander@2762
   788
  orig = orig;
dvander@2762
   789
  copy1 = copy1;
dvander@2762
   790
  copy2 = copy2;
dvander@2762
   791
  CHECK(orig.FullMatch(str));
dvander@2762
   792
  CHECK(copy1.FullMatch(str));
dvander@2762
   793
  CHECK(copy2.FullMatch(str));
dvander@2762
   794
}
dvander@2762
   795
dvander@2762
   796
int main(int argc, char** argv) {
dvander@2762
   797
  // Treat any flag as --help
dvander@2762
   798
  if (argc > 1 && argv[1][0] == '-') {
dvander@2762
   799
    printf("Usage: %s [timing1|timing2|timing3 num-iters]\n"
dvander@2762
   800
           "       If 'timingX ###' is specified, run the given timing test\n"
dvander@2762
   801
           "       with the given number of iterations, rather than running\n"
dvander@2762
   802
           "       the default corectness test.\n", argv[0]);
dvander@2762
   803
    return 0;
dvander@2762
   804
  }
dvander@2762
   805
dvander@2762
   806
  if (argc > 1) {
dvander@2762
   807
    if ( argc == 2 || atoi(argv[2]) == 0) {
dvander@2762
   808
      printf("timing mode needs a num-iters argument\n");
dvander@2762
   809
      return 1;
dvander@2762
   810
    }
dvander@2762
   811
    if (!strcmp(argv[1], "timing1"))
dvander@2762
   812
      Timing1(atoi(argv[2]));
dvander@2762
   813
    else if (!strcmp(argv[1], "timing2"))
dvander@2762
   814
      Timing2(atoi(argv[2]));
dvander@2762
   815
    else if (!strcmp(argv[1], "timing3"))
dvander@2762
   816
      Timing3(atoi(argv[2]));
dvander@2762
   817
    else
dvander@2762
   818
      printf("Unknown argument '%s'\n", argv[1]);
dvander@2762
   819
    return 0;
dvander@2762
   820
  }
dvander@2762
   821
dvander@2762
   822
  printf("Testing FullMatch\n");
dvander@2762
   823
dvander@2762
   824
  int i;
dvander@2762
   825
  string s;
dvander@2762
   826
dvander@2762
   827
  /***** FullMatch with no args *****/
dvander@2762
   828
dvander@2762
   829
  CHECK(RE("h.*o").FullMatch("hello"));
dvander@2762
   830
  CHECK(!RE("h.*o").FullMatch("othello"));     // Must be anchored at front
dvander@2762
   831
  CHECK(!RE("h.*o").FullMatch("hello!"));      // Must be anchored at end
dvander@2762
   832
  CHECK(RE("a*").FullMatch("aaaa"));           // Fullmatch with normal op
dvander@2762
   833
  CHECK(RE("a*?").FullMatch("aaaa"));          // Fullmatch with nongreedy op
dvander@2762
   834
  CHECK(RE("a*?\\z").FullMatch("aaaa"));       // Two unusual ops
dvander@2762
   835
dvander@2762
   836
  /***** FullMatch with args *****/
dvander@2762
   837
dvander@2762
   838
  // Zero-arg
dvander@2762
   839
  CHECK(RE("\\d+").FullMatch("1001"));
dvander@2762
   840
dvander@2762
   841
  // Single-arg
dvander@2762
   842
  CHECK(RE("(\\d+)").FullMatch("1001",   &i));
dvander@2762
   843
  CHECK_EQ(i, 1001);
dvander@2762
   844
  CHECK(RE("(-?\\d+)").FullMatch("-123", &i));
dvander@2762
   845
  CHECK_EQ(i, -123);
dvander@2762
   846
  CHECK(!RE("()\\d+").FullMatch("10", &i));
dvander@2762
   847
  CHECK(!RE("(\\d+)").FullMatch("1234567890123456789012345678901234567890",
dvander@2762
   848
                                &i));
dvander@2762
   849
dvander@2762
   850
  // Digits surrounding integer-arg
dvander@2762
   851
  CHECK(RE("1(\\d*)4").FullMatch("1234", &i));
dvander@2762
   852
  CHECK_EQ(i, 23);
dvander@2762
   853
  CHECK(RE("(\\d)\\d+").FullMatch("1234", &i));
dvander@2762
   854
  CHECK_EQ(i, 1);
dvander@2762
   855
  CHECK(RE("(-\\d)\\d+").FullMatch("-1234", &i));
dvander@2762
   856
  CHECK_EQ(i, -1);
dvander@2762
   857
  CHECK(RE("(\\d)").PartialMatch("1234", &i));
dvander@2762
   858
  CHECK_EQ(i, 1);
dvander@2762
   859
  CHECK(RE("(-\\d)").PartialMatch("-1234", &i));
dvander@2762
   860
  CHECK_EQ(i, -1);
dvander@2762
   861
dvander@2762
   862
  // String-arg
dvander@2762
   863
  CHECK(RE("h(.*)o").FullMatch("hello", &s));
dvander@2762
   864
  CHECK_EQ(s, string("ell"));
dvander@2762
   865
dvander@2762
   866
  // StringPiece-arg
dvander@2762
   867
  StringPiece sp;
dvander@2762
   868
  CHECK(RE("(\\w+):(\\d+)").FullMatch("ruby:1234", &sp, &i));
dvander@2762
   869
  CHECK_EQ(sp.size(), 4);
dvander@2762
   870
  CHECK(memcmp(sp.data(), "ruby", 4) == 0);
dvander@2762
   871
  CHECK_EQ(i, 1234);
dvander@2762
   872
dvander@2762
   873
  // Multi-arg
dvander@2762
   874
  CHECK(RE("(\\w+):(\\d+)").FullMatch("ruby:1234", &s, &i));
dvander@2762
   875
  CHECK_EQ(s, string("ruby"));
dvander@2762
   876
  CHECK_EQ(i, 1234);
dvander@2762
   877
dvander@2762
   878
  // Ignore non-void* NULL arg
dvander@2762
   879
  CHECK(RE("he(.*)lo").FullMatch("hello", (char*)NULL));
dvander@2762
   880
  CHECK(RE("h(.*)o").FullMatch("hello", (string*)NULL));
dvander@2762
   881
  CHECK(RE("h(.*)o").FullMatch("hello", (StringPiece*)NULL));
dvander@2762
   882
  CHECK(RE("(.*)").FullMatch("1234", (int*)NULL));
dvander@2762
   883
#ifdef HAVE_LONG_LONG
dvander@2762
   884
  CHECK(RE("(.*)").FullMatch("1234567890123456", (long long*)NULL));
dvander@2762
   885
#endif
dvander@2762
   886
  CHECK(RE("(.*)").FullMatch("123.4567890123456", (double*)NULL));
dvander@2762
   887
  CHECK(RE("(.*)").FullMatch("123.4567890123456", (float*)NULL));
dvander@2762
   888
dvander@2762
   889
  // Fail on non-void* NULL arg if the match doesn't parse for the given type.
dvander@2762
   890
  CHECK(!RE("h(.*)lo").FullMatch("hello", &s, (char*)NULL));
dvander@2762
   891
  CHECK(!RE("(.*)").FullMatch("hello", (int*)NULL));
dvander@2762
   892
  CHECK(!RE("(.*)").FullMatch("1234567890123456", (int*)NULL));
dvander@2762
   893
  CHECK(!RE("(.*)").FullMatch("hello", (double*)NULL));
dvander@2762
   894
  CHECK(!RE("(.*)").FullMatch("hello", (float*)NULL));
dvander@2762
   895
dvander@2762
   896
  // Ignored arg
dvander@2762
   897
  CHECK(RE("(\\w+)(:)(\\d+)").FullMatch("ruby:1234", &s, (void*)NULL, &i));
dvander@2762
   898
  CHECK_EQ(s, string("ruby"));
dvander@2762
   899
  CHECK_EQ(i, 1234);
dvander@2762
   900
dvander@2762
   901
  // Type tests
dvander@2762
   902
  {
dvander@2762
   903
    char c;
dvander@2762
   904
    CHECK(RE("(H)ello").FullMatch("Hello", &c));
dvander@2762
   905
    CHECK_EQ(c, 'H');
dvander@2762
   906
  }
dvander@2762
   907
  {
dvander@2762
   908
    unsigned char c;
dvander@2762
   909
    CHECK(RE("(H)ello").FullMatch("Hello", &c));
dvander@2762
   910
    CHECK_EQ(c, static_cast<unsigned char>('H'));
dvander@2762
   911
  }
dvander@2762
   912
  {
dvander@2762
   913
    short v;
dvander@2762
   914
    CHECK(RE("(-?\\d+)").FullMatch("100",     &v));    CHECK_EQ(v, 100);
dvander@2762
   915
    CHECK(RE("(-?\\d+)").FullMatch("-100",    &v));    CHECK_EQ(v, -100);
dvander@2762
   916
    CHECK(RE("(-?\\d+)").FullMatch("32767",   &v));    CHECK_EQ(v, 32767);
dvander@2762
   917
    CHECK(RE("(-?\\d+)").FullMatch("-32768",  &v));    CHECK_EQ(v, -32768);
dvander@2762
   918
    CHECK(!RE("(-?\\d+)").FullMatch("-32769", &v));
dvander@2762
   919
    CHECK(!RE("(-?\\d+)").FullMatch("32768",  &v));
dvander@2762
   920
  }
dvander@2762
   921
  {
dvander@2762
   922
    unsigned short v;
dvander@2762
   923
    CHECK(RE("(\\d+)").FullMatch("100",     &v));    CHECK_EQ(v, 100);
dvander@2762
   924
    CHECK(RE("(\\d+)").FullMatch("32767",   &v));    CHECK_EQ(v, 32767);
dvander@2762
   925
    CHECK(RE("(\\d+)").FullMatch("65535",   &v));    CHECK_EQ(v, 65535);
dvander@2762
   926
    CHECK(!RE("(\\d+)").FullMatch("65536",  &v));
dvander@2762
   927
  }
dvander@2762
   928
  {
dvander@2762
   929
    int v;
dvander@2762
   930
    static const int max_value = 0x7fffffff;
dvander@2762
   931
    static const int min_value = -max_value - 1;
dvander@2762
   932
    CHECK(RE("(-?\\d+)").FullMatch("100",         &v)); CHECK_EQ(v, 100);
dvander@2762
   933
    CHECK(RE("(-?\\d+)").FullMatch("-100",        &v)); CHECK_EQ(v, -100);
dvander@2762
   934
    CHECK(RE("(-?\\d+)").FullMatch("2147483647",  &v)); CHECK_EQ(v, max_value);
dvander@2762
   935
    CHECK(RE("(-?\\d+)").FullMatch("-2147483648", &v)); CHECK_EQ(v, min_value);
dvander@2762
   936
    CHECK(!RE("(-?\\d+)").FullMatch("-2147483649", &v));
dvander@2762
   937
    CHECK(!RE("(-?\\d+)").FullMatch("2147483648",  &v));
dvander@2762
   938
  }
dvander@2762
   939
  {
dvander@2762
   940
    unsigned int v;
dvander@2762
   941
    static const unsigned int max_value = 0xfffffffful;
dvander@2762
   942
    CHECK(RE("(\\d+)").FullMatch("100",         &v)); CHECK_EQ(v, 100);
dvander@2762
   943
    CHECK(RE("(\\d+)").FullMatch("4294967295",  &v)); CHECK_EQ(v, max_value);
dvander@2762
   944
    CHECK(!RE("(\\d+)").FullMatch("4294967296", &v));
dvander@2762
   945
  }
dvander@2762
   946
#ifdef HAVE_LONG_LONG
dvander@2762
   947
# if defined(__MINGW__) || defined(__MINGW32__)
dvander@2762
   948
#   define LLD "%I64d"
dvander@2762
   949
#   define LLU "%I64u"
dvander@2762
   950
# else
dvander@2762
   951
#   define LLD "%lld"
dvander@2762
   952
#   define LLU "%llu"
dvander@2762
   953
# endif
dvander@2762
   954
  {
dvander@2762
   955
    long long v;
dvander@2762
   956
    static const long long max_value = 0x7fffffffffffffffLL;
dvander@2762
   957
    static const long long min_value = -max_value - 1;
dvander@2762
   958
    char buf[32];  // definitely big enough for a long long
dvander@2762
   959
dvander@2762
   960
    CHECK(RE("(-?\\d+)").FullMatch("100", &v)); CHECK_EQ(v, 100);
dvander@2762
   961
    CHECK(RE("(-?\\d+)").FullMatch("-100",&v)); CHECK_EQ(v, -100);
dvander@2762
   962
dvander@2762
   963
    sprintf(buf, LLD, max_value);
dvander@2762
   964
    CHECK(RE("(-?\\d+)").FullMatch(buf,&v)); CHECK_EQ(v, max_value);
dvander@2762
   965
dvander@2762
   966
    sprintf(buf, LLD, min_value);
dvander@2762
   967
    CHECK(RE("(-?\\d+)").FullMatch(buf,&v)); CHECK_EQ(v, min_value);
dvander@2762
   968
dvander@2762
   969
    sprintf(buf, LLD, max_value);
dvander@2762
   970
    assert(buf[strlen(buf)-1] != '9');
dvander@2762
   971
    buf[strlen(buf)-1]++;
dvander@2762
   972
    CHECK(!RE("(-?\\d+)").FullMatch(buf, &v));
dvander@2762
   973
dvander@2762
   974
    sprintf(buf, LLD, min_value);
dvander@2762
   975
    assert(buf[strlen(buf)-1] != '9');
dvander@2762
   976
    buf[strlen(buf)-1]++;
dvander@2762
   977
    CHECK(!RE("(-?\\d+)").FullMatch(buf, &v));
dvander@2762
   978
  }
dvander@2762
   979
#endif
dvander@2762
   980
#if defined HAVE_UNSIGNED_LONG_LONG && defined HAVE_LONG_LONG
dvander@2762
   981
  {
dvander@2762
   982
    unsigned long long v;
dvander@2762
   983
    long long v2;
dvander@2762
   984
    static const unsigned long long max_value = 0xffffffffffffffffULL;
dvander@2762
   985
    char buf[32];  // definitely big enough for a unsigned long long
dvander@2762
   986
dvander@2762
   987
    CHECK(RE("(-?\\d+)").FullMatch("100",&v)); CHECK_EQ(v, 100);
dvander@2762
   988
    CHECK(RE("(-?\\d+)").FullMatch("-100",&v2)); CHECK_EQ(v2, -100);
dvander@2762
   989
dvander@2762
   990
    sprintf(buf, LLU, max_value);
dvander@2762
   991
    CHECK(RE("(-?\\d+)").FullMatch(buf,&v)); CHECK_EQ(v, max_value);
dvander@2762
   992
dvander@2762
   993
    assert(buf[strlen(buf)-1] != '9');
dvander@2762
   994
    buf[strlen(buf)-1]++;
dvander@2762
   995
    CHECK(!RE("(-?\\d+)").FullMatch(buf, &v));
dvander@2762
   996
  }
dvander@2762
   997
#endif
dvander@2762
   998
  {
dvander@2762
   999
    float v;
dvander@2762
  1000
    CHECK(RE("(.*)").FullMatch("100", &v));
dvander@2762
  1001
    CHECK(RE("(.*)").FullMatch("-100.", &v));
dvander@2762
  1002
    CHECK(RE("(.*)").FullMatch("1e23", &v));
dvander@2762
  1003
  }
dvander@2762
  1004
  {
dvander@2762
  1005
    double v;
dvander@2762
  1006
    CHECK(RE("(.*)").FullMatch("100", &v));
dvander@2762
  1007
    CHECK(RE("(.*)").FullMatch("-100.", &v));
dvander@2762
  1008
    CHECK(RE("(.*)").FullMatch("1e23", &v));
dvander@2762
  1009
  }
dvander@2762
  1010
dvander@2762
  1011
  // Check that matching is fully anchored
dvander@2762
  1012
  CHECK(!RE("(\\d+)").FullMatch("x1001",  &i));
dvander@2762
  1013
  CHECK(!RE("(\\d+)").FullMatch("1001x",  &i));
dvander@2762
  1014
  CHECK(RE("x(\\d+)").FullMatch("x1001", &i)); CHECK_EQ(i, 1001);
dvander@2762
  1015
  CHECK(RE("(\\d+)x").FullMatch("1001x", &i)); CHECK_EQ(i, 1001);
dvander@2762
  1016
dvander@2762
  1017
  // Braces
dvander@2762
  1018
  CHECK(RE("[0-9a-f+.-]{5,}").FullMatch("0abcd"));
dvander@2762
  1019
  CHECK(RE("[0-9a-f+.-]{5,}").FullMatch("0abcde"));
dvander@2762
  1020
  CHECK(!RE("[0-9a-f+.-]{5,}").FullMatch("0abc"));
dvander@2762
  1021
dvander@2762
  1022
  // Complicated RE
dvander@2762
  1023
  CHECK(RE("foo|bar|[A-Z]").FullMatch("foo"));
dvander@2762
  1024
  CHECK(RE("foo|bar|[A-Z]").FullMatch("bar"));
dvander@2762
  1025
  CHECK(RE("foo|bar|[A-Z]").FullMatch("X"));
dvander@2762
  1026
  CHECK(!RE("foo|bar|[A-Z]").FullMatch("XY"));
dvander@2762
  1027
dvander@2762
  1028
  // Check full-match handling (needs '$' tacked on internally)
dvander@2762
  1029
  CHECK(RE("fo|foo").FullMatch("fo"));
dvander@2762
  1030
  CHECK(RE("fo|foo").FullMatch("foo"));
dvander@2762
  1031
  CHECK(RE("fo|foo$").FullMatch("fo"));
dvander@2762
  1032
  CHECK(RE("fo|foo$").FullMatch("foo"));
dvander@2762
  1033
  CHECK(RE("foo$").FullMatch("foo"));
dvander@2762
  1034
  CHECK(!RE("foo\\$").FullMatch("foo$bar"));
dvander@2762
  1035
  CHECK(!RE("fo|bar").FullMatch("fox"));
dvander@2762
  1036
dvander@2762
  1037
  // Uncomment the following if we change the handling of '$' to
dvander@2762
  1038
  // prevent it from matching a trailing newline
dvander@2762
  1039
  if (false) {
dvander@2762
  1040
    // Check that we don't get bitten by pcre's special handling of a
dvander@2762
  1041
    // '\n' at the end of the string matching '$'
dvander@2762
  1042
    CHECK(!RE("foo$").PartialMatch("foo\n"));
dvander@2762
  1043
  }
dvander@2762
  1044
dvander@2762
  1045
  // Number of args
dvander@2762
  1046
  int a[16];
dvander@2762
  1047
  CHECK(RE("").FullMatch(""));
dvander@2762
  1048
dvander@2762
  1049
  memset(a, 0, sizeof(0));
dvander@2762
  1050
  CHECK(RE("(\\d){1}").FullMatch("1",
dvander@2762
  1051
                                 &a[0]));
dvander@2762
  1052
  CHECK_EQ(a[0], 1);
dvander@2762
  1053
dvander@2762
  1054
  memset(a, 0, sizeof(0));
dvander@2762
  1055
  CHECK(RE("(\\d)(\\d)").FullMatch("12",
dvander@2762
  1056
                                   &a[0],  &a[1]));
dvander@2762
  1057
  CHECK_EQ(a[0], 1);
dvander@2762
  1058
  CHECK_EQ(a[1], 2);
dvander@2762
  1059
dvander@2762
  1060
  memset(a, 0, sizeof(0));
dvander@2762
  1061
  CHECK(RE("(\\d)(\\d)(\\d)").FullMatch("123",
dvander@2762
  1062
                                        &a[0],  &a[1],  &a[2]));
dvander@2762
  1063
  CHECK_EQ(a[0], 1);
dvander@2762
  1064
  CHECK_EQ(a[1], 2);
dvander@2762
  1065
  CHECK_EQ(a[2], 3);
dvander@2762
  1066
dvander@2762
  1067
  memset(a, 0, sizeof(0));
dvander@2762
  1068
  CHECK(RE("(\\d)(\\d)(\\d)(\\d)").FullMatch("1234",
dvander@2762
  1069
                                             &a[0],  &a[1],  &a[2],  &a[3]));
dvander@2762
  1070
  CHECK_EQ(a[0], 1);
dvander@2762
  1071
  CHECK_EQ(a[1], 2);
dvander@2762
  1072
  CHECK_EQ(a[2], 3);
dvander@2762
  1073
  CHECK_EQ(a[3], 4);
dvander@2762
  1074
dvander@2762
  1075
  memset(a, 0, sizeof(0));
dvander@2762
  1076
  CHECK(RE("(\\d)(\\d)(\\d)(\\d)(\\d)").FullMatch("12345",
dvander@2762
  1077
                                                  &a[0],  &a[1],  &a[2],
dvander@2762
  1078
                                                  &a[3],  &a[4]));
dvander@2762
  1079
  CHECK_EQ(a[0], 1);
dvander@2762
  1080
  CHECK_EQ(a[1], 2);
dvander@2762
  1081
  CHECK_EQ(a[2], 3);
dvander@2762
  1082
  CHECK_EQ(a[3], 4);
dvander@2762
  1083
  CHECK_EQ(a[4], 5);
dvander@2762
  1084
dvander@2762
  1085
  memset(a, 0, sizeof(0));
dvander@2762
  1086
  CHECK(RE("(\\d)(\\d)(\\d)(\\d)(\\d)(\\d)").FullMatch("123456",
dvander@2762
  1087
                                                       &a[0],  &a[1],  &a[2],
dvander@2762
  1088
                                                       &a[3],  &a[4],  &a[5]));
dvander@2762
  1089
  CHECK_EQ(a[0], 1);
dvander@2762
  1090
  CHECK_EQ(a[1], 2);
dvander@2762
  1091
  CHECK_EQ(a[2], 3);
dvander@2762
  1092
  CHECK_EQ(a[3], 4);
dvander@2762
  1093
  CHECK_EQ(a[4], 5);
dvander@2762
  1094
  CHECK_EQ(a[5], 6);
dvander@2762
  1095
dvander@2762
  1096
  memset(a, 0, sizeof(0));
dvander@2762
  1097
  CHECK(RE("(\\d)(\\d)(\\d)(\\d)(\\d)(\\d)(\\d)").FullMatch("1234567",
dvander@2762
  1098
                                                            &a[0],  &a[1],  &a[2],  &a[3],
dvander@2762
  1099
                                                            &a[4],  &a[5],  &a[6]));
dvander@2762
  1100
  CHECK_EQ(a[0], 1);
dvander@2762
  1101
  CHECK_EQ(a[1], 2);
dvander@2762
  1102
  CHECK_EQ(a[2], 3);
dvander@2762
  1103
  CHECK_EQ(a[3], 4);
dvander@2762
  1104
  CHECK_EQ(a[4], 5);
dvander@2762
  1105
  CHECK_EQ(a[5], 6);
dvander@2762
  1106
  CHECK_EQ(a[6], 7);
dvander@2762
  1107
dvander@2762
  1108
  memset(a, 0, sizeof(0));
dvander@2762
  1109
  CHECK(RE("(\\d)(\\d)(\\d)(\\d)(\\d)(\\d)(\\d)(\\d)"
dvander@2762
  1110
           "(\\d)(\\d)(\\d)(\\d)(\\d)(\\d)(\\d)(\\d)").FullMatch(
dvander@2762
  1111
               "1234567890123456",
dvander@2762
  1112
               &a[0],  &a[1],  &a[2],  &a[3],
dvander@2762
  1113
               &a[4],  &a[5],  &a[6],  &a[7],
dvander@2762
  1114
               &a[8],  &a[9],  &a[10], &a[11],
dvander@2762
  1115
               &a[12], &a[13], &a[14], &a[15]));
dvander@2762
  1116
  CHECK_EQ(a[0], 1);
dvander@2762
  1117
  CHECK_EQ(a[1], 2);
dvander@2762
  1118
  CHECK_EQ(a[2], 3);
dvander@2762
  1119
  CHECK_EQ(a[3], 4);
dvander@2762
  1120
  CHECK_EQ(a[4], 5);
dvander@2762
  1121
  CHECK_EQ(a[5], 6);
dvander@2762
  1122
  CHECK_EQ(a[6], 7);
dvander@2762
  1123
  CHECK_EQ(a[7], 8);
dvander@2762
  1124
  CHECK_EQ(a[8], 9);
dvander@2762
  1125
  CHECK_EQ(a[9], 0);
dvander@2762
  1126
  CHECK_EQ(a[10], 1);
dvander@2762
  1127
  CHECK_EQ(a[11], 2);
dvander@2762
  1128
  CHECK_EQ(a[12], 3);
dvander@2762
  1129
  CHECK_EQ(a[13], 4);
dvander@2762
  1130
  CHECK_EQ(a[14], 5);
dvander@2762
  1131
  CHECK_EQ(a[15], 6);
dvander@2762
  1132
dvander@2762
  1133
  /***** PartialMatch *****/
dvander@2762
  1134
dvander@2762
  1135
  printf("Testing PartialMatch\n");
dvander@2762
  1136
dvander@2762
  1137
  CHECK(RE("h.*o").PartialMatch("hello"));
dvander@2762
  1138
  CHECK(RE("h.*o").PartialMatch("othello"));
dvander@2762
  1139
  CHECK(RE("h.*o").PartialMatch("hello!"));
dvander@2762
  1140
  CHECK(RE("((((((((((((((((((((x))))))))))))))))))))").PartialMatch("x"));
dvander@2762
  1141
dvander@2762
  1142
  /***** other tests *****/
dvander@2762
  1143
dvander@2762
  1144
  RadixTests();
dvander@2762
  1145
  TestReplace();
dvander@2762
  1146
  TestExtract();
dvander@2762
  1147
  TestConsume();
dvander@2762
  1148
  TestFindAndConsume();
dvander@2762
  1149
  TestQuoteMetaAll();
dvander@2762
  1150
  TestMatchNumberPeculiarity();
dvander@2762
  1151
dvander@2762
  1152
  // Check the pattern() accessor
dvander@2762
  1153
  {
dvander@2762
  1154
    const string kPattern = "http://([^/]+)/.*";
dvander@2762
  1155
    const RE re(kPattern);
dvander@2762
  1156
    CHECK_EQ(kPattern, re.pattern());
dvander@2762
  1157
  }
dvander@2762
  1158
dvander@2762
  1159
  // Check RE error field.
dvander@2762
  1160
  {
dvander@2762
  1161
    RE re("foo");
dvander@2762
  1162
    CHECK(re.error().empty());  // Must have no error
dvander@2762
  1163
  }
dvander@2762
  1164
dvander@2762
  1165
#ifdef SUPPORT_UTF8
dvander@2762
  1166
  // Check UTF-8 handling
dvander@2762
  1167
  {
dvander@2762
  1168
    printf("Testing UTF-8 handling\n");
dvander@2762
  1169
dvander@2762
  1170
    // Three Japanese characters (nihongo)
dvander@2762
  1171
    const unsigned char utf8_string[] = {
dvander@2762
  1172
         0xe6, 0x97, 0xa5, // 65e5
dvander@2762
  1173
         0xe6, 0x9c, 0xac, // 627c
dvander@2762
  1174
         0xe8, 0xaa, 0x9e, // 8a9e
dvander@2762
  1175
         0
dvander@2762
  1176
    };
dvander@2762
  1177
    const unsigned char utf8_pattern[] = {
dvander@2762
  1178
         '.',
dvander@2762
  1179
         0xe6, 0x9c, 0xac, // 627c
dvander@2762
  1180
         '.',
dvander@2762
  1181
         0
dvander@2762
  1182
    };
dvander@2762
  1183
dvander@2762
  1184
    // Both should match in either mode, bytes or UTF-8
dvander@2762
  1185
    RE re_test1(".........");
dvander@2762
  1186
    CHECK(re_test1.FullMatch(utf8_string));
dvander@2762
  1187
    RE re_test2("...", pcrecpp::UTF8());
dvander@2762
  1188
    CHECK(re_test2.FullMatch(utf8_string));
dvander@2762
  1189
dvander@2762
  1190
    // Check that '.' matches one byte or UTF-8 character
dvander@2762
  1191
    // according to the mode.
dvander@2762
  1192
    string ss;
dvander@2762
  1193
    RE re_test3("(.)");
dvander@2762
  1194
    CHECK(re_test3.PartialMatch(utf8_string, &ss));
dvander@2762
  1195
    CHECK_EQ(ss, string("\xe6"));
dvander@2762
  1196
    RE re_test4("(.)", pcrecpp::UTF8());
dvander@2762
  1197
    CHECK(re_test4.PartialMatch(utf8_string, &ss));
dvander@2762
  1198
    CHECK_EQ(ss, string("\xe6\x97\xa5"));
dvander@2762
  1199
dvander@2762
  1200
    // Check that string matches itself in either mode
dvander@2762
  1201
    RE re_test5(utf8_string);
dvander@2762
  1202
    CHECK(re_test5.FullMatch(utf8_string));
dvander@2762
  1203
    RE re_test6(utf8_string, pcrecpp::UTF8());
dvander@2762
  1204
    CHECK(re_test6.FullMatch(utf8_string));
dvander@2762
  1205
dvander@2762
  1206
    // Check that pattern matches string only in UTF8 mode
dvander@2762
  1207
    RE re_test7(utf8_pattern);
dvander@2762
  1208
    CHECK(!re_test7.FullMatch(utf8_string));
dvander@2762
  1209
    RE re_test8(utf8_pattern, pcrecpp::UTF8());
dvander@2762
  1210
    CHECK(re_test8.FullMatch(utf8_string));
dvander@2762
  1211
  }
dvander@2762
  1212
dvander@2762
  1213
  // Check that ungreedy, UTF8 regular expressions don't match when they
dvander@2762
  1214
  // oughtn't -- see bug 82246.
dvander@2762
  1215
  {
dvander@2762
  1216
    // This code always worked.
dvander@2762
  1217
    const char* pattern = "\\w+X";
dvander@2762
  1218
    const string target = "a aX";
dvander@2762
  1219
    RE match_sentence(pattern);
dvander@2762
  1220
    RE match_sentence_re(pattern, pcrecpp::UTF8());
dvander@2762
  1221
dvander@2762
  1222
    CHECK(!match_sentence.FullMatch(target));
dvander@2762
  1223
    CHECK(!match_sentence_re.FullMatch(target));
dvander@2762
  1224
  }
dvander@2762
  1225
dvander@2762
  1226
  {
dvander@2762
  1227
    const char* pattern = "(?U)\\w+X";
dvander@2762
  1228
    const string target = "a aX";
dvander@2762
  1229
    RE match_sentence(pattern);
dvander@2762
  1230
    RE match_sentence_re(pattern, pcrecpp::UTF8());
dvander@2762
  1231
dvander@2762
  1232
    CHECK(!match_sentence.FullMatch(target));
dvander@2762
  1233
    CHECK(!match_sentence_re.FullMatch(target));
dvander@2762
  1234
  }
dvander@2762
  1235
#endif  /* def SUPPORT_UTF8 */
dvander@2762
  1236
dvander@2762
  1237
  printf("Testing error reporting\n");
dvander@2762
  1238
dvander@2762
  1239
  { RE re("a\\1"); CHECK(!re.error().empty()); }
dvander@2762
  1240
  {
dvander@2762
  1241
    RE re("a[x");
dvander@2762
  1242
    CHECK(!re.error().empty());
dvander@2762
  1243
  }
dvander@2762
  1244
  {
dvander@2762
  1245
    RE re("a[z-a]");
dvander@2762
  1246
    CHECK(!re.error().empty());
dvander@2762
  1247
  }
dvander@2762
  1248
  {
dvander@2762
  1249
    RE re("a[[:foobar:]]");
dvander@2762
  1250
    CHECK(!re.error().empty());
dvander@2762
  1251
  }
dvander@2762
  1252
  {
dvander@2762
  1253
    RE re("a(b");
dvander@2762
  1254
    CHECK(!re.error().empty());
dvander@2762
  1255
  }
dvander@2762
  1256
  {
dvander@2762
  1257
    RE re("a\\");
dvander@2762
  1258
    CHECK(!re.error().empty());
dvander@2762
  1259
  }
dvander@2762
  1260
dvander@2762
  1261
  // Test that recursion is stopped
dvander@2762
  1262
  TestRecursion();
dvander@2762
  1263
dvander@2762
  1264
  // Test Options
dvander@2762
  1265
  if (getenv("VERBOSE_TEST") != NULL)
dvander@2762
  1266
    VERBOSE_TEST  = true;
dvander@2762
  1267
  TestOptions();
dvander@2762
  1268
dvander@2762
  1269
  // Test the constructors
dvander@2762
  1270
  TestConstructors();
dvander@2762
  1271
dvander@2762
  1272
  // Done
dvander@2762
  1273
  printf("OK\n");
dvander@2762
  1274
dvander@2762
  1275
  return 0;
dvander@2762
  1276
}