12 #include "util/util.h"
13 #include "util/flags.h"
14 #include "util/logging.h"
15 #include "util/strutil.h"
16 #include "re2/testing/tester.h"
19 #include "re2/regexp.h"
21 DEFINE_FLAG(
bool, dump_prog,
false,
"dump regexp program");
22 DEFINE_FLAG(
bool, log_okay,
false,
"log successful runs");
23 DEFINE_FLAG(
bool, dump_rprog,
false,
"dump reversed regexp program");
26 "maximum number of regexp test failures (-1 = unlimited)");
29 "pattern to select regexp engines to test");
60 static bool did_parse =
false;
64 return cached_engines;
71 cached_engines |= 1<<
i;
74 if (cached_engines == 0)
75 LOG(
INFO) <<
"Warning: no engines enabled.";
79 if (cached_engines & (1<<
i))
84 return cached_engines;
117 if (s.data() == NULL)
120 s.begin() -
text.begin(),
121 s.end() -
text.begin());
126 for (
size_t i = 0;
i <
text.size();
i++)
138 return "longest match";
140 return "first match";
187 : regexp_str_(regexp_str),
204 if (regexp_ == NULL) {
210 num_captures_ = regexp_->NumCaptures();
211 prog_ = regexp_->CompileToProg(0);
217 if (
GetFlag(FLAGS_dump_prog)) {
229 rprog_ = regexp_->CompileToReverseProg(0);
230 if (rprog_ == NULL) {
256 options.set_longest_match(
true);
258 if (!re2_->error().empty()) {
283 re_ =
new PCRE(
"("+re+
")", o);
284 if (!re_->error().empty()) {
292 TestInstance::~TestInstance() {
305 const StringPiece& orig_text,
306 const StringPiece& orig_context,
309 if (regexp_ == NULL) {
313 int nsubmatch = 1 + num_captures_;
317 StringPiece
text = orig_text;
318 StringPiece
context = orig_context;
330 prog_->UnsafeSearchBacktrack(
text,
context, anchor, kind_,
331 result->submatch, nsubmatch);
332 result->have_submatch =
true;
342 result->submatch, nsubmatch);
343 result->have_submatch =
true;
356 if (prog_ == NULL || rprog_ == NULL) {
367 Prog::kAnchored, Prog::kLongestMatch,
369 &
result->skipped, NULL)) {
370 LOG(
ERROR) <<
"Reverse DFA inconsistency: "
376 result->have_submatch0 =
true;
381 !prog_->IsOnePass() ||
382 anchor == Prog::kUnanchored ||
383 nsubmatch > Prog::kMaxOnePassCapture) {
388 result->submatch, nsubmatch);
389 result->have_submatch =
true;
394 !prog_->CanBitState()) {
399 result->submatch, nsubmatch);
400 result->have_submatch =
true;
411 RE2::Anchor re_anchor;
412 if (anchor == Prog::kAnchored)
413 re_anchor = RE2::ANCHOR_START;
415 re_anchor = RE2::UNANCHORED;
416 if (kind_ == Prog::kFullMatch)
417 re_anchor = RE2::ANCHOR_BOTH;
419 result->matched = re2_->Match(
421 static_cast<size_t>(
text.begin() -
context.begin()),
426 result->have_submatch = nsubmatch > 0;
441 if (regexp_str_.find(
"\\v") != StringPiece::npos &&
442 (
text.find(
'\n') != StringPiece::npos ||
443 text.find(
'\f') != StringPiece::npos ||
444 text.find(
'\r') != StringPiece::npos)) {
451 if ((regexp_str_.find(
"\\s") != StringPiece::npos ||
452 regexp_str_.find(
"\\S") != StringPiece::npos) &&
453 text.find(
'\v') != StringPiece::npos) {
460 for (
int i = 0;
i < nsubmatch;
i++) {
465 PCRE::Anchor pcre_anchor;
466 if (anchor == Prog::kAnchored)
467 pcre_anchor = PCRE::ANCHOR_START;
469 pcre_anchor = PCRE::UNANCHORED;
470 if (kind_ == Prog::kFullMatch)
471 pcre_anchor = PCRE::ANCHOR_BOTH;
472 re_->ClearHitLimit();
478 if (re_->HitLimit()) {
484 result->have_submatch =
true;
503 if (
r.have_submatch ||
r.have_submatch0) {
508 if (!
r.have_submatch)
516 bool TestInstance::RunCase(
const StringPiece&
text,
const StringPiece&
context,
517 Prog::Anchor anchor) {
521 if (correct.skipped) {
536 bool all_okay =
true;
545 LogMatch(
r.skipped ?
"Skipped: " :
"Okay: ",
i,
text,
context, anchor);
560 LogMatch(
r.untrusted ?
"(Untrusted) Mismatch: " :
"Mismatch: ",
i,
text,
562 if (
r.matched != correct.matched) {
564 LOG(
INFO) <<
" Should not match (but does).";
566 LOG(
INFO) <<
" Should match (but does not).";
570 for (
int i = 0;
i < 1+num_captures_;
i++) {
571 if (
r.submatch[
i].data() != correct.submatch[
i].data() ||
572 r.submatch[
i].size() != correct.submatch[
i].size()) {
589 static int max_regexp_failures =
GetFlag(FLAGS_max_regexp_failures);
590 if (max_regexp_failures > 0 && --max_regexp_failures == 0)
591 LOG(QFATAL) <<
"Too many regexp failures.";
597 void TestInstance::LogMatch(
const char*
prefix,
Engine e,
598 const StringPiece&
text,
const StringPiece&
context,
599 Prog::Anchor anchor) {
605 <<
CEscape(regexp_->ToString())
627 Tester::Tester(
const StringPiece& regexp) {
631 TestInstance* t =
new TestInstance(regexp,
kinds[
i],
640 for (
size_t i = 0;
i < v_.size();
i++)
645 Prog::Anchor anchor) {
647 for (
size_t i = 0;
i < v_.size();
i++)
657 bool Tester::TestInput(
const StringPiece&
text) {
658 bool okay = TestInputInContext(
text,
text);
663 okay &= TestInputInContext(sp,
text);
666 okay &= TestInputInContext(sp,
text);
671 bool Tester::TestInputInContext(
const StringPiece&
text,
680 const StringPiece&
text) {
682 return t.TestInput(
text);